|
- #!/usr/bin/python2.5
- #
- # Copyright 2009 Olivier Gillet.
- #
- # Author: Olivier Gillet (ol.gillet@gmail.com)
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- # -----------------------------------------------------------------------------
- #
- # Generates .cc and .h files for string, lookup tables, etc.
-
- """Compiles python string tables/arrays into .cc and .h files."""
-
- import os
- import string
- import sys
-
-
- class ResourceEntry(object):
-
- def __init__(self, index, key, value, dupe_of, table):
- self._index = index
- self._key = key
- self._value = value
- self._dupe_of = self._key if dupe_of is None else dupe_of
- self._table = table
-
- @property
- def variable_name(self):
- return '%s_%s' % (self._table.prefix.lower(), self._dupe_of)
-
- @property
- def declaration(self):
- c_type = self._table.c_type
- name = self.variable_name
- return 'const %(c_type)s %(name)s[] PROGMEM' % locals()
-
- def Declare(self, f):
- if self._dupe_of == self._key:
- # Dupes are not declared.
- f.write('extern %s;\n' % self.declaration)
-
- def DeclareAlias(self, f):
- prefix = self._table.prefix
- key = self._key.upper()
- index = self._index
- if self._table.python_type == str:
- comment = ' // %s' % self._value
- size = None
- else:
- comment = ''
- size = len(self._value)
- f.write('#define %(prefix)s_%(key)s %(index)d%(comment)s\n' % locals())
- if not size is None:
- f.write('#define %(prefix)s_%(key)s_SIZE %(size)d\n' % locals())
-
- def Compile(self, f):
- # Do not create declaration for dupes.
- if self._dupe_of != self._key:
- return
-
- declaration = self.declaration
- if self._table.python_type == str:
- value = self._value
- f.write('static %(declaration)s = "%(value)s";\n' % locals())
- else:
- f.write('%(declaration)s = {\n' % locals())
- n_elements = len(self._value)
- for i in xrange(0, n_elements, 8):
- f.write(' ');
- f.write(', '.join(
- '%6d' % self._value[j] for j in xrange(i, min(n_elements, i + 8))))
- f.write(',\n');
- f.write('};\n')
-
-
- class ResourceTable(object):
-
- def __init__(self, resource_tuple):
- self.name = resource_tuple[1]
- self.prefix = resource_tuple[2]
- self.c_type = resource_tuple[3]
- self.python_type = resource_tuple[4]
- self.ram_based_table = resource_tuple[5]
- self.entries = []
- self._ComputeIdentifierRewriteTable()
- keys = set()
- values = {}
- for index, entry in enumerate(resource_tuple[0]):
- if self.python_type == str:
- # There is no name/value for string entries
- key, value = entry, entry.strip()
- else:
- key, value = entry
-
- # Add a prefix to avoid key duplicates.
- key = self._MakeIdentifier(key)
- while key in keys:
- key = '_%s' % key
- keys.add(key)
- hashable_value = tuple(value)
- self.entries.append(ResourceEntry(index, key, value,
- values.get(hashable_value, None), self))
- if not hashable_value in values:
- values[hashable_value] = key
-
- def _ComputeIdentifierRewriteTable(self):
- in_chr = ''.join(map(chr, range(256)))
- out_chr = [ord('_')] * 256
- # Tolerated characters.
- for i in string.uppercase + string.lowercase + string.digits:
- out_chr[ord(i)] = ord(i.lower())
-
- # Rewritten characters.
- in_rewritten = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09~*+=><^"|'
- out_rewritten = '0123456789TPSeglxpv'
- for rewrite in zip(in_rewritten, out_rewritten):
- out_chr[ord(rewrite[0])] = ord(rewrite[1])
-
- table = string.maketrans(in_chr, ''.join(map(chr, out_chr)))
- bad_chars = '\t\n\r-:()[]"\',;'
- self._MakeIdentifier = lambda s:s.translate(table, bad_chars)
-
- def DeclareEntries(self, f):
- if self.python_type != str:
- for entry in self.entries:
- entry.Declare(f)
-
- def DeclareAliases(self, f):
- for entry in self.entries:
- entry.DeclareAlias(f)
-
- def Compile(self, f):
- # Write a declaration for each entry.
- for entry in self.entries:
- entry.Compile(f)
-
- # Write the resource pointer table.
- modifier = 'PROGMEM ' if not self.ram_based_table else ''
- c_type = self.c_type
- name = self.name
- f.write(
- '\n\n%(modifier)sconst %(c_type)s* const %(name)s_table[] = {\n' % locals())
- for entry in self.entries:
- f.write(' %s,\n' % entry.variable_name)
- f.write('};\n\n')
-
-
- class ResourceLibrary(object):
-
- def __init__(self, root):
- self._tables = []
- self._root = root
- # Create resource table objects for all resources.
- for resource_tuple in root.resources:
- # Split a multiline string into a list of strings
- if resource_tuple[-2] == str:
- resource_tuple = list(resource_tuple)
- resource_tuple[0] = [x for x in resource_tuple[0].split('\n') if x]
- resource_tuple = tuple(resource_tuple)
- self._tables.append(ResourceTable(resource_tuple))
-
- @property
- def max_num_entries(self):
- max_num_entries = 0
- for table in self._tables:
- max_num_entries = max(max_num_entries, len(table.entries))
- return max_num_entries
-
- def _OpenNamespace(self, f):
- if self._root.namespace:
- f.write('\nnamespace %s {\n\n' % self._root.namespace)
-
- def _CloseNamespace(self, f):
- if self._root.namespace:
- f.write('\n} // namespace %s\n' % self._root.namespace)
-
- def _DeclareTables(self, f):
- for table in self._tables:
- f.write('extern const %s* const %s_table[];\n\n' % (table.c_type, table.name))
-
- def _DeclareEntries(self, f):
- for table in self._tables:
- table.DeclareEntries(f)
-
- def _DeclareAliases(self, f):
- for table in self._tables:
- table.DeclareAliases(f)
-
- def _CompileTables(self, f):
- for table in self._tables:
- table.Compile(f)
-
- def GenerateHeader(self):
- root = self._root
- f = file(os.path.join(root.target, 'resources.h'), 'wb')
- # Write header and header guard
- header_guard = root.target.replace(os.path.sep, '_').upper()
- header_guard = '%s_RESOURCES_H_' % header_guard
- f.write(root.header + '\n\n')
- f.write('#ifndef %s\n' % header_guard)
- f.write('#define %s\n\n' % header_guard)
- f.write(root.includes + '\n\n')
- if root.create_specialized_manager:
- f.write('#include "avrlib/resources_manager.h"\n')
- self._OpenNamespace(f)
- f.write('typedef %s ResourceId;\n\n' % \
- root.types[self.max_num_entries > 255])
- self._DeclareTables(f)
- self._DeclareEntries(f)
- self._DeclareAliases(f)
- if root.create_specialized_manager:
- f.write('typedef avrlib::ResourcesManager<\n')
- f.write(' ResourceId,\n')
- f.write(' avrlib::ResourcesTables<\n')
- f.write(' %s_table,\n' % root.resources[0][1])
- f.write(' %s_table> > ResourcesManager; \n' % root.resources[1][1])
- self._CloseNamespace(f)
- f.write('\n#endif // %s\n' % (header_guard))
- f.close()
-
- def GenerateCc(self):
- root = self._root
- file_name = os.path.join(self._root.target, 'resources.cc')
- f = file(file_name, 'wb')
- f.write(self._root.header + '\n\n')
- f.write('#include "%s"\n' % file_name.replace('.cc', '.h'))
- self._OpenNamespace(f)
- self._CompileTables(f)
- self._CloseNamespace(f)
- f.close()
-
-
- def Compile(path):
- # A hacky way of loading the py file passed as an argument as a module +
- # a descent along the module path.
- base_name = os.path.splitext(path)[0]
- sys.path += [os.path.abspath('.')]
- resource_module = __import__(base_name.replace('/', '.'))
- for part in base_name.split('/')[1:]:
- resource_module = getattr(resource_module, part)
-
- library = ResourceLibrary(resource_module)
- library.GenerateHeader()
- library.GenerateCc()
-
-
- def main(argv):
- for i in xrange(1, len(argv)):
- Compile(argv[i])
-
-
- if __name__ == '__main__':
- main(sys.argv)
|