-#!/usr/bin/env python
+#!/usr/bin/python3
from __future__ import print_function
import ply.lex as lex
# Global dictionary of new types (including enums)
global_types = {}
-global_crc = 0
-def global_type_add(name):
+def global_type_add(name, obj):
'''Add new type to the dictionary of types '''
type_name = 'vl_api_' + name + '_t'
- if type_name in global_types:
- raise KeyError('Type is already defined: {}'.format(name))
- global_types[type_name] = True
+ global_types[type_name] = obj
# All your trace are belong to us!
t_ignore_LINE_COMMENT = '//.*'
def t_NUM(self, t):
- r'0[xX][0-9a-fA-F]+|\d+'
+ r'0[xX][0-9a-fA-F]+|-?\d+\.?\d*'
base = 16 if t.value.startswith('0x') else 10
- t.value = int(t.value, base)
+ if '.' in t.value:
+ t.value = float(t.value)
+ else:
+ t.value = int(t.value, base)
return t
def t_ID(self, t):
t_ignore = ' \t'
-#
-# Side-effect: Sets global_crc
-#
-def crc_block(block):
- global global_crc
+def crc_block_combine(block, crc):
s = str(block).encode()
- global_crc = binascii.crc32(s, global_crc)
- return binascii.crc32(s) & 0xffffffff
+ return binascii.crc32(s, crc) & 0xffffffff
class Service():
- def __init__(self, caller, reply, events=[], stream=False):
+ def __init__(self, caller, reply, events=None, stream=False):
self.caller = caller
self.reply = reply
self.stream = stream
- self.events = events
+ self.events = [] if events is None else events
+
+ def __repr__(self):
+ return "Service(caller={!r}, reply={!r}, events={!r}, stream={!r})".\
+ format(self.caller, self.reply, self.events, self.stream)
class Typedef():
self.name = name
self.flags = flags
self.block = block
- self.crc = crc_block(block)
+ self.crc = str(block).encode()
self.manual_print = False
self.manual_endian = False
for f in flags:
self.manual_print = True
elif f == 'manual_endian':
self.manual_endian = True
- global_type_add(name)
+ global_type_add(name, self)
def __repr__(self):
- return self.name + str(self.flags) + str(self.block)
+ return "Typedef(name={!r}, flags={!r}, block={!r})".format(
+ self.name, self.flags, self.block)
class Using():
def __init__(self, name, alias):
- global global_crc
self.name = name
+ # save constructor values for repr()
+ self._alias = alias
+
if isinstance(alias, Array):
- a = { 'type': alias.fieldtype,
- 'length': alias.length }
+ a = {'type': alias.fieldtype,
+ 'length': alias.length}
else:
- a = { 'type': alias.fieldtype }
+ a = {'type': alias.fieldtype}
self.alias = a
- self.crc = binascii.crc32(str(alias)) & 0xffffffff
- global_crc = binascii.crc32(str(alias), global_crc)
- global_type_add(name)
+ self.crc = str(alias).encode()
+ global_type_add(name, self)
def __repr__(self):
- return self.name + str(self.alias)
+ return "Using(name={!r}, alias={!r})".format(self.name, self._alias)
class Union():
self.type = 'Union'
self.manual_print = False
self.manual_endian = False
- global global_crc
self.name = name
self.block = block
- self.crc = crc_block(block)
- global_type_add(name)
+ self.crc = str(block).encode()
+ global_type_add(name, self)
def __repr__(self):
- return str(self.block)
+ return "Union(name={!r}, block={!r})".format(self.name, self.block)
class Define():
self.name = name
self.flags = flags
self.block = block
- self.crc = crc_block(block)
+ self.crc = str(block).encode()
self.dont_trace = False
self.manual_print = False
self.manual_endian = False
block.remove(b)
def __repr__(self):
- return self.name + str(self.flags) + str(self.block)
+ return "Define(name={!r}, flags={!r}, block={!r})".format(
+ self.name, self.flags, self.block)
class Enum():
block[i] = [b, count]
self.block = block
- self.crc = crc_block(block)
- global_type_add(name)
+ self.crc = str(block).encode()
+ global_type_add(name, self)
def __repr__(self):
- return self.name + str(self.block)
+ return "Enum(name={!r}, block={!r}, enumtype={!r})".format(
+ self.name, self.block, self.enumtype)
class Import():
self.result = parser.parse_file(fd, None)
def __repr__(self):
- return self.filename
+ return "Import(filename={!r})".format(self.filename)
class Option():
def __init__(self, option):
self.option = option
- self.crc = crc_block(option)
+ self.crc = str(option).encode()
def __repr__(self):
- return str(self.option)
+ return "Option({!r})".format(self.option)
def __getitem__(self, index):
return self.option[index]
def __init__(self, fieldtype, name, length):
self.type = 'Array'
self.fieldtype = fieldtype
+
+ # save constructor values for repr()
+ self._name = name
+ self._length = length
+
self.fieldname = name
if type(length) is str:
self.lengthfield = length
self.lengthfield = None
def __repr__(self):
- return str([self.fieldtype, self.fieldname, self.length,
- self.lengthfield])
+ return "Array(fieldtype={!r}, name={!r}, length={!r})".format(
+ self.fieldtype, self._name, self._length)
class Field():
- def __init__(self, fieldtype, name):
+ def __init__(self, fieldtype, name, limit=None):
self.type = 'Field'
self.fieldtype = fieldtype
self.fieldname = name
+ self.limit = limit
def __repr__(self):
- return str([self.fieldtype, self.fieldname])
+ return "Field(fieldtype={!r}, name={!r}, limit={!r})".format(
+ self.fieldtype, self.fieldname, self.limit)
class Coord(object):
def p_enum_statements(self, p):
'''enum_statements : enum_statement
- | enum_statements enum_statement'''
+ | enum_statements enum_statement'''
if len(p) == 2:
p[0] = [p[1]]
else:
else:
p[0] = p[1]
+ def p_field_options(self, p):
+ '''field_options : field_option
+ | field_options field_option'''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = {**p[1], **p[2]}
+
+ def p_field_option(self, p):
+ '''field_option : ID '=' assignee ','
+ | ID '=' assignee
+ '''
+ p[0] = {p[1]: p[3]}
+
def p_declaration(self, p):
- '''declaration : type_specifier ID ';' '''
- if len(p) != 4:
+ '''declaration : type_specifier ID ';'
+ | type_specifier ID '[' field_options ']' ';' '''
+ if len(p) == 7:
+ p[0] = Field(p[1], p[2], p[4])
+ elif len(p) == 4:
+ p[0] = Field(p[1], p[2])
+ else:
self._parse_error('ERROR')
self.fields.append(p[2])
- p[0] = Field(p[1], p[2])
def p_declaration_array(self, p):
'''declaration : type_specifier ID '[' NUM ']' ';'
s['types'] = []
s['Import'] = []
s['Alias'] = {}
+ crc = 0
for o in objs:
tname = o.__class__.__name__
+ try:
+ crc = binascii.crc32(o.crc, crc)
+ except AttributeError:
+ pass
if isinstance(o, Define):
s[tname].append(o)
if o.autoreply:
replies = {s.reply: s for s in s['Service']}
seen_services = {}
+ s['file_crc'] = crc
+
for service in svcs:
if service not in msgs:
raise ValueError(
return dirlist
+def foldup_blocks(block, crc):
+ for b in block:
+ # Look up CRC in user defined types
+ if b.fieldtype.startswith('vl_api_'):
+ # Recursively
+ t = global_types[b.fieldtype]
+ try:
+ crc = crc_block_combine(t.block, crc)
+ return foldup_blocks(t.block, crc)
+ except:
+ pass
+ return crc
+
+
+def foldup_crcs(s):
+ for f in s:
+ f.crc = foldup_blocks(f.block,
+ binascii.crc32(f.crc))
+
+
#
# Main
#
if sys.version[0] == '2':
cliparser.add_argument('--input', type=argparse.FileType('r'),
default=sys.stdin)
+ cliparser.add_argument('--output', nargs='?',
+ type=argparse.FileType('w'),
+ default=sys.stdout)
+
else:
cliparser.add_argument('--input',
type=argparse.FileType('r', encoding='UTF-8'),
default=sys.stdin)
- cliparser.add_argument('--output', nargs='?', type=argparse.FileType('w'),
- default=sys.stdout)
+ cliparser.add_argument('--output', nargs='?',
+ type=argparse.FileType('w', encoding='UTF-8'),
+ default=sys.stdout)
cliparser.add_argument('output_module', nargs='?', default='C')
cliparser.add_argument('--debug', action='store_true')
# Add msg_id field
s['Define'] = add_msg_id(s['Define'])
- file_crc = global_crc & 0xffffffff
+ # Fold up CRCs
+ foldup_crcs(s['Define'])
#
# Debug
#
# Generate representation
#
- import imp
+ from importlib.machinery import SourceFileLoader
# Default path
pluginpath = ''
args.output_module.lower())
try:
- plugin = imp.load_source(args.output_module, module_path)
+ plugin = SourceFileLoader(args.output_module,
+ module_path).load_module()
except Exception as err:
raise Exception('Error importing output plugin: {}, {}'
.format(module_path, err))
- result = plugin.run(filename, s, file_crc)
+ result = plugin.run(filename, s)
if result:
print(result, file=args.output)
else: