Example #1
0
class CompilationEngine:

    ##############################################  Consructor  ############################################

    # Creates a new compilation engine
    # with the given input and output.
    # The next routine calles must be compileClass().
    def __init__(self, inputLines, filePath):
        # input information
        self.lines = inputLines
        self.destFile = filePath
        # Grammar rules
        grammar = JackGrammar()
        self.subroutineDec = grammar.getSubroutineDec()
        self.subs = grammar.getSubs()
        self.varDecs = grammar.getVarDecs()
        self.statements = grammar.getStatements()
        self.terms = grammar.getTerms()
        self.unaryOp = grammar.getUnaryOp()
        self.op = grammar.getOp()
        self.classVarDec = grammar.getClassVarDec()
        # global variables
        self.currentToken = ""
        self.currentTokenType = ""
        self.currentLine = ""
        self.nextToken = ""
        self.nextTokenType = ""
        self.isSubroutine = False
        self.className = ""
        self.currentFuncionName = ""
        self.nArgs = 0
        self.isRight = False
        self.had_else = False
        self.whileLabelIndex = 0
        self.ifLabelIndex = 0
        self.isConstructor = False
        self.isMethod = False
        self.isArray = False
        self.wasRightArray = False
        self.wasArgument = False
        # SymbolTable
        self.symbolTable = SymbolTable()
        # VMWriter
        self.vmwriter = VMWriter(filePath)

##############################################  Compile Class  ##############################################

# Compiles a complete class.

    def CompileClass(self):
        self.compileClassHelper()

    # Grammar:
    # class className {classVarDec* subroutine*}
    def compileClassHelper(self):
        if (len(self.lines) == 0):
            return

        self.manageNextTranslation()
        if self.currentTokenType == "identifier":
            self.className = self.currentToken
            self.compileClassHelper()
        elif self.currentTokenType == "symbol":
            self.compileClassHelper()
        elif self.currentToken in self.classVarDec:
            self.compileClassVarDec()
            self.compileClassHelper()
        elif self.currentToken in self.subroutineDec:
            self.CompileSubroutineDec()
            self.compileClassHelper()
        elif self.currentToken == "class":
            self.compileClassHelper()

##############################################  Compile ClassVarDec  ##############################################

    def compileClassVarDec(self):
        kind = ""
        type = ""
        while (self.currentToken not in self.subroutineDec):
            kind = self.currentToken
            self.manageNextTranslation()
            type = self.currentToken
            self.manageNextTranslation()
            name = self.currentToken
            self.symbolTable.Define(name, type, kind)

            self.manageNextTranslation()

            while self.currentToken != ";":
                self.manageNextTranslation()
                name = self.currentToken
                self.symbolTable.Define(name, type, kind)
                self.manageNextTranslation()

            self.manageNextTranslation()
        if self.currentToken == "constructor":
            self.isConstructor = True
        self.compileSubroutineDecHelper()
        self.isMethod = False

##############################################  Compile SubroutineDec  ##############################################

# Compiles a static declaration or a field declaration.

    def CompileSubroutineDec(self):
        self.compileSubroutineDecHelper()
        self.isMethod = False

    # Grammar:
    # 'constructor', 'function', 'method'
    # ('void' | type) subroutineName (parameterList)
    # subroutineBody
    def compileSubroutineDecHelper(self):
        if (len(self.lines) == 0):
            return

        self.checkNextToken()
        if self.nextToken == "}":
            return
        if self.currentToken == "method":
            self.isMethod = True
        if self.currentToken != ")":
            self.manageNextTranslation()
        if self.currentToken in self.subroutineDec:
            self.compileSubroutineDecHelper()
        elif self.currentToken in self.subs:
            self.compileSubroutineDecHelper()

        elif self.currentTokenType == "identifier":
            self.currentFuncionName = self.currentToken
            self.symbolTable.startSubroutine()
            self.compileSubroutineDecHelper()

        elif self.currentTokenType == "symbol":
            if self.currentToken == "(":
                self.compileParameterList()
                self.compileSubroutineDecHelper()
            elif self.currentToken == ")":
                self.getSubroutineBody()
            elif self.currentToken == ",":
                self.compileSubroutineDecHelper()

##############################################  Compile SubroutineBody  ##############################################

    def getSubroutineBody(self):
        self.subroutineBodyhelper()

    def subroutineBodyhelper(self):
        self.checkNextToken()

        if self.nextToken == "}":
            self.manageNextTranslation()
            return
        if self.currentToken == "}" and self.had_else:
            self.had_else = False
            return
        self.manageNextTranslation()

        if self.currentTokenType == "symbol":
            if self.currentToken == "{":
                self.compileVarDec()
                self.checkNextToken()

        self.subroutineBodyhelper()

##############################################  Compile VarDec  ##############################################

# Compiles a var declaration.

    def compileVarDec(self):
        self.manageNextTranslation()
        if self.currentToken == "var":
            self.manageNextTranslation()
            type = self.currentToken
            self.varDecHelper(type)
        elif self.currentToken in self.statements:
            self.vmwriter.WriteFunction(
                self.className + "." + self.currentFuncionName,
                str(self.symbolTable.getSize()))
            if self.isConstructor:
                count = self.symbolTable.VarCount("field")
                self.vmwriter.writePush("constant", count)
                self.vmwriter.WriteCall("Memory.alloc", 1)
                self.vmwriter.writePop("pointer", 0)
                self.isConstructor = False
            elif self.isMethod:
                self.vmwriter.writePush("argument", 0)
                self.vmwriter.writePop("pointer", 0)
            self.compileStatements()

    def varDecHelper(self, type):
        self.manageNextTranslation()
        if self.currentToken in self.varDecs or self.currentTokenType in self.varDecs:
            self.symbolTable.Define(self.currentToken, type, "var")
            self.varDecHelper(type)
        elif self.currentTokenType == "symbol":
            if self.currentToken == ";":
                self.compileVarDec()
            else:
                self.varDecHelper(type)

##############################################  Compile ParameterList  ##############################################

# Compiles a (possibly empty) parameter list,
# not including the enclosing "()".

    def compileParameterList(self):
        if self.isMethod:
            self.symbolTable.Define("this", self.className, "argument")
        self.manageNextTranslation()

        if self.currentToken != ")":
            self.paramListHelper()

    def paramListHelper(self):
        if self.currentTokenType == "symbol":
            if self.currentToken == ",":
                self.manageNextTranslation()
                self.paramListHelper()

        else:
            type = self.currentToken
            if type != "Array":
                type = self.currentTokenType
            self.manageNextTranslation()
            varName = self.currentToken
            self.symbolTable.Define(varName, type, "arg")
            self.manageNextTranslation()
            self.checkNextToken()
            self.paramListHelper()

##############################################  Compile Statements  ##############################################

# Compiles a sequence of statements, not including the enclosing "{}".

    def compileStatements(self):
        self.compileStatementsHelper()

    def compileStatementsHelper(self):
        if self.currentToken == "do":
            self.compileDo()
            self.manageNextTranslation()
            self.compileStatementsHelper()
        elif self.currentToken == "let":
            self.compileLet()
            if self.nextToken == ";":
                self.manageNextTranslation()
            self.manageNextTranslation()
            self.compileStatementsHelper()
        elif self.currentToken == "while":
            self.compileWhile()
            self.manageNextTranslation()
            self.compileStatementsHelper()
        elif self.currentToken == "if":
            saved = self.ifLabelIndex
            self.compileIf()
            self.checkNextToken()
            self.checkNextToken()
            if self.nextToken == "else":
                self.manageNextTranslation()
                self.vmwriter.WriteGoto("IF_END_LABEL" + str(saved))
                self.vmwriter.WriteLabel("IF_FALSE_LABEL" + str(saved))
                self.had_else = True
                self.compileIf()
                self.vmwriter.WriteLabel("IF_END_LABEL" + str(saved))
            else:
                self.vmwriter.WriteLabel("IF_FALSE_LABEL" + str(saved))
            self.checkNextToken()
            if self.currentToken == "{" or self.currentToken == "}":
                self.manageNextTranslation()

            self.checkNextToken()
            self.compileStatementsHelper()
        elif self.currentToken == "return":
            self.compileReturn()

##############################################  Compile do  ##############################################

# Compiles a do statement.

    def compileDo(self):
        self.compileDoHelper()
        self.vmwriter.writePop("temp", 0)

    def compileDoHelper(self):
        self.compileTermHelper()
        self.manageNextTranslation()

##############################################  Compile Let  ##############################################

# Compiles a let statement.

    def compileLet(self):
        self.checkNextToken()
        varName = self.nextToken
        self.isArray = False
        self.wasRightArray = False
        self.isRight = False
        self.compileLetHelper()

        type = self.symbolTable.TypeOf(varName)

        kind = self.symbolTable.KindOf(varName)
        if self.wasRightArray and type == "Array":
            self.vmwriter.writePop("temp", 0)
            self.vmwriter.writePop("pointer", 1)
            self.vmwriter.writePush("temp", 0)
            self.vmwriter.writePop("that", 0)
            self.isArray = False
        else:
            kind = self.symbolTable.KindOf(varName)
            if kind != "none":
                self.vmwriter.writePop(kind, self.symbolTable.IndexOf(varName))

    def compileLetHelper(self):
        self.manageNextTranslation()
        savedName = self.currentToken
        self.manageNextTranslation()
        if self.currentToken == "[":
            self.CompileExpression()
            kind = self.symbolTable.KindOf(savedName)
            indx = self.symbolTable.IndexOf(savedName)
            if kind != "none":
                self.vmwriter.writePush(kind, indx)
            self.vmwriter.WriteArithmetic("add")
            self.manageNextTranslation()
            self.isArray = True
            self.wasRightArray = True
            self.manageNextTranslation()
        if self.currentToken != "=":
            self.manageNextTranslation()
        self.isRight = True
        self.CompileExpression()

##############################################  Compile While  ##############################################

# Compiles a while statement.

    def compileWhile(self):
        self.compileWhileHelper()

    def compileWhileHelper(self):
        if self.currentTokenType == "keyword":
            self.manageNextTranslation()
            self.compileWhileHelper()
        elif self.currentTokenType == "symbol":
            if self.currentToken == "(":
                self.vmwriter.WriteLabel("WHILE_EXPRESSIONS" +
                                         str(self.whileLabelIndex))
                self.CompileExpression()
                self.manageNextTranslation()
                self.vmwriter.WriteArithmetic("not")
                self.vmwriter.WriteIf("WHILE_END" + str(self.whileLabelIndex))
                self.manageNextTranslation()
                self.compileWhileHelper()

            elif self.currentToken == "{":
                saved = self.whileLabelIndex
                self.manageNextTranslation()
                self.whileLabelIndex += 1
                self.compileStatements()
                self.vmwriter.WriteGoto("WHILE_EXPRESSIONS" + str(saved))
                self.vmwriter.WriteLabel("WHILE_END" + str(saved))

##############################################  Compile return  ##############################################

# Compiles a return statement.

    def compileReturn(self):
        self.checkNextToken()
        if self.nextToken != ";":
            self.CompileExpression()
        else:
            self.vmwriter.writePush("constant", 0)

        self.vmwriter.writeReturn()
        self.manageNextTranslation()

##############################################  Compile If  ##############################################

# Compiles an if statement, posibly with a trailing else clause.

    def compileIf(self):
        self.compileIfHelper()

    def compileIfHelper(self):
        self.manageNextTranslation()
        if self.currentTokenType in "symbol":
            if self.currentToken == "(":
                self.CompileExpression()
                self.vmwriter.WriteIf("IF_TRUE_LABEL" + str(self.ifLabelIndex))
                self.vmwriter.WriteGoto("IF_FALSE_LABEL" +
                                        str(self.ifLabelIndex))
                self.vmwriter.WriteLabel("IF_TRUE_LABEL" +
                                         str(self.ifLabelIndex))
                self.manageNextTranslation()
                self.compileIfHelper()
            elif self.currentToken == "{":
                self.ifLabelIndex += 1
                self.manageNextTranslation()
                self.compileStatements()
                if self.currentToken == ";":
                    self.manageNextTranslation()

##############################################  Compile Expression  ##############################################

# Compiles an expression.

    def CompileExpression(self):
        self.compileExpressionHelper()

    def compileExpressionHelper(self):
        self.CompileTerm()

        self.checkNextToken()
        if self.nextToken in self.op:
            self.manageNextTranslation()
            saved = self.currentToken
            self.compileExpressionHelper()
            if saved == "<":
                self.vmwriter.WriteArithmetic("lt")
            elif saved == ">":
                self.vmwriter.WriteArithmetic("gt")
            elif saved == "+":
                self.vmwriter.WriteArithmetic("add")
            elif saved == "-":
                self.vmwriter.WriteArithmetic("sub")
            elif saved == "*":
                self.vmwriter.WriteCall("Math.multiply", 2)
            elif saved == "/":
                self.vmwriter.WriteCall("Math.divide", 2)
            elif saved == "=":
                self.vmwriter.WriteArithmetic("eq")
            elif saved == "|":
                self.vmwriter.WriteArithmetic("or")
            elif saved == "&":
                self.vmwriter.WriteArithmetic("and")

        elif self.nextToken == ",":
            self.manageNextTranslation()

