Example #1
0
def compile_whileStatement():  # while ( expression ) { statements }
    print("---COMPILING WHILE STATEMENT---")

    global global_while_index
    global_while_index += 1

    while_index = global_while_index  # local var used; ensure while_index consistent throughout this function
    # global_while_index may be changed by other functions without you knowing

    VMWriter.writeLabel("WHILE_EXP" + str(while_index))  # label WHILE_1

    advance()  # (
    compile_expression()  # expression
    VMWriter.writeArithmetic("not")  # NOT expression
    advance()  # )
    advance()  # {

    VMWriter.writeIfGoto("WHILE_END" + str(while_index))  # if-goto WHILE_END_1
    compile_statements()
    VMWriter.writeGoto("WHILE_EXP" + str(while_index))  # goto WHILE_1

    VMWriter.writeLabel("WHILE_END" + str(while_index))
    advance()  # }

    print("---DONE COMPILING WHILE STATEMENT---")
Example #2
0
 def __init__(self, tokenizer):
     """
     Ctor
     _writer: a VM writer object
     _cur_class: the current class
     _cur_func: the current function
     _cur_func_type: the current function type
     _subroutine_table: a symbol table of the subroutine
     _class_table: a list of the symbols in the class
     _tokenizer: the tokenizer object
     _result: a list that is written in the output file
     counters: the kind counters
     label_counters: the label counters
     """
     self._writer = VMWriter()
     self._cur_class = None
     self._cur_func = None
     self._cur_func_type = None
     self._subroutine_table = None
     self._class_table = []
     self._tokenizer = tokenizer
     self._result = []
     self.counters = {'static': 0, 'field': 0, 'argument': 0, 'local': 0}
     self.label_counters = {"if": 0, "while": 0}
     self.compileClass()
Example #3
0
 def compileSubroutine(self):
     self.SubroutineScope.reset()
     ftype = self.takeWord()  # (constructor|method|function)
     self.advance()  # type
     subroutineName = self.takeWord()  # SubroutineName
     self.advance()  # (
     self.complieParameterList()
     self.advance()  # )
     self.advance()  # {
     num_locals = 0
     while self.tokens[self.count]["token"] in ["var"]:
         num_locals += self.compileVarDec()
     self.vmcode += VMWriter.writeFunction(
         self.className + "." + subroutineName, num_locals)
     # if function is constructor, it should allocate memory for produced object
     if ftype == "constructor":
         # allocate needed memory
         num_field = self.ClassScope.varCount("field")
         self.vmcode += VMWriter.writePush("constant", num_field)
         self.vmcode += VMWriter.writeCall("Memory.alloc", 1)
         # link it to This
         self.vmcode += VMWriter.writePop("pointer", 0)
         # change all FIELD in ClassScope to THIS
         self.ClassScope.field2This()
     self.compileStatements()
     self.advance()  # }
     self.label_count["if"] = 0
     self.label_count["while"] = 0
 def __init__(self, file):
     self.lex = Lex(file)
     self.symbols = SymbolTable()
     self.vm = VMWriter()
     self.openout(file)
     self.compile_class()
     self.closeout()
Example #5
0
 def openXMLFile(self, xml_file):
     self.xml_tree = ET.parse(xml_file)
     self.tokens = list(self.xml_tree.getroot())
     self.tokens.reverse()
     self.st = SymbolTable()
     self.current_class = xml_file[:-5]
     self.vm = VMWriter(self.current_class + '.vm')
Example #6
0
 def compileDo(self):
     self.advance()  # do
     caller = self.takeWord()  # (className|varName)
     symbol = self.findSymbol(caller)
     # if object exist, push it in to stack
     if symbol:
         self.advance()  # .
         func = self.takeWord()  # subroutineName
         segment = 'local'
         index = symbol['index']
         self.vmcode += VMWriter.writePush(segment, index)
         symbolType = symbol['type']
     # Static method called
     elif self.tokens[self.count]["token"] == ".":
         symbolType = caller
         self.advance()  # .
         func = self.takeWord()  # subroutineName
     else:
         symbolType = self.className
         func = caller
     # decide subroutine name
     subroutineName = symbolType + '.' + func
     self.advance()  # (
     num_args = self.compileExpressionList()
     if symbol:
         # add "this"
         num_args += 1
     # call the function
     self.vmcode += VMWriter.writeCall(subroutineName, num_args)
     # since this code will not save returned value in to variable, pop it out.
     self.vmcode += VMWriter.writePop('temp', '0')
     self.advance()  # )
     self.advance()  # ;
Example #7
0
def compile_doStatement():  # do subroutineCall ;
    print("---COMPILING DO STATEMENT---")

    compile_subroutineCall()  # subroutineCall
    VMWriter.writePop("temp", 0)
    advance()

    print("---DONE COMPILING DO STATEMENT---")
Example #8
0
 def __init__(self, tokens, file_path):
     self.tokens = tokens
     self.class_symboltable = SymbolTable()
     self.subroutine_symboltable = SymbolTable()
     self.cur_class = None
     self.cur_subroutine_type = None  # for the compile return function
     self.vmwriter = VMWriter(file_path)
     self.labelcounter = 0
Example #9
0
    def __init__(self, inputFile, outputFile):
        # self.outFile = outputFile
        self.tokenizer = JackTokenizer(inputFile)
        self.vmwriter = VMWriter(outputFile)
        self.outFile = outputFile
        self.currToken = ""
        self.tabber = ""

        self.argumentsCounter = 0
 def __init__(self, input_file, xml_file, vm_file):
     ''' Initialize the xml file, the symbol table adn the VMwriter '''
     super().__init__(input_file)
     self.xml_file = xml_file
     self.symbol_tab = SymbolTable()
     self.vm_writer = VMWriter(vm_file)
     self.subroutine_type = None
     self.if_label, self.while_label = 0, 0
     self.isarray = None
Example #11
0
 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
Example #12
0
 def compileString(self, s):
     # use standard library String
     str_len = len(s)
     self.vmcode += VMWriter.writePush("constant", str_len)
     self.vmcode += VMWriter.writeCall("String.new", 1)
     for c in s:
         if not c == "\"":
             asciic = ord(c)
             self.vmcode += VMWriter.writePush("constant", asciic)
             self.vmcode += VMWriter.writeCall("String.appendChar", 2)
Example #13
0
 def compileReturn(self):
     self.advance()  # return
     if not self.tokens[self.count]["token"] == ";":
         # push result to stack
         self.compileExpression()
     else:
         # push constant 0 to stack for void
         self.vmcode += VMWriter.writePush("constant", "0")
     self.advance()  # ;
     self.vmcode += VMWriter.writeReturn()
Example #14
0
 def __init__(self, tokenizer, output):
     """Creates a new compilation engine with the given input and output.
              The next routine called must be compileClass(). """
     self.tokenizer = tokenizer
     self.tags = []
     self.scope = 0
     self.writer = VMWriter(output)
     self.class_table = SymbolTable()
     self.method_table = SymbolTable()
     self.class_name = ''
     self.method_or_constructor = False
Example #15
0
    def __init__(self, file):
        """ """
        self.label_num = 0
        self.tokenizer = JackTokenizer(file)
        self.advance()

        self.symbols = SymbolTable()
        self.vm = VMWriter()

        self.open_outfile(file)
        self.compile_class()
        self.close_outfile()
Example #16
0
 def __init__(self, input_path, output_path):
     """
     creates a new compilation engine with the given input and output. the next routine called must be compileClass()
     :param input_path: input stream/file
     :param output_path: output stream/file
     """
     self.labels = 0
     self.jack_class = None
     self.class_subroutine = None
     self.tokenizer = JackTokenizer(input_path)
     self._writer = VMWriter(output_path)
     self.CompileClass()
 def __init__(self, in_file, out_file):
     """
     A compilation engine constructor
     :param in_file: the file we are currently compiling
     :param out_file: the file where we save the output
     """
     self._tokenizer = JackTokenizer(in_file)
     self._class_table = SymbolTable()
     self._method_table = SymbolTable()
     self._cur_class_name = ""
     self._vm_writer = VMWriter(out_file)
     self._label_count_while = 0
     self._label_count_if = 0
Example #18
0
def compile_returnStatement():  # return expression? ;
    print("---COMPILING RETURN STATEMENT---")

    if (get_current_token() !=
            ";"):  # there must be an expression if current token is not ';'
        compile_expression()  # push return value of expression onto stack
    else:
        VMWriter.writePush("constant", 0)  # if void function, push constant 0

    VMWriter.writeReturn()
    advance()  # ;

    print("---DONE COMPILING RETURN STATEMENT---")
Example #19
0
    def __init__(self, input_file, output_file):
        self.tokenizer = JackTokenizer(input_file)
        self.symbol_table = SymbolTable()
        self.vm_writer = VMWriter(output_file)
        self.current_sub_name = None
        self.class_name = None
        self.func_counter = 0
        self.while_counter = 0
        self.if_counter = 0

        # starts the process
        self.tokenizer.advance()
        self.compile_class()
        self.vm_writer.close()
Example #20
0
 def compileArrayEXP(self):
     symbolName = self.takeWord()  # varName
     symbol = self.findSymbol(symbolName)
     self.advance()  # [
     self.compileExpression()
     # push base address to stack
     self.vmcode += VMWriter.writePush("local", symbol['index'])
     # add index(expression result) and base addresses
     self.vmcode += VMWriter.writeArithmetic('+')
     # pop address into THAT
     self.vmcode += VMWriter.writePop("pointer", "1")
     # push value to stack
     self.vmcode += VMWriter.writePush("that", "0")
     self.advance()  # ]
Example #21
0
 def compileExpression(self):
     # Order of operations is from front to back
     self.compileTerm()
     while self.tokens[self.count]["token"] in [
             "+", "-", "*", "/", "&", "|", "<", ">", "="
     ]:
         op = self.takeWord()  # op
         self.compileTerm()
         # execute op
         if op == "*":
             self.vmcode += VMWriter.writeCall("Math.multiply", 2)
         elif op == "/":
             self.vmcode += VMWriter.writeCall("Math.divide", 2)
         else:
             self.vmcode += VMWriter.writeArithmetic(op)
Example #22
0
def generateFile(foldername, filename):  # (Square/mine/, Main.jack)

    jack_filename = foldername.rsplit(
        "/", 2)[0] + "/" + filename  # "Square" + "/" + "Main.jack"
    tokens = JackTokenizer.tokenize(
        jack_filename)  # returns tokens generated from .jack file

    vm_filename = foldername + filename.split(
        ".")[0] + ".vm"  # let VMWriter know what file to write to
    VMWriter.initializeFile(
        vm_filename)  # open .vm file to begin writing to it

    # pass tokens from Tokenizer to CompilationEngine
    class_name = filename.split(".")[0]
    CompilationEngine.compileTokens(tokens, class_name)
    def __init__(self, inFilename, outFilename):
        global f
        global vmWriter
        global symbolTable
        global filename
        global currentLine
        global currentClass
        global currentSubroutine
        global ifEndLabelIndex
        global ifFalseLabelIndex
        global ifTrueLabelIndex
        global whileExpLabelIndex
        global whileEndLabelIndex

        f = None
        filename = ''
        currentLine = 1
        currentClass = ''
        currentSubroutine = ''
        labelIndex = 0
        vmWriter = None
        symbolTable = None

        ifEndLabelIndex = 0
        ifTrueLabelIndex = 0
        ifFalseLabelIndex = 0
        whileExpLabelIndex = 0
        whileEndLabelIndex = 0
        filename = inFilename
        vmWriter = VMWriter.vmWriter(outFilename)
        symbolTable = SymbolTable.symbolTable()
        f = open(inFilename, "r")
        compileClass()
