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---")
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()
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()
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')
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() # ;
def compile_doStatement(): # do subroutineCall ; print("---COMPILING DO STATEMENT---") compile_subroutineCall() # subroutineCall VMWriter.writePop("temp", 0) advance() print("---DONE COMPILING DO STATEMENT---")
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
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
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 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)
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()
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
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()
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
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---")
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()
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() # ]
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)
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()
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
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
def parseOneFile(fileName): listOfTokens = PassingTokenArray(fileName) outFile = fileName[:-5] + ".vm" writerObj = VMWriter.Translator(outFile) classRoot = clssNode() parser = JackParser(listOfTokens, writerObj, classRoot) parser.initProcess()
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()
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
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()
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()
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
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)