##############################################  Compile term  ##############################################

    def CompileTerm(self):
        self.compileTermHelper()

        if self.currentToken in self.unaryOp:
            saved = self.currentToken
            self.CompileTerm()
            if saved == "-":
                self.vmwriter.WriteArithmetic("neg")
            else:
                self.vmwriter.WriteArithmetic("not")

        self.isSubroutine = False

    # subName className varName
    def compileTermHelper(self):
        self.manageNextTranslation()

        if self.currentToken in self.terms or self.currentTokenType in self.terms:
            if self.currentTokenType == "integerConstant":
                self.vmwriter.writePush("constant", self.currentToken)
            elif self.currentTokenType == "stringConstant":
                self.vmwriter.writePush("constant", len(self.currentToken))
                self.vmwriter.WriteCall("String.new", 1)
                for ch in self.currentToken:
                    self.vmwriter.writePush("constant", ord(ch))
                    self.vmwriter.WriteCall("String.appendChar", 2)
            elif self.currentTokenType == "keyword":
                if self.currentToken == "null":
                    self.vmwriter.writePush("constant", 0)
                elif self.currentToken == "true":
                    self.vmwriter.writePush("constant", 0)
                    self.vmwriter.WriteArithmetic("not")
                elif self.currentToken == "false":
                    self.vmwriter.writePush("constant", 0)
                elif self.currentToken == "this":
                    self.vmwriter.writePush("pointer", 0)
            elif self.currentTokenType == "identifier":

                if self.isSubroutine:
                    varName = self.currentToken
                    kind = self.symbolTable.KindOf(varName)
                else:
                    self.checkNextToken()
                    if self.nextToken == ";":
                        kind = self.symbolTable.KindOf(self.currentToken)
                        indx = self.symbolTable.IndexOf(self.currentToken)
                        self.vmwriter.writePush(kind, indx)
                        return
                    if self.nextTokenType == "symbol" and self.nextToken != ".":
                        varName = self.currentToken
                        kind = self.symbolTable.KindOf(varName)
                        if kind == "none":
                            self.vmwriter.writePush("pointer", 0)
                            self.isSubroutine = True
                            self.compileTermHelper()
                            self.vmwriter.WriteCall(
                                self.className + "." + varName, self.nArgs + 1)
                            return

                self.currentFuncionName = self.currentToken
                self.isSubroutine = True
                self.checkNextToken()
                savedName = self.currentToken
                savednxt = self.nextToken
                self.checkNextToken()
                if savednxt not in self.op and self.nextToken != ")" and self.nextToken != "]" and self.nextToken != "(":
                    self.manageNextTranslation()
                if self.currentToken == "[":
                    self.CompileExpression()
                    if not self.isRight:
                        self.wasRightArray = True
                    self.isArray = True
                    self.manageNextTranslation()
                if self.symbolTable.KindOf(savedName) != "none":
                    self.vmwriter.writePush(
                        self.symbolTable.KindOf(savedName),
                        self.symbolTable.IndexOf(savedName))
                kind = self.symbolTable.KindOf(self.currentToken)
                if kind == "argument":
                    self.wasArgument = True
                if self.isArray and not self.wasArgument and not self.isSubroutine:
                    if self.isRight:
                        self.isArray = False
                    self.vmwriter.WriteArithmetic("add")
                    self.vmwriter.writePop("pointer", 1)
                    self.vmwriter.writePush("that", 0)
                if self.currentToken == ".":
                    saved = savedName
                    self.manageNextTranslation()

                    toWrite = self.currentFuncionName + "." + self.currentToken
                    savedCurrent = self.currentToken
                    self.compileTermHelper()
                    type = self.symbolTable.TypeOf(savedCurrent)
                    if type == "none":
                        type = self.symbolTable.TypeOf(saved)

                    if type == "none":  # function
                        self.vmwriter.WriteCall(toWrite, self.nArgs)
                    else:
                        kind = self.symbolTable.TypeOf(savedCurrent)
                        indx = self.symbolTable.IndexOf(savedCurrent)
                        if kind != "none":
                            self.vmwriter.writePush(kind, indx)
                        self.currentFuncionName = type
                        saved = self.symbolTable.TypeOf(saved)
                        toWrite = saved + "." + savedCurrent
                        self.nArgs += 1
                        self.vmwriter.WriteCall(toWrite, self.nArgs)

                if self.nextToken not in ["[", "(", "."]:
                    return

                self.compileTermHelper()

        if self.currentTokenType == "symbol":

            if self.currentToken == "(":
                if self.isSubroutine == True:
                    self.nArgs = 0
                    self.CompileExpressionList()
                    self.isSubroutine = False
                else:
                    self.CompileExpression()

                self.manageNextTranslation()

##############################################  Compile ExpressionList  ##############################################

# Compiles a (possibly empty) comma-separated
# list of expressions.

    def CompileExpressionList(self):
        self.checkNextToken()

        if self.nextToken in self.unaryOp:
            self.CompileExpression()
            return

        self.checkNextToken()

        while self.nextToken != ")":
            self.nArgs += 1
            self.CompileExpression()

##############################################  Some Helper Functions  ##############################################

# updates next token (token itself and its type)
# without removing from general list

    def checkNextToken(self):
        toCheck = self.lines[0]
        type = toCheck[1:toCheck.find(">")]
        startIndx = toCheck.find(">") + 2
        endIndx = toCheck.find("<", startIndx) - 1
        token = toCheck[startIndx:endIndx]
        self.nextToken = token
        self.nextTokenType = type

    # removes next token from general list
    # and updates information about current token
    def manageNextTranslation(self):
        toTranslate = self.lines.pop(0)
        self.currentLine = toTranslate
        type = toTranslate[1:toTranslate.find(">")]
        startIndx = toTranslate.find(">") + 2
        endIndx = toTranslate.find("<", startIndx) - 1
        token = toTranslate[startIndx:endIndx]
        self.currentToken = token
        self.currentTokenType = type