Example #24
0
    def __init__(self, jackTokenizerOutput, outfileName, outVMName):
        '''
		In: jackTokenizerOutput which is the array of tokens output by JackTokenizer.py
		Function: Creates a new compilation engine with the given input and output. 
		The next routine called must be compileClass().
		'''

        self.tokenArray = jackTokenizerOutput
        self.tokenIndex = 0
        self.line = self.tokenArray[0]  # first item of array is class

        self.curToken = self.line.split()[
            1]  # the second item in a line is the token

        self.curTokenType = self.line.split()[
            0]  # gets the first tag of the token

        # set buffersize to 0
        self.f1 = open(outfileName, 'a', 0)

        # project 11 part: add Symbol table and VMWriter output
        self.sTable = st.SymbolTable()
        self.vm = vmw.VMWriter(outVMName)

        # project 11 class variables
        self.curClass = ''  # name of the current class
        self.whileCount = 0
        self.ifCount = 0
Example #25
0
 def __init__(self, jack_lines):
     self._jack_lines = jack_lines
     self._token = tk.JackTokenizer(jack_lines)
     self._writer = vmw.VMWriter()
     self._table = st.SymbolTable()
     self._class = None
     self._cur_subroutine_ret_type = None
Example #26
0
 def __init__(self, file):
     self.lex = Lex(file)
     self.symbols = SymbolTable()
     self.vm = VMWriter()
     self.openout(file)
     self.compile_class()
     self.closeout()
Example #27
0
def parseOneFile(fileName):
    listOfTokens = PassingTokenArray(fileName)
    outFile = fileName[:-5] + ".vm"
    writerObj = VMWriter.Translator(outFile)
    classRoot = clssNode()
    parser = JackParser(listOfTokens, writerObj, classRoot)
    parser.initProcess()
Example #28
0
 def __init__(self, tokenizer, ostream, file_name_no_ext):
     '''Initialize the compilation engine
     @tokenizer the tokenizer from the input code file
     @ostream the output stream to write the code to'''
     self.tokenizer = tokenizer
     self.vm_writer = VMWriter.VMWriter(ostream)
     self.className = file_name_no_ext
 def __init__(self, in_filename, in_file, out_xml, out_vm):
     """
     Creates a new compilation engine with the given input and output.
     The next routine called must be compileClass().
     :param in_file: Open source Jack file.
     :param out_xml: Open XML file.
     :param out_vm: Open VM file.
     """
     self.__in_filename = in_filename
     self.__in_file, self.__out_xml = in_file, out_xml
     self.__tokenizer = JackTokenizer(in_file)
     self.__symbolTable = SymbolTable()
     self.__vmWriter = VMWriter(in_filename, out_vm)
     self.__stack = list()
     self.__tokenizer.advance()
     self.__resetUniqueLabels()
Example #30
0
    def __init__(self, input_filename, output_file=None):
        self.input_filename = input_filename
        self.output_file = output_file
        self.symbol_table = SymbolTable.SymbolTable()

        self.subtoutine_name = ''
        self.subroutine_type = ''
        self.class_name = ''
        self.if_index = 0
        self.while_index = 0
        self.var_number = 0

        self.in_xml = xml.dom.minidom.parse(self.input_filename)
        self.input_child_node_idx = 1

        self.vm_writer = VMWriter.VMWriter(input_filename[:-5])

        self.current_token = self.in_xml.documentElement.childNodes[
            self.input_child_node_idx]
        self.doc = xml.dom.minidom.Document()
        while self.current_token.nodeName == 'keyword' and self.current_token.childNodes[
                0].nodeValue == 'class':
            self.compile_class()
        self.__save_xml()

        pass
Example #31
0
    def __init__(self, inFile, outFile):
        """ Creates a new CompilationEngine with given
            input and output. The next routine called must
            be compileClass() """

        # Create an object of JackTokenizer with the input file
        self.tokenizer = JackTokenizer.JackTokenizer(inFile)

        # Create an object of SymbolTable
        self.symbolTable = SymbolTable.SymbolTable()

        # Create an object of VMWriter
        self.vmWriter = VMWriter.VMWriter(outFile[:-3] + 'vm')

        # Open a output file to write to
        self.out = open(outFile, 'w')

        self.currentToken = ''
        self.currentTokenType = ''
        self.tabs = 0
        self.i = 0  # for creating unique labels
        self.nfield = 0
        self.nstatic = 0

        self.__advance()
Example #32
0
 def __init__(self, jackTokenizer):
     self.jackTokenizer = jackTokenizer
     self.symbolTabel = SymbolTabel()
     self.vmWriter = VMWriter()
     self.result = []
     self.labelCount = 0 #用来解决不同if等等语句中相同label的问题
     self.fieldCount = 0
     self.compileClass()
Example #33
0
class Parser(object):
    def __init__(self, file):
        self.lex = Lex(file)
        self.symbols = SymbolTable()
        self.vm = VMWriter()
        self.openout(file)
        self.compile_class()
        self.closeout()

    # VMWriter support
    def openout(self, path):
        outdir = os.path.join(os.path.dirname(path), "output")
        file = os.path.join(outdir, os.path.basename(path))
        try:
            os.mkdir(outdir)
        except OSError as e:
            pass
        self.vm.openout(file)

    def closeout(self):
        self.vm.closeout()

    def vm_function_name(self):
        return self._cur_class + "." + self._cur_subroutine

    def vm_push_variable(self, name):
        (type, kind, index) = self.symbols.lookup(name)
        self.vm.write_push(segments[kind], index)

    def vm_pop_variable(self, name):
        (type, kind, index) = self.symbols.lookup(name)
        self.vm.write_pop(segments[kind], index)

    # Routines to advance the token
    def _require(self, tok, val=None):
        lextok, lexval = self._advance()
        if tok != lextok or tok in (T_KEYWORD, T_SYM) and val != lexval:
            raise ParserError(self._require_failed_msg(tok, val))
        else:
            return lexval

    def _require_failed_msg(self, tok, val):
        if val == None:
            val = tokens[tok]
        return "Expected " + val

    def _advance(self):
        return self.lex.advance()

    def _is_token(self, tok, val=None):
        lextok, lexval = self.lex.peek()
        return val == None and lextok == tok or (lextok, lexval) == (tok, val)

    def _is_keyword(self, *keywords):
        lextok, lexval = self.lex.peek()
        return lextok == T_KEYWORD and lexval in keywords

    def _is_sym(self, symbols):
        lextok, lexval = self.lex.peek()
        return lextok == T_SYM and lexval in symbols

    # Parser and compile Jack code
    # class: 'class' className '{' classVarDec* subroutineDec* '}'
    def compile_class(self):
        self._require(T_KEYWORD, KW_CLASS)
        self.compile_class_name()
        self._require(T_SYM, "{")
        while self._is_class_var_dec():
            self.compile_class_var_dec()
        while self._is_subroutine():
            self.compile_subroutine()
        self._require(T_SYM, "}")

    # className: identifier
    def compile_class_name(self):
        self._cur_class = self.compile_var_name()  # Class names don't have to go into the symbol table

    # Variable declarations
    def _is_class_var_dec(self):
        return self._is_keyword(KW_STATIC, KW_FIELD)

    # classVarDec: {'static'|'field'} type varName (',' varName)* ';'
    def compile_class_var_dec(self):
        tok, kwd = self._advance()  # static | field
        self._compile_dec(kwd_to_kind[kwd])

    # type varName (',' varName)* ';'
    def _compile_dec(self, kind):
        type = self.compile_type()
        name = self.compile_var_name()
        self.symbols.define(name, type, kind)
        while self._is_sym(","):
            self._advance()
            name = self.compile_var_name()
            self.symbols.define(name, type, kind)
        self._require(T_SYM, ";")

    def _is_type(self):
        return self._is_token(T_ID) or self._is_keyword(KW_INT, KW_CHAR, KW_BOOLEAN)

    # 'void' | type
    def compile_void_or_type(self):
        if self._is_keyword(KW_VOID):
            return self._advance()[1]
        else:
            return self.compile_type()

    # type: 'int' | 'char' | 'boolean' | className
    def compile_type(self):
        if self._is_type():
            return self._advance()[1]
        else:
            raise ParserError(self._require_failed_msg(*self.lex.peek()))

    def _is_var_name(self):
        return self._is_token(T_ID)

    # varName: identifier
    def compile_var_name(self):
        return self._require(T_ID)

    # Subroutine declarations
    def _is_subroutine(self):
        return self._is_keyword(KW_CONSTRUCTOR, KW_FUNCTION, KW_METHOD)

    # subroutineDec: ('constructor'|'function'|'method') ('void'|type)
    #                subroutineName '(' parameterList ')' subroutineBody
    def compile_subroutine(self):
        tok, kwd = self._advance()
        type = self.compile_void_or_type()
        self.compile_subroutine_name()
        self.symbols.start_subroutine()
        if kwd == KW_METHOD:
            self.symbols.define("this", self._cur_class, SK_ARG)
        self._require(T_SYM, "(")
        self.compile_parameter_list()
        self._require(T_SYM, ")")
        self.compile_subroutine_body(kwd)

    # subroutineName: identifier
    def compile_subroutine_name(self):
        self._cur_subroutine = self.compile_var_name()  # subroutine names don't have to go in the symbol table

    # parameterList: (parameter (',' parameter)*)?
    def compile_parameter_list(self):
        if self._is_type():
            self.compile_parameter()
            while self._is_sym(","):
                self._advance()
                self.compile_parameter()

    # parameter: type varName
    def compile_parameter(self):
        if self._is_type():
            type = self.compile_type()
            name = self.compile_var_name()
            self.symbols.define(name, type, SK_ARG)

    # subroutineBody: '{' varDec* statements '}'
    def compile_subroutine_body(self, kwd):
        self._require(T_SYM, "{")
        while self._is_var_dec():
            self.compile_var_dec()
        self.write_func_decl(kwd)
        self.compile_statements()
        self._require(T_SYM, "}")

    def write_func_decl(self, kwd):
        self.vm.write_function(self.vm_function_name(), self.symbols.var_count(SK_VAR))
        self.load_this_ptr(kwd)

    def load_this_ptr(self, kwd):
        if kwd == KW_METHOD:
            self.vm.push_arg(0)
            self.vm.pop_this_ptr()  # set up 'this' pointer to point to new object
        elif kwd == KW_CONSTRUCTOR:
            self.vm.push_const(self.symbols.var_count(SK_FIELD))  # object size
            self.vm.write_call("Memory.alloc", 1)
            self.vm.pop_this_ptr()  # set up 'this' pointer to point to new object

    def _is_var_dec(self):
        return self._is_keyword(KW_VAR)

    # varDec: 'var' type varName (',' varName)* ';'
    def compile_var_dec(self):
        self._require(T_KEYWORD, KW_VAR)
        return self._compile_dec(SK_VAR)

    # Statements
    # statement: statement*
    def compile_statements(self):
        while self._is_statement():
            self._compile_statement()

    def _is_statement(self):
        return self._is_let() or self._is_if() or self._is_while() or self._is_do() or self._is_return()

    # statement: letStatement | ifStatement | whileStatement | doStatement | returnStatement
    def _compile_statement(self):
        if self._is_let():
            self.compile_let()
        elif self._is_if():
            self.compile_if()
        elif self._is_while():
            self.compile_while()
        elif self._is_do():
            self.compile_do()
        elif self._is_return():
            self.compile_return()

    def _is_let(self):
        return self._is_keyword(KW_LET)

    # letStatement: 'let' varName ('[' expression ']')? '=' expression ';'
    def compile_let(self):
        self._require(T_KEYWORD, KW_LET)
        name = self.compile_var_name()
        subscript = self._is_sym("[")
        if subscript:
            self.compile_base_plus_index(name)  # calculate base+index
        self._require(T_SYM, "=")
        self.compile_expression()  # calculate expression to assign
        self._require(T_SYM, ";")
        if subscript:
            self.pop_array_element()  # *(base+index) = expr
        else:
            self.vm_pop_variable(name)  # pop value directly into variable

    # ('[' expression ']')?
    def compile_base_plus_index(self, name):
        self.vm_push_variable(name)  # push array ptr onto stack
        self._advance()
        self.compile_expression()  # push index onto stack
        self._require(T_SYM, "]")
        self.vm.write_vm_cmd("add")  # base+index - leave on the stack for later

    def pop_array_element(self):
        self.vm.pop_temp(TEMP_ARRAY)  # Pop expr value to temp register
        self.vm.pop_that_ptr()  # Pop base+index into 'that' register
        self.vm.push_temp(TEMP_ARRAY)  # Push expr back onto stack
        self.vm.pop_that()  # Pop value into *(base+index)

    def _is_if(self):
        return self._is_keyword(KW_IF)

    # ifStatement: 'if' '(' expression ')' '{' statements '}'
    #              ('else' '{' statements '}')?
    def compile_if(self):
        self._require(T_KEYWORD, KW_IF)
        end_label = self.new_label()
        self._compile_cond_expression_statements(end_label)  # VM code for condition and if statements
        if self._is_keyword(KW_ELSE):
            self._advance()
            self._require(T_SYM, "{")
            self.compile_statements()  # VM code for else statements
            self._require(T_SYM, "}")
        self.vm.write_label(end_label)  # label end_label

    def _is_while(self):
        return self._is_keyword(KW_WHILE)

    # whileStatement: 'while' '(' expression ')' '{' statements '}'
    def compile_while(self):
        self._require(T_KEYWORD, KW_WHILE)
        top_label = self.new_label()
        self.vm.write_label(top_label)  # label top_label
        self._compile_cond_expression_statements(top_label)  # VM code for condition and while statements

    # '(' expression ')' '{' statements '}'
    def _compile_cond_expression_statements(self, label):
        self._require(T_SYM, "(")
        self.compile_expression()
        self._require(T_SYM, ")")
        self.vm.write_vm_cmd("not")  # ~(cond)
        notif_label = self.new_label()
        self.vm.write_if(notif_label)  # if-goto notif_label
        self._require(T_SYM, "{")
        self.compile_statements()  # VM code for if statements
        self._require(T_SYM, "}")
        self.vm.write_goto(label)  # goto label
        self.vm.write_label(notif_label)  # label notif_label

    label_num = 0

    def new_label(self):
        self.label_num += 1
        return "label" + str(self.label_num)

    def _is_do(self):
        return self._is_keyword(KW_DO)

    # do_statement: 'do' subroutineCall ';'
    def compile_do(self):
        self._require(T_KEYWORD, KW_DO)
        name = self._require(T_ID)
        self.compile_subroutine_call(name)  # VM code for subroutine call
        self.vm.pop_temp(TEMP_RETURN)  # Pop return value and discard
        self._require(T_SYM, ";")

    def _is_return(self):
        return self._is_keyword(KW_RETURN)

    # returnStatement: 'return' expression? ';'
    def compile_return(self):
        self._require(T_KEYWORD, KW_RETURN)
        if not self._is_sym(";"):
            self.compile_expression()  # VM code for return expression if any
        else:
            self.vm.push_const(0)  # push 0 if not returning a value
        self._require(T_SYM, ";")
        self.vm.write_return()  # return

    # Expressions
    # expression: term (op term)*
    def compile_expression(self):
        self.compile_term()
        # Doesn't handle normal order of operations - just left to right for now
        while self._is_op():
            op = self._advance()
            self.compile_term()
            self.vm.write_vm_cmd(vm_cmds[op[1]])  # op

    def _is_term(self):
        return self._is_const() or self._is_var_name() or self._is_sym("(") or self._is_unary_op()

    # term: integerConstant | stringConstant | keywordConstant | varName
    #     | varName '[' expression ']' | subroutineCall | '(' expression ')'
    #     | unaryOp term
    def compile_term(self):
        if self._is_const():
            self.compile_const()
        elif self._is_sym("("):
            self._advance()
            self.compile_expression()  # VM code to evaluate expression
            self._require(T_SYM, ")")
        elif self._is_unary_op():
            tok, op = self._advance()
            self.compile_term()
            self.vm.write_vm_cmd(vm_unary_cmds[op])  # op
        elif self._is_var_name():
            tok, name = self._advance()
            if self._is_sym("["):
                self.compile_array_subscript(name)  # VM code for array subscript
            elif self._is_sym("(."):
                self.compile_subroutine_call(name)  # VM code for subroutine call
            else:
                self.vm_push_variable(name)  # push variable on stack

    def _is_const(self):
        return self._is_token(T_NUM) or self._is_token(T_STR) or self._is_keyword_constant()

    def _is_keyword_constant(self):
        return self._is_keyword(KW_TRUE, KW_FALSE, KW_NULL, KW_THIS)

    def _is_op(self):
        return self._is_sym("+-*/&|<>=")

    def _is_unary_op(self):
        return self._is_sym("-~")

    # integerConstant | stringConstant | keywordConstant
    def compile_const(self):
        tok, val = self._advance()
        if tok == T_NUM:
            self.vm.push_const(val)  # push constant val
        elif tok == T_STR:
            self.write_string_const_init(val)  # initialize string & push str addr
        elif tok == T_KEYWORD:
            self.compile_kwd_const(val)  # push TRUE, FALSE, NULL etc.

    def write_string_const_init(self, val):
        self.vm.push_const(len(val))
        self.vm.write_call("String.new", 1)  # String.new(len(str))
        for c in val:
            self.vm.push_const(ord(c))
            self.vm.write_call("String.appendChar", 2)  # String.appendChar(nextchar)

    # keywordConstant: 'true' | 'false' | 'null' | 'this'
    def compile_kwd_const(self, kwd):
        if kwd == KW_THIS:
            self.vm.push_this_ptr()
        elif kwd == KW_TRUE:
            self.vm.push_const(1)
            self.vm.write_vm_cmd("neg")
        else:  # KW_FALSE or KW_NULL
            self.vm.push_const(0)

    # '[' expression ']'
    def compile_array_subscript(self, name):
        self.vm_push_variable(name)  # push array ptr onto stack
        self._require(T_SYM, "[")
        self.compile_expression()  # push index onto stack
        self._require(T_SYM, "]")
        self.vm.write_vm_cmd("add")  # base+index
        self.vm.pop_that_ptr()  # pop into 'that' ptr
        self.vm.push_that()  # push *(base+index) onto stack

    # subroutineCall: subroutineName '(' expressionList ')'
    #               | (className | varName) '.' subroutineName '(' expressionList ')'
    def compile_subroutine_call(self, name):
        (type, kind, index) = self.symbols.lookup(name)
        if self._is_sym("."):
            num_args, name = self.compile_dotted_subroutine_call(name, type)
        else:
            num_args = 1
            self.vm.push_this_ptr()
            name = self._cur_class + "." + name
        self._require(T_SYM, "(")
        num_args += self.compile_expr_list()  # VM code to push arguments
        self._require(T_SYM, ")")
        self.vm.write_call(name, num_args)  # call name num_args

    def compile_dotted_subroutine_call(self, name, type):
        num_args = 0
        obj_name = name
        self._advance()
        name = self.compile_var_name()
        if self._is_builtin_type(type):  # e.g. int.func(123) not allowed
            ParserError('Cannot use "." operator on builtin type')
        elif type == None:  # Calling using class name
            name = obj_name + "." + name
        else:  # Calling using object variable name
            num_args = 1
            self.vm_push_variable(obj_name)  # push object ptr onto stack
            name = self.symbols.type_of(obj_name) + "." + name
        return num_args, name

    def _is_builtin_type(self, type):
        return type in [KW_INT, KW_CHAR, KW_BOOLEAN, KW_VOID]

    # expressionList: (expression (',' expression)*)?
    def compile_expr_list(self):
        num_args = 0
        if self._is_term():
            self.compile_expression()
            num_args = 1
            while self._is_sym(","):
                self._advance()
                self.compile_expression()
                num_args += 1
        return num_args
