#!/usr/bin/env python # (C) Copyright IBM Corporation 2005 # All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # on the rights to use, copy, modify, merge, publish, distribute, sub # license, and/or sell copies of the Software, and to permit persons to whom # the Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # Authors: # Ian Romanick import string, copy class type_node(object): def __init__(self): self.pointer = 0 # bool self.const = 0 # bool self.signed = 1 # bool self.integer = 1 # bool # If elements is set to non-zero, then field is an array. self.elements = 0 self.name = None self.size = 0 # type's size in bytes return def string(self): """Return string representation of this type_node.""" s = "" if self.pointer: s = "* " if self.const: s += "const " if not self.pointer: if self.integer: if self.signed: s += "signed " else: s += "unsigned " if self.name: s += "%s " % (self.name) return s class type_table(object): def __init__(self): self.types_by_name = {} return def add_type(self, type_expr): self.types_by_name[ type_expr.get_base_name() ] = type_expr return def find_type(self, name): if name in self.types_by_name: return self.types_by_name[ name ] else: return None def create_initial_types(): tt = type_table() basic_types = [ ("char", 1, 1), ("short", 2, 1), ("int", 4, 1), ("long", 4, 1), ("float", 4, 0), ("double", 8, 0), ("enum", 4, 1) ] for (type_name, type_size, integer) in basic_types: te = type_expression(None) tn = type_node() tn.name = type_name tn.size = type_size tn.integer = integer te.expr.append(tn) tt.add_type( te ) type_expression.built_in_types = tt return class type_expression(object): built_in_types = None def __init__(self, type_string, extra_types = None): self.expr = [] if not type_string: return self.original_string = type_string if not type_expression.built_in_types: raise RuntimeError("create_initial_types must be called before creating type_expression objects.") # Replace '*' with ' * ' in type_string. Then, split the string # into tokens, separated by spaces. tokens = string.split( string.replace( type_string, "*", " * " ) ) const = 0 t = None signed = 0 unsigned = 0 for i in tokens: if i == "const": if t and t.pointer: t.const = 1 else: const = 1 elif i == "signed": signed = 1 elif i == "unsigned": unsigned = 1 elif i == "*": # This is a quirky special-case because of the # way the C works for types. If 'unsigned' is # specified all by itself, it is treated the # same as "unsigned int". if unsigned: self.set_base_type( "int", signed, unsigned, const, extra_types ) const = 0 signed = 0 unsigned = 0 if not self.expr: raise RuntimeError("Invalid type expression (dangling pointer)") if signed: raise RuntimeError("Invalid type expression (signed / unsigned applied to pointer)") t = type_node() t.pointer = 1 self.expr.append( t ) else: if self.expr: raise RuntimeError('Invalid type expression (garbage after pointer qualifier -> "%s")' % (self.original_string)) self.set_base_type( i, signed, unsigned, const, extra_types ) const = 0 signed = 0 unsigned = 0 if signed and unsigned: raise RuntimeError("Invalid type expression (both signed and unsigned specified)") if const: raise RuntimeError("Invalid type expression (dangling const)") if unsigned: raise RuntimeError("Invalid type expression (dangling signed)") if signed: raise RuntimeError("Invalid type expression (dangling unsigned)") return def set_base_type(self, type_name, signed, unsigned, const, extra_types): te = type_expression.built_in_types.find_type( type_name ) if not te: te = extra_types.find_type( type_name ) if not te: raise RuntimeError('Unknown base type "%s".' % (type_name)) self.expr = copy.deepcopy(te.expr) t = self.expr[ len(self.expr) - 1 ] t.const = const if signed: t.signed = 1 elif unsigned: t.signed = 0 def set_base_type_node(self, tn): self.expr = [tn] return def set_elements(self, count): tn = self.expr[0] tn.elements = count return def string(self): s = "" for t in self.expr: s += t.string() return s def get_base_type_node(self): return self.expr[0] def get_base_name(self): if len(self.expr): return self.expr[0].name else: return None def get_element_size(self): tn = self.expr[0] if tn.elements: return tn.elements * tn.size else: return tn.size def get_element_count(self): tn = self.expr[0] return tn.elements def get_stack_size(self): tn = self.expr[ -1 ] if tn.elements or tn.pointer: return 4 elif not tn.integer: return tn.size else: return 4 def is_pointer(self): tn = self.expr[ -1 ] return tn.pointer def format_string(self): tn = self.expr[ -1 ] if tn.pointer: return "%p" elif not tn.integer: return "%f" else: return "%d" if __name__ == '__main__': types_to_try = [ "int", "int *", "const int *", "int * const", "const int * const", \ "unsigned * const *", \ "float", "const double", "double * const"] create_initial_types() for t in types_to_try: print 'Trying "%s"...' % (t) te = type_expression( t ) print 'Got "%s" (%u, %u).' % (te.string(), te.get_stack_size(), te.get_element_size())