#!/usr/bin/env python """ genpyx.py - parse c declarations (c) 2002, 2003, 2004, 2005 Simon Burton 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&%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 = &%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) ) )