Squash commits for public release
This commit is contained in:
232
utils/compilers/ConnectionCompiler/Generator/generator.py
Normal file
232
utils/compilers/ConnectionCompiler/Generator/generator.py
Normal file
@@ -0,0 +1,232 @@
|
||||
class Message:
|
||||
def __init__(self, name, id, reply_id, decoder_magic, params, protected=False):
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.reply_id = reply_id
|
||||
self.decoder_magic = decoder_magic
|
||||
self.params = params
|
||||
self.protected = protected
|
||||
|
||||
|
||||
class Generator:
|
||||
|
||||
def __init__(self):
|
||||
self.output = None
|
||||
|
||||
def out(self, str, tabs=0):
|
||||
for i in range(tabs):
|
||||
self.output.write(" ")
|
||||
self.output.write(str)
|
||||
self.output.write("\n")
|
||||
|
||||
def params_readable(self, params):
|
||||
res = ""
|
||||
if len(params) > 0:
|
||||
for i in params:
|
||||
res += "{0} {1},".format(i[0], i[1])
|
||||
res = res[:-1]
|
||||
return res
|
||||
|
||||
def message_create_std_funcs(self, msg):
|
||||
self.out("int id() const override {{ return {0}; }}".format(msg.id), 1)
|
||||
self.out("int reply_id() const override {{ return {0}; }}".format(
|
||||
msg.reply_id), 1)
|
||||
if msg.protected:
|
||||
self.out("int key() const override { return m_key; }", 1)
|
||||
self.out("int decoder_magic() const override {{ return {0}; }}".format(
|
||||
msg.decoder_magic), 1)
|
||||
for i in msg.params:
|
||||
if i[0] in ["int", "uint32_t", "bool", "int32_t"]:
|
||||
self.out(
|
||||
"{0} {1}() const {{ return m_{1}; }}".format(i[0], i[1]), 1)
|
||||
else:
|
||||
self.out(
|
||||
"{0}& {1}() {{ return m_{1}; }}".format(i[0], i[1]), 1)
|
||||
|
||||
def message_create_vars(self, msg):
|
||||
if msg.protected:
|
||||
self.out("message_key_t m_key;", 1)
|
||||
for i in msg.params:
|
||||
self.out("{0} m_{1};".format(i[0], i[1]), 1)
|
||||
|
||||
def message_create_constructor(self, msg):
|
||||
params = msg.params
|
||||
if msg.protected:
|
||||
params = [('message_key_t', 'key')] + msg.params
|
||||
res = "{0}({1})".format(msg.name, self.params_readable(params))
|
||||
if len(params) > 0:
|
||||
self.out(res, 1)
|
||||
sign = ':'
|
||||
for i in params:
|
||||
self.out("{0} m_{1}({1})".format(sign, i[1]), 2)
|
||||
sign = ','
|
||||
|
||||
self.out("{", 1)
|
||||
self.out("}", 1)
|
||||
else:
|
||||
self.out(res+" {}", 1)
|
||||
|
||||
def message_create_encoder(self, msg):
|
||||
self.out("EncodedMessage encode() const override".format(
|
||||
msg.decoder_magic), 1)
|
||||
self.out("{", 1)
|
||||
|
||||
self.out("EncodedMessage buffer;", 2)
|
||||
self.out("Encoder::append(buffer, decoder_magic());", 2)
|
||||
self.out("Encoder::append(buffer, id());", 2)
|
||||
if msg.protected:
|
||||
self.out("Encoder::append(buffer, key());", 2)
|
||||
for i in msg.params:
|
||||
self.out("Encoder::append(buffer, m_{0});".format(i[1]), 2)
|
||||
|
||||
self.out("return buffer;", 2)
|
||||
self.out("}", 1)
|
||||
|
||||
def generate_message(self, msg):
|
||||
self.out("class {0} : public Message {{".format(msg.name))
|
||||
self.out("public:")
|
||||
self.message_create_constructor(msg)
|
||||
self.message_create_std_funcs(msg)
|
||||
self.message_create_encoder(msg)
|
||||
self.out("private:")
|
||||
self.message_create_vars(msg)
|
||||
self.out("};")
|
||||
self.out("")
|
||||
|
||||
def decoder_create_vars(self, messages, offset=0):
|
||||
var_names = set()
|
||||
for (name, params) in messages.items():
|
||||
for i in params:
|
||||
if 'var_{0}'.format(i[1]) not in var_names:
|
||||
self.out("{0} var_{1};".format(i[0], i[1]), offset)
|
||||
var_names.add('var_{0}'.format(i[1]))
|
||||
|
||||
def decoder_decode_message(self, msg, offset=0):
|
||||
params_str = ""
|
||||
if msg.protected:
|
||||
params_str = "secret_key, "
|
||||
for i in msg.params:
|
||||
params_str += "var_{0}, ".format(i[1])
|
||||
|
||||
if len(params_str) > 0:
|
||||
params_str = params_str[:-2]
|
||||
for i in msg.params:
|
||||
self.out(
|
||||
"Encoder::decode(buf, decoded_msg_len, var_{0});".format(i[1]), offset)
|
||||
self.out("return new {0}({1});".format(msg.name, params_str), offset)
|
||||
|
||||
def decoder_create_std_funcs(self, decoder):
|
||||
self.out("int magic() const {{ return {0}; }}".format(
|
||||
decoder.magic), 1)
|
||||
|
||||
def decoder_create_decode(self, decoder):
|
||||
self.out(
|
||||
"std::unique_ptr<Message> decode(const char* buf, size_t size, size_t& decoded_msg_len) override", 1)
|
||||
self.out("{", 1)
|
||||
self.out("int msg_id, decoder_magic;", 2)
|
||||
self.out("size_t saved_dml = decoded_msg_len;", 2)
|
||||
self.out("Encoder::decode(buf, decoded_msg_len, decoder_magic);", 2)
|
||||
self.out("Encoder::decode(buf, decoded_msg_len, msg_id);", 2)
|
||||
self.out("if (magic() != decoder_magic) {", 2)
|
||||
self.out("decoded_msg_len = saved_dml;", 3)
|
||||
self.out("return nullptr;", 3)
|
||||
self.out("}", 2)
|
||||
|
||||
if decoder.protected:
|
||||
self.out("message_key_t secret_key;", 2)
|
||||
self.out("Encoder::decode(buf, decoded_msg_len, secret_key);", 2)
|
||||
self.out("", 0)
|
||||
|
||||
self.decoder_create_vars(decoder.messages, 2)
|
||||
|
||||
unique_msg_id = 1
|
||||
self.out("", 2)
|
||||
self.out("switch(msg_id) {", 2)
|
||||
for (name, params) in decoder.messages.items():
|
||||
self.out("case {0}:".format(unique_msg_id), 2)
|
||||
# Here it doen't need to know the real reply_id, so we can put 0 here.
|
||||
self.decoder_decode_message(
|
||||
Message(name, unique_msg_id, 0, decoder.magic, params, decoder.protected), 3)
|
||||
unique_msg_id += 1
|
||||
|
||||
self.out("default:", 2)
|
||||
self.out("decoded_msg_len = saved_dml;", 3)
|
||||
self.out("return nullptr;", 3)
|
||||
self.out("}", 2)
|
||||
self.out("}", 1)
|
||||
self.out("", 1)
|
||||
|
||||
def decoder_create_handle(self, decoder):
|
||||
self.out("std::unique_ptr<Message> handle(Message& msg) override", 1)
|
||||
self.out("{", 1)
|
||||
self.out("if (magic() != msg.decoder_magic()) {", 2)
|
||||
self.out("return nullptr;", 3)
|
||||
self.out("}", 2)
|
||||
|
||||
unique_msg_id = 1
|
||||
self.out("", 2)
|
||||
self.out("switch(msg.id()) {", 2)
|
||||
for (name, params) in decoder.messages.items():
|
||||
if name in decoder.functions:
|
||||
self.out("case {0}:".format(unique_msg_id), 2)
|
||||
self.out(
|
||||
"return handle(static_cast<{0}&>(msg));".format(name), 3)
|
||||
|
||||
unique_msg_id += 1
|
||||
|
||||
self.out("default:", 2)
|
||||
self.out("return nullptr;", 3)
|
||||
self.out("}", 2)
|
||||
self.out("}", 1)
|
||||
self.out("", 1)
|
||||
|
||||
def decoder_create_virtual_handle(self, decoder):
|
||||
for (accept, ret) in decoder.functions.items():
|
||||
self.out(
|
||||
"virtual std::unique_ptr<Message> handle({0}& msg) {{ return nullptr; }}".format(accept), 1)
|
||||
|
||||
def generate_decoder(self, decoder):
|
||||
self.out("class {0} : public MessageDecoder {{".format(decoder.name))
|
||||
self.out("public:")
|
||||
self.out("{0}() {{}}".format(decoder.name), 1)
|
||||
self.decoder_create_std_funcs(decoder)
|
||||
self.decoder_create_decode(decoder)
|
||||
self.decoder_create_handle(decoder)
|
||||
self.decoder_create_virtual_handle(decoder)
|
||||
self.out("};")
|
||||
self.out("")
|
||||
|
||||
def includes(self):
|
||||
self.out("// Auto generated with utils/ConnectionCompiler")
|
||||
self.out("// See .ipc file")
|
||||
self.out("")
|
||||
self.out("#pragma once")
|
||||
self.out("#include <libipc/Encoder.h>")
|
||||
self.out("#include <libipc/ClientConnection.h>")
|
||||
self.out("#include <libipc/ServerConnection.h>")
|
||||
self.out("#include <libipc/StringEncoder.h>")
|
||||
self.out("#include <libipc/VectorEncoder.h>")
|
||||
self.out("#include <new>")
|
||||
self.out("#include <libg/Rect.h>")
|
||||
self.out("")
|
||||
|
||||
def generate(self, filename, decoders):
|
||||
self.output = open(filename, "w+")
|
||||
self.includes()
|
||||
for decoder in decoders:
|
||||
msgd = {}
|
||||
unique_msg_id = 1
|
||||
for (name, params) in decoder.messages.items():
|
||||
msgd[name] = unique_msg_id
|
||||
unique_msg_id += 1
|
||||
|
||||
for (name, params) in decoder.messages.items():
|
||||
reply_name = decoder.functions.get(name, None)
|
||||
reply_id = -1
|
||||
if reply_name is not None:
|
||||
reply_id = msgd[reply_name]
|
||||
self.generate_message(
|
||||
Message(name, msgd[name], reply_id, decoder.magic, params, decoder.protected))
|
||||
|
||||
self.generate_decoder(decoder)
|
||||
self.output.close()
|
||||
108
utils/compilers/ConnectionCompiler/Lexer/lexer.py
Normal file
108
utils/compilers/ConnectionCompiler/Lexer/lexer.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from token import Token
|
||||
from Lexer.reserved_symbols import *
|
||||
from type_file import Type
|
||||
|
||||
|
||||
class Lexer():
|
||||
MAX_OPERATION_SIZE = 2
|
||||
|
||||
def __init__(self, code: [str]):
|
||||
self.code = code
|
||||
self.current_code_part = code[0]
|
||||
self.current_code_line = 0
|
||||
self.code_lines = len(code)
|
||||
self.current_position = 0
|
||||
self.current_char = self.current_code_part[self.current_position]
|
||||
|
||||
def advance(self):
|
||||
self.current_position += 1
|
||||
if self.current_position < len(self.current_code_part):
|
||||
self.current_char = self.current_code_part[self.current_position]
|
||||
else:
|
||||
self.current_code_line += 1
|
||||
if self.current_code_line < self.code_lines:
|
||||
self.current_code_part = self.code[self.current_code_line]
|
||||
self.current_position = 0
|
||||
self.current_char = self.current_code_part[0]
|
||||
else:
|
||||
self.current_char = None
|
||||
|
||||
def skip_rest_of_line(self):
|
||||
start_with_line = self.current_code_line
|
||||
while self.current_char is not None and self.current_code_line == start_with_line:
|
||||
self.advance()
|
||||
|
||||
def lookup(self, count):
|
||||
peek_pos = self.current_position + count
|
||||
if peek_pos < len(self.current_code_part):
|
||||
return self.current_code_part[peek_pos]
|
||||
else:
|
||||
return None
|
||||
|
||||
def skip_gaps(self):
|
||||
while self.current_char is not None and self.current_char == ' ':
|
||||
self.advance()
|
||||
|
||||
def read_number(self):
|
||||
result = ""
|
||||
was_dot = False
|
||||
while self.current_char is not None and (self.current_char.isdigit() or self.current_char == '.'):
|
||||
if self.current_char == '.':
|
||||
if was_dot:
|
||||
print(">2 dots in number")
|
||||
exit(0)
|
||||
was_dot = True
|
||||
result += self.current_char
|
||||
self.advance()
|
||||
if was_dot:
|
||||
return Token(Type.Number.Real, float(result))
|
||||
else:
|
||||
return Token(Type.Number.Integer, int(result))
|
||||
|
||||
def read_word(self):
|
||||
type = Type.Word
|
||||
result = ""
|
||||
while self.current_char is not None and (self.current_char.isalpha() or self.current_char.isdigit() or self.current_char == '_' or self.current_char == '<' or self.current_char == '>' or (self.current_char == ':' and self.lookup(1) == ':')):
|
||||
if (self.current_char == ':'):
|
||||
result += self.current_char
|
||||
self.advance()
|
||||
result += self.current_char
|
||||
self.advance()
|
||||
|
||||
if result.upper() in reserved_words:
|
||||
return Token(reserved_words[result.upper()], result.upper())
|
||||
|
||||
return Token(type, result)
|
||||
|
||||
def read_operation(self):
|
||||
token = Token()
|
||||
operation = ""
|
||||
for i in range(self.MAX_OPERATION_SIZE):
|
||||
next_element = self.lookup(i)
|
||||
if next_element is None:
|
||||
break
|
||||
operation += next_element
|
||||
if operation in reserved_symbols.keys():
|
||||
token = Token(reserved_symbols[operation], operation)
|
||||
|
||||
if token.value is not None:
|
||||
for i in range(len(token.value)):
|
||||
self.advance()
|
||||
|
||||
return token
|
||||
|
||||
def next_token(self):
|
||||
self.skip_gaps()
|
||||
|
||||
while self.current_char == '#':
|
||||
self.skip_rest_of_line()
|
||||
self.skip_gaps()
|
||||
|
||||
if self.current_char is None:
|
||||
return Token(Type.Special.EOF, None)
|
||||
elif self.current_char.isdigit():
|
||||
return self.read_number()
|
||||
elif self.current_char.isalpha():
|
||||
return self.read_word()
|
||||
else:
|
||||
return self.read_operation()
|
||||
24
utils/compilers/ConnectionCompiler/Lexer/reserved_symbols.py
Normal file
24
utils/compilers/ConnectionCompiler/Lexer/reserved_symbols.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from type_file import Type
|
||||
|
||||
reserved_symbols = {
|
||||
'(': Type.Lang.LeftBracket,
|
||||
')': Type.Lang.RightBracket,
|
||||
';': Type.Lang.Semi,
|
||||
'.': Type.Lang.Dot,
|
||||
',': Type.Lang.Comma,
|
||||
':': Type.Lang.Colon,
|
||||
|
||||
'=>': Type.Reserved.Return,
|
||||
|
||||
'{': Type.Reserved.Begin,
|
||||
'}': Type.Reserved.End,
|
||||
}
|
||||
|
||||
reserved_words = {
|
||||
'NAME': Type.Reserved.Name,
|
||||
'MAGIC': Type.Reserved.Magic,
|
||||
'KEYPROTECTED': Type.Reserved.KeyProtected,
|
||||
}
|
||||
|
||||
available_var_types = [Type.Number.Integer,
|
||||
Type.Number.Real, Type.Number.Boolean]
|
||||
140
utils/compilers/ConnectionCompiler/Parser/parser.py
Normal file
140
utils/compilers/ConnectionCompiler/Parser/parser.py
Normal file
@@ -0,0 +1,140 @@
|
||||
from Lexer.lexer import Lexer
|
||||
from token import Token
|
||||
from type_file import Type
|
||||
from connection import Connection
|
||||
|
||||
|
||||
class Parser:
|
||||
|
||||
def set_code_lines(self, code: [str]):
|
||||
self.lexer = Lexer(code)
|
||||
self.token = Token()
|
||||
self.current_token_id = -1
|
||||
self.read_tokens = 0
|
||||
self.lexer_rich_the_end = 0
|
||||
self.tokens = []
|
||||
self.next_token()
|
||||
|
||||
def next_token(self):
|
||||
self.current_token_id += 1
|
||||
self.token = self.get_token_at(self.current_token_id)
|
||||
|
||||
def get_token_at(self, pos):
|
||||
if pos >= self.read_tokens and not self.lexer_rich_the_end:
|
||||
for i in range(pos - self.read_tokens + 1):
|
||||
self.tokens.append(self.lexer.next_token())
|
||||
self.read_tokens += 1
|
||||
if self.tokens[-1].type == Type.Special.EOF:
|
||||
self.lexer_rich_the_end = True
|
||||
break
|
||||
|
||||
return self.tokens[min(pos, self.read_tokens - 1)]
|
||||
|
||||
def is_nth(self, type_of_token, n):
|
||||
if isinstance(type_of_token, list):
|
||||
for type_of_cur_token in type_of_token:
|
||||
if self.get_token_at(self.current_token_id+n).type == type_of_cur_token:
|
||||
return True
|
||||
return False
|
||||
return self.get_token_at(self.current_token_id+n).type == type_of_token
|
||||
|
||||
def is_next(self, type_of_token):
|
||||
if isinstance(type_of_token, list):
|
||||
for type_of_cur_token in type_of_token:
|
||||
if self.token.type == type_of_cur_token:
|
||||
return True
|
||||
return False
|
||||
return self.token.type == type_of_token
|
||||
|
||||
def must_next(self, type_of_token):
|
||||
if not self.is_next(type_of_token):
|
||||
print("{0} is not {1}".format(self.token, type_of_token))
|
||||
exit(1)
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def eat_name(self):
|
||||
self.must_next(Type.Reserved.Name)
|
||||
self.next_token()
|
||||
self.must_next(Type.Lang.Colon)
|
||||
self.next_token()
|
||||
self.must_next(Type.Word)
|
||||
res = self.token.value
|
||||
self.next_token()
|
||||
return res
|
||||
|
||||
def eat_protected(self):
|
||||
if (self.is_next(Type.Reserved.KeyProtected)):
|
||||
self.next_token()
|
||||
return True
|
||||
return False
|
||||
|
||||
def eat_magic(self):
|
||||
self.must_next(Type.Reserved.Magic)
|
||||
self.next_token()
|
||||
self.must_next(Type.Lang.Colon)
|
||||
self.next_token()
|
||||
self.must_next(Type.Number.Integer)
|
||||
res = self.token.value
|
||||
self.next_token()
|
||||
return res
|
||||
|
||||
def eat_params(self):
|
||||
params = []
|
||||
self.must_next(Type.Lang.LeftBracket)
|
||||
self.next_token()
|
||||
while not self.is_next(Type.Lang.RightBracket):
|
||||
self.must_next(Type.Word)
|
||||
typ = self.token.value
|
||||
self.next_token()
|
||||
|
||||
self.must_next(Type.Word)
|
||||
nam = self.token.value
|
||||
self.next_token()
|
||||
|
||||
params.append([typ, nam])
|
||||
|
||||
if self.is_next(Type.Lang.Comma):
|
||||
self.must_next(Type.Lang.Comma)
|
||||
self.next_token()
|
||||
|
||||
self.must_next(Type.Lang.RightBracket)
|
||||
self.next_token()
|
||||
return params
|
||||
|
||||
def eat_message(self, decoder):
|
||||
self.must_next(Type.Word)
|
||||
msgname = self.token.value
|
||||
self.next_token()
|
||||
decoder.add_message(msgname, self.eat_params())
|
||||
return msgname
|
||||
|
||||
def eat_function(self, decoder):
|
||||
ms1 = self.eat_message(decoder)
|
||||
ms2 = None
|
||||
|
||||
if self.is_next(Type.Reserved.Return):
|
||||
self.must_next(Type.Reserved.Return)
|
||||
self.next_token()
|
||||
ms2 = self.eat_message(decoder)
|
||||
|
||||
decoder.add_function(ms1, ms2)
|
||||
|
||||
def eat_decoder(self):
|
||||
self.must_next(Type.Reserved.Begin)
|
||||
self.next_token()
|
||||
is_protected = self.eat_protected()
|
||||
decoder = Connection(self.eat_name(), self.eat_magic(), is_protected)
|
||||
while not self.is_next(Type.Reserved.End):
|
||||
self.eat_function(decoder)
|
||||
self.must_next(Type.Reserved.End)
|
||||
self.next_token()
|
||||
return decoder
|
||||
|
||||
def parse(self):
|
||||
decoders = []
|
||||
while self.is_next(Type.Reserved.Begin):
|
||||
decoders.append(self.eat_decoder())
|
||||
print("connc: {0} decoders parsed!".format(len(decoders)))
|
||||
return decoders
|
||||
30
utils/compilers/ConnectionCompiler/__main__.py
Normal file
30
utils/compilers/ConnectionCompiler/__main__.py
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from Parser.parser import Parser
|
||||
from Generator.generator import Generator
|
||||
from type_file import Type
|
||||
from token import Token
|
||||
import argparse
|
||||
|
||||
def run(input_f, output_f):
|
||||
|
||||
code = []
|
||||
|
||||
file = open(input_f, "r")
|
||||
for line in file:
|
||||
line = line.replace('\n', '')
|
||||
if len(line) > 0:
|
||||
code.append(line)
|
||||
|
||||
parser = Parser()
|
||||
gen = Generator()
|
||||
parser.set_code_lines(code)
|
||||
gen.generate(output_f, parser.parse())
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('inf', type=str, help='Input file')
|
||||
parser.add_argument('outf', type=str, help='Output file')
|
||||
|
||||
args = parser.parse_args()
|
||||
run(args.inf, args.outf)
|
||||
30
utils/compilers/ConnectionCompiler/connc
Normal file
30
utils/compilers/ConnectionCompiler/connc
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from Parser.parser import Parser
|
||||
from Generator.generator import Generator
|
||||
from type_file import Type
|
||||
from token import Token
|
||||
import argparse
|
||||
|
||||
def run(input_f, output_f):
|
||||
|
||||
code = []
|
||||
|
||||
file = open(input_f, "r")
|
||||
for line in file:
|
||||
line = line.replace('\n', '')
|
||||
if len(line) > 0:
|
||||
code.append(line)
|
||||
|
||||
parser = Parser()
|
||||
gen = Generator()
|
||||
parser.set_code_lines(code)
|
||||
gen.generate(output_f, parser.parse())
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('inf', type=str, help='Input file')
|
||||
parser.add_argument('outf', type=str, help='Output file')
|
||||
|
||||
args = parser.parse_args()
|
||||
run(args.inf, args.outf)
|
||||
21
utils/compilers/ConnectionCompiler/connection.py
Normal file
21
utils/compilers/ConnectionCompiler/connection.py
Normal file
@@ -0,0 +1,21 @@
|
||||
class Connection:
|
||||
def __init__(self, name, magic, protected=False):
|
||||
self.name = name
|
||||
self.magic = magic
|
||||
self.protected = protected
|
||||
self.messages = {}
|
||||
self.functions = {}
|
||||
|
||||
def add_message(self, msg_name, params):
|
||||
if msg_name in self.messages:
|
||||
op = self.messages[msg_name]
|
||||
if (params != op):
|
||||
print("{0} has 2 different params".format(msg1_name))
|
||||
exit(1)
|
||||
self.messages[msg_name] = params
|
||||
|
||||
def add_function(self, msg1_name, msg2_name=None):
|
||||
if msg1_name in self.functions:
|
||||
print("{0} has 2 functions".format(msg1_name))
|
||||
exit(1)
|
||||
self.functions[msg1_name] = msg2_name
|
||||
8
utils/compilers/ConnectionCompiler/token.py
Normal file
8
utils/compilers/ConnectionCompiler/token.py
Normal file
@@ -0,0 +1,8 @@
|
||||
class Token:
|
||||
|
||||
def __init__(self, type=None, value=None):
|
||||
self.type = type
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return "Token({0}, {1})".format(self.type, self.value)
|
||||
39
utils/compilers/ConnectionCompiler/type_file.py
Normal file
39
utils/compilers/ConnectionCompiler/type_file.py
Normal file
@@ -0,0 +1,39 @@
|
||||
class Type:
|
||||
|
||||
Word = 'WORD'
|
||||
|
||||
class Number:
|
||||
Integer = 'INTEGER'
|
||||
Real = 'REAL'
|
||||
Boolean = 'BOOLEAN'
|
||||
|
||||
class BinaryOperation:
|
||||
Plus = 'PLUS'
|
||||
Minus = 'MINUS'
|
||||
Mul = 'MUL'
|
||||
Div = 'DIV'
|
||||
|
||||
class UnaryOperation:
|
||||
fill = 'FILL'
|
||||
Plus = 'PLUS'
|
||||
Minus = 'MINUS'
|
||||
Not = 'NOT'
|
||||
|
||||
class Lang:
|
||||
LeftBracket = 'LeftBracket'
|
||||
RightBracket = 'RightBracket'
|
||||
Semi = 'SEMI'
|
||||
Dot = 'DOT'
|
||||
Comma = 'COMMA'
|
||||
Colon = 'COLON'
|
||||
|
||||
class Reserved:
|
||||
Begin = 'BEGIN'
|
||||
End = 'END'
|
||||
Return = 'RETURN'
|
||||
Name = 'NAME'
|
||||
Magic = 'MAGIC'
|
||||
KeyProtected = 'KEYP'
|
||||
|
||||
class Special:
|
||||
EOF = 'EOF'
|
||||
39
utils/compilers/DevTreeCompiler/ABI/Structs.py
Normal file
39
utils/compilers/DevTreeCompiler/ABI/Structs.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from construct import *
|
||||
|
||||
DEVTREE_HEADER_SIGNATURE = "odtr3"
|
||||
|
||||
DEVTREE_HEADER = Struct(
|
||||
"signature" / PaddedString(8, "ascii"),
|
||||
"revision" / Int32ul,
|
||||
"flags" / Int32ul,
|
||||
"entries_count" / Int32ul,
|
||||
"name_list_offset" / Int32ul
|
||||
)
|
||||
|
||||
DEVTREE_ENTRY_FLAGS_MMIO = (1 << 0)
|
||||
DEVTREE_ENTRY_TYPE_IO = 0
|
||||
DEVTREE_ENTRY_TYPE_FB = 1
|
||||
DEVTREE_ENTRY_TYPE_UART = 2
|
||||
DEVTREE_ENTRY_TYPE_RAM = 3
|
||||
DEVTREE_ENTRY_TYPE_STORAGE = 4
|
||||
DEVTREE_ENTRY_TYPE_BUS_CONTROLLER = 5
|
||||
DEVTREE_ENTRY_TYPE_RTC = 6
|
||||
|
||||
# Currently flags maps to irq_flags_t in the kernel.
|
||||
# Later we might need to enhance irq_flags_from_devtree() to use as translator.
|
||||
DEVTREE_IRQ_FLAGS_EDGE_TRIGGER = (1 << 0)
|
||||
|
||||
DEVTREE_ENTRY = Struct(
|
||||
"type" / Int32ul,
|
||||
"flags" / Int32ul,
|
||||
"region_base" / Int64ul,
|
||||
"region_size" / Int64ul,
|
||||
"irq_lane" / Int32ul,
|
||||
"irq_flags" / Int32ul,
|
||||
"irq_priority" / Int32ul,
|
||||
"rel_name_offset" / Int32ul,
|
||||
"aux1" / Int64ul,
|
||||
"aux2" / Int64ul,
|
||||
"aux3" / Int64ul,
|
||||
"aux4" / Int64ul,
|
||||
)
|
||||
47
utils/compilers/DevTreeCompiler/ABI/Translation.py
Normal file
47
utils/compilers/DevTreeCompiler/ABI/Translation.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from ABI.Structs import *
|
||||
|
||||
|
||||
class Translator():
|
||||
|
||||
@staticmethod
|
||||
def entry_flag_translator(s):
|
||||
translation = {
|
||||
"MMIO": DEVTREE_ENTRY_FLAGS_MMIO,
|
||||
}
|
||||
return translation.get(s, 0)
|
||||
|
||||
@staticmethod
|
||||
def irq_flag_translator(s):
|
||||
translation = {
|
||||
"EDGE_TRIGGER": DEVTREE_IRQ_FLAGS_EDGE_TRIGGER,
|
||||
}
|
||||
return translation.get(s, 0)
|
||||
|
||||
@staticmethod
|
||||
def entry_type(s):
|
||||
translation = {
|
||||
"IO": DEVTREE_ENTRY_TYPE_IO,
|
||||
"FB": DEVTREE_ENTRY_TYPE_FB,
|
||||
"UART": DEVTREE_ENTRY_TYPE_UART,
|
||||
"RAM": DEVTREE_ENTRY_TYPE_RAM,
|
||||
"STORAGE": DEVTREE_ENTRY_TYPE_STORAGE,
|
||||
"BUS_CONTROLLER": DEVTREE_ENTRY_TYPE_BUS_CONTROLLER,
|
||||
"RTC": DEVTREE_ENTRY_TYPE_RTC
|
||||
}
|
||||
return translation.get(s, DEVTREE_ENTRY_TYPE_IO)
|
||||
|
||||
@staticmethod
|
||||
def number(s):
|
||||
return int(s, base=0)
|
||||
|
||||
@staticmethod
|
||||
def flags(s, flagcb):
|
||||
flags = 0x0
|
||||
ents = s.split(" ")
|
||||
|
||||
for ent in ents:
|
||||
t = flagcb(s)
|
||||
if t != None:
|
||||
flags |= t
|
||||
|
||||
return flags
|
||||
24
utils/compilers/DevTreeCompiler/DevTreeCompiler.py
Normal file
24
utils/compilers/DevTreeCompiler/DevTreeCompiler.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from Parser.Parser import Parser
|
||||
from Generator.IRManager import IRManager
|
||||
from Generator.BinWriter import BinWriter
|
||||
from Generator.CWriter import CWriter
|
||||
from Generator.Compiler import Compiler
|
||||
import argparse
|
||||
|
||||
class DevTreeCompiler():
|
||||
|
||||
@staticmethod
|
||||
def compile(input_f, output_f):
|
||||
parser = Parser(input_f)
|
||||
irmng = IRManager(parser)
|
||||
compiler = Compiler(irmng)
|
||||
binw = BinWriter(output_f)
|
||||
binw.write(compiler.compile())
|
||||
|
||||
@staticmethod
|
||||
def to_c_arr(input_f):
|
||||
parser = Parser(input_f)
|
||||
irmng = IRManager(parser)
|
||||
compiler = Compiler(irmng)
|
||||
binw = CWriter()
|
||||
binw.write(compiler.compile())
|
||||
8
utils/compilers/DevTreeCompiler/Generator/BinWriter.py
Normal file
8
utils/compilers/DevTreeCompiler/Generator/BinWriter.py
Normal file
@@ -0,0 +1,8 @@
|
||||
class BinWriter():
|
||||
def __init__(self, output_file):
|
||||
self.output_file = output_file
|
||||
|
||||
def write(self, data):
|
||||
binfile = open(self.output_file, "wb")
|
||||
binfile.write(bytes(data))
|
||||
binfile.close()
|
||||
9
utils/compilers/DevTreeCompiler/Generator/CWriter.py
Normal file
9
utils/compilers/DevTreeCompiler/Generator/CWriter.py
Normal file
@@ -0,0 +1,9 @@
|
||||
class CWriter():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def write(self, data):
|
||||
print("static uint8_t _devtree_raw[] = {")
|
||||
for byte in bytearray(data):
|
||||
print(hex(byte), end = ",")
|
||||
print("0x0};")
|
||||
110
utils/compilers/DevTreeCompiler/Generator/Compiler.py
Normal file
110
utils/compilers/DevTreeCompiler/Generator/Compiler.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from Generator.IRManager import IRManager
|
||||
from ABI.Structs import *
|
||||
from ABI.Translation import *
|
||||
|
||||
|
||||
class Compiler():
|
||||
__debug = False
|
||||
|
||||
def __init__(self, irmng):
|
||||
self.irmng = irmng
|
||||
|
||||
self.res_binarr = bytearray()
|
||||
self.header_binarr = bytearray()
|
||||
self.devs_binarr = bytearray()
|
||||
self.names_binarr = bytearray()
|
||||
|
||||
def build_header(self):
|
||||
count_of_devs = len(self.irmng.device_list())
|
||||
|
||||
result = {
|
||||
"signature": DEVTREE_HEADER_SIGNATURE,
|
||||
"revision": 1,
|
||||
"flags": 0,
|
||||
"entries_count": count_of_devs,
|
||||
"name_list_offset": DEVTREE_HEADER.sizeof() + len(self.devs_binarr),
|
||||
}
|
||||
|
||||
self.header_binarr = DEVTREE_HEADER.build(result)
|
||||
|
||||
def build_dev(self, dev):
|
||||
result = {
|
||||
"type": 0,
|
||||
"flags": 0,
|
||||
"region_base": 0,
|
||||
"region_size": 0,
|
||||
"irq_lane": 0,
|
||||
"irq_flags": 0,
|
||||
"irq_priority": 0,
|
||||
"rel_name_offset": len(self.names_binarr),
|
||||
"aux1": 0,
|
||||
"aux2": 0,
|
||||
"aux3": 0,
|
||||
"aux4": 0,
|
||||
}
|
||||
|
||||
if "type" in dev:
|
||||
result["type"] = Translator.entry_type(dev["type"])
|
||||
|
||||
if "flags" in dev:
|
||||
result["flags"] = Translator.flags(
|
||||
dev["flags"], Translator.entry_flag_translator)
|
||||
|
||||
if "mem" in dev:
|
||||
devmem = dev["mem"]
|
||||
if "base" in devmem:
|
||||
result["region_base"] = Translator.number(devmem["base"])
|
||||
if "size" in devmem:
|
||||
result["region_size"] = Translator.number(devmem["size"])
|
||||
|
||||
if "irq" in dev:
|
||||
devint = dev["irq"]
|
||||
if "lane" in devint:
|
||||
result["irq_lane"] = Translator.number(devint["lane"])
|
||||
if "flags" in devint:
|
||||
result["irq_flags"] = Translator.flags(
|
||||
devint["flags"], Translator.irq_flag_translator)
|
||||
if "priority" in devint:
|
||||
result["irq_priority"] = Translator.number(devint["priority"])
|
||||
|
||||
if "aux1" in dev:
|
||||
result["aux1"] = Translator.number(dev["aux1"])
|
||||
if "aux2" in dev:
|
||||
result["aux2"] = Translator.number(dev["aux2"])
|
||||
if "aux3" in dev:
|
||||
result["aux3"] = Translator.number(dev["aux3"])
|
||||
if "aux4" in dev:
|
||||
result["aux4"] = Translator.number(dev["aux4"])
|
||||
|
||||
self.devs_binarr += DEVTREE_ENTRY.build(result)
|
||||
self.names_binarr += bytearray((map(ord,
|
||||
dev["name"]))) + bytearray([0])
|
||||
|
||||
def build_dev_list(self):
|
||||
self.devs_binarr = bytearray()
|
||||
self.names_binarr = bytearray()
|
||||
for dev in self.irmng.device_list():
|
||||
self.build_dev(dev)
|
||||
|
||||
def build_binarr(self):
|
||||
self.res_binarr = bytearray()
|
||||
self.header_binarr = bytearray()
|
||||
self.devs_binarr = bytearray()
|
||||
self.names_binarr = bytearray()
|
||||
|
||||
self.build_dev_list()
|
||||
self.build_header()
|
||||
|
||||
self.res_binarr = self.header_binarr + self.devs_binarr + self.names_binarr
|
||||
|
||||
if self.__debug:
|
||||
print("Header", self.header_binarr)
|
||||
print("Devs", self.devs_binarr)
|
||||
print("Names", self.names_binarr)
|
||||
print("Res", self.res_binarr)
|
||||
|
||||
def compile(self):
|
||||
if len(self.res_binarr) == 0:
|
||||
self.build_binarr()
|
||||
|
||||
return self.res_binarr
|
||||
12
utils/compilers/DevTreeCompiler/Generator/IRManager.py
Normal file
12
utils/compilers/DevTreeCompiler/Generator/IRManager.py
Normal file
@@ -0,0 +1,12 @@
|
||||
class IRManager():
|
||||
def __init__(self, parser):
|
||||
self.parser = parser
|
||||
|
||||
def platform_name(self):
|
||||
return self.parser.data()["name"]
|
||||
|
||||
def device_count(self):
|
||||
return len(self.parser.data()["devices"])
|
||||
|
||||
def device_list(self):
|
||||
return self.parser.data()["devices"]
|
||||
20
utils/compilers/DevTreeCompiler/Parser/Parser.py
Normal file
20
utils/compilers/DevTreeCompiler/Parser/Parser.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import json
|
||||
|
||||
class Parser():
|
||||
def __init__(self, input_file):
|
||||
self.decoded_data = None
|
||||
self.input_file = input_file
|
||||
|
||||
def data(self):
|
||||
if self.decoded_data is None:
|
||||
f = open(self.input_file)
|
||||
self.decoded_data = json.load(f)
|
||||
f.close()
|
||||
|
||||
return self.decoded_data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
18
utils/compilers/DevTreeCompiler/__main__.py
Normal file
18
utils/compilers/DevTreeCompiler/__main__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from DevTreeCompiler import DevTreeCompiler
|
||||
import argparse
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('i', type=str, help='Input file')
|
||||
parser.add_argument('o', type=str, help='Output file')
|
||||
parser.add_argument('--dumpc', action='store_true',
|
||||
help='Dumping C array')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.dumpc:
|
||||
DevTreeCompiler.to_c_arr(args.i)
|
||||
else:
|
||||
DevTreeCompiler.compile(args.i, args.o)
|
||||
Reference in New Issue
Block a user