class Parser(): def __init__(self,tokens,vmwriter): try: tokens[0].value tokens[0].type except: sys.exit("Parser did not take in a list of tokens!") self.tokens=tokens self.vmwriter=vmwriter self.symTable=SymbolTable() def parse(self): self.index = 0 self.compileClass() def compileClass(self): self.createChild() self.className=self.createChild().value self.createChild() while(self.lookChild().value in ["static","field"]): self.varDec() while(self.lookChild().value in ["constructor","function","method"]): self.subroutineDec() self.createChild() #"}" def lookChild(self): #Helper method. Returns current token. return self.tokens[self.index] def createChild(self): #Helper method. Returns and increments child #Note: This function is designed to input the NEXT element, as it will iterate the counter by one. child = self.tokens[self.index] self.index+=1 return child def varDec(self): #Adds all the vars varKind = self.createChild().value varType = self.createChild().value varName = self.createChild().value self.symDef(varType,varKind,varName) while(self.createChild().value==","): #Adds all additional variables, will also increment semicolon varName = self.createChild().value self.symDef(varType,varKind,varName) def subroutineDec(self): self.whileLoops=0 self.ifStatements=0 self.symTable.startSubroutine() if(self.lookChild().value=="method"): self.symDef(self.className,"arg","this") subroutineKind="method" elif(self.lookChild().value=="constructor"): subroutineKind="constructor" elif(self.lookChild().value=="function"): subroutineKind="function" self.createChild() #Pass over the type of subroutine self.createChild() #Pass over the kind of subroutine subroutineName=self.createChild().value #name of function/method/construct self.createChild() #Skip "(" while(self.lookChild().value!=")"): varType = self.createChild().value varName = self.createChild().value self.symDef(varType,"arg",varName) if(self.lookChild().value==","): self.createChild() self.createChild() #Passes up to and over ")" self.subRoutineBody(subroutineKind,subroutineName) def subRoutineBody(self,subKind,subName): #builds method body self.createChild() #{ while(self.lookChild().value)=="var": self.varDec() self.vmwriter.writeFunction(self.className+"."+subName,self.symTable.varCount("var")) if subKind=="constructor": self.vmwriter.writePush("constant",self.symTable.varCount("field")) self.vmwriter.writeCall("Memory.alloc",1) self.vmwriter.writePop("pointer",0) elif subKind=="method": self.vmwriter.writePush("argument",0) self.vmwriter.writePop("pointer",0) self.statements() self.createChild()#"}" def subRoutineCall(self): nArgs=0 beforeDot=self.createChild().value label=beforeDot if self.lookChild().value ==".": self.createChild() #. isObject=self.symTable.getItem(beforeDot) if(isObject): self.vmwriter.writePush(self.tranKind(isObject.kind),isObject.index) nArgs=1 label=isObject.type label+="."+self.createChild().value #identifier else: self.vmwriter.writePush("pointer",0) nArgs=1 label=self.className+"."+label self.createChild() #( nArgs+=self.expressionList() #expression self.createChild() #) self.vmwriter.writeCall(label, nArgs) def statements(self): while(self.lookChild().value in ["let","if","while","do","return"]): tokVal = self.lookChild().value #This is a shortcut mainly to save typing if tokVal=="let": self.letStatement() elif tokVal=="if": self.ifStatement() elif tokVal=="while": self.whileStatement() elif tokVal=="do": self.doStatement() elif tokVal=="return": self.returnStatement() def letStatement(self): self.createChild() #"let" varVal=self.createChild().value getItem=self.symTable.getItem(varVal) if self.lookChild().value=="[": #arrays self.createChild() #[ self.expression() #expression self.vmwriter.writePush(self.tranKind(getItem.kind),getItem.index) self.vmwriter.writeArithmetic("add") self.createChild() #] self.createChild() #"=" self.expression() #expression self.vmwriter.writePop("temp",0) #pop temp0 self.vmwriter.writePop("pointer",1) #pop pointer 1 self.vmwriter.writePush("temp",0) #write push temp 0 self.vmwriter.writePop("that",0) #pop that 0 else: self.createChild() #"=" self.expression() #expression self.vmwriter.writePop(self.tranKind(getItem.kind),getItem.index) self.createChild() #; def ifStatement(self): self.createChild() #"if" self.createChild() #"(" ifTrue="IF_TRUE"+str(self.ifStatements) ifFalse="IF_FALSE"+str(self.ifStatements) ifEnd="IF_END"+str(self.ifStatements) self.ifStatements+=1 self.expression() #expression self.vmwriter.writeIf(ifTrue) self.vmwriter.writeGoto(ifFalse) self.vmwriter.writeLabel(ifTrue) self.createChild() #")" self.createChild() #"{" while self.lookChild().value!="}": self.statements() self.createChild() #"}" if self.lookChild().value == "else": self.createChild() #"else" self.createChild() #"{ self.vmwriter.writeGoto(ifEnd) self.vmwriter.writeLabel(ifFalse) self.statements() self.vmwriter.writeLabel(ifEnd) self.createChild() #"} else: self.vmwriter.writeLabel(ifFalse) def whileStatement(self): self.createChild() #"while" self.createChild() #"(" whileExp = "WHILE_EXP"+str(self.whileLoops) whileEnd = "WHILE_END"+str(self.whileLoops) self.whileLoops+=1 self.vmwriter.writeLabel(whileExp) self.expression() #expression self.vmwriter.writeArithmetic("not") self.vmwriter.writeIf(whileEnd) self.createChild() #")" self.createChild() #"{" while self.lookChild().value!="}": self.statements() self.vmwriter.writeGoto(whileExp) self.vmwriter.writeLabel(whileEnd) self.createChild() #"}" def doStatement(self): self.createChild() #"do" self.subRoutineCall() self.vmwriter.writePop("temp",0) self.createChild() #";" def returnStatement(self): self.createChild() #return if self.lookChild().value==";": self.vmwriter.writePush("constant",0) else: self.expression() #expression self.createChild() #semicolon self.vmwriter.writeReturn() def expression(self): self.term() writeTerms={ '+':"add", '-':"sub", '*':"multiply", '/':"divide", '&':"and", '|':"or", '<':"lt", '>':"gt", '=':"eq" } while(self.lookChild().value in writeTerms): op=self.createChild().value self.term() if(op in ["*","/"]): self.vmwriter.writeCall("Math."+writeTerms[op],2) else: self.vmwriter.writeArithmetic(writeTerms[op]) def term(self): if self.lookChild().type == "integerConstant": self.vmwriter.writePush("constant",self.createChild().value) elif self.lookChild().type == "stringConstant": stringVal=self.createChild().value self.vmwriter.writePush("constant",len(stringVal)) self.vmwriter.writeCall("String.new",1) for i in stringVal: self.vmwriter.writePush("constant",ord(i)) self.vmwriter.writeCall("String.appendChar",2) elif self.lookChild().type == "keyword": keyword=self.createChild().value if keyword == 'true': self.vmwriter.writePush("constant",0) self.vmwriter.writeArithmetic("not") elif keyword == 'false': self.vmwriter.writePush("constant",0) elif keyword == 'null': self.vmwriter.writePush("constant",0) elif keyword == 'this': self.vmwriter.writePush("pointer",0) elif self.lookChild().value == "~": self.createChild() self.term() self.vmwriter.writeArithmetic("not") elif self.lookChild().value == "-": self.createChild() self.term() self.vmwriter.writeArithmetic("neg") elif self.lookChild().value == "(": self.createChild() #( self.expression() self.createChild() #) pass else: #identifier if self.tokens[self.index+1].value == "[": getItem=self.symTable.getItem(self.createChild().value) self.createChild() #[ self.expression() #expression self.createChild() #] self.vmwriter.writePush(self.tranKind(getItem.kind),getItem.index) self.vmwriter.writeArithmetic("add") self.vmwriter.writePop("pointer",1) self.vmwriter.writePush("that",0) else: if self.tokens[self.index+1].value in [".","("]: #Subroutine call self.subRoutineCall() else: currTerm=self.symTable.getItem(self.createChild().value) self.vmwriter.writePush(self.tranKind(currTerm.kind),currTerm.index) def expressionList(self): numExpr=0 if self.lookChild().value == ")": return numExpr self.expression() numExpr+=1 while self.lookChild().value==",": self.createChild() self.expression() numExpr+=1 return numExpr def symDef(self,varType,varKind,varName): self.symTable.define(varType,varKind,varName) def tranKind(self, kind): if kind == "static": return "static" elif kind == "field": return "this" elif kind == "var": return "local" elif kind == "arg": return "argument" def toXML(self,fileName): outFile = minidom.parseString(ElementTree.tostring(self.XML)).toprettyxml() fileName=fileName.split(".")[0] try:#Safely open output file outFi = open(fileName+".xml","w+") outFi.write(outFile) outFi.close() except: sys.exit("There was an error opening "+fileName+".xml")