import compiler, traceback, os.path import types ########################################################################### ## External API def compile(filename): """ Compile a Python source file to IMCC instructions """ main=os.path.basename(filename).split('.')[0] prefix = """.HLL \"Python\", \"python_group\" """ print prefix astTree = compiler.parseFile(filename) print "#" + str( astTree ) push() setModuleName( main ) output(".sub %s::__main__ @MAIN" % main) outputInBlock(".param pmc sys::argv") moduleInitSubName = evaluate( astTree ) tempReg = nextPRegister() outputInBlock("find_global %s, \"%s\", \"%s\"" % ( tempReg, main, moduleInitSubName ) ) outputInBlock("%s()" % ( tempReg ) ) output(".end") pop() ########################################################################### ## Internal API rootBlock=None currentBlock=rootBlock currentContainer=None labelNumber=0 blockDepth=0 namespaces=[] def push(): """ Suspend current block, start a new block """ pushBlock( block() ) def pushContainer(): """ Suspend current block, start a new block """ global currentContainer newContainerBlock = ContainerBlock() pushBlock( newContainerBlock ) newContainerBlock.parentContainer = currentContainer currentContainer = newContainerBlock def pushBlock( block ): """ Suspend current block, start a new block """ global currentContainer global currentBlock global blockDepth newBlock = block newBlock.parentBlock = currentBlock if currentContainer and currentContainer.__class__ == ContainerBlock: currentContainer.append( newBlock ) currentBlock = newBlock blockDepth += 1 def pop(): """ Complete current block, resume previous block """ global currentContainer global currentBlock global blockDepth parentBlock = currentBlock.parentBlock if currentBlock.__class__ == ContainerBlock: print currentBlock.writeOut() currentContainer = currentContainer.parentContainer elif not currentContainer: print currentBlock.writeOut() currentBlock = parentBlock blockDepth -= 1 def lookup(symbol): """ Lookup a symbol in the current scope """ currentBlock.lookup(symbol) def addSymbolIfNotPresent(symbol): """ Lookup a symbol in the current scope """ currentBlock.addSymbolIfNotPresent(symbol) def addSymbolOnlyIfNotPresent(symbol): currentBlock.addSymbolOnlyIfNotPresent(symbol) def addSymbolToParentBlock(symbol): """ Lookup a symbol in the current scope """ blocks[-2].addSymbolOnlyIfNotPresent(symbol) def execute(node): """ execute (emit instructions for) a given compiler.ast node """ map[node.__class__](node) def evaluate(node): """ evaluate (return symbol/constant/register for) a given compiler.ast node """ return map[node.__class__](node) def outputInBlock(instruction): output("\t" + instruction) def outputLabel(label): output(label + ":") def output(instruction): """ output a single IMCC instruction """ indentLength = 2 commentStart = 80 instructionLength = len(instruction) padLeftLength = indentLength * ( blockDepth - 1 ) if len(instruction) and instruction[0]=='\t': instructionLength+=indentLength - 1 padRightLength = commentStart - instructionLength # pad right instruction+=' '* padRightLength # determine caller (file,line,func)=traceback.extract_stack()[-2][:3] if func == "outputInBlock": (file,line,func)=traceback.extract_stack()[-3][:3] file=os.path.basename(file).split('.')[0] # append to current block currentBlock.append("%s\t# %s.%s:%d" % (instruction, file, func, line)) def fail(message): """ report an error """ print "***", message def nextIRegister(): return "$I" + str(currentBlock.nextIRegister()) def nextSRegister(): return "$S" + str(currentBlock.nextSRegister()) def nextPRegister(): return "$P" + str(currentBlock.nextPRegister()) def nextLabelNumber(): global labelNumber number = labelNumber labelNumber += 1 return number def nextLabel(): return "L" + str(nextLabelNumber()) def setBreakLabel( label ): currentBlock.breakLabel = label def setContinueLabel( label ): currentBlock.continueLabel = label def getBreakLabel(): return currentBlock.breakLabel def getContinueLabel(): return currentBlock.continueLabel def symbolExists(symbol): return currentBlock.symbolExists(symbol) def enterClassDefinition(): currentBlock.inClassDefinition = True def leaveClassDefinition(): currentBlock.inClassDefinition = False def getInClassDefintion(): return currentBlock.inClassDefinition def setIsNamespace( namespace ): currentBlock.isNameSpace = namespace def getIsNamespace(): return currentBlock.isNameSpace def setIsModuleScope( moduleScope ): currentBlock.isModuleScope = moduleScope def getIsModuleScope(): return currentBlock.isModuleScope def setModuleName( moduleName ): currentBlock.moduleName = moduleName def getModuleName(): return currentBlock.moduleName def addModuleMember( moduleMember ): currentBlock.parentBlock.moduleMembers.append( moduleMember ) def getModuleMembers( level ): return currentBlock.parentBlock.moduleMembers def pushNamespace( namespace ): namespaces.append( namespace ) def popNamespace(): return namespaces.pop() def printNamespace(): return "::".join( namespaces ) ########################################################################### class block: def __init__(self): self.moduleMembers=[] self.moduleName="" self.parentBlock=None self.instructions=[] self.symbols=[] self.nextIReg=0 self.nextSReg=0 self.nextPReg=0 self.breakLabel="" self.continueLabel="" self.inClassDefinition=False self.isNameSpace=False self.isModuleScope=False def writeOut(self): body = "" for x in self.instructions: if x.__class__ == ContainerBlock or x.__class__ == block: body += x.writeOut() else: body += x + "\n" return body def addSymbolIfNotPresent(self, symbol): if symbol not in self.symbols: self.symbols.append(symbol) outputInBlock(".local pmc " + symbol) return True else: return False def addSymbolOnlyIfNotPresent(self, symbol): if symbol not in self.symbols: self.symbols.append(symbol) return True else: return False def symbolExists(self, symbol): if symbol in self.symbols: return True else: return False def append(self, instruction): self.instructions.append(instruction) def nextIRegister(self): regNum = self.nextIReg self.nextIReg += 1 return regNum def nextSRegister(self): regNum = self.nextSReg self.nextSReg += 1 return regNum def nextPRegister(self): regNum = self.nextPReg self.nextPReg += 1 return regNum class ContainerBlock(block): def __init__(self): block.__init__(self) self.containerBlock = None # # create a map between compiler.ast classes and pyrate.ast process functions # for efficient dispatch # map={} for node in compiler.ast.__dict__: nodeClass = getattr(compiler.ast,node) if node[0].isupper() and node[1].islower() and type(nodeClass) == types.ClassType: try: process=getattr(getattr(__import__("ast."+node),node),"process") map[nodeClass]=process except: print "Mapping to pyrate.ast doesn't exist" print node print node.__class__ print dir(node) def diag( node ): print node print node.__class__ print dir(node)