mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-protocol
synced 2025-12-26 14:18:31 +00:00
Initial import of spice protocol description and demarshall generator
The "spice.proto" file describes in detail the networking prototcol that spice uses and spice_codegen.py can parse this and generate demarshallers for such network messages.
This commit is contained in:
commit
b1dc7fae2a
0
python_modules/__init__.py
Normal file
0
python_modules/__init__.py
Normal file
354
python_modules/codegen.py
Normal file
354
python_modules/codegen.py
Normal file
@ -0,0 +1,354 @@
|
||||
from cStringIO import StringIO
|
||||
|
||||
def camel_to_underscores(s, upper = False):
|
||||
res = ""
|
||||
for i in range(len(s)):
|
||||
c = s[i]
|
||||
if i > 0 and c.isupper():
|
||||
res = res + "_"
|
||||
if upper:
|
||||
res = res + c.upper()
|
||||
else:
|
||||
res = res + c.lower()
|
||||
return res
|
||||
|
||||
def underscores_to_camel(s):
|
||||
res = ""
|
||||
do_upper = True
|
||||
for i in range(len(s)):
|
||||
c = s[i]
|
||||
if c == "_":
|
||||
do_upper = True
|
||||
else:
|
||||
if do_upper:
|
||||
res = res + c.upper()
|
||||
else:
|
||||
res = res + c
|
||||
do_upper = False
|
||||
return res
|
||||
|
||||
proto_prefix = "Temp"
|
||||
|
||||
def set_prefix(prefix):
|
||||
global proto_prefix
|
||||
global proto_prefix_upper
|
||||
global proto_prefix_lower
|
||||
proto_prefix = prefix
|
||||
proto_prefix_upper = prefix.upper()
|
||||
proto_prefix_lower = prefix.lower()
|
||||
|
||||
def prefix_underscore_upper(*args):
|
||||
s = proto_prefix_upper
|
||||
for arg in args:
|
||||
s = s + "_" + arg
|
||||
return s
|
||||
|
||||
def prefix_underscore_lower(*args):
|
||||
s = proto_prefix_lower
|
||||
for arg in args:
|
||||
s = s + "_" + arg
|
||||
return s
|
||||
|
||||
def prefix_camel(*args):
|
||||
s = proto_prefix
|
||||
for arg in args:
|
||||
s = s + underscores_to_camel(arg)
|
||||
return s
|
||||
|
||||
def increment_identifier(idf):
|
||||
v = idf[-1:]
|
||||
if v.isdigit():
|
||||
return idf[:-1] + str(int(v) + 1)
|
||||
return idf + "2"
|
||||
|
||||
def sum_array(array):
|
||||
if len(array) == 0:
|
||||
return 0
|
||||
return " + ".join(array)
|
||||
|
||||
class CodeWriter:
|
||||
def __init__(self):
|
||||
self.out = StringIO()
|
||||
self.contents = [self.out]
|
||||
self.indentation = 0
|
||||
self.at_line_start = True
|
||||
self.indexes = ["i", "j", "k", "ii", "jj", "kk"]
|
||||
self.current_index = 0
|
||||
self.generated = {}
|
||||
self.vars = []
|
||||
self.has_error_check = False
|
||||
self.options = {}
|
||||
self.function_helper_writer = None
|
||||
|
||||
def set_option(self, opt, value = True):
|
||||
self.options[opt] = value
|
||||
|
||||
def has_option(self, opt):
|
||||
return self.options.has_key(opt)
|
||||
|
||||
def set_is_generated(self, kind, name):
|
||||
if not self.generated.has_key(kind):
|
||||
v = {}
|
||||
self.generated[kind] = v
|
||||
else:
|
||||
v = self.generated[kind]
|
||||
v[name] = 1
|
||||
|
||||
def is_generated(self, kind, name):
|
||||
if not self.generated.has_key(kind):
|
||||
return False
|
||||
v = self.generated[kind]
|
||||
return v.has_key(name)
|
||||
|
||||
def getvalue(self):
|
||||
strs = map(lambda writer: writer.getvalue(), self.contents)
|
||||
return "".join(strs)
|
||||
|
||||
def get_subwriter(self):
|
||||
writer = CodeWriter()
|
||||
self.contents.append(writer)
|
||||
self.out = StringIO()
|
||||
self.contents.append(self.out)
|
||||
writer.indentation = self.indentation
|
||||
writer.at_line_start = self.at_line_start
|
||||
writer.generated = self.generated
|
||||
writer.options = self.options
|
||||
|
||||
return writer;
|
||||
|
||||
def write(self, s):
|
||||
# Ensure its a string
|
||||
s = str(s)
|
||||
|
||||
if len(s) == 0:
|
||||
return
|
||||
|
||||
if self.at_line_start:
|
||||
for i in range(self.indentation):
|
||||
self.out.write(" ")
|
||||
self.at_line_start = False
|
||||
self.out.write(s)
|
||||
return self
|
||||
|
||||
def newline(self):
|
||||
self.out.write("\n")
|
||||
self.at_line_start = True
|
||||
return self
|
||||
|
||||
def writeln(self, s):
|
||||
self.write(s)
|
||||
self.newline()
|
||||
return self
|
||||
|
||||
def label(self, s):
|
||||
self.indentation = self.indentation - 1
|
||||
self.write(s + ":")
|
||||
self.indentation = self.indentation + 1
|
||||
self.newline()
|
||||
|
||||
def statement(self, s):
|
||||
self.write(s)
|
||||
self.write(";")
|
||||
self.newline()
|
||||
return self
|
||||
|
||||
def assign(self, var, val):
|
||||
self.write("%s = %s" % (var, val))
|
||||
self.write(";")
|
||||
self.newline()
|
||||
return self
|
||||
|
||||
def increment(self, var, val):
|
||||
self.write("%s += %s" % (var, val))
|
||||
self.write(";")
|
||||
self.newline()
|
||||
return self
|
||||
|
||||
def comment(self, str):
|
||||
self.write("/* " + str + " */")
|
||||
return self
|
||||
|
||||
def todo(self, str):
|
||||
self.comment("TODO: *** %s ***" % str).newline()
|
||||
return self
|
||||
|
||||
def error_check(self, check, label = "error"):
|
||||
self.has_error_check = True
|
||||
with self.block("if (SPICE_UNLIKELY(%s))" % check):
|
||||
if self.has_option("print_error"):
|
||||
self.statement('printf("%%s: Caught error - %s", __PRETTY_FUNCTION__)' % check)
|
||||
if self.has_option("assert_on_error"):
|
||||
self.statement("assert(0)")
|
||||
self.statement("goto %s" % label)
|
||||
|
||||
def indent(self):
|
||||
self.indentation += 4;
|
||||
|
||||
def unindent(self):
|
||||
self.indentation -= 4;
|
||||
if self.indentation < 0:
|
||||
self.indenttation = 0
|
||||
|
||||
def begin_block(self, prefix= "", comment = ""):
|
||||
if len(prefix) > 0:
|
||||
self.write(prefix)
|
||||
if self.at_line_start:
|
||||
self.write("{")
|
||||
else:
|
||||
self.write(" {")
|
||||
if len(comment) > 0:
|
||||
self.write(" ")
|
||||
self.comment(comment)
|
||||
self.newline()
|
||||
self.indent()
|
||||
|
||||
def end_block(self, semicolon=False, newline=True):
|
||||
self.unindent()
|
||||
if self.at_line_start:
|
||||
self.write("}")
|
||||
else:
|
||||
self.write(" }")
|
||||
if semicolon:
|
||||
self.write(";")
|
||||
if newline:
|
||||
self.newline()
|
||||
|
||||
class Block:
|
||||
def __init__(self, writer, semicolon, newline):
|
||||
self.writer = writer
|
||||
self.semicolon = semicolon
|
||||
self.newline = newline
|
||||
|
||||
def __enter__(self):
|
||||
return self.writer.get_subwriter()
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.writer.end_block(self.semicolon, self.newline)
|
||||
|
||||
class PartialBlock:
|
||||
def __init__(self, writer, scope, semicolon, newline):
|
||||
self.writer = writer
|
||||
self.scope = scope
|
||||
self.semicolon = semicolon
|
||||
self.newline = newline
|
||||
|
||||
def __enter__(self):
|
||||
return self.scope
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.writer.end_block(self.semicolon, self.newline)
|
||||
|
||||
class NoBlock:
|
||||
def __init__(self, scope):
|
||||
self.scope = scope
|
||||
|
||||
def __enter__(self):
|
||||
return self.scope
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def block(self, prefix= "", comment = "", semicolon=False, newline=True):
|
||||
self.begin_block(prefix, comment)
|
||||
return self.Block(self, semicolon, newline)
|
||||
|
||||
def partial_block(self, scope, semicolon=False, newline=True):
|
||||
return self.PartialBlock(self, scope, semicolon, newline)
|
||||
|
||||
def no_block(self, scope):
|
||||
return self.NoBlock(scope)
|
||||
|
||||
def optional_block(self, scope):
|
||||
if scope != None:
|
||||
return self.NoBlock(scope)
|
||||
return self.block()
|
||||
|
||||
def for_loop(self, index, limit):
|
||||
return self.block("for (%s = 0; %s < %s; %s++)" % (index, index, limit, index))
|
||||
|
||||
def while_loop(self, expr):
|
||||
return self.block("while (%s)" % (expr))
|
||||
|
||||
def if_block(self, check, elseif=False, newline=True):
|
||||
s = "if (%s)" % (check)
|
||||
if elseif:
|
||||
s = " else " + s
|
||||
self.begin_block(s, "")
|
||||
return self.Block(self, False, newline)
|
||||
|
||||
def variable_defined(self, name):
|
||||
for n in self.vars:
|
||||
if n == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def variable_def(self, ctype, *names):
|
||||
for n in names:
|
||||
# Strip away initialization
|
||||
i = n.find("=")
|
||||
if i != -1:
|
||||
n = n[0:i]
|
||||
self.vars.append(n.strip())
|
||||
# only add space for non-pointer types
|
||||
if ctype[-1] == "*":
|
||||
ctype = ctype[:-1].rstrip()
|
||||
self.writeln("%s *%s;"%(ctype, ", *".join(names)))
|
||||
else:
|
||||
self.writeln("%s %s;"%(ctype, ", ".join(names)))
|
||||
return self
|
||||
|
||||
def function_helper(self):
|
||||
if self.function_helper_writer != None:
|
||||
writer = self.function_helper_writer.get_subwriter()
|
||||
self.function_helper_writer.newline()
|
||||
else:
|
||||
writer = self.get_subwriter()
|
||||
return writer
|
||||
|
||||
def function(self, name, return_type, args, static = False):
|
||||
self.has_error_check = False
|
||||
self.function_helper_writer = self.get_subwriter()
|
||||
if static:
|
||||
self.write("static ")
|
||||
self.write(return_type)
|
||||
self.write(" %s(%s)"% (name, args)).newline()
|
||||
self.begin_block()
|
||||
self.function_variables_writer = self.get_subwriter()
|
||||
self.function_variables = {}
|
||||
return self.function_variables_writer
|
||||
|
||||
def macro(self, name, args, define):
|
||||
self.write("#define %s(%s) %s" % (name, args, define)).newline()
|
||||
|
||||
def add_function_variable(self, ctype, name):
|
||||
if self.function_variables.has_key(name):
|
||||
assert(self.function_variables[name] == ctype)
|
||||
else:
|
||||
self.function_variables[name] = ctype
|
||||
self.function_variables_writer.variable_def(ctype, name)
|
||||
|
||||
def pop_index(self):
|
||||
index = self.indexes[self.current_index]
|
||||
self.current_index = self.current_index + 1
|
||||
self.add_function_variable("uint32_t", index)
|
||||
return index
|
||||
|
||||
def push_index(self):
|
||||
self.current_index = self.current_index - 1
|
||||
|
||||
class Index:
|
||||
def __init__(self, writer, val):
|
||||
self.writer = writer
|
||||
self.val = val
|
||||
|
||||
def __enter__(self):
|
||||
return self.val
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.writer.push_index()
|
||||
|
||||
def index(self, no_block = False):
|
||||
if no_block:
|
||||
return self.no_block(None)
|
||||
val = self.pop_index()
|
||||
return self.Index(self, val)
|
||||
1033
python_modules/demarshal.py
Normal file
1033
python_modules/demarshal.py
Normal file
File diff suppressed because it is too large
Load Diff
965
python_modules/ptypes.py
Normal file
965
python_modules/ptypes.py
Normal file
@ -0,0 +1,965 @@
|
||||
import codegen
|
||||
import types
|
||||
|
||||
_types_by_name = {}
|
||||
_types = []
|
||||
|
||||
def type_exists(name):
|
||||
return _types_by_name.has_key(name)
|
||||
|
||||
def lookup_type(name):
|
||||
return _types_by_name[name]
|
||||
|
||||
def get_named_types():
|
||||
return _types
|
||||
|
||||
class FixedSize:
|
||||
def __init__(self, val = 0, minor = 0):
|
||||
if isinstance(val, FixedSize):
|
||||
self.vals = val.vals
|
||||
else:
|
||||
self.vals = [0] * (minor + 1)
|
||||
self.vals[minor] = val
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, types.IntType):
|
||||
other = FixedSize(other)
|
||||
|
||||
new = FixedSize()
|
||||
l = max(len(self.vals), len(other.vals))
|
||||
shared = min(len(self.vals), len(other.vals))
|
||||
|
||||
new.vals = [0] * l
|
||||
|
||||
for i in range(shared):
|
||||
new.vals[i] = self.vals[i] + other.vals[i]
|
||||
|
||||
for i in range(shared,len(self.vals)):
|
||||
new.vals[i] = self.vals[i];
|
||||
|
||||
for i in range(shared,len(other.vals)):
|
||||
new.vals[i] = new.vals[i] + other.vals[i];
|
||||
|
||||
return new
|
||||
|
||||
def __radd__(self, other):
|
||||
return self.__add__(other)
|
||||
|
||||
def __str__(self):
|
||||
s = "%d" % (self.vals[0])
|
||||
|
||||
for i in range(1,len(self.vals)):
|
||||
if self.vals[i] > 0:
|
||||
s = s + " + ((minor >= %d)?%d:0)" % (i, self.vals[i])
|
||||
return s
|
||||
|
||||
class Type:
|
||||
def __init__(self):
|
||||
self.attributes = {}
|
||||
self.registred = False
|
||||
self.name = None
|
||||
|
||||
def has_name(self):
|
||||
return self.name != None
|
||||
|
||||
def get_type(self, recursive=False):
|
||||
return self
|
||||
|
||||
def is_primitive(self):
|
||||
return False
|
||||
|
||||
def is_fixed_sizeof(self):
|
||||
return True
|
||||
|
||||
def is_extra_size(self):
|
||||
return False
|
||||
|
||||
def contains_extra_size(self):
|
||||
return False
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return True
|
||||
|
||||
def is_array(self):
|
||||
return isinstance(self, ArrayType)
|
||||
|
||||
def is_struct(self):
|
||||
return isinstance(self, StructType)
|
||||
|
||||
def is_pointer(self):
|
||||
return isinstance(self, PointerType)
|
||||
|
||||
def get_num_pointers(self):
|
||||
return 0
|
||||
|
||||
def get_pointer_names(self):
|
||||
return []
|
||||
|
||||
def sizeof(self):
|
||||
return "sizeof(%s)" % (self.c_type())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __str__(self):
|
||||
if self.name != None:
|
||||
return self.name
|
||||
return "anonymous type"
|
||||
|
||||
def resolve(self):
|
||||
return self
|
||||
|
||||
def register(self):
|
||||
if self.registred or self.name == None:
|
||||
return
|
||||
self.registred = True
|
||||
if _types_by_name.has_key(self.name):
|
||||
raise Exception, "Type %s already defined" % self.name
|
||||
_types.append(self)
|
||||
_types_by_name[self.name] = self
|
||||
|
||||
def has_pointer(self):
|
||||
return False
|
||||
|
||||
def has_attr(self, name):
|
||||
return self.attributes.has_key(name)
|
||||
|
||||
class TypeRef(Type):
|
||||
def __init__(self, name):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return "ref to %s" % (self.name)
|
||||
|
||||
def resolve(self):
|
||||
if not _types_by_name.has_key(self.name):
|
||||
raise Exception, "Unknown type %s" % self.name
|
||||
return _types_by_name[self.name]
|
||||
|
||||
def register(self):
|
||||
assert True, "Can't register TypeRef!"
|
||||
|
||||
|
||||
class IntegerType(Type):
|
||||
def __init__(self, bits, signed):
|
||||
Type.__init__(self)
|
||||
self.bits = bits
|
||||
self.signed = signed
|
||||
|
||||
if signed:
|
||||
self.name = "int%d" % bits
|
||||
else:
|
||||
self.name = "uint%d" % bits
|
||||
|
||||
def primitive_type(self):
|
||||
return self.name
|
||||
|
||||
def c_type(self):
|
||||
return self.name + "_t"
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
return self.bits / 8
|
||||
|
||||
def is_primitive(self):
|
||||
return True
|
||||
|
||||
class TypeAlias(Type):
|
||||
def __init__(self, name, the_type, attribute_list):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
self.the_type = the_type
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def get_type(self, recursive=False):
|
||||
if recursive:
|
||||
return self.the_type.get_type(True)
|
||||
else:
|
||||
return self.the_type
|
||||
|
||||
def primitive_type(self):
|
||||
return self.the_type.primitive_type()
|
||||
|
||||
def resolve(self):
|
||||
self.the_type = self.the_type.resolve()
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return "alias %s" % self.name
|
||||
|
||||
def is_primitive(self):
|
||||
return self.the_type.is_primitive()
|
||||
|
||||
def is_fixed_sizeof(self):
|
||||
return self.the_type.is_fixed_sizeof()
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return self.the_type.is_fixed_nw_size()
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
return self.the_type.get_fixed_nw_size()
|
||||
|
||||
def get_num_pointers(self):
|
||||
return self.the_type.get_num_pointers()
|
||||
|
||||
def get_pointer_names(self):
|
||||
return self.the_type.get_pointer_names()
|
||||
|
||||
def c_type(self):
|
||||
if self.has_attr("ctype"):
|
||||
return self.attributes["ctype"][0]
|
||||
return self.name
|
||||
|
||||
def has_pointer(self):
|
||||
return self.the_type.has_pointer()
|
||||
|
||||
class EnumBaseType(Type):
|
||||
def is_enum(self):
|
||||
return isinstance(self, EnumType)
|
||||
|
||||
def primitive_type(self):
|
||||
return "uint%d" % (self.bits)
|
||||
|
||||
def c_type(self):
|
||||
return "uint%d_t" % (self.bits)
|
||||
|
||||
def c_name(self):
|
||||
return codegen.prefix_camel(self.name)
|
||||
|
||||
def c_enumname(self, value):
|
||||
if self.has_attr("prefix"):
|
||||
return self.attributes["prefix"][0] + self.names[value]
|
||||
return codegen.prefix_underscore_upper(self.name.upper(), self.names[value])
|
||||
|
||||
def c_enumname_by_name(self, name):
|
||||
if self.has_attr("prefix"):
|
||||
return self.attributes["prefix"][0] + self.names[value]
|
||||
return codegen.prefix_underscore_upper(self.name.upper(), name)
|
||||
|
||||
def is_primitive(self):
|
||||
return True
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
return self.bits / 8
|
||||
|
||||
class EnumType(EnumBaseType):
|
||||
def __init__(self, bits, name, enums, attribute_list):
|
||||
Type.__init__(self)
|
||||
self.bits = bits
|
||||
self.name = name
|
||||
|
||||
last = -1
|
||||
names = {}
|
||||
values = {}
|
||||
for v in enums:
|
||||
name = v[0]
|
||||
if len(v) > 1:
|
||||
value = v[1]
|
||||
else:
|
||||
value = last + 1
|
||||
last = value
|
||||
|
||||
assert not names.has_key(value)
|
||||
names[value] = name
|
||||
values[name] = value
|
||||
|
||||
self.names = names
|
||||
self.values = values
|
||||
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def __str__(self):
|
||||
return "enum %s" % self.name
|
||||
|
||||
def c_define(self, writer):
|
||||
writer.write("enum ")
|
||||
writer.write(self.c_name())
|
||||
writer.begin_block()
|
||||
values = self.names.keys()
|
||||
values.sort()
|
||||
current_default = 0
|
||||
for i in values:
|
||||
writer.write(self.c_enumname(i))
|
||||
if i != current_default:
|
||||
writer.write(" = %d" % (i))
|
||||
writer.write(",")
|
||||
writer.newline()
|
||||
current_default = i + 1
|
||||
writer.newline()
|
||||
writer.write(codegen.prefix_underscore_upper(self.name.upper(), "ENUM_END"))
|
||||
writer.newline()
|
||||
writer.end_block(semicolon=True)
|
||||
writer.newline()
|
||||
|
||||
class FlagsType(EnumBaseType):
|
||||
def __init__(self, bits, name, flags, attribute_list):
|
||||
Type.__init__(self)
|
||||
self.bits = bits
|
||||
self.name = name
|
||||
|
||||
last = -1
|
||||
names = {}
|
||||
values = {}
|
||||
for v in flags:
|
||||
name = v[0]
|
||||
if len(v) > 1:
|
||||
value = v[1]
|
||||
else:
|
||||
value = last + 1
|
||||
last = value
|
||||
|
||||
assert not names.has_key(value)
|
||||
names[value] = name
|
||||
values[name] = value
|
||||
|
||||
self.names = names
|
||||
self.values = values
|
||||
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def __str__(self):
|
||||
return "flags %s" % self.name
|
||||
|
||||
def c_define(self, writer):
|
||||
writer.write("enum ")
|
||||
writer.write(self.c_name())
|
||||
writer.begin_block()
|
||||
values = self.names.keys()
|
||||
values.sort()
|
||||
mask = 0
|
||||
for i in values:
|
||||
writer.write(self.c_enumname(i))
|
||||
mask = mask | (1<<i)
|
||||
writer.write(" = (1 << %d)" % (i))
|
||||
writer.write(",")
|
||||
writer.newline()
|
||||
current_default = i + 1
|
||||
writer.newline()
|
||||
writer.write(codegen.prefix_underscore_upper(self.name.upper(), "MASK"))
|
||||
writer.write(" = 0x%x" % (mask))
|
||||
writer.newline()
|
||||
writer.end_block(semicolon=True)
|
||||
writer.newline()
|
||||
|
||||
class ArrayType(Type):
|
||||
def __init__(self, element_type, size):
|
||||
Type.__init__(self)
|
||||
self.name = None
|
||||
|
||||
self.element_type = element_type
|
||||
self.size = size
|
||||
|
||||
def __str__(self):
|
||||
if self.size == None:
|
||||
return "%s[]" % (str(self.element_type))
|
||||
else:
|
||||
return "%s[%s]" % (str(self.element_type), str(self.size))
|
||||
|
||||
def resolve(self):
|
||||
self.element_type = self.element_type.resolve()
|
||||
return self
|
||||
|
||||
def is_constant_length(self):
|
||||
return isinstance(self.size, types.IntType)
|
||||
|
||||
def is_remaining_length(self):
|
||||
return isinstance(self.size, types.StringType) and len(self.size) == 0
|
||||
|
||||
def is_identifier_length(self):
|
||||
return isinstance(self.size, types.StringType) and len(self.size) > 0
|
||||
|
||||
def is_image_size_length(self):
|
||||
if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
|
||||
return False
|
||||
return self.size[0] == "image_size"
|
||||
|
||||
def is_bytes_length(self):
|
||||
if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
|
||||
return False
|
||||
return self.size[0] == "bytes"
|
||||
|
||||
def is_cstring_length(self):
|
||||
if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType):
|
||||
return False
|
||||
return self.size[0] == "cstring"
|
||||
|
||||
def is_fixed_sizeof(self):
|
||||
return self.is_constant_length() and self.element_type.is_fixed_sizeof()
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return self.is_constant_length() and self.element_type.is_fixed_nw_size()
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
if not self.is_fixed_nw_size():
|
||||
raise Exception, "Not a fixed size type"
|
||||
|
||||
return self.element_type.get_fixed_nw_size() * self.size
|
||||
|
||||
def get_num_pointers(self):
|
||||
element_count = self.element_type.get_num_pointers()
|
||||
if element_count == 0:
|
||||
return 0
|
||||
if self.is_constant_length(self):
|
||||
return element_count * self.size
|
||||
raise Exception, "Pointers in dynamic arrays not supported"
|
||||
|
||||
def get_pointer_names(self):
|
||||
element_count = self.element_type.get_num_pointers()
|
||||
if element_count == 0:
|
||||
return []
|
||||
raise Exception, "Pointer names in arrays not supported"
|
||||
|
||||
def contains_extra_size(self):
|
||||
return self.element_type.contains_extra_size()
|
||||
|
||||
def sizeof(self):
|
||||
return "%s * %s" % (self.element_type.sizeof(), self.size)
|
||||
|
||||
def c_type(self):
|
||||
return self.element_type.c_type()
|
||||
|
||||
class PointerType(Type):
|
||||
def __init__(self, target_type):
|
||||
Type.__init__(self)
|
||||
self.name = None
|
||||
self.target_type = target_type
|
||||
|
||||
def __str__(self):
|
||||
return "%s*" % (str(self.target_type))
|
||||
|
||||
def resolve(self):
|
||||
self.target_type = self.target_type.resolve()
|
||||
return self
|
||||
|
||||
def get_fixed_size(self):
|
||||
return 8 # offsets are 64bit
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return True
|
||||
|
||||
def is_primitive(self):
|
||||
return True
|
||||
|
||||
def primitive_type(self):
|
||||
return "uint64"
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
return 8
|
||||
|
||||
def c_type(self):
|
||||
return "SPICE_ADDRESS"
|
||||
|
||||
def has_pointer(self):
|
||||
return True
|
||||
|
||||
def contains_extra_size(self):
|
||||
return True
|
||||
|
||||
def get_num_pointers(self):
|
||||
return 1
|
||||
|
||||
class Containee:
|
||||
def __init__(self):
|
||||
self.attributes = {}
|
||||
|
||||
def is_switch(self):
|
||||
return False
|
||||
|
||||
def is_pointer(self):
|
||||
return not self.is_switch() and self.member_type.is_pointer()
|
||||
|
||||
def is_array(self):
|
||||
return not self.is_switch() and self.member_type.is_array()
|
||||
|
||||
def is_struct(self):
|
||||
return not self.is_switch() and self.member_type.is_struct()
|
||||
|
||||
def is_primitive(self):
|
||||
return not self.is_switch() and self.member_type.is_primitive()
|
||||
|
||||
def has_attr(self, name):
|
||||
return self.attributes.has_key(name)
|
||||
|
||||
def has_minor_attr(self):
|
||||
return self.has_attr("minor")
|
||||
|
||||
def has_end_attr(self):
|
||||
return self.has_attr("end")
|
||||
|
||||
def get_minor_attr(self):
|
||||
return self.attributes["minor"][0]
|
||||
|
||||
class Member(Containee):
|
||||
def __init__(self, name, member_type, attribute_list):
|
||||
Containee.__init__(self)
|
||||
self.name = name
|
||||
self.member_type = member_type
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def resolve(self, container):
|
||||
self.container = container
|
||||
self.member_type = self.member_type.resolve()
|
||||
self.member_type.register()
|
||||
return self
|
||||
|
||||
def is_primitive(self):
|
||||
return self.member_type.is_primitive()
|
||||
|
||||
def is_fixed_sizeof(self):
|
||||
if self.has_end_attr():
|
||||
return False
|
||||
return self.member_type.is_fixed_sizeof()
|
||||
|
||||
def is_extra_size(self):
|
||||
return self.has_end_attr()
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return self.member_type.is_fixed_nw_size()
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
size = self.member_type.get_fixed_nw_size()
|
||||
if self.has_minor_attr():
|
||||
minor = self.get_minor_attr()
|
||||
size = FixedSize(size, minor)
|
||||
return size
|
||||
|
||||
def contains_extra_size(self):
|
||||
return self.member_type.contains_extra_size()
|
||||
|
||||
def sizeof(self):
|
||||
return self.member_type.sizeof()
|
||||
|
||||
def __repr__(self):
|
||||
return "%s (%s)" % (str(self.name), str(self.member_type))
|
||||
|
||||
def has_pointer(self):
|
||||
return self.member_type.has_pointer()
|
||||
|
||||
def get_num_pointers(self):
|
||||
return self.member_type.get_num_pointers()
|
||||
|
||||
def get_pointer_names(self):
|
||||
if self.member_type.is_pointer():
|
||||
names = [self.name + "_out"]
|
||||
else:
|
||||
names = self.member_type.get_pointer_names()
|
||||
if self.has_attr("outvar"):
|
||||
prefix = self.attributes["outvar"][0]
|
||||
names = map(lambda name: prefix + "_" + name, names)
|
||||
return names
|
||||
|
||||
class SwitchCase:
|
||||
def __init__(self, values, member):
|
||||
self.values = values
|
||||
self.member = member
|
||||
self.members = [member]
|
||||
|
||||
def get_check(self, var_cname, var_type):
|
||||
checks = []
|
||||
for v in self.values:
|
||||
if v == None:
|
||||
return "1"
|
||||
elif var_type.is_enum():
|
||||
checks.append("%s == %s" % (var_cname, var_type.c_enumname_by_name(v)))
|
||||
else:
|
||||
checks.append("(%s & %s)" % (var_cname, var_type.c_enumname_by_name(v)))
|
||||
return " || ".join(checks)
|
||||
|
||||
def resolve(self, container):
|
||||
self.switch = container
|
||||
self.member = self.member.resolve(self)
|
||||
return self
|
||||
|
||||
def has_pointer(self):
|
||||
return self.member.has_pointer()
|
||||
|
||||
def get_num_pointers(self):
|
||||
return self.member.get_num_pointers()
|
||||
|
||||
def get_pointer_names(self):
|
||||
return self.member.get_pointer_names()
|
||||
|
||||
class Switch(Containee):
|
||||
def __init__(self, variable, cases, name, attribute_list):
|
||||
Containee.__init__(self)
|
||||
self.variable = variable
|
||||
self.name = name
|
||||
self.cases = cases
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def is_switch(self):
|
||||
return True
|
||||
|
||||
def has_switch_member(self, member):
|
||||
for c in self.cases:
|
||||
if c.member == member:
|
||||
return True
|
||||
return False
|
||||
|
||||
def resolve(self, container):
|
||||
self.container = container
|
||||
self.cases = map(lambda c : c.resolve(self), self.cases)
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "switch on %s %s" % (str(self.variable),str(self.name))
|
||||
|
||||
def is_fixed_sizeof(self):
|
||||
# Kinda weird, but we're unlikely to have a real struct if there is an @end
|
||||
if self.has_end_attr():
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
if self.has_attr("fixedsize"):
|
||||
return True
|
||||
|
||||
size = None
|
||||
for c in self.cases:
|
||||
if not c.member.is_fixed_nw_size():
|
||||
return False
|
||||
if size == None:
|
||||
size = c.member.get_fixed_nw_size()
|
||||
elif size != c.member.get_fixed_nw_size():
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_extra_size(self):
|
||||
return self.has_end_attr()
|
||||
|
||||
def contains_extra_size(self):
|
||||
for c in self.cases:
|
||||
if c.member.is_extra_size():
|
||||
return True
|
||||
if c.member.contains_extra_size():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
if not self.is_fixed_nw_size():
|
||||
raise Exception, "Not a fixed size type"
|
||||
size = 0;
|
||||
for c in self.cases:
|
||||
size = max(size, c.member.get_fixed_nw_size())
|
||||
return size
|
||||
|
||||
def sizeof(self):
|
||||
return "sizeof(((%s *)NULL)->%s)" % (self.container.c_type(),
|
||||
self.name)
|
||||
|
||||
def has_pointer(self):
|
||||
for c in self.cases:
|
||||
if c.has_pointer():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_num_pointers(self):
|
||||
count = 0
|
||||
for c in self.cases:
|
||||
count = max(count, c.get_num_pointers())
|
||||
return count
|
||||
|
||||
def get_pointer_names(self):
|
||||
names = []
|
||||
for c in self.cases:
|
||||
names = names + c.get_pointer_names()
|
||||
return names
|
||||
|
||||
class ContainerType(Type):
|
||||
def is_fixed_sizeof(self):
|
||||
for m in self.members:
|
||||
if not m.is_fixed_sizeof():
|
||||
return False
|
||||
return True
|
||||
|
||||
def contains_extra_size(self):
|
||||
for m in self.members:
|
||||
if m.is_extra_size():
|
||||
return True
|
||||
if m.contains_extra_size():
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
for i in self.members:
|
||||
if not i.is_fixed_nw_size():
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_fixed_nw_size(self):
|
||||
size = 0
|
||||
for i in self.members:
|
||||
size = size + i.get_fixed_nw_size()
|
||||
return size
|
||||
|
||||
def get_fixed_nw_offset(self, member):
|
||||
size = 0
|
||||
for i in self.members:
|
||||
if i == member:
|
||||
break
|
||||
if i.is_fixed_nw_size():
|
||||
size = size + i.get_fixed_nw_size()
|
||||
return size
|
||||
|
||||
def resolve(self):
|
||||
self.members = map(lambda m : m.resolve(self), self.members)
|
||||
return self
|
||||
|
||||
def get_num_pointers(self):
|
||||
count = 0
|
||||
for m in self.members:
|
||||
count = count + m.get_num_pointers()
|
||||
return count
|
||||
|
||||
def get_pointer_names(self):
|
||||
names = []
|
||||
for m in self.members:
|
||||
names = names + m.get_pointer_names()
|
||||
return names
|
||||
|
||||
def has_pointer(self):
|
||||
for m in self.members:
|
||||
if m.has_pointer():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_nw_offset(self, member, prefix = "", postfix = ""):
|
||||
fixed = self.get_fixed_nw_offset(member)
|
||||
v = []
|
||||
for m in self.members:
|
||||
if m == member:
|
||||
break
|
||||
if m.is_switch() and m.has_switch_member(member):
|
||||
break
|
||||
if not m.is_fixed_nw_size():
|
||||
v.append(prefix + m.name + postfix)
|
||||
if len(v) > 0:
|
||||
return str(fixed) + " + " + (" + ".join(v))
|
||||
else:
|
||||
return str(fixed)
|
||||
|
||||
def lookup_member(self, name):
|
||||
return self.members_by_name[name]
|
||||
|
||||
class StructType(ContainerType):
|
||||
def __init__(self, name, members, attribute_list):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
self.members = members
|
||||
self.members_by_name = {}
|
||||
for m in members:
|
||||
self.members_by_name[m.name] = m
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def __str__(self):
|
||||
if self.name == None:
|
||||
return "anonymous struct"
|
||||
else:
|
||||
return "struct %s" % self.name
|
||||
|
||||
def c_type(self):
|
||||
if self.has_attr("ctype"):
|
||||
return self.attributes["ctype"][0]
|
||||
return codegen.prefix_camel(self.name)
|
||||
|
||||
class MessageType(ContainerType):
|
||||
def __init__(self, name, members, attribute_list):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
self.members = members
|
||||
self.members_by_name = {}
|
||||
for m in members:
|
||||
self.members_by_name[m.name] = m
|
||||
self.reverse_members = {} # ChannelMembers referencing this message
|
||||
for attr in attribute_list:
|
||||
self.attributes[attr[0][1:]] = attr[1:]
|
||||
|
||||
def __str__(self):
|
||||
if self.name == None:
|
||||
return "anonymous message"
|
||||
else:
|
||||
return "message %s" % self.name
|
||||
|
||||
def c_name(self):
|
||||
if self.name == None:
|
||||
cms = self.reverse_members.keys()
|
||||
if len(cms) != 1:
|
||||
raise "Unknown typename for message"
|
||||
cm = cms[0]
|
||||
channelname = cm.channel.member_name
|
||||
if channelname == None:
|
||||
channelname = ""
|
||||
else:
|
||||
channelname = channelname + "_"
|
||||
if cm.is_server:
|
||||
return "msg_" + channelname + cm.name
|
||||
else:
|
||||
return "msgc_" + channelname + cm.name
|
||||
else:
|
||||
return codegen.prefix_camel("Msg", self.name)
|
||||
|
||||
def c_type(self):
|
||||
if self.has_attr("ctype"):
|
||||
return self.attributes["ctype"][0]
|
||||
if self.name == None:
|
||||
cms = self.reverse_members.keys()
|
||||
if len(cms) != 1:
|
||||
raise "Unknown typename for message"
|
||||
cm = cms[0]
|
||||
channelname = cm.channel.member_name
|
||||
if channelname == None:
|
||||
channelname = ""
|
||||
if cm.is_server:
|
||||
return codegen.prefix_camel("Msg", channelname, cm.name)
|
||||
else:
|
||||
return codegen.prefix_camel("Msgc", channelname, cm.name)
|
||||
else:
|
||||
return codegen.prefix_camel("Msg", self.name)
|
||||
|
||||
class ChannelMember(Containee):
|
||||
def __init__(self, name, message_type, value):
|
||||
Containee.__init__(self)
|
||||
self.name = name
|
||||
self.message_type = message_type
|
||||
self.value = value
|
||||
|
||||
def resolve(self, channel):
|
||||
self.channel = channel
|
||||
self.message_type = self.message_type.resolve()
|
||||
self.message_type.reverse_members[self] = 1
|
||||
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "%s (%s)" % (str(self.name), str(self.message_type))
|
||||
|
||||
class ChannelType(Type):
|
||||
def __init__(self, name, base, members):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
self.base = base
|
||||
self.member_name = None
|
||||
self.members = members
|
||||
|
||||
def __str__(self):
|
||||
if self.name == None:
|
||||
return "anonymous channel"
|
||||
else:
|
||||
return "channel %s" % self.name
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return False
|
||||
|
||||
def get_client_message(self, name):
|
||||
return self.client_messages_byname[name]
|
||||
|
||||
def get_server_message(self, name):
|
||||
return self.server_messages_byname[name]
|
||||
|
||||
def resolve(self):
|
||||
if self.base != None:
|
||||
self.base = self.base.resolve()
|
||||
|
||||
server_messages = self.base.server_messages[:]
|
||||
server_messages_byname = self.base.server_messages_byname.copy()
|
||||
client_messages = self.base.client_messages[:]
|
||||
client_messages_byname = self.base.client_messages_byname.copy()
|
||||
else:
|
||||
server_messages = []
|
||||
server_messages_byname = {}
|
||||
client_messages = []
|
||||
client_messages_byname = {}
|
||||
|
||||
server_count = 1
|
||||
client_count = 1
|
||||
|
||||
server = True
|
||||
for m in self.members:
|
||||
if m == "server":
|
||||
server = True
|
||||
elif m == "client":
|
||||
server = False
|
||||
elif server:
|
||||
m.is_server = True
|
||||
m = m.resolve(self)
|
||||
if m.value:
|
||||
server_count = m.value + 1
|
||||
else:
|
||||
m.value = server_count
|
||||
server_count = server_count + 1
|
||||
server_messages.append(m)
|
||||
server_messages_byname[m.name] = m
|
||||
else:
|
||||
m.is_server = False
|
||||
m = m.resolve(self)
|
||||
if m.value:
|
||||
client_count = m.value + 1
|
||||
else:
|
||||
m.value = client_count
|
||||
client_count = client_count + 1
|
||||
client_messages.append(m)
|
||||
client_messages_byname[m.name] = m
|
||||
|
||||
self.server_messages = server_messages
|
||||
self.server_messages_byname = server_messages_byname
|
||||
self.client_messages = client_messages
|
||||
self.client_messages_byname = client_messages_byname
|
||||
|
||||
return self
|
||||
|
||||
class ProtocolMember:
|
||||
def __init__(self, name, channel_type, value):
|
||||
self.name = name
|
||||
self.channel_type = channel_type
|
||||
self.value = value
|
||||
|
||||
def resolve(self, protocol):
|
||||
self.channel_type = self.channel_type.resolve()
|
||||
assert(self.channel_type.member_name == None)
|
||||
self.channel_type.member_name = self.name
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "%s (%s)" % (str(self.name), str(self.channel_type))
|
||||
|
||||
class ProtocolType(Type):
|
||||
def __init__(self, name, channels):
|
||||
Type.__init__(self)
|
||||
self.name = name
|
||||
self.channels = channels
|
||||
|
||||
def __str__(self):
|
||||
if self.name == None:
|
||||
return "anonymous protocol"
|
||||
else:
|
||||
return "protocol %s" % self.name
|
||||
|
||||
def is_fixed_nw_size(self):
|
||||
return False
|
||||
|
||||
def resolve(self):
|
||||
count = 1
|
||||
for m in self.channels:
|
||||
m = m.resolve(self)
|
||||
if m.value:
|
||||
count = m.value + 1
|
||||
else:
|
||||
m.value = count
|
||||
count = count + 1
|
||||
|
||||
return self
|
||||
|
||||
int8 = IntegerType(8, True)
|
||||
uint8 = IntegerType(8, False)
|
||||
int16 = IntegerType(16, True)
|
||||
uint16 = IntegerType(16, False)
|
||||
int32 = IntegerType(32, True)
|
||||
uint32 = IntegerType(32, False)
|
||||
int64 = IntegerType(64, True)
|
||||
uint64 = IntegerType(64, False)
|
||||
157
python_modules/spice_parser.py
Normal file
157
python_modules/spice_parser.py
Normal file
@ -0,0 +1,157 @@
|
||||
from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
|
||||
Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
|
||||
alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
|
||||
|
||||
import ptypes
|
||||
import sys
|
||||
|
||||
cvtInt = lambda toks: int(toks[0])
|
||||
|
||||
def parseVariableDef(toks):
|
||||
t = toks[0][0]
|
||||
pointer = toks[0][1]
|
||||
name = toks[0][2]
|
||||
array_size = toks[0][3]
|
||||
attributes = toks[0][4]
|
||||
|
||||
if array_size != None:
|
||||
t = ptypes.ArrayType(t, array_size)
|
||||
|
||||
if pointer != None:
|
||||
t = ptypes.PointerType(t);
|
||||
|
||||
return ptypes.Member(name, t, attributes)
|
||||
|
||||
bnf = None
|
||||
def SPICE_BNF():
|
||||
global bnf
|
||||
|
||||
if not bnf:
|
||||
|
||||
# punctuation
|
||||
colon = Literal(":").suppress()
|
||||
lbrace = Literal("{").suppress()
|
||||
rbrace = Literal("}").suppress()
|
||||
lbrack = Literal("[").suppress()
|
||||
rbrack = Literal("]").suppress()
|
||||
lparen = Literal("(").suppress()
|
||||
rparen = Literal(")").suppress()
|
||||
equals = Literal("=").suppress()
|
||||
comma = Literal(",").suppress()
|
||||
semi = Literal(";").suppress()
|
||||
|
||||
# primitive types
|
||||
int8_ = Keyword("int8").setParseAction(replaceWith(ptypes.int8))
|
||||
uint8_ = Keyword("uint8").setParseAction(replaceWith(ptypes.uint8))
|
||||
int16_ = Keyword("int16").setParseAction(replaceWith(ptypes.int16))
|
||||
uint16_ = Keyword("uint16").setParseAction(replaceWith(ptypes.uint16))
|
||||
int32_ = Keyword("int32").setParseAction(replaceWith(ptypes.int32))
|
||||
uint32_ = Keyword("uint32").setParseAction(replaceWith(ptypes.uint32))
|
||||
int64_ = Keyword("int64").setParseAction(replaceWith(ptypes.int64))
|
||||
uint64_ = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64))
|
||||
|
||||
# keywords
|
||||
channel_ = Keyword("channel")
|
||||
enum32_ = Keyword("enum32").setParseAction(replaceWith(32))
|
||||
enum16_ = Keyword("enum16").setParseAction(replaceWith(16))
|
||||
enum8_ = Keyword("enum8").setParseAction(replaceWith(8))
|
||||
flags32_ = Keyword("flags32").setParseAction(replaceWith(32))
|
||||
flags16_ = Keyword("flags16").setParseAction(replaceWith(16))
|
||||
flags8_ = Keyword("flags8").setParseAction(replaceWith(8))
|
||||
channel_ = Keyword("channel")
|
||||
server_ = Keyword("server")
|
||||
client_ = Keyword("client")
|
||||
protocol_ = Keyword("protocol")
|
||||
typedef_ = Keyword("typedef")
|
||||
struct_ = Keyword("struct")
|
||||
message_ = Keyword("message")
|
||||
image_size_ = Keyword("image_size")
|
||||
bytes_ = Keyword("bytes")
|
||||
cstring_ = Keyword("cstring")
|
||||
switch_ = Keyword("switch")
|
||||
default_ = Keyword("default")
|
||||
case_ = Keyword("case")
|
||||
|
||||
identifier = Word( alphas, alphanums + "_" )
|
||||
enumname = Word( alphanums + "_" )
|
||||
|
||||
integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) |
|
||||
Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt)
|
||||
|
||||
typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0])))
|
||||
|
||||
# This is just normal "types", i.e. not channels or messages
|
||||
typeSpec = Forward()
|
||||
|
||||
attributeValue = integer ^ identifier
|
||||
attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen))
|
||||
attributes = Group(ZeroOrMore(attribute))
|
||||
arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen)
|
||||
arraySizeSpecBytes = Group(bytes_ + lparen + identifier + rparen)
|
||||
arraySizeSpecCString = Group(cstring_ + lparen + rparen)
|
||||
arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack
|
||||
variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \
|
||||
.setParseAction(parseVariableDef)
|
||||
|
||||
switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | case_.suppress() + identifier + colon)) + variableDef) \
|
||||
.setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1]))
|
||||
switchBody = Group(switch_ + lparen + identifier + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \
|
||||
.setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4]))
|
||||
messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace)
|
||||
structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
|
||||
|
||||
# have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type"
|
||||
typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^
|
||||
int32_ ^ uint32_ ^ int64_ ^ uint64_ ^
|
||||
typename).setName("type")
|
||||
|
||||
flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer))) + Optional(comma) + rbrace)
|
||||
|
||||
messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename
|
||||
|
||||
channelParent = Optional(colon + typename, default=None)
|
||||
channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \
|
||||
.setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2]))
|
||||
channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage) + rbrace)
|
||||
|
||||
enum_ = (enum32_ | enum16_ | enum8_)
|
||||
flags_ = (flags32_ | flags16_ | flags8_)
|
||||
enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
|
||||
flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3]))
|
||||
messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3]))
|
||||
channelDef = Group(channel_ + identifier + channelBody - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3]))
|
||||
structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3]))
|
||||
typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3]))
|
||||
|
||||
definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef
|
||||
|
||||
protocolChannel = Group(typename + identifier + Optional(equals + integer, default=None) + semi) \
|
||||
.setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2]))
|
||||
protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \
|
||||
.setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2]))
|
||||
|
||||
bnf = ZeroOrMore (definitions) + protocolDef + StringEnd()
|
||||
|
||||
singleLineComment = "//" + restOfLine
|
||||
bnf.ignore( singleLineComment )
|
||||
bnf.ignore( cStyleComment )
|
||||
|
||||
return bnf
|
||||
|
||||
|
||||
def parse(filename):
|
||||
try:
|
||||
bnf = SPICE_BNF()
|
||||
types = bnf.parseFile(filename)
|
||||
except ParseException, err:
|
||||
print >> sys.stderr, err.line
|
||||
print >> sys.stderr, " "*(err.column-1) + "^"
|
||||
print >> sys.stderr, err
|
||||
return None
|
||||
|
||||
for t in types:
|
||||
t.resolve()
|
||||
t.register()
|
||||
protocol = types[-1]
|
||||
return protocol
|
||||
|
||||
1086
spice.proto
Normal file
1086
spice.proto
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user