aboutsummaryrefslogtreecommitdiff
path: root/tools/python-yasm/pyxelator/genpyx.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/python-yasm/pyxelator/genpyx.py')
-rwxr-xr-xtools/python-yasm/pyxelator/genpyx.py530
1 files changed, 530 insertions, 0 deletions
diff --git a/tools/python-yasm/pyxelator/genpyx.py b/tools/python-yasm/pyxelator/genpyx.py
new file mode 100755
index 0000000..3f2a4cc
--- /dev/null
+++ b/tools/python-yasm/pyxelator/genpyx.py
@@ -0,0 +1,530 @@
+#!/usr/bin/env python
+""" genpyx.py - parse c declarations
+
+(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
+Released under GNU LGPL license.
+
+version 0.xx
+
+This is a module of mixin classes for ir.py .
+
+Towards the end of ir.py our global class definitions
+are remapped to point to the class definitions in ir.py .
+So, for example, when we refer to Node we get ir.Node .
+
+"""
+
+import sys
+from datetime import datetime
+
+# XX use this Context class instead of all those kw dicts !! XX
+class Context(object):
+ " just a record (struct) "
+ def __init__( self, **kw ):
+ for key, value in kw.items():
+ setattr( self, key, value )
+ def __getattr__( self, name ):
+ return None # ?
+ def __getitem__( self, name ):
+ return getattr(self, name)
+
+class OStream(object):
+ def __init__( self, filename=None ):
+ self.filename = filename
+ self.tokens = []
+ self._indent = 0
+ def put( self, token="" ):
+ assert type(token) is str
+ self.tokens.append( token )
+ def startln( self, token="" ):
+ assert type(token) is str
+ self.tokens.append( ' '*self._indent + token )
+ def putln( self, ln="" ):
+ assert type(ln) is str
+ self.tokens.append( ' '*self._indent + ln + '\n')
+ def endln( self, token="" ):
+ assert type(token) is str
+ self.tokens.append( token + '\n')
+ def indent( self ):
+ self._indent += 1
+ def dedent( self ):
+ self._indent -= 1
+ assert self._indent >= 0, self._indent
+ def join( self ):
+ return ''.join( self.tokens )
+ def close( self ):
+ s = ''.join( self.tokens )
+ f = open( self.filename, 'w' )
+ f.write(s)
+
+#
+###############################################################################
+#
+
+class Node(object):
+ """
+ tree structure
+ """
+ _unique_id = 0
+ def get_unique_id(cls):
+ Node._unique_id += 1
+ return Node._unique_id
+ get_unique_id = classmethod(get_unique_id)
+
+# XX toks: use a tree of tokens: a list that can be push'ed and pop'ed XX
+ def pyxstr(self,toks=None,indent=0,**kw):
+ """
+ Build a list of tokens; return the joined tokens string
+ """
+ if toks is None:
+ toks = []
+ for x in self:
+ if isinstance(x,Node):
+ x.pyxstr(toks, indent, **kw)
+ else:
+ toks.insert(0,str(x)+' ')
+ s = ''.join(toks)
+ return s
+
+#
+#################################################
+
+class Named(object):
+ "has a .name property"
+ pass
+
+class BasicType(object):
+ "float double void char int"
+ pass
+
+class Qualifier(object):
+ "register signed unsigned short long const volatile inline"
+ def pyxstr(self,toks=None,indent=0,**kw):
+ if toks is None:
+ toks = []
+ x = self[0]
+ if x not in ( 'const','volatile','inline','register'): # ignore these
+ toks.insert(0,str(x)+' ')
+ s = ''.join(toks)
+ return s
+
+class StorageClass(object):
+ "extern static auto"
+ def pyxstr(self,toks=None,indent=0,**kw):
+ return ""
+
+class Ellipses(object):
+ "..."
+ pass
+
+class GCCBuiltin(BasicType):
+ "things with __builtin prefix"
+ pass
+
+class Identifier(object):
+ """
+ """
+ def pyxstr(self,toks=None,indent=0,**kw):
+ if toks is None:
+ toks=[]
+ if self.name:
+ toks.append( self.name )
+ return " ".join(toks)
+
+class TypeAlias(object):
+ """
+ typedefed things, eg. size_t
+ """
+ def pyxstr(self,toks=None,indent=0,cprefix="",**kw):
+ if toks is None:
+ toks = []
+ for x in self:
+ if isinstance(x,Node):
+ x.pyxstr(toks, indent, cprefix=cprefix, **kw)
+ else:
+ s = str(x)+' '
+ if cprefix:
+ s = cprefix+s
+ toks.insert(0,s)
+ s = ''.join(toks)
+ return s
+
+class Function(object):
+ """
+ """
+ def pyxstr(self,toks,indent=0,**kw):
+ #print '%s.pyxstr(%s)'%(self,toks)
+ _toks=[]
+ assert len(self)
+ i=0
+ while isinstance(self[i],Declarator):
+ if not self[i].is_void():
+ _toks.append( self[i].pyxstr(indent=indent, **kw) )
+ i=i+1
+ toks.append( '(%s)'% ', '.join(_toks) )
+ while i<len(self):
+ self[i].pyxstr(toks, indent=indent, **kw)
+ i=i+1
+ return " ".join(toks)
+
+class Pointer(object):
+ """
+ """
+ def pyxstr(self,toks,indent=0,**kw):
+ assert len(self)
+ node=self[0]
+ toks.insert(0,'*')
+ if isinstance(node,Function):
+ toks.insert(0,'(')
+ toks.append(')')
+ elif isinstance(node,Array):
+ toks.insert(0,'(')
+ toks.append(')')
+ return Node.pyxstr(self,toks,indent, **kw)
+
+class Array(object):
+ """
+ """
+ def pyxstr(self,toks,indent=0,**kw):
+ if self.size is None:
+ toks.append('[]')
+ else:
+ try:
+ int(self.size)
+ toks.append('[%s]'%self.size)
+ except:
+ toks.append('[]')
+ return Node( *self[:-1] ).pyxstr( toks,indent, **kw )
+
+class Tag(object):
+ " the tag of a Struct, Union or Enum "
+ pass
+
+class Taged(object):
+ "Struct, Union or Enum "
+ pass
+
+class Compound(Taged):
+ "Struct or Union"
+ def pyxstr(self,_toks=None,indent=0,cprefix="",shadow_name=True,**kw):
+ if _toks is None:
+ _toks=[]
+ names = kw.get('names',{})
+ kw['names'] = names
+ tag_lookup = kw.get('tag_lookup')
+ if self.tag:
+ tag=self.tag.name
+ else:
+ tag = ''
+ if isinstance(self,Struct):
+ descr = 'struct'
+ elif isinstance(self,Union):
+ descr = 'union'
+ _node = names.get(self.tag.name,None)
+ if ( _node is not None and _node.has_members() ) or \
+ ( _node is not None and not self.has_members() ):
+ descr = '' # i am not defining myself here
+ #print "Compound.pyxstr", tag
+ #print self.deepstr()
+ if descr:
+ if cprefix and shadow_name:
+ tag = '%s%s "%s"'%(cprefix,tag,tag)
+ elif cprefix:
+ tag = cprefix+tag
+ toks = [ descr+' '+tag ] # struct foo
+ if self.has_members():
+ toks.append(':\n')
+ for decl in self[1:]: # XX self.members
+ toks.append( decl.pyxstr(indent=indent+1, cprefix=cprefix, shadow_name=shadow_name, **kw)+"\n" ) # shadow_name = False ?
+ #elif not tag_lookup.get( self.tag.name, self ).has_members():
+ # define empty struct here, it's the best we're gonna get
+ #pass
+ else:
+ if cprefix: # and shadow_name:
+ tag = cprefix+tag
+ toks = [ ' '+tag+' ' ] # foo
+ while toks:
+ _toks.insert( 0, toks.pop() )
+ return "".join( _toks )
+
+class Struct(Compound):
+ """
+ """
+ pass
+
+class Union(Compound):
+ """
+ """
+ pass
+
+
+class Enum(Taged):
+ """
+ """
+ def pyxstr(self,_toks=None,indent=0,cprefix="",shadow_name=True,**kw):
+ if _toks is None:
+ _toks=[]
+ names = kw.get('names',{})
+ kw['names'] = names
+ if self.tag:
+ tag=self.tag.name
+ else:
+ tag = ''
+ _node = names.get(self.tag.name,None)
+ if ( _node is not None and _node.has_members() ) or \
+ ( _node is not None and not self.has_members() ):
+ descr = '' # i am not defining myself here
+ else:
+ descr = 'enum'
+ if descr:
+ #if not names.has_key(self.tag.name):
+ toks = [ descr+' '+tag ] # enum foo
+ toks.append(':\n')
+ idents = [ ident for ident in self.members if ident.name not in names ]
+ for ident in idents:
+ if cprefix and shadow_name:
+ ident = ident.clone()
+ ident.name = '%s%s "%s"' % ( cprefix, ident.name, ident.name )
+ #else: assert 0
+ toks.append( ' '+' '*indent + ident.pyxstr(**kw)+"\n" )
+ names[ ident.name ] = ident
+ if not idents:
+ # empty enum def'n !
+ #assert 0 # should be handled by parents...
+ toks.append( ' '+' '*indent + "pass\n" )
+ else:
+ toks = [ ' '+tag+' ' ] # foo
+ while toks:
+ _toks.insert( 0, toks.pop() )
+ return "".join( _toks )
+
+class Declarator(object):
+ 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 ... XX
+ self = self.cbasetype() # WARNING: cbasetype may be cached
+ 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 _pyxstr( self, toks, indent, cprefix, use_cdef, shadow_name, **kw ):
+ " this is the common part of pyxstr that gets called from both Declarator and Typedef "
+ names = kw.get('names',{}) # what names have been defined ?
+ kw['names']=names
+ for node in self.nodes(): # depth-first
+ if isinstance(node,Taged):
+ #print "Declarator.pyxstr", node.cstr()
+ if not node.tag.name:
+ node.tag.name = "_anon_%s" % Node.get_unique_id()
+ _node = names.get(node.tag.name,None)
+ #tag_lookup = kw.get('tag_lookup')
+ #other = tag_lookup.get(node.tag.name, node)
+ #if ((_node is None and (not isinstance(other,Compound) or not other.has_members()))
+ # or node.has_members()):
+ if _node is None or node.has_members():
+ # either i am not defined at all, or this is my _real_ definition
+ # emit def'n of this node
+ #if isinstance(self,Typedef):
+ #toks.append( ' '*indent + 'ctypedef ' + node.pyxstr(indent=indent, cprefix=cprefix, shadow_name=shadow_name, **kw).strip() )
+ #else:
+ toks.append( ' '*indent + 'cdef ' + node.pyxstr(indent=indent, cprefix=cprefix, shadow_name=shadow_name, **kw).strip() )
+ names[ node.tag.name ] = node
+ elif isinstance(node,GCCBuiltin) and node[0] not in names:
+ #toks.append( ' '*indent + 'ctypedef long ' + node.pyxstr(indent=indent, **kw).strip() + ' # XX ??' ) # XX ??
+ toks.append( ' '*indent + 'struct __unknown_builtin ' )
+ toks.append( ' '*indent + 'ctypedef __unknown_builtin ' + node.pyxstr(indent=indent, **kw).strip() )
+ names[ node[0] ] = node
+ for idx, child in enumerate(node):
+ if type(child)==Array and not child.has_size():
+ # mutate this mystery array into a pointer XX method: Array.to_pointer()
+ node[idx] = Pointer()
+ node[idx].init_from( child ) # warning: shallow init
+ node[idx].pop() # pop the size element
+
+ def pyxstr(self,toks=None,indent=0,cprefix="",use_cdef=True,shadow_name=True,**kw):
+ " note: i do not check if my name is already in 'names' "
+ self = self.clone() # <----- NOTE
+ toks=[]
+ names = kw.get('names',{}) # what names have been defined ?
+ kw['names']=names
+
+ self._pyxstr( toks, indent, cprefix, use_cdef, shadow_name, **kw )
+
+ if self.name and not names.has_key( self.name ):
+ names[ self.name ] = self
+ if self.identifier is not None:
+ comment = ""
+ if self.name in python_kws:
+ comment = "#"
+ if cprefix and use_cdef and shadow_name:
+ # When we are defining this guy, we refer to it using the pyrex shadow syntax.
+ self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name )
+ cdef = 'cdef '
+ if not use_cdef: cdef = '' # sometimes we don't want the cdef (eg. in a cast)
+ # this may need shadow_name=False:
+ toks.append( ' '*indent + comment + cdef + Node.pyxstr(self,indent=indent, cprefix=cprefix, **kw).strip() ) # + "(cprefix=%s)"%cprefix)
+ #else: i am just a struct def (so i already did that) # huh ?? XX bad comment
+ return ' \n'.join(toks)
+
+ def pyxsym(self, ostream, names=None, tag_lookup=None, cprefix="", modname=None, cobjects=None):
+ assert self.name is not None, self.deepstr()
+ ostream.putln( '# ' + self.cstr() )
+# This cdef is no good: it does not expose a python object
+# and we can't reliably set a global var
+ #ostream.putln( 'cdef %s %s' % ( self.pyx_adaptor_decl(cobjects), self.name ) ) # _CObject
+ #ostream.putln( '%s = %s()' % (self.name, self.pyx_adaptor_name(cobjects)) )
+ #ostream.putln( '%s.p = <void*>&%s' % (self.name, cprefix+self.name) )
+ ## expose a python object:
+ #ostream.putln( '%s.%s = %s' % (modname,self.name, self.name) )
+ ostream.putln( '%s = %s( addr = <long>&%s )' % (self.name, self.pyx_adaptor_name(cobjects), cprefix+self.name) )
+ return ostream
+
+
+class Typedef(Declarator):
+ def pyxstr(self,toks=None,indent=0,cprefix="",use_cdef=True,shadow_name=True,**kw): # shadow_name=True
+ " warning: i do not check if my name is already in 'names' "
+ assert shadow_name == True
+ self = self.clone() # <----- NOTE
+ toks=[]
+ names = kw.get('names',{}) # what names have been defined ?
+ kw['names']=names
+
+ #if self.tagged and not self.tagged.tag.name:
+ ## "typedef struct {...} foo;" => "typedef struct foo {...} foo;"
+ ## (to be emitted in the node loop below, and suppressed in the final toks.append)
+ #self.tagged.tag = Tag( self.name ) # this is how pyrex does it: tag.name == self.name
+ # XX that doesn't work (the resulting c fails to compile) XX
+
+ self._pyxstr( toks, indent, cprefix, use_cdef, shadow_name, **kw )
+
+ #print self.deepstr()
+ if self.name and not names.has_key( self.name ):
+ names[ self.name ] = self
+ if not (self.tagged and self.name == self.tagged.tag.name):
+ comment = ""
+ if self.name in python_kws:
+ comment = "#"
+ #if cprefix:
+ # self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name ) # XX pyrex can't do this
+ if cprefix: # shadow_name=True
+ # My c-name gets this prefix. See also TypeAlias.pyxstr(): it also prepends the cprefix.
+ self.name = '%s%s "%s" ' % ( cprefix, self.name, self.name )
+ toks.append( ' '*indent + comment + 'ctypedef ' + Node.pyxstr(self,indent=indent, cprefix=cprefix, **kw).strip() )
+ return ' \n'.join(toks)
+
+
+class AbstractDeclarator(Declarator):
+ """ used in Function; may lack an identifier """
+ def pyxstr(self,toks=None,indent=0,**kw):
+ if self.name in python_kws:
+ # Would be better to do this in __init__, but our subclass doesn't call our __init__.
+ self.name = '_' + self.name
+ #return ' '*indent + Node.pyxstr(self,toks,indent, **kw).strip()
+ return Node.pyxstr(self,toks,indent, **kw).strip()
+
+
+class FieldLength(object):
+ """
+ """
+ def pyxstr(self,toks,indent,**kw):
+ pass
+
+
+class StructDeclarator(Declarator): # also used in Union
+ """
+ """
+ def pyxstr(self,toks=None,indent=0,**kw):
+ comment = ""
+ if self.name in python_kws:
+ comment = "#"
+ return ' '*indent + comment + Node.pyxstr(self,toks,indent, **kw).strip()
+
+class DeclarationSpecifiers(object):
+ """
+ """
+ pass
+
+class TypeSpecifiers(DeclarationSpecifiers):
+ """
+ """
+ pass
+
+class Initializer(object):
+ """
+ """
+ pass
+
+class Declaration(object):
+ """
+ """
+ pass
+
+class ParameterDeclaration(Declaration):
+ """
+ """
+ pass
+
+class StructDeclaration(Declaration):
+ """
+ """
+ pass
+
+class TransUnit(object):
+ """
+ Top level node.
+ """
+ def pyx_decls(self, filenames, modname, macros = {}, names = {}, func_cb=None, cprefix="", **kw):
+ # PART 1: emit extern declarations
+ ostream = OStream()
+ now = datetime.today()
+ ostream.putln( now.strftime('# Code generated by pyxelator on %x at %X') + '\n' )
+ ostream.putln("# PART 1: extern declarations")
+ for filename in filenames:
+ ostream.putln( 'cdef extern from "%s":\n pass\n' % filename )
+ ostream.putln( 'cdef extern from *:' )
+ file = None # current file
+ for node in self:
+ ostream.putln('')
+ ostream.putln(' # ' + node.cstr() )
+ assert node.marked
+ comment = False
+ if node.name and node.name in names:
+ comment = True # redeclaration
+ #ostream.putln( node.deepstr( comment=True ) )
+ s = node.pyxstr(indent=1, names=names, tag_lookup = self.tag_lookup, cprefix=cprefix, **kw)
+ if s.split():
+ if comment:
+ s = "#"+s.replace( '\n', '\n#' ) + " # redeclaration "
+ if node.file != file:
+ file = node.file
+ #ostream.putln( 'cdef extern from "%s":' % file )
+ ostream.putln( ' # "%s"' % file )
+ ostream.putln( s )
+ ostream.putln('\n')
+ #s = '\n'.join(toks)
+ return ostream.join()
+
+# XX warn when we find a python keyword XX
+python_kws = """
+break continue del def except exec finally pass print raise
+return try global assert lambda yield
+for while if elif else and in is not or import from """.split()
+python_kws = dict( zip( python_kws, (None,)*len(python_kws) ) )
+
+