Example #34
0
class CompilationEngine():

    def __init__(self, jackTokenizer):
        self.jackTokenizer = jackTokenizer
        self.symbolTabel = SymbolTabel()
        self.vmWriter = VMWriter()
        self.result = []
        self.labelCount = 0 #用来解决不同if等等语句中相同label的问题
        self.fieldCount = 0
        self.compileClass()

    def __getFieldNums(self): #获取一个对象中的成员变量的数量, 以便构造函数编译时分配空间, 增量代码在compileClassVarDec中
        return self.fieldCount

    def __getLocalNums(self): #用来解决function name n 的参数问题
        pointer = self.jackTokenizer.pointer+1
        n = 0
        while(self.jackTokenizer.context[pointer]=="var"):
            n += 1
            pointer += 3
            while(self.jackTokenizer.context[pointer]!=";"):
                pointer += 2
                n += 1
            pointer += 1
        return n
            
    def __match(self, label):
        self.jackTokenizer.advance()

    def __getAndAdvanceLabel(self):
        self.labelCount += 1
        return str(self.labelCount)

    def __getToken(self):
        return self.jackTokenizer.getToken()

    def __getTokenType(self):
        return self.jackTokenizer.tokenType()

    def __getFurtureToken(self, n):
        return self.jackTokenizer.context[self.jackTokenizer.pointer+n]

    def __getPastToken(self, n):
        return self.jackTokenizer.context[self.jackTokenizer.pointer-n]

    def compileClass(self):
        self.__match("class")
        self.__match("className")
        self.__match("{")

        while(self.__getToken()=="static" or self.__getToken()=="field"):
            self.compileClassVarDec()

        while(self.__getToken()=="constructor" or self.__getToken()=="function" or self.__getToken()=="method"):
            self.symbolTabel.startSubroutine() #子程序的符号表重启
            self.compileSubroutineDec()

        self.__match("}")

    def compileClassVarDec(self):
        kind = self.__getToken()
        self.__match("static|field")
        
        typE = self.__getToken()
        self.__match("type")

        name = []
        name.append(self.__getToken())
        self.__match("varName")

        while(self.__getToken()!=";"):
            if(self.__getToken()==","):
                self.__match(",")
            else:
                name.append(self.__getToken())
                self.__match("varName")

        self.__match(";")

        if(kind=="field"):
            self.fieldCount += len(name)

        for i in name:
            self.symbolTabel.define(i, typE, kind)

    def compileSubroutineDec(self):

        kind = self.__getToken()
        self.__match("constructor|function|method")

        typE = self.__getToken()
        self.__match("void|type")
        
        functionName = self.__getToken()
        self.__match("subroutineName")

        self.__match("(")
        self.compileParameterList() 
        self.__match(")")

        n = self.__getLocalNums()
        self.vmWriter.writeFunction(self.jackTokenizer.context[1]+"."+functionName, str(n))

        if(kind=="constructor"):
            self.vmWriter.writePush("constant", str(self.__getFieldNums()))
            self.vmWriter.writeCall("Memory.alloc", "1")
            self.vmWriter.writePop("pointer", "0") 

        elif(kind=="method"):
            #将this指向传入的对象
            self.vmWriter.writePush("argument", "0")
            self.vmWriter.writePop("pointer", "0")

        self.compileSubroutineBody() 

    def compileSubroutineBody(self):
        self.__match("{")

        while(self.__getToken()=="var"):
            self.compileVarDec()

        self.compileStatements()

        self.__match("}")

        
    def compileStatements(self):

        tmp = ["let", "if", "while", "do", "return"]

        while(self.__getToken() in tmp):
            if(self.__getToken() == "while"):
                self.compileWhileStatement()

            elif(self.__getToken() == "if"):
                self.compileIfStatement()

            elif(self.__getToken() == "return"):
                self.compileReturnStatement()

            elif(self.__getToken() == "let"):
                self.compileLetStatement()

            else:
                self.compileDoStatement()

    def compileDoStatement(self): #do后面跟的必定是void类型的函数或方法
        self.__match("do")
        name = ""
        n = 0

        if(self.__getFurtureToken(1)=="."):
            prefix = self.__getToken()
            self.__match("className|varName")
            self.__match(".")
            name = self.__getToken()
            self.__match("subroutineName")
            
            if(self.symbolTabel.kindOf(prefix)!="none"): #varName.method
                n += 1

                #调用method, 所以要把对象的指针push进去
                if(self.symbolTabel.kindOf(prefix)=="field"):
                    self.vmWriter.writePush("this", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="var"):
                    self.vmWriter.writePush("local", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="argument"):
                    self.vmWriter.writePush("argument", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="static"):
                    self.vmWriter.writePush("static", self.symbolTabel.indexOf(prefix))

                name = self.symbolTabel.typeOf(prefix)+"."+name
            else: #className.function
                name = prefix+"."+name

            self.__match("(")
            n += self.compileExpressionList()
            self.__match(")")

        else:  #do method()
            name = self.jackTokenizer.context[1]+"."+self.__getToken()
            self.__match("subroutineName")
            self.vmWriter.writePush("pointer", "0")
            self.__match("(")
            n = self.compileExpressionList()
            n += 1 #对象的方法
            self.__match(")")

        self.__match(";")
        self.vmWriter.writeCall(name, str(n))
        self.vmWriter.writePop("temp", "0")

    def compileLetStatement(self):
        isArray = False

        self.__match("let")
        name = self.__getToken()
        self.__match("varName")
        if(self.__getToken()=="["):
            isArray = True
            self.__match("[")
            self.compileExpression()
            self.__match("]")
        
        self.__match("=")
        self.compileExpression()
        self.__match(";")

        #以下为代码生成
        if(isArray==True):
            self.vmWriter.writePop("temp", "0") # "="右边的值
            
            kind = self.symbolTabel.kindOf(name)
            index = self.symbolTabel.indexOf(name)

            if(kind=="field"): #把数组的指针push进去, 现在栈顶是指针和偏移值
                self.vmWriter.writePush("this", str(index))
            elif(kind=="argument"):
                self.vmWriter.writePush("argument", str(index))
            elif(kind=="var"):
                self.vmWriter.writePush("local", str(index))
            elif(kind=="static"):
                self.vmWriter.writePush("static", str(index))

            self.vmWriter.writeArithmetic("add")
            self.vmWriter.writePop("pointer", "1")
            self.vmWriter.writePush("temp", "0")
            self.vmWriter.writePop("that", "0")

        else:
            kind = self.symbolTabel.kindOf(name)
            index = self.symbolTabel.indexOf(name)
            if(kind=="field"):
                self.vmWriter.writePop("this", index)
            elif(kind=="argument"):
                self.vmWriter.writePop("argument", index)
            elif(kind=="var"):
                self.vmWriter.writePop("local", index)
            elif(kind=="static"):
                self.vmWriter.writePop("static", index)

    def compileWhileStatement(self): 
        label = self.__getAndAdvanceLabel()

        self.__match("while")
        self.vmWriter.writeLabel("exp-examination"+label)
        self.__match("(")
        self.compileExpression()
        self.__match(")")
        self.vmWriter.writeIfGoto("loop"+label)

        self.vmWriter.writeGoto("end"+label)

        self.vmWriter.writeLabel("loop"+label)
        self.__match("{")
        self.compileStatements()
        self.__match("}")
        self.vmWriter.writeGoto("exp-examination"+label)
        self.vmWriter.writeLabel("end"+label)


    def compileIfStatement(self): 
        label = self.__getAndAdvanceLabel()
        self.__match("if")
        self.__match("(")
        self.compileExpression()
        self.__match(")")
        
        self.vmWriter.writeIfGoto("true"+label)
        self.vmWriter.writeGoto("false"+label)


        self.vmWriter.writeLabel("true"+label)
        self.__match("{")
        self.compileStatements()
        self.__match("}")
        self.vmWriter.writeGoto("end"+label)

        self.vmWriter.writeLabel("false"+label)

        if(self.__getToken()=="else"):
            self.__match("else")
            self.__match("{")
            self.compileStatements()
            self.__match("}")

        self.vmWriter.writeLabel("end"+label)
        
    def compileReturnStatement(self):
        self.__match("return")
        if(self.__getToken()!=";"):
            self.compileExpression()
        else: #return;
            self.vmWriter.writePush("constant", "0")

        self.vmWriter.writeReturn()
        self.__match(";")

    def compileVarDec(self):
        kind = "var"
        self.__match("var")

        typE = self.__getToken()
        self.__match("type")

        name = []
        name.append(self.__getToken())
        self.__match("name")

        while(self.__getToken()!=";"):
            if(self.__getToken()==","):
                self.__match(",")
            name.append(self.__getToken())
            self.__match("name")

        self.__match(";")

        for i in name:
            self.symbolTabel.define(i, typE, kind)

    def compileParameterList(self): 
        kind = "argument"
        typE = []
        name = []

        if(self.__getPastToken(4)=="method"): #对于方法, 第一个参数是对象的指针
            typE.append(self.jackTokenizer.context[1]) #className
            name.append("this")

        while(self.__getToken()!=")"):
            typE.append(self.__getToken())
            self.__match("type")
            name.append(self.__getToken())
            self.__match("varName")
            if(self.__getToken()==","):
                self.__match(",")

        for i,j in zip(name,typE):
            self.symbolTabel.define(i, j, kind)

        
    def compileExpression(self): #遇到op就放到term后面压栈, term求值之后压栈, expression求值之后压栈
        op = ["+", "-", "*", "/", "&", "|", "<", ">", "="]
        self.compileTerm()
        while(self.__getToken() in op):
            tmp_op = self.__getToken()
            self.__match("op")
            self.compileTerm()

            #压入运算符
            if(tmp_op=="*"):
                self.vmWriter.writeCall("Math.multiply", "2")
            elif(tmp_op=="+"):
                self.vmWriter.writeArithmetic("add") 
            elif(tmp_op=="-"):
                self.vmWriter.writeArithmetic("sub")
            elif(tmp_op=="/"):
                self.vmWriter.writeCall("Math.divide", "2")
            elif(tmp_op=="&"): 
                self.vmWriter.writeArithmetic("and")
            elif(tmp_op=="|"):
                self.vmWriter.writeArithmetic("or")
            elif(tmp_op=="<"):
                self.vmWriter.writeArithmetic("lt")
            elif(tmp_op==">"):
                self.vmWriter.writeArithmetic("gt")
            elif(tmp_op=="="):
                self.vmWriter.writeArithmetic("eq")
                

    def compileTerm(self): 
        keywordConstant = ["true", "false", "null", "this"]
        unaryOp = ["-", "~"]

        if(self.__getTokenType()=="integerConstant"):
            self.vmWriter.writePush("constant", self.__getToken())
            self.__match("integerConstant")

        elif(self.__getTokenType()=="stringConstant"): 
            string = self.__getToken()
            string = string.replace('"', "")
            self.__match("string")

            #申请空间
            self.vmWriter.writePush("constant", str(len(string)))
            self.vmWriter.writeCall("String.new", "1")

            #调用String.appendChar <- method, 接收一个char, 返回一个字符串的地址)
            for i in string:
                self.vmWriter.writePush("constant", str(ord(i)))
                self.vmWriter.writeCall("String.appendChar", "2")

            
        elif(self.__getToken() in keywordConstant):
            tmp = self.__getToken()
            if(tmp=="null"):
                self.vmWriter.writePush("constant", "0")
            elif(tmp=="false"):
                self.vmWriter.writePush("constant", "0")
            elif(tmp=="true"):
                self.vmWriter.writePush("constant", "1")
                self.vmWriter.writeArithmetic("neg")
            elif(tmp=="this"):
                self.vmWriter.writePush("pointer", "0") 

            self.__match("keywordConstant")
            
        elif(self.__getToken()=="("): #(expression)
            self.__match("(")
            self.compileExpression()
            self.__match(")")
            
        elif(self.__getToken() in unaryOp): #unaryOp term
            tmp_uop = self.__getToken()
            self.__match("unaryOp")

            self.compileTerm()
            
            if(tmp_uop=="-"):
                self.vmWriter.writeArithmetic("neg")

            elif(tmp_uop=="~"):
                label = self.__getAndAdvanceLabel()
                self.vmWriter.writeIfGoto("true"+label)
                self.vmWriter.writeGoto("false"+label)

                self.vmWriter.writeLabel("true"+label)
                self.vmWriter.writePush("constant", "0")
                self.vmWriter.writeGoto("end"+label)

                self.vmWriter.writeLabel("false"+label)
                self.vmWriter.writePush("constant", "1")
                self.vmWriter.writeArithmetic("neg")

                self.vmWriter.writeLabel("end"+label)
            
        elif(self.__getFurtureToken(1)=="["): #varName[expression]
            name = self.__getToken()
            typE = self.symbolTabel.typeOf(name)
            kind = self.symbolTabel.kindOf(name)
            index = self.symbolTabel.indexOf(name)
            
            if(kind=="field"):
                self.vmWriter.writePush("this", str(index))
            elif(kind=="var"):
                self.vmWriter.writePush("local", str(index))
            else:
                self.vmWriter.writePush(kind, str(index))

            self.__match("varName")
            self.__match("[")
            self.compileExpression()
            self.__match("]")

            self.vmWriter.writeArithmetic("add")
            self.vmWriter.writePop("pointer", "1")
            self.vmWriter.writePush("that", "0")
            
        elif(self.__getFurtureToken(1)=="("): #subroutineName(expressionList)
            name = self.__getToken()
            name = self.jackTokenizer.context[1]+"."+self.__getToken()
            self.__match("subroutineCall")
            self.__match("(")
            n = self.compileExpressionList()
            n += 1
            self.__match(")")
            self.vmWriter.writePush("pointer", "0")
            self.vmWriter.writeCall(name, str(n))
            
        elif(self.__getFurtureToken(1)=="."): #(className|varName).subroutineName(expressionList)
            prefix = self.__getToken()
            self.__match("className|varName")
            self.__match(".")
            name = self.__getToken()
            self.__match("subroutineName")
            self.__match("(")
            n = self.compileExpressionList()
            self.__match(")")
            
            if(self.symbolTabel.kindOf(prefix)=="none"): #className
                name = prefix+"."+name
                self.vmWriter.writeCall(name, str(n))
            else: #varName
                name = self.symbolTabel.typeOf(prefix)+"."+name
                n += 1

                #调用method, 所以要把对象的指针push进去
                if(self.symbolTabel.kindOf(prefix)=="field"):
                    self.vmWriter.writePush("this", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="var"):
                    self.vmWriter.writePush("local", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="argument"):
                    self.vmWriter.writePush("argument", self.symbolTabel.indexOf(prefix))
                elif(self.symbolTabel.kindOf(prefix)=="static"):
                    self.vmWriter.writePush("static", self.symbolTabel.indexOf(prefix))

                self.vmWriter.writeCall(name, str(n))
                
        else:   #varName
            name = self.__getToken()
            kind = self.symbolTabel.kindOf(name)
            index = self.symbolTabel.indexOf(name)

            if(kind=="field"):
                self.vmWriter.writePush("this", index)
            elif(kind=="var"):
                self.vmWriter.writePush("local", index)
            else:
                self.vmWriter.writePush(kind, index)

            self.__match("varName")

    def compileExpressionList(self): #返回expression的数量
        n = 0
        if(self.__getToken()!=")"):
            self.compileExpression()
            n += 1
            while(self.__getToken()==","):
                self.__match(",")
                self.compileExpression()
                n += 1
        return n

    def write(self, path):
        for i in range(len(self.result)):
            self.result[i] += "\n"

        with open(path, "w") as f:
            f.writelines(self.result)