Example #2
0
class CompilationEngine:
    def __init__(self, tokenizer, outputFile):
        self.XMLCode = []
        self.CodeIndent = 0
        self.tokenizer = tokenizer
        self.symbolTable = SymbolTable()
        self.vmWriter = VMWriter(outputFile)
        self.class_name = None
        self.segment_local_dict = segment_dict
        self.while_count = 0
        self.if_count = 0

    def nextToken(self):
        "advancing and retreiving the next token by Tokenizer"
        self.tokenizer.advance()
        current_token = self.tokenizer.getCurrentToken()
        token_type = self.tokenizer.typeOfToken()
        return current_token, token_type

    def compileToken(self, token):
        current_token, token_type = self.nextToken()
        self.compileLine(current_token, token_type)
        return current_token

    def compileTitle(self, title_name, isEntered):
        self.XMLCode.append(self.writeXMLCodeTitle(title_name, isEntered))

    def compileLine(self, current_token, token_type):
        self.XMLCode.append(self.writeXMLCodeLine(current_token, token_type))

    def writeXMLCodeLine(self, token_to_write, type_of_token):
        """writes into XML line all sorts of tokens which are not title
        @:param token_to_write: the current token to write
        @:param type_of_token: the current's token's type
        @:return: the XML code line"""

        return " " * self.CodeIndent + "<" + str(
            type_of_token) + ">" + " " + token_to_write.lstrip(
            ) + " " + "</" + str(type_of_token) + ">"

    def writeXMLCodeTitle(self, type_of_token, isEntered):
        """writes into XML line all sorts of tokens which are  titles
                @:param isEntered: a boolean parameter implies if the current token is already opened
                 if it is the token's first occurance isEntered== True, and False otherwise
                @:param type_of_token: the current's token's type
                @:return: the XML code line"""

        if isEntered == True:  #if the title is opening
            myLine = " " * self.CodeIndent + "<" + str(type_of_token) + ">"
            self.CodeIndent += 2  #indent the lines of all other tokens within the current_token's scope
            return myLine
        else:
            #if isEntered == False we have to close the title token
            self.CodeIndent -= 2
            myLine = " " * self.CodeIndent + "</" + str(type_of_token) + ">"
            return myLine

    def compileIdentifier(self, isClass=False):
        current_token, token_type = self.nextToken()
        if isClass:
            self.class_name = current_token  # i've changed it because it was swapped

        self.XMLCode.append(self.writeXMLCodeLine(current_token, token_type))
        return current_token

    def compileClass(self):
        self.compileTitle("class", True)
        self.compileToken(
            "class"
        )  # increnmenting the tokenizer and checking if the current token is indeed a class declaration
        self.compileIdentifier(True)
        self.compileToken("{")
        current_token, token_type = self.nextToken()
        while current_token in ["field", "static"]:
            self.compileClassVarDeclaration(current_token, token_type)
            current_token, token_type = self.nextToken()

        while current_token in ["constructor", "function", "method"]:
            self.compilesubRoutineDec(current_token, token_type)
            current_token, token_type = self.nextToken()

        self.compileToken("}")
        self.compileTitle("class", False)
        return self.XMLCode

    def compileClassVarDeclaration(self, current_token, token_type):
        #self.compileTitle("classVarDec",True)  # first opening a new class title in XML
        #self.compileLine(current_token,token_type)
        VarKind = self.tokenizer.getCurrentToken()
        current_token, token_type = self.nextToken()
        VarType = current_token
        #self.compileType(current_token, token_type)
        VarName = self.compileIdentifier()
        self.symbolTable.define(VarName, VarType, VarKind)
        current_token, token_type = self.nextToken()
        while current_token == ",":  # also the validation itself so no need of compile token
            self.compileLine(current_token, token_type)
            VarName = self.compileIdentifier()
            self.symbolTable.define(VarName, VarType, VarKind)
            current_token, token_type = self.nextToken()
        self.compileLine(current_token, token_type)
        self.compileTitle("classVarDec", False)

    def compileType(self, current_token, token_type):
        if current_token in ["int", "char", "boolean", self.class_name]:
            self.compileLine(current_token, token_type)
        else:
            self.compileLine(current_token, token_type)
        return current_token

    def compilesubRoutineDec(self, current_token, token_type):
        self.symbolTable.startSubroutine()
        self.if_count = 0
        self.while_count = 0
        #self.compileTitle("subroutineDec", True)
        #self.compileLine(current_token, token_type)
        func_type = self.tokenizer.getCurrentToken()

        current_token, token_type = self.nextToken()
        return_type = current_token
        if current_token in ["int", "char", "boolean", self.class_name
                             ] or current_token == "void":
            self.compileLine(current_token, token_type)
        func_name = self.compileIdentifier()
        self.symbolTable.set_functionName(func_name, self.class_name)
        self.symbolTable.setFuncType(func_type)
        self.symbolTable.setReturnType(return_type)
        if func_type == "method":
            self.symbolTable.define("this", return_type, "arg")
        self.compileToken("(")
        self.compileParameterList()
        self.compileLine(")", "symbol")
        self.compileSubroutineBody()
        self.compileTitle("subroutineDec", False)

    def compileParameterList(self):
        self.compileTitle("parameterList", True)
        current_token, token_type = self.nextToken()
        while current_token != ")":
            VarType = self.compileType(current_token, token_type)
            VarName = self.compileIdentifier()
            self.symbolTable.define(VarName, VarType, "arg")
            current_token, token_type = self.nextToken()
            if current_token == ",":
                self.compileLine(current_token, token_type)
                current_token, token_type = self.nextToken()
        self.compileTitle("parameterList", False)

    def compileSubroutineBody(self):
        #self.compileTitle("subroutineBody", True)# first opening a new subroutineBody title in XML
        self.compileToken("{")

        current_token = self.tokenizer.showNextToken()
        while current_token == "var":
            self.compilevarDec()
            current_token = self.tokenizer.showNextToken()
        self.vmWriter.writeFunction(self.symbolTable.function_name,
                                    str(self.symbolTable.VarCount("var")))
        # check wether the function type is method or constructor /*todo*/
        if self.symbolTable.function_type == "method":

            self.vmWriter.writePush("argument", "0")
            self.vmWriter.writePop("pointer", "0")

        if self.symbolTable.function_type == "constructor":
            #slide 6 (7:00) about constructors
            field_num = self.symbolTable.VarCount("field")
            self.vmWriter.writePush("constant", str(field_num))
            self.vmWriter.writeCall("Memory.alloc", "1")
            self.vmWriter.writePop("pointer", "0")
        current_token, token_type = self.nextToken()
        self.compileStatements(current_token, token_type)
        #self.compileLine("}","symbol")
        #self.compileTitle("subroutineBody", False)

    def compilevarDec(self):
        #self.compileTitle("varDec", True)
        current_token, token_type = self.nextToken()
        VarKind = "var"
        current_token, token_type = self.nextToken()
        VarType = current_token
        current_token, token_type = self.nextToken()
        VarName = current_token
        self.symbolTable.define(VarName, VarType, VarKind)
        #self.compileLine(current_token, token_type)
        current_token, token_type = self.nextToken()
        while current_token == ",":
            #self.compileLine(current_token, token_type)
            VarName = self.compileIdentifier()
            self.symbolTable.define(VarName, VarType, VarKind)
            current_token, token_type = self.nextToken()
        #self.compileLine(";", "symbol")
        #self.compileTitle("varDec", False)

    def compileStatements(self, current_token, token_type):
        self.compileTitle("statements", True)
        while current_token != "}":
            if current_token == "let":
                self.compileLet()
            elif current_token == "if":
                self.compileIf()
            elif current_token == "while":
                self.compileWhile()
            elif current_token == "do":
                self.compileDo()
            elif current_token == "return":
                self.compileReturn()
            current_token, token_type = self.nextToken()
        self.compileTitle("statements", False)

    def compileLet(self):
        self.compileTitle("letStatement", True)
        self.compileLine("let", "keyword")
        current_token, token_type = self.nextToken()
        temp = current_token  # saves the new local variable
        current_token, token_type = self.nextToken()
        if current_token == "[":  # if the left side is array
            self.compileLine("[", "symbol")
            self.compileExpression()
            self.compileLine("]", "symbol")
            var_memory_segment = self.segment_local_dict[
                self.symbolTable.KindOf(temp)]  #the kind of current var
            var_index = self.symbolTable.IndexOf(temp)
            self.vmWriter.writePush(var_memory_segment, str(var_index))
            self.vmWriter.WriteArithmetic(
                "add"
            )  #if the left side is  an array - add the index to get the value
            self.nextToken()

        #self.compileLine("=","symbol")
        self.compileExpression()
        #self.compileLine(";", "symbol")
        #self.compileTitle("letStatement", False)
        var_kind = self.symbolTable.KindOf(temp)
        var_type = self.symbolTable.TypeOf(temp)
        index_segment = self.symbolTable.IndexOf(temp)
        kind_seg = self.segment_local_dict[var_kind]
        if current_token == "[" and kind_seg in ["local", "argument"]:
            #slide 8 (20:00) !!!
            self.vmWriter.writePop("temp", "0")
            self.vmWriter.writePop("pointer", "1")
            self.vmWriter.writePush("temp", "0")
            self.vmWriter.writePop("that", "0")
        else:
            #if the first var was not an Arrayso just pop the value from the expression to it
            self.vmWriter.writePop(kind_seg, str(index_segment))

    def compileIf(self):
        #self.compileTitle("ifStatement", True)
        #self.compileLine("if", "keyword")
        self.compileToken("(")
        self.compileExpression()
        self.compileLine(")", "symbol")

        if_true_label = "TRUE" + str(
            self.if_count)  #define true and false labels!!
        if_false_label = "FALSE" + str(self.if_count)
        end_if_label = "END" + str(self.if_count)
        self.if_count += 1
        self.vmWriter.WriteIf(
            if_true_label
        )  # after pushing to stack the expression write labels
        self.vmWriter.WriteGoto(if_false_label)

        self.compileToken("{")
        self.vmWriter.WriteLabel(
            if_true_label
        )  # put the TRUE_LABEL at the begining of the if clause
        current_token, token_type = self.nextToken()
        self.compileStatements(current_token, token_type)
        #self.compileLine("}","symbol")

        #check if there is "else" statement
        temp = self.tokenizer.showNextToken()
        if temp == "else":
            #put the END_LABEL and put the False_label If the condionn not true
            self.vmWriter.WriteGoto(end_if_label)
            self.vmWriter.WriteLabel(if_false_label)
            current_token, token_type = self.nextToken()
            #self.compileLine("else","keyword")
            self.compileToken("{")
            current_token, token_type = self.nextToken()
            self.compileStatements(current_token, token_type)
            self.vmWriter.WriteLabel(end_if_label)
            #self.compileLine("}","symbol")
        else:
            self.vmWriter.WriteLabel(if_false_label)
        #self.compileTitle("ifStatement", False)

    def compileWhile(self):
        #self.compileTitle("whileStatement", True)
        #self.compileLine("while", "keyword")
        while_start_label = "STRAT" + str(
            self.while_count)  # defining astart and stop labels!!
        while_end_label = "END" + str(self.while_count)
        self.while_count += 1

        self.vmWriter.WriteLabel(while_start_label)
        self.compileToken("(")
        self.compileExpression()
        #self.compileLine(")","symbol")
        #negating the boolean expression and check whether to enter or not
        self.vmWriter.WriteArithmetic("not")
        self.vmWriter.WriteIf(while_end_label)
        self.compileToken("{")
        current_token, token_type = self.nextToken()
        self.compileStatements(current_token, token_type)
        self.vmWriter.WriteGoto(while_start_label)
        self.vmWriter.WriteLabel(while_end_label)
        #self.compileLine("}", "symbol")
        #self.compileTitle("whileStatement", False)

    def compileDo(self):
        #self.compileTitle("doStatement", True)
        #self.compileLine("do", "keyword")
        self.compileSubroutineCall()
        self.vmWriter.writePop("temp", "0")
        self.nextToken()
        #self.nextToken()
        #self.compileLine(";","symbol")
        #self.compileTitle("doStatement", False)

    def compileReturn(self):
        #self.compileTitle("returnStatement", True)
        #self.compileLine("return", "keyword")
        if self.symbolTable.return_type == "void":
            self.vmWriter.writePush("constant",
                                    "0")  # always push 0 to the stack!!
            temp = self.tokenizer.showNextToken()
            while not temp == ";":
                self.nextToken()
                temp = self.tokenizer.showNextToken()
        else:
            temp = self.tokenizer.showNextToken()
            if temp != ";":
                self.compileExpression()
            else:
                self.vmWriter.writePush("constant", "0")
        self.vmWriter.writeReturn()

        #self.compileLine(";","symbol")
        #self.compileTitle("returnStatement", False)

    def compileExpression(self):
        #self.compileTitle("expression", True)
        self.compileTerm()
        current_token, token_type = self.nextToken()
        while current_token in op:
            self.compileLine(current_token, token_type)
            self.compileTerm()
            self.vmWriter.WriteArithmetic(
                current_token
            )  # after two expression/terms we will write arithmetic
            current_token, token_type = self.nextToken()
        self.compileTitle("expression", False)

    def compileExpressionList(self):
        num_of_args = 0
        self.compileTitle("expressionList", True)
        current_token = self.tokenizer.showNextToken()
        if current_token != ")":
            self.compileExpression()
            num_of_args += 1  # add the first parameter found inside paranthesis( )
            while (self.tokenizer.getCurrentToken() == ","):
                num_of_args += 1
                self.compileLine(",", "symbol")
                self.compileExpression()
        if current_token == ")":
            self.nextToken()
        self.compileTitle("expressionList", False)
        return num_of_args

    def compileTerm(self):
        #self.compileTitle("term", True)
        current_token, token_type = self.nextToken()
        kind = self.symbolTable.KindOf(current_token)
        temp = self.tokenizer.showNextToken()
        if token_type == "int_constant":
            # self.compileLine(current_token,"integerConstant")
            self.vmWriter.writePush("constant", str(current_token))

        elif kind == "var" and temp != "[" and temp != ".":
            self.vmWriter.writePush(
                "local", str(self.symbolTable.IndexOf(current_token)))

        elif kind == "arg" and current_token != "this":
            self.vmWriter.writePush(
                "argument", str(self.symbolTable.IndexOf(current_token)))

        elif token_type == "string_constant":
            #self.compileLine(current_token.strip("\""),"stringConstant")
            string_constant = current_token.strip("\"")
            string_lenth = len(string_constant)
            self.vmWriter.writePush("constant", str(string_lenth))
            self.vmWriter.writeCall("String.new", 1)
            #now getting the numerical value of each char in the string and append them
            for char in string_constant:
                self.vmWriter.writePush("constant", str(ord(char)))
                self.vmWriter.writeCall("String.appendChar", "2")

        elif kind == "static" and temp != "." and temp != "[":
            self.vmWriter.writePush(
                "static", str(self.symbolTable.IndexOf(current_token)))

        elif kind == "field" and temp != "." and temp != "]":
            self.vmWriter.writePush(
                "this", str(self.symbolTable.IndexOf(current_token)))

        elif current_token in [
                "true", "false", "null", "this"
        ]:  # not the kind it only means that the tokens itself is one of them
            #self.compileLine(current_token,token_type) #its a keyword!
            if current_token == "true":
                self.vmWriter.writePush("constant", "0")
                self.vmWriter.WriteArithmetic("not")
            elif current_token == "this":
                self.vmWriter.writePush("pointer", "0")
            else:  # its false or null
                self.vmWriter.writePush("constant", "0")
        # if its ( expression )
        elif current_token == "(":
            self.compileLine(current_token, token_type)
            self.compileExpression()
            self.compileLine(")", "symbol")
        #if its Unary Op
        elif current_token in ["~", "-"]:
            self.compileLine(current_token, token_type)
            self.compileTerm()
            if current_token == "~":
                self.vmWriter.WriteArithmetic("not")
            else:
                self.vmWriter.WriteArithmetic("neg")
        #if its varName [ expression ]
        elif token_type == "identifier" and temp != ".":  # maybe add and temp != ";"  ????????
            self.compileLine(current_token, token_type)
            if temp == "[":
                self.compileLine(temp, "symbol")
                var_name = current_token
                current_token, token_type = self.nextToken()
                self.compileExpression()
                self.compileLine("]", "symbol")
                var_memory_segment = self.segment_local_dict[
                    self.symbolTable.KindOf(
                        var_name)]  # the kind of current var
                var_index = self.symbolTable.IndexOf(var_name)
                self.vmWriter.writePush(var_memory_segment, str(var_index))
                self.vmWriter.WriteArithmetic(
                    "add")  # if the left side is  an array
                self.vmWriter.writePop("pointer", "1")
                self.vmWriter.writePush("that", "0")

        # subroutine
        elif token_type == "identifier" and temp in ["(", "."]:
            self.tokenizer.previousToken()
            self.compileSubroutineCall()
        # if its a var_name
        elif token_type == "identifier" and not temp in ["[", "(", "."]:
            var_name = current_token
            var_memory_segment = self.segment_local_dict[
                self.symbolTable.KindOf(var_name)]  # the kind of current var
            var_index = self.symbolTable.IndexOf(var_name)
            self.vmWriter.writePush(var_memory_segment, str(var_index))
        self.compileTitle("term", False)

    def compileSubroutineCall(self):
        num_of_args = 0
        func_name = self.compileIdentifier(
        )  # func_name first contain the class name
        current_token, token_type = self.nextToken()
        if current_token == ".":
            var_kind = self.symbolTable.KindOf(func_name)
            var_index = self.symbolTable.IndexOf(func_name)
            var_type = self.symbolTable.TypeOf(func_name)
            if var_type != False:  # enter only if it is a method called by an object
                num_of_args += 1  # num of arguments of a method starts from 1 because of the "self" argument
                func_name = var_type
                mem_segment = self.segment_local_dict[var_kind]
                self.vmWriter.writePush(
                    mem_segment, str(var_index)
                )  # push memory segment to stack be calling function
            func_name += "."
            func_name += self.compileIdentifier()
            #self.compileLine(".", "symbol")
            self.compileToken("(")
            num_of_args += self.compileExpressionList()
            self.compileLine(")", "symbol")
            self.vmWriter.writeCall(func_name, str(num_of_args))

        else:
            self.vmWriter.writePush("pointer", "0")
            num_of_args += 1
            func_name = self.class_name + "." + func_name
            self.compileLine("(", "symbol")
            num_of_args += self.compileExpressionList()
            self.compileLine(")", "symbol")
            self.vmWriter.writeCall(func_name, str(num_of_args))