| #!/usr/bin/env python |
| """ ir.py - parse c declarations |
| |
| (c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com> |
| Released under GNU LGPL license. |
| |
| version 0.xx |
| |
| """ |
| |
| import sys |
| #import cPickle as pickle |
| import pickle |
| |
| #from lexer import Lexer |
| from parse_core import Symbols #, Parser |
| import node as node_module |
| import cparse |
| import genpyx |
| |
| class Node(genpyx.Node, node_module.Node): |
| """ |
| tree structure |
| """ |
| def __init__( self, *args, **kw ): |
| node_module.Node.__init__( self, *args, **kw ) |
| self._marked = False |
| def get_marked( self ): |
| return self._marked |
| def set_marked( self, marked ): |
| # if marked: |
| # print "MARK", self |
| self._marked = marked |
| marked = property( get_marked, set_marked ) |
| |
| # def __getstate__( self ): |
| # return self.__class__, tuple( [ item.__getstate__() for item in self ] ) |
| # def __setstate__( self, state ): |
| # cls, states = state |
| # states = list(states) |
| # for idx, state in enumerate(states): |
| # items[idx] = items[idx].__setstate__( |
| def __getstate__(self): |
| return str(self) |
| def __setstate__(self, state): |
| Node.__init__(self) |
| self[:] = eval(state) |
| |
| # _unique_id = 0 |
| # def get_unique_id(cls): |
| # Node._unique_id += 1 |
| # return Node._unique_id |
| # get_unique_id = classmethod(get_unique_id) |
| |
| def __hash__( self ): |
| return hash( tuple([hash(type(self))]+[hash(item) for item in self]) ) |
| |
| def clone(self): |
| l = [] |
| for item in self: |
| if isinstance(item,Node): |
| item = item.clone() |
| l.append(item) |
| return self.__class__(*l, **self.__dict__) |
| |
| def init_from( self, other ): # class method ? |
| # Warning: shallow init |
| self[:] = other |
| self.__dict__.update( other.__dict__ ) |
| return self |
| |
| # def is_struct(self): |
| # for x in self: |
| # if isinstance(x,Node): |
| # if x.is_struct(): |
| # return 1 |
| # return 0 |
| |
| |
| #def explain(self): |
| #l = [] |
| #for x in self: |
| #if isinstance(x,Node): |
| #l.append(x.explain()) |
| #else: |
| #l.append(str(x)) |
| #return string.join(l," ") |
| ##(self.__class__.__name__,string.join(l) ) |
| |
| def psource(self): |
| if hasattr(self,'lines'): |
| # print "# "+string.join(self.lines,"\n# ")+"\n" |
| print "# "+"\n# ".join(self.lines)+"\n" |
| |
| def cstr(self,l=None): |
| """ |
| Build a list of tokens; return the joined tokens string |
| """ |
| if l is None: |
| l = [] |
| for x in self: |
| if isinstance(x,Node): |
| x.cstr(l) |
| else: |
| l.insert(0,str(x)+' ') |
| s = ''.join(l) |
| return s |
| |
| def ctype(self): # anon_clone |
| " return clone of self without identifiers " |
| #print "%s.ctype()"%self |
| l=[] |
| for x in self: |
| if isinstance(x,Node): |
| l.append(x.ctype()) |
| else: |
| l.append(x) |
| #print "%s.__class__(*%s)"%(self,l) |
| return self.__class__(*l, **self.__dict__) # XX **self.__dict__ ? |
| |
| def cbasetype(self): |
| " return ctype with all TypeAlias's replaced " |
| # WARNING: we cache results (so do not mutate self!!) |
| l=[] |
| for x in self: |
| if isinstance(x,Node): |
| l.append(x.cbasetype()) |
| else: |
| l.append(x) |
| #print "%s.__class__(*%s)"%(self,l) |
| return self.__class__(*l, **self.__dict__) # XX **self.__dict__ ? |
| |
| def signature( self, tank=None ): |
| if tank is None: |
| tank = {} |
| for node in self.nodes(): |
| if not tank.has_key( type(node) ): |
| tank[ type(node) ] = {} |
| type(node).tank = tank[type(node)] |
| shape = tuple( [ type(_node).__name__ for _node in node ] ) |
| if not tank[type(node)].has_key(shape): |
| tank[type(node)][shape] = [] |
| tank[type(node)][shape].append( node ) |
| return tank |
| |
| def psig( self, tank=None ): |
| if tank is None: |
| tank = {} |
| tank = self.signature(tank) |
| for key in tank.keys(): |
| print key.__name__ |
| for shape in tank[key].keys(): |
| print " ", shape |
| |
| # |
| ################################################# |
| |
| class Named(genpyx.Named, Node): |
| " has a .name property " |
| def get_name(self): |
| if self: |
| assert type(self[0])==str |
| return self[0] |
| return None |
| def set_name(self, name): |
| if self: |
| self[0] = name |
| else: |
| self.append(name) |
| name = property(get_name,set_name) |
| |
| |
| class BasicType(genpyx.BasicType, Named): |
| "float double void char int" |
| pass |
| |
| class Qualifier(genpyx.Qualifier, Named): |
| "register signed unsigned short long const volatile inline" |
| pass |
| |
| class StorageClass(genpyx.StorageClass, Named): |
| "extern static auto" |
| pass |
| |
| class Ellipses(genpyx.Ellipses, Named): |
| "..." |
| pass |
| |
| class GCCBuiltin(genpyx.GCCBuiltin, BasicType): |
| "things with __builtin prefix" |
| pass |
| |
| class Identifier(genpyx.Identifier, Named): |
| """ |
| shape = +( str, +ConstExpr ) |
| """ |
| #def explain(self): |
| #if len(self)==1: |
| #return "%s"%self.name |
| #else: |
| #return "%s initialized to %s"%(self.name, |
| #Node(self[1]).explain()) # will handle Initializer |
| |
| # def ctype(self): |
| # return self.__class__(*self[1:]) #.clone() ? |
| |
| # def get_name(self): |
| # if self: |
| # return self[0] |
| # def set_name(self, name): |
| # if self: |
| # self[0] = name |
| # else: |
| # self.append(name) |
| # name = property(get_name,set_name) |
| |
| def cstr(self,l=None): |
| if l is None: |
| l=[] |
| if len(self)>1: |
| assert len(self)==2 |
| l.append( '%s = %s'%(self[0],self[1]) ) |
| elif len(self)==1: |
| l.append( str(self[0]) ) |
| return " ".join(l) |
| |
| class TypeAlias(genpyx.TypeAlias, Named): |
| """ |
| typedefed things, eg. size_t |
| |
| """ |
| def cbasetype( self ): |
| node = self.typedef.cbasetype().get_rest() |
| return node |
| |
| class Function(genpyx.Function, Node): |
| """ |
| """ |
| #def explain(self): |
| #if len(self): |
| #return "function (%s), returning"%\ |
| #", ".join( map(lambda x:x.explain(),self) ) |
| #else: |
| #return "function returning" |
| |
| def cstr(self,l): |
| #print '%s.cstr(%s)'%(self,l) |
| _l=[] |
| assert len(self) |
| i=0 |
| while isinstance(self[i],Declarator): |
| _l.append( self[i].cstr() ) |
| i=i+1 |
| l.append( '(%s)'% ', '.join(_l) ) |
| while i<len(self): |
| self[i].cstr(l) |
| i=i+1 |
| return " ".join(l) |
| |
| def return_type(self): |
| node = self[-1] |
| #assert isinstance(node,DeclarationSpecifiers) |
| return Declarator( Identifier(), node ) |
| ret = property(return_type) |
| |
| def get_args(self): |
| args = [ arg for arg in self[:-1] if not arg.is_void() ] |
| return args |
| args = property(get_args) |
| |
| def arg_types(self): |
| return [ AbstractDeclarator().init_from( arg.ctype() ) for arg in self[:-1]] |
| |
| def is_varargs(self): |
| for node in self.nodes(): |
| if isinstance(node,Ellipses) or 'va_list' in node: |
| # print self, 'is_varargs' |
| return True |
| # print self, 'is_varargs' |
| return False |
| # return fn.deepfind(Ellipses) or fn.deepfind('va_list') |
| |
| def ctype(self): |
| return Function(*self.arg_types()+[self[-1]]) # XX self[-1].ctype |
| |
| |
| class Pointer(genpyx.Pointer, Node): |
| """ |
| """ |
| def get_spec(self): |
| if type(self[0])==TypeSpecifiers: # isinstance ?? |
| return self[0] |
| spec = property(get_spec) |
| |
| #def explain(self): |
| #return "pointer to" |
| |
| def cstr(self,l): |
| assert len(self) |
| node=self[0] |
| l.insert(0,'*') |
| if isinstance(node,Function): |
| l.insert(0,'(') |
| l.append(')') |
| elif isinstance(node,Array): |
| l.insert(0,'(') |
| l.append(')') |
| return Node.cstr(self,l) |
| |
| class Array(genpyx.Array, Node): |
| """ |
| """ |
| #def explain(self): |
| #s='' |
| #if len(self): |
| #if type(self[0])==int: |
| #s='0 to %s '%(self[0]-1) |
| #return "array %sof"%s |
| def has_size(self): |
| try: |
| int(self.size) |
| return True |
| except: |
| return False |
| |
| def get_size(self): |
| if type(self[-1])==str: |
| try: return int(self[-1]) |
| except: return self[-1] |
| return self[-1] # None |
| size = property(get_size) |
| |
| def get_spec(self): |
| if type(self[0])==TypeSpecifiers: # isinstance ?? |
| return self[0] |
| spec = property(get_spec) |
| |
| def to_pointer(self): |
| node = Pointer() |
| node.init_from( self.clone() ) |
| node.pop() # pop the size element |
| return node |
| |
| def cstr(self,l): |
| if self.size is None: |
| l.append('[]') |
| else: |
| l.append('[%s]'%self.size) |
| return Node( *self[:-1] ).cstr( l ) |
| |
| class Tag(genpyx.Tag, Named): |
| " the tag of a Struct, Union or Enum " |
| pass |
| |
| class Taged(genpyx.Taged, Node): |
| "Struct, Union or Enum " |
| def get_tag(self): |
| if len(self): |
| tag = self[0] |
| assert type(tag)==Tag # isinstance ?? |
| else: |
| tag = None |
| return tag |
| def set_tag(self,tag): |
| if len(self): |
| self[0] = tag |
| else: |
| self.append(tag) |
| tag = property( get_tag, set_tag ) |
| def has_members(self): |
| return len(self)>1 # more than just a tag |
| def get_members(self): |
| return self[1:] |
| members = property(get_members) # fields ? |
| |
| def ctype(self): |
| if not self.tag.name: |
| #print "# WARNING : anonymous struct " # OK i think |
| return self.clone() |
| # self = self.clone() |
| # return self[:1] # just the tag |
| return self.__class__( self.tag, **self.__dict__ ) # just the Tag |
| # return self.__class__( *self, **self.__dict__ ) |
| |
| def cbasetype(self): |
| return self.ctype() # is this enough ??? |
| # return Node.cbasetype(self) # XX lookup my tag if i am empty ..? |
| |
| |
| class Compound(genpyx.Compound, Taged): |
| "Struct or Union" |
| |
| def cstr(self,_l=None): |
| assert isinstance( self[0], Tag ) |
| tag='' |
| if len(self[0]): |
| tag=' '+self[0][0] |
| if isinstance(self,Struct): |
| l=[ 'struct%s '%tag ] |
| elif isinstance(self,Union): |
| l=[ 'union%s '%tag ] |
| if len(self)>1: |
| l.append(' { ') |
| for decl in self[1:]: |
| l.append( decl.cstr()+"; " ) |
| l.append('} ') |
| if _l is None: |
| _l=[] |
| while l: |
| _l.insert( 0, l.pop() ) |
| # XX empty struct with no tag -> "struct" XX |
| return "".join( _l ) |
| |
| def ctype(self): |
| tp = Taged.ctype(self) |
| for i in range(1,len(tp)): |
| tp[i] = StructDeclarator().init_from( tp[i] ) |
| return tp |
| |
| class Struct(genpyx.Struct, Compound): |
| """ |
| """ |
| pass |
| |
| |
| class Union(genpyx.Union, Compound): |
| """ |
| """ |
| pass |
| |
| |
| class Enum(genpyx.Enum, Taged): |
| """ |
| """ |
| def cstr(self,_l=None): |
| assert isinstance( self[0], Tag ) |
| tag='' |
| if len(self[0]): |
| tag=' '+self[0][0] |
| l=[ 'enum%s '%tag ] |
| if len(self)>1: |
| l.append(' { ') |
| for node in self[1:]: |
| l.append( node.cstr()+', ' ) |
| l.append('} ') |
| if _l is None: |
| _l=[] |
| while l: |
| _l.insert( 0, l.pop() ) |
| return ''.join( _l ) |
| |
| class Declarator(genpyx.Declarator, Node): |
| """ |
| """ |
| |
| def __eq__(self,other): |
| " unordered equality " |
| # ordering sometimes gets lost when we do a cbasetype |
| if not isinstance(other,Node): |
| return False |
| a, b = self[:], other[:] |
| a.sort() |
| b.sort() |
| return a == b |
| |
| def __hash__( self ): |
| hs = [hash(item) for item in self] |
| hs.sort() |
| return hash( tuple([hash(type(self))]+hs) ) |
| |
| def transform(self): |
| return |
| |
| def get_identifier(self): |
| if len(self)>1: |
| return self[0] |
| def set_identifier(self, identifier): |
| if len(self)>1: |
| self[0] = identifier |
| else: |
| self.insert(0,identifier) |
| identifier = property(get_identifier,set_identifier) |
| |
| def get_spec(self): |
| spec = self[-1] |
| if type(spec)==TypeSpecifiers: # isinstance ?? |
| return spec |
| spec = property(get_spec) |
| |
| def get_type_alias(self): |
| if self.spec: |
| if isinstance(self.spec[0], TypeAlias): |
| return self.spec[0] |
| type_alias = property(get_type_alias) |
| |
| def get_tagged(self): |
| if self.spec: |
| return self.spec.tagged # i am a tagged |
| tagged = property(get_tagged) |
| |
| def get_compound(self): |
| if self.spec: |
| return self.spec.compound # i am a compound |
| compound = property(get_compound) |
| |
| def get_struct(self): |
| if self.spec: |
| return self.spec.struct # i am a struct |
| struct = property(get_struct) |
| |
| def get_union(self): |
| if self.spec: |
| return self.spec.union # i am a union |
| union = property(get_union) |
| |
| def get_enum(self): |
| if self.spec: |
| return self.spec.enum # i am an enum |
| enum = property(get_enum) |
| |
| def get_function(self): |
| if len(self)>1 and type(self[1])==Function: # isinstance ?? |
| return self[1] |
| function = property(get_function) |
| |
| def get_pointer(self): |
| if len(self)>1 and type(self[1])==Pointer: # isinstance ?? |
| return self[1] |
| pointer = property(get_pointer) |
| |
| def get_array(self): |
| if len(self)>1 and type(self[1])==Array: # isinstance ?? |
| return self[1] |
| array = property(get_array) |
| |
| def get_name(self): |
| if self.identifier: |
| return self.identifier.name |
| def set_name(self, name): |
| assert self.identifier is not None |
| self.identifier.name = name |
| name = property(get_name, set_name) |
| |
| def get_rest(self): # XX needs a better name |
| if len(self)>1: |
| return self[1] |
| return self[0] |
| |
| def pointer_to( self ): |
| " return Declarator pointing to self's type " |
| decl = Declarator(Identifier(), Pointer(self.get_rest().clone())) |
| return decl |
| |
| def deref( self ): |
| " return (clone of) Declarator that self is pointing to " |
| node = self.ctype() # clone |
| pointer = node.pointer or node.array |
| assert pointer, "cannot dereference non-pointer" |
| node[1:2] = pointer |
| return node |
| |
| def is_void(self): |
| return self.spec and BasicType('void') in self.spec |
| |
| def is_pointer_to_fn(self): |
| return self.pointer and self.deref().function |
| |
| def is_pointer_to_char(self): |
| # return self.ctype() == TransUnit("char *a;").transform()[0].ctype() |
| node = self.pointer or self.array |
| if node: |
| spec = node.spec |
| if spec and BasicType('char') in spec and not BasicType('unsigned') in spec: |
| return True |
| return False |
| |
| def is_callback(self): |
| " i am a pointer to a function whose last arg is void* " |
| if self.is_pointer_to_fn(): |
| fn = self.deref().function |
| if fn.args: |
| arg = fn.args[-1] |
| if arg.pointer and arg.deref().is_void(): |
| return True |
| |
| def is_complete( self, tag_lookup ): |
| if self.tagged and self.tagged.tag.name in tag_lookup and not tag_lookup[self.tagged.tag.name].has_members(): |
| return False |
| return True |
| |
| def is_primative( self ): |
| "i am a char,short,int,float,double... " |
| spec = self.cbasetype().spec |
| return spec and spec.find(BasicType) |
| |
| def is_pyxnative( self ): |
| # pyrex handles char* too |
| # but i don't know if we should make this the default |
| # sometimes we want to send a NULL, so ... XXX |
| self = self.cbasetype() |
| if self.is_void(): |
| return False |
| if self.is_primative(): |
| return True |
| if self.enum: |
| return True |
| # pointer = None |
| # if self.pointer: |
| # pointer = self.pointer |
| # elif self.array: |
| # pointer = self.array |
| # if pointer and pointer.spec: |
| # spec = pointer.spec |
| # if BasicType("char") in spec and not Qualifier("unsigned") in spec: |
| # # char*, const char* |
| ## print self.deepstr() |
| # return True |
| return False |
| |
| def cstr(self,l=None): |
| return Node.cstr(self,l).strip() |
| |
| def ctype(self): |
| decl=Declarator() |
| decl.init_from( self.clone() ) |
| decl.identifier = Identifier() |
| for i in range(1,len(decl)): |
| decl[i]=decl[i].ctype() |
| return decl |
| |
| def cbasetype(self): |
| # WARNING: we cache results (so do not mutate self!!) |
| try: |
| # this cache improves performance by 50% |
| return self.__cbasetype.clone() |
| except AttributeError: |
| pass |
| decl = self.ctype() # gets rid of Identifier names |
| for i, node in enumerate(decl): |
| decl[i] = decl[i].cbasetype() |
| # return decl.get_rest() |
| |
| done = False |
| while not done: |
| done = True |
| nodes = decl.deepfilter( TypeSpecifiers ) |
| for node in nodes: |
| if node.deepfind( TypeSpecifiers ) != node: |
| # this node has another TypeSpecifier; |
| decl.expose_node( node ) |
| done = False |
| break # start again... |
| |
| # each TypeSpecifier needs to absorb primitive siblings (StorageClass, BasicType etc.) |
| nodes = decl.deepfilter( TypeSpecifiers ) |
| for node in nodes: |
| parent = decl.get_parent(node) |
| i = 0 |
| while i < len(parent): |
| assert not type(parent[i]) in (TypeAlias, Enum, Struct, Union) |
| if type(parent[i]) in (StorageClass, BasicType, Qualifier): |
| node.append( parent.pop(i) ) |
| else: |
| i = i + 1 |
| |
| self.__cbasetype = decl.clone() |
| return decl |
| |
| def invalidate(self): |
| # flush cache, etc. |
| try: |
| del self.__cbasetype |
| except AttributeError: |
| pass |
| |
| def declare_str(self,name): |
| " return c string declaring name with same type as self " |
| tp = self.ctype() |
| tp.name = name |
| return tp.cstr()+";" |
| |
| class Typedef(genpyx.Typedef, Declarator): |
| def cstr(self,l=None): |
| return 'typedef ' + Declarator.cstr(self,l) #.strip() |
| |
| class AbstractDeclarator(genpyx.AbstractDeclarator, Declarator): |
| """ used in Function; may lack an identifier """ |
| |
| #def cstr(self,l=None): |
| #return Node.cstr(self,l) |
| |
| # def ctype(self): |
| # # _type_ ignores the name of our identifier |
| # return Node.ctype(self) |
| |
| class FieldLength(genpyx.FieldLength, Node): |
| """ |
| """ |
| #def explain(self): |
| #return "" |
| |
| def cstr(self,l): |
| l.append(':%s'%self[0]) |
| |
| class StructDeclarator(genpyx.StructDeclarator, Declarator): # also used in Union |
| """ |
| """ |
| #def explain(self): |
| #flen = self.find(FieldLength) |
| #if flen is not None: |
| #i = self.index(flen) |
| #self.pop(i) |
| #s = Declarator.explain(self) |
| #self.insert(i,flen) |
| #width = flen[0] |
| #if width > 0: |
| #return s+" bitfield %s wide"%width |
| #else: |
| #return s+" alignment bitfield" |
| #else: |
| #return Declarator.explain(self) |
| # def ctype(self): |
| # return self |
| def get_field_length(self): |
| if len(self)>1 and isinstance( self[1], FieldLength ): |
| return self[1] |
| field_length = property(get_field_length) |
| |
| |
| class DeclarationSpecifiers(genpyx.DeclarationSpecifiers, Node): |
| #class TypeSpecifiers(Node): |
| """ |
| """ |
| def __eq__(self,other): |
| " unordered equality " |
| if not isinstance(other,Node): |
| return False |
| a, b = self[:], other[:] |
| a.sort() |
| b.sort() |
| return a == b |
| |
| def __hash__( self ): |
| hs = [hash(item) for item in self] |
| hs.sort() |
| return hash( tuple([hash(type(self))]+hs) ) |
| |
| # def is_struct(self): |
| # return self.find(Struct) is not None |
| |
| |
| class TypeSpecifiers(genpyx.TypeSpecifiers, DeclarationSpecifiers): |
| """ |
| """ |
| def get_tagged(self): |
| if self and isinstance(self[0],Taged): |
| return self[0] |
| tagged = property(get_tagged) |
| |
| def get_compound(self): |
| if self and isinstance(self[0],Compound): |
| return self[0] |
| compound = property(get_compound) |
| |
| def get_struct(self): |
| if self and isinstance(self[0],Struct): |
| return self[0] |
| struct = property(get_struct) |
| |
| def get_union(self): |
| if self and isinstance(self[0],Union): |
| return self[0] |
| union = property(get_union) |
| |
| def get_enum(self): |
| if self and isinstance(self[0],Enum): |
| return self[0] |
| enum = property(get_enum) |
| |
| def cbasetype(self): |
| node = Node.cbasetype(self) |
| # node.expose( TypeSpecifiers ) |
| # if node.deepfind(TypeSpecifiers) != node: |
| return node |
| |
| class Initializer(genpyx.Initializer, Node): |
| """ |
| """ |
| pass |
| |
| |
| |
| class Declaration(genpyx.Declaration, Node): |
| """ |
| """ |
| def do_spec(self): |
| " distribute DeclarationSpecifiers over each Declarator " |
| spec=self[0] |
| assert isinstance(spec,DeclarationSpecifiers), spec.deepstr() |
| self.pop(0) |
| for declarator in self: |
| assert isinstance(declarator,Declarator) |
| #if isinstance(declarator,DeclarationSpecifiers #huh? |
| ##for node in spec: |
| ##declarator.append(node.clone()) |
| declarator.append(spec) |
| |
| def transform(self): |
| # children go first |
| for node in self.nodes(): |
| if isinstance(node,Declaration): |
| node.do_spec() |
| node.file = self.file # overkill ? |
| self.expose(Declaration) |
| |
| #def explain(self): |
| #return string.join([x.explain() for x in self],", ") |
| #return string.join(map(lambda x:x.explain(),self),", ") |
| |
| |
| class ParameterDeclaration(genpyx.ParameterDeclaration, Declaration): |
| """ |
| """ |
| pass |
| |
| |
| class StructDeclaration(genpyx.StructDeclaration, Declaration): |
| """ |
| """ |
| pass |
| |
| |
| class TransUnit(genpyx.TransUnit, Node): |
| """ |
| Top level node. |
| """ |
| def __init__( self, item ): # XX __init__ uses different signature ! XX |
| if type(item)==str: |
| node = cparse.TransUnit() |
| node.parse(item) |
| else: |
| node = item |
| assert isinstance( node, cparse.TransUnit ), str(node) |
| Node.__init__(self) |
| self[:] = [ self.convert(child) for child in node ] |
| self.__dict__.update( node.__dict__ ) |
| assert "name" not in node.__dict__ |
| |
| self.syms = {} # map identifier names to their Declarator's |
| self.typedefs = {} # map names to Typedef's |
| self.tag_lookup = {} # map struct, union, enum tags to Taged's |
| |
| # XX should call transform here XX |
| |
| # print self.deepstr() |
| def __getstate__( self ): |
| nodes = tuple( [ repr(node) for node in self ] ) |
| typedefs = tuple( [ (key,repr(val)) for key,val in self.typedefs.items() ] ) |
| return nodes, typedefs |
| def __setstate__( self, state ): |
| Node.__init__(self) |
| nodes, typedefs = state |
| nodes = [ eval(node) for node in nodes ] |
| self[:] = nodes |
| typedefs = [ (key,eval(val)) for key,val in typedefs ] |
| self.typedefs = dict(typedefs) |
| |
| def convert( self, node ): |
| # name = node.__class__.__name__ |
| # cls = globals()[ name ] |
| cls = cls_lookup[ type(node) ] |
| _node = cls() |
| for child in node: |
| if isinstance(child, node_module.Node): |
| child = self.convert( child ) |
| else: |
| assert child is None or type(child) in (str, int), type(child) |
| _node.append( child ) |
| _node.__dict__.update( node.__dict__ ) |
| return _node |
| |
| def strip(self,files): |
| " leave only the declarations from <files> " |
| i=0 |
| while i<len(self): |
| if self[i].file in files: |
| i=i+1 |
| else: |
| self.pop(i) |
| |
| def mark(self,cb,verbose=False): |
| " mark our child nodes such that cb(node).. mark dependants too. prune unmarked objects. " |
| # mark the nodes: |
| for node in self: |
| node.marked = cb(self, node) |
| if verbose and node.marked: |
| print '1:', node.cstr() |
| # propagate dependancy: |
| i=len(self) |
| while i: |
| i-=1 # we go backwards |
| for node in self[i].nodes(): # bottom-up search |
| if verbose and self[i].marked and not node.marked: |
| print '2:', str(node), '<--', self[i].cstr() |
| node.marked = self[i].marked or node.marked |
| if type(node)==TypeAlias: |
| if verbose and node.marked and not node.typedef.marked: |
| print '3:', node.typedef.cstr(), '<--', node.cstr() |
| node.typedef.marked = node.typedef.marked or node.marked |
| if isinstance(node, Taged): |
| if node.tag.name in self.tag_lookup: |
| _node = self.tag_lookup[ node.tag.name ] # look-up the def'n |
| if verbose and node.marked and not _node.marked: |
| print '4:', _node.cstr(), '<--', self[i].cstr() |
| # _node.marked = _node.marked or self[i].marked |
| _node.marked = _node.marked or node.marked |
| # else: |
| # # this guy has no tag |
| # print "lost tag:", self[i].cstr() |
| |
| # XX struct defs acquire marks from members, but XX |
| # XX ordinary definitions do not XX |
| # if node.marked and not self[i].marked: |
| # # one of my descendants is marked |
| # if verbose: |
| # print '5:', self[i].cstr(), '<--', node.cstr() |
| # self[i].marked = True |
| # if verbose: |
| # for node in self: |
| # print '-'*79 |
| # if node.enum: |
| # print str(node.marked) + ': ' + node.cstr() |
| # prune: |
| f = open(".tmp/pruned.txt","w") |
| f.write("// This file autogenerated by '%s' .\n"%__file__) |
| f.write("// List of functions pruned from parse tree, for various reasons.\n\n") |
| i=0 |
| while i<len(self): |
| if not self[i].marked: |
| if verbose: print 'pop:', self[i].cstr() |
| f.write( self[i].cstr() + "\n" ) |
| self.pop(i) |
| # elif self[i].compound: |
| # # XXXX for now, rip out all struct members XXXX |
| # self[i].compound[1:] = [] # XX encapsulation |
| # i = i + 1 |
| else: |
| i = i + 1 |
| for key, value in self.syms.items(): |
| if not value.marked: |
| del self.syms[key] |
| for key, value in self.typedefs.items(): |
| if not value.marked: |
| del self.typedefs[key] |
| for key, value in self.tag_lookup.items(): |
| if not value.marked: |
| del self.tag_lookup[key] |
| # sys.exit(1) |
| |
| def assert_no_dups(self): |
| check={} |
| for node in self.nodes(): |
| assert not check.has_key(id(node)) |
| check[id(node)]=1 |
| |
| def transform(self, verbose=False, test_parse=False, test_types=False ): |
| i=0 |
| while i < len(self): |
| if verbose: print "##"*25 |
| declaration=self[i] |
| |
| if verbose: declaration.psource() |
| if verbose: print declaration.deepstr(),'\n' |
| assert isinstance(declaration,Declaration) |
| if verbose: print "# expose declarators from declaration" |
| |
| # STAGE 1 |
| declaration.transform() |
| |
| if verbose: print declaration.deepstr(),'\n' |
| self[i:i+1] = declaration # expose declarators from declaration |
| |
| for j in range(len(declaration)): |
| declarator=self[i] |
| |
| assert isinstance(declarator,Declarator) |
| if verbose: print "# declarator.transform()" |
| |
| # STAGE 2 |
| declarator.transform() |
| |
| if verbose: print declarator.deepstr(),'\n' |
| if verbose: print "# self.visit_declarator(declarator)" |
| |
| # STAGE 3 |
| self[i] = declarator = self.visit_declarator(declarator) |
| |
| # STAGE 4 |
| if declarator.name: |
| if isinstance(declarator, Typedef): |
| if verbose: print "# typedef %s" % declarator.name |
| self.typedefs[ declarator.name ] = declarator |
| else: |
| if verbose: print "# sym %s" % declarator.name |
| self.syms[ declarator.name ] = declarator |
| |
| for node in declarator.nodes(): |
| if isinstance(node,Taged) and node.tag.name: |
| assert type(node.tag.name)==str, node.deepstr() |
| taged = self.tag_lookup.get( node.tag.name, None ) |
| if taged is None: |
| if verbose: print "# tag lookup %s = %s" % (declarator.name, node.tag.name) |
| self.tag_lookup[ node.tag.name ] = node |
| elif not taged.has_members(): |
| # this is (maybe) the definition of this tag |
| if verbose: print "# definition %s = %s" % (declarator.name, node.tag.name) |
| self.tag_lookup[ node.tag.name ] = node |
| |
| # Annotate the TypeAlias's |
| for node in declarator.deepfilter( TypeAlias ): |
| name = node[0] |
| assert type( name ) == str |
| node.typedef = self.typedefs[ name ] |
| |
| if verbose: print declarator.deepstr(),'\n' |
| #print declarator.ctype().deepstr(),'\n' |
| #assert declarator.clone() == declarator |
| |
| ################################################### |
| # TESTS: |
| if test_parse: |
| # test that parse of cstr gives same answer |
| cstr = declarator.cstr()+';\n' |
| if verbose: print '# '+cstr.replace('\n','\n# ') |
| #print |
| if isinstance(declarator,Typedef): |
| name = declarator[0][0] |
| assert type(name)==str |
| self.lexer.rmtypedef( name ) |
| declaration = cparse.Declaration() |
| self.lexer.lex( cstr ) |
| #print self.lexer.err_string() |
| declaration.parse( self.lexer, Symbols() ) # use new name-space |
| #declaration.parse( Lexer( cstr ), Symbols() ) |
| declaration = self.convert(declaration) |
| declaration.transform() |
| assert len(declaration)==1 |
| decl=declaration[0] |
| decl.transform() |
| decl = self.visit_declarator(decl) |
| if decl!=declarator: |
| if verbose: print "#???????????" |
| if verbose: print decl.deepstr(),'\n\n' |
| #if verbose: print declaration.deepstr(),'\n\n' |
| #assert 0 |
| elif verbose: print '# OK\n' |
| |
| if test_types: |
| node = declarator.ctype() |
| declare_str= node.declare_str("my_name") |
| if verbose: print "# declarator.ctype() " |
| if verbose: print node.deepstr(),"\n" |
| if verbose: print "#",declare_str.replace('\n','\n# '), '\n' |
| |
| i=i+1 |
| return self |
| |
| def visit(self,node): |
| #print 'visit(%s)'%node |
| for _node in node: |
| if isinstance(_node,Declarator): |
| _node = self.visit_declarator(_node) # XX replace _node |
| elif isinstance(_node,Node): |
| _node = self.visit(_node) # XX replace _node |
| return node |
| |
| def visit_declarator(self,decl): |
| assert isinstance(decl,Declarator) |
| |
| # STAGE 3.a |
| tp = decl.deepfind(Typedef) |
| if tp is not None: |
| decl.deeprm(tp) |
| tp.init_from( decl ) # warning: shallow init |
| decl = tp |
| |
| # STAGE 3.b |
| i=len(decl) |
| # accumulate nodes (they become the children of decl) |
| children=[] |
| while i: |
| i=i-1 |
| node=decl.pop(i) |
| if isinstance(node,Declarator): |
| node = self.visit_declarator(node) # replace node |
| else: |
| node = self.visit(node) # replace node |
| if isinstance(node,Pointer): |
| node+=children |
| children=[node] |
| elif isinstance(node,Function): |
| node+=children |
| children=[node] |
| elif isinstance(node,Array): |
| while children: |
| node.insert(0,children.pop()) |
| children=[node] |
| # array size (if any) at end |
| #elif isinstance(node,Identifier): |
| #node+=children |
| #children=[node] |
| else: |
| # accumulate |
| children.insert(0,node) |
| decl[:]=children |
| return decl |
| |
| cstr = None |
| ctype = None |
| cbasetype = None |
| |
| |
| # remap the global class definitions in genpyx to |
| # point to the definitions in this module |
| gbl = globals() |
| for key, val in gbl.items(): |
| if type(val)==type: |
| if issubclass(val,Node): |
| setattr( genpyx, key, val ) |
| assert genpyx.Node == Node |
| |
| cls_lookup = { |
| # Node : Node , |
| cparse.BasicType : BasicType , |
| cparse.Qualifier : Qualifier , |
| cparse.StorageClass : StorageClass , |
| cparse.Ellipses : Ellipses , |
| cparse.GCCBuiltin : GCCBuiltin , |
| cparse.Identifier : Identifier , |
| cparse.TypeAlias : TypeAlias , |
| cparse.Function : Function , |
| cparse.Pointer : Pointer , |
| cparse.Array : Array , |
| cparse.Tag : Tag , |
| cparse.Compound : Compound , |
| cparse.Struct : Struct , |
| cparse.Union : Union , |
| cparse.Enum : Enum , |
| cparse.Declarator : Declarator , |
| cparse.Typedef : Typedef , |
| cparse.AbstractDeclarator : AbstractDeclarator , |
| cparse.FieldLength : FieldLength , |
| cparse.StructDeclarator : StructDeclarator , |
| cparse.DeclarationSpecifiers : TypeSpecifiers , |
| cparse.TypeSpecifiers : TypeSpecifiers , |
| cparse.Initializer : Initializer , |
| cparse.Declaration : Declaration , |
| cparse.ParameterDeclaration : ParameterDeclaration , |
| cparse.StructDeclaration : StructDeclaration , |
| cparse.TransUnit : TransUnit , |
| } |
| |
| |