Example #1
0
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")