mirror of https://github.com/yasm/yasm.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1163 lines
35 KiB
1163 lines
35 KiB
#!/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 , |
|
} |
|
|
|
|
|
|