class CompilationEngine: def __init__(self, input_file, output_file): self.jack_tokenizer = JackTokenizer(input_file) self.symbol_table = SymbolTable() self.writer = VMWriter(output_file) self.class_name = "" self.subroutine_name = "" self.return_type = "" self.label_counter_if = 0 self.label_counter_while = 0 self.num_args_called_function = 0 self.is_unary = False self.dic_arithmetic = {"+" : "add" , "-" : "sub", "*" : "call Math.multiply 2", "/" : "call Math.divide 2", "&" : "and", "|" : "or", "<" : "lt", ">" : "gt", "=" : "eq"} def compile_class(self): # "class className { for i in range(NUM_TOKENS_CLASS_DEC): self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # saves the className if self.jack_tokenizer.token_type() == IDENTIFIER: self.class_name = self.jack_tokenizer.identifier() # classVarDec* or SubroutineDec* while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == KEYWORD and (self.jack_tokenizer.key_word() == "static" or self.jack_tokenizer.key_word() == "field"): self.compile_class_var_dec() if token_type == KEYWORD and (self.jack_tokenizer.key_word() == "function" or self.jack_tokenizer.key_word() == "method" or self.jack_tokenizer.key_word() == "constructor"): self.compile_subroutine() if token_type == SYMBOL and self.jack_tokenizer.symbol() == "}": break def compile_class_var_dec(self): # "static" of "field" kind = self.jack_tokenizer.key_word() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # type if self.jack_tokenizer.token_type() == KEYWORD: type = self.jack_tokenizer.key_word() else: type = self.jack_tokenizer.identifier() while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == IDENTIFIER: name = self.jack_tokenizer.identifier() self.symbol_table.define(name,type,kind) elif token_type == SYMBOL: if self.jack_tokenizer.symbol() == ";": break def compile_subroutine(self): self.symbol_table.start_subroutine() self.subroutine_name = "" self.return_type = "" self.label_counter_if = 0 self.label_counter_while = 0 # the curr token : "constructor" or "function" or "method type_of_subroutine = self.jack_tokenizer.key_word() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # the curr token : return type of the subroutine if self.jack_tokenizer.token_type() == KEYWORD: self.return_type = self.jack_tokenizer.key_word() else: self.return_type = self.jack_tokenizer.identifier() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.subroutine_name = self.jack_tokenizer.identifier() while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() if self.jack_tokenizer.symbol() == "(": if type_of_subroutine == "method": self.symbol_table.define(THIS, self.class_name, ARG) self.compile_parameter_list() # the curr token should be - ")" if self.jack_tokenizer.symbol() == '{': while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == KEYWORD: if self.jack_tokenizer.key_word() == "var": self.compile_var_dec() continue else: self.writer.write_function(self.class_name + "." + self.subroutine_name, self.symbol_table.var_count(VAR)) if type_of_subroutine == "constructor": self.writer.write_push(CONST, self.symbol_table.var_count(FIELD)) self.writer.write_call("Memory.alloc", 1) self.writer.write_pop("pointer", 0) elif type_of_subroutine == "method": self.writer.write_push(ARGUMENT, 0) self.writer.write_pop("pointer", 0) self.compile_statements() # the curr token should be - "}" break break def compile_parameter_list(self): kind = ARG while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() # int, bool.... if token_type == KEYWORD: type = self.jack_tokenizer.key_word() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() name = self.jack_tokenizer.identifier() self.symbol_table.define(name, type, kind) # className elif token_type == IDENTIFIER: type = self.jack_tokenizer.identifier() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() name = self.jack_tokenizer.identifier() self.symbol_table.define(name, type, kind) # end of parameter list if token_type == SYMBOL and self.jack_tokenizer.symbol() == ")": break def compile_var_dec(self): # should be "var" kind = self.jack_tokenizer.key_word() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # type if self.jack_tokenizer.token_type() == KEYWORD: type = self.jack_tokenizer.key_word() else: type = self.jack_tokenizer.identifier() while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == IDENTIFIER: name = self.jack_tokenizer.identifier() self.symbol_table.define(name, type, kind) if token_type == SYMBOL: if self.jack_tokenizer.symbol() == ";": break def compile_statements(self): while True: if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "do": self.compile_do() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "let": self.compile_let() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "while": self.compile_while() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "return": self.compile_return() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # compile_if returns advanced if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "if": self.compile_if() if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "}": break def compile_do(self): self.num_args_called_function = 0 self.compile_subroutine_call() self.writer.write_pop(TEMP , 0) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # return from compile_subroutine_call with ";" def compile_let(self): init = True # the curr token - "let" while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == IDENTIFIER: name = self.jack_tokenizer.identifier() type = self.symbol_table.type_of(name) kind = self.symbol_table.kind_of(name) index = self.symbol_table.index_of(name) if token_type == SYMBOL: # there is an assignment to an array if self.jack_tokenizer.symbol() == "[": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # handle - [expression] self.compile_expression() # the curr token - "]" self.writer.write_push(self.find_segment(kind), index) self.writer.write_arithmetic("add") self.writer.write_pop("pointer", 1) init = False # should return from the compile_expression only with ";" or "]" if self.jack_tokenizer.symbol() == "=": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # handle the = expression self.compile_expression() # that is only for array if init == False: # was also if type == "Array" self.writer.write_pop(THAT, 0) else: self.writer.write_pop(self.find_segment(kind), index) # end of let statement if self.jack_tokenizer.symbol() == ";": break def compile_while(self): while_counter = self.label_counter_while self.label_counter_while += 1 # the curr token - "while" self.writer.write_label("WHILE_EXP" + str(while_counter)) while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == SYMBOL: if self.jack_tokenizer.symbol() == "(": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_expression() # the curr token - ")" self.writer.write_arithmetic("not") self.writer.write_if("WHILE_END" + str(while_counter)) if self.jack_tokenizer.symbol() == "{": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_statements() # the curr token - "}" self.writer.write_go_to("WHILE_EXP" + str(while_counter)) self.writer.write_label("WHILE_END" + str(while_counter)) if token_type == SYMBOL and self.jack_tokenizer.symbol() == "}": break def compile_return(self): # the curr token - "return" self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == ";": self.writer.write_push(CONST, "0") else: self.compile_expression() # should return from "compile_expression" only with ";" self.writer.write_return() def compile_if(self): if_counter = self.label_counter_if self.label_counter_if += 1 # the curr token - "if" while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() token_type = self.jack_tokenizer.token_type() if token_type == SYMBOL: if self.jack_tokenizer.symbol() == "(": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_expression() # the curr token - ")" self.writer.write_if("IF_TRUE" + str(if_counter)) self.writer.write_go_to("IF_FALSE" + str(if_counter)) if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "{": self.writer.write_label("IF_TRUE" + str(if_counter)) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_statements() # ~~~~~~~~~~ change : was token_type ~~~~~~~~~~~~~~ if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "}": break self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == KEYWORD and self.jack_tokenizer.key_word() == "else": # print "else" self.writer.write_go_to("IF_END" + str(if_counter)) self.writer.write_label("IF_FALSE" + str(if_counter)) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # print "{" self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_statements() # print "}" self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.writer.write_label("IF_END" + str(if_counter)) else: self.writer.write_label("IF_FALSE" + str(if_counter)) def compile_subroutine_call(self): to_add = False self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # "subRoutineName" or ("className" | "varName", as part of className.subRoutineName) called_statement = self.jack_tokenizer.identifier() type = self.symbol_table.type_of(called_statement) kind = self.symbol_table.kind_of(called_statement) index = self.symbol_table.index_of(called_statement) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # case of "subRoutineCall(expressionList) if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "(": to_add = True called_statement = self.class_name + "." + called_statement self.writer.write_push(POINTER, 0) self.compile_expression_list() # the curr token - ")" # (className | varName).subroutineName(expressionList) elif self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == ".": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # subroutineName if kind <> NONE: to_add = True self.writer.write_push(self.find_segment(kind), index) called_statement = type + "." + self.jack_tokenizer.identifier() else: called_statement = called_statement + "." + self.jack_tokenizer.identifier() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # "(" # expressionList self.compile_expression_list() # ")" if to_add: self.writer.write_call(called_statement, self.num_args_called_function + 1) else: self.writer.write_call(called_statement, self.num_args_called_function) def compile_expression(self): is_print_unary = False if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "-": self.is_unary = True self.compile_term() while self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() in\ ["+", "-", "*", "/", "&", "|", "<", ">", "="]: arit_symbol = self.jack_tokenizer.symbol() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "-": self.is_unary = True is_print_unary = True self.compile_term() # if not is_print_unary and self.writer.write_arithmetic(self.dic_arithmetic[arit_symbol]) def compile_term(self): while True: token_type = self.jack_tokenizer.token_type() if token_type == SYMBOL and not self.is_unary and self.jack_tokenizer.symbol() in\ [",", ";", ")", "}","]", "+", "-", "*", "/", "&", "|", "<", ">", "="]: break if token_type == INT_CONST: self.writer.write_push(CONST, self.jack_tokenizer.int_val()) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break if token_type == STRING_CONST: self.compile_string() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break if token_type == KEYWORD and self.jack_tokenizer.key_word() in ["true", "false", "null"]: self.writer.write_push(CONST, 0) if self.jack_tokenizer.key_word() == "true": self.writer.write_arithmetic("not") self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break # like in return this if token_type == KEYWORD and self.jack_tokenizer.key_word() == "this": self.writer.write_push(POINTER, 0) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break if token_type == SYMBOL and self.jack_tokenizer.symbol() in ["~", "-"]: symbol = self.jack_tokenizer.symbol() self.is_unary = False self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_term() if symbol == "~": self.writer.write_arithmetic("not") else: self.writer.write_arithmetic("neg") break if token_type == SYMBOL and self.jack_tokenizer.symbol() == "(": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_expression() # should return from compile_expression only with ")" self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break if token_type == IDENTIFIER: is_add = True name = self.jack_tokenizer.identifier() kind = self.symbol_table.kind_of(name) index = self.symbol_table.index_of(name) if name[0].isupper(): is_add = False self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() in\ [",", ";", ")", "}","]", "+", "-", "*", "/", "&", "|", "<", ">", "=", "&", "<",">"]: # in case of a > ...or b; self.writer.write_push(self.find_segment(kind), self.symbol_table.index_of(name)) break if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "[": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() self.compile_expression() # should return only "]" self.writer.write_push(self.find_segment(kind), self.symbol_table.index_of(name)) self.writer.write_arithmetic("add") self.writer.write_pop(POINTER, 1) self.writer.write_push(THAT, 0) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() break if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == "(": self.writer.write_push(POINTER, 0) self.compile_expression_list() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # case of a = ... bar() self.writer.write_call(self.class_name + "." + name,self.num_args_called_function + 1) break # (className | varName).subroutineName(expressionList) if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == ".": self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # subroutineName if is_add: type = self.symbol_table.type_of(name) name = type + "." + self.jack_tokenizer.identifier() else: name = name + "." + self.jack_tokenizer.identifier() self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() # "(" # expressionList if is_add: self.writer.write_push(self.find_segment(kind), index) self.compile_expression_list() # ")" if is_add: self.writer.write_call(name, self.num_args_called_function + 1) else: self.writer.write_call(name, self.num_args_called_function) self.jack_tokenizer.has_more_tokens() self.jack_tokenizer.advance() def compile_expression_list(self): num_args = 0 while self.jack_tokenizer.has_more_tokens(): self.jack_tokenizer.advance() if self.jack_tokenizer.token_type() == SYMBOL and self.jack_tokenizer.symbol() == ")": break else: num_args += 1 self.compile_expression() if self.jack_tokenizer.symbol() == ")": break # print "," self.num_args_called_function = num_args def find_segment(self, kind): if kind == ARG: return ARGUMENT if kind == VAR: return LCL if kind == FIELD: return THIS if kind == STATIC: return STATIC def compile_string(self): length = len(self.jack_tokenizer.string_val()) self.writer.write_push(CONST, length) self.writer.write_call("String.new", 1) for i in range(len(self.jack_tokenizer.string_val())): uni = ord(self.jack_tokenizer.string_val()[i]) self.writer.write_push(CONST, uni) self.writer.write_call("String.appendChar", 2)
def compileIf(self): self.open_tag('ifStatement') if self.words_exist(['if', 'keyword']): self.format_and_write_line() self.advance() else: raise if self.words_exist(['symbol', '(']): self.format_and_write_line() self.advance() else: raise self.compileExpression() if self.words_exist(['symbol', ')']): self.format_and_write_line() self.advance() else: raise # Now the condition result is on the stack # we need to negate it to use it with if-goto else else_block = str(randint(500, 700)) exit_address = str(randint(500, 700)) self.compiled.write( VMWriter.write_arithmetic('~') ) self.compiled.write( VMWriter.write_if(else_block) ) if self.words_exist(['symbol', '{']): self.format_and_write_line() self.advance() else: raise self.compileStatements() if self.words_exist(['symbol', '}']): self.format_and_write_line() self.advance() else: raise self.compiled.write( VMWriter.write_go_to(exit_address) ) if self.words_exist(['else', 'keyword']): self.here = True # omg what is this hack? i have no recollection self.format_and_write_line() self.advance() self.compiled.write( VMWriter.write_label(else_block) ) if self.words_exist(['symbol', '{']): self.format_and_write_line() self.advance() else: raise self.compileStatements() if self.words_exist(['symbol', '}']): self.format_and_write_line() self.advance() else: raise self.compiled.write( VMWriter.write_label(exit_address) ) self.close_tag('ifStatement')
class CompilationEngine: DEBUG = False translate_dict = { '+': 'add', '-': 'sub', '=': 'eq', '>': 'gt', '<': 'lt', '&': 'and', '|': 'or', 'unary-': 'neg', 'unary~': 'not', 'argument': 'argument', 'static': 'static', 'var': 'local', 'field': 'this', '*': 'Math.multiply', '/': 'Math.divide' } def __init__(self, input: JackTokenizer, output_file_path): self.tokenizer = input self.vmwriter = VMWriter(output_file_path) self.symbol_table = SymbolTable() self.label_index = 0 self.curr_token = '' self.curr_token_type = '' self.depth = 0 def compile_class(self): self.print_open('compile_class') self.__next_token() # class self.__next_token() # className self.class_name = self.curr_token self.__next_token() # { self.__next_token() while self.curr_token == 'static' or self.curr_token == 'field': self.compile_class_var_dec() while self.curr_token == 'constructor' or self.curr_token == 'function' or self.curr_token == 'method': self.compile_subroutine_dec() self.__next_token() # after } self.vmwriter.close() self.print_close('compile_class_end') def compile_class_var_dec(self): self.print_open('compile_class_var_dec') kind = self.curr_token # (static|field) self.__next_token() var_type = self.curr_token # type self.__next_token() var_name = self.curr_token # varName self.symbol_table.define(var_name, var_type, self.translate_dict[kind]) self.__next_token() # , or ; while (self.curr_token != ';'): self.__next_token() var_name = self.curr_token # varName self.symbol_table.define(var_name, var_type, self.translate_dict[kind]) self.__next_token() # , or ; self.__next_token() # after ; self.print_close('compile_class_var_dec_end') def compile_subroutine_dec(self): self.print_open('compile_subroutine_dec') self.symbol_table.start_subroutine() kind = self.curr_token # (constructor|function|method) self.__next_token() var_type = self.curr_token # (void|type) self.__next_token() subroutine_name = self.curr_token # subroutineName self.__next_token() # '(' if kind == 'method': self.symbol_table.define('this', self.class_name, 'argument') self.__next_token() self.compile_parameter_list() self.__next_token() # after ')' self.compile_subroutine_body(kind, var_type, subroutine_name) self.print_close('compile_subroutine_dec_end') def compile_parameter_list(self): self.print_open('compile_parameter_list') while self.curr_token != ')': if self.curr_token == ',': self.__next_token() var_type = self.curr_token # type self.__next_token() var_name = self.curr_token # varName self.symbol_table.define(var_name, var_type, 'argument') self.__next_token() self.print_close('compile_parameter_list_end') def compile_subroutine_body(self, kind, var_type, subroutine_name): self.print_open('compile_subroutine_body') self.__next_token() # after '{' while self.curr_token == 'var': self.compile_var_dec() self.vmwriter.write_function(self.class_name + '.' + subroutine_name, self.symbol_table.var_count('local')) if kind == 'method': self.vmwriter.write_push('argument', 0) self.vmwriter.write_pop('pointer', 0) elif kind == 'constructor': self.vmwriter.write_push('constant', self.symbol_table.var_count('this')) self.vmwriter.write_call('Memory.alloc', 1) self.vmwriter.write_pop('pointer', 0) self.compile_statements() self.__next_token() # after '}' self.print_close('compile_subroutine_body_end') def compile_var_dec(self): self.print_open('compile_var_dec') # curr token is var self.__next_token() var_type = self.curr_token # type self.__next_token() var_name = self.curr_token # varName self.symbol_table.define(var_name, var_type, 'local') self.__next_token() # , or ; while self.curr_token != ';': self.__next_token() self.symbol_table.define(self.curr_token, type, 'local') self.__next_token() self.__next_token() # after ; self.print_close('compile_var_dec_end') def compile_statements(self): self.print_open('compile_statements') while True: if self.curr_token == 'let': self.compile_let() elif self.curr_token == 'if': self.compile_if() elif self.curr_token == 'while': self.compile_while() elif self.curr_token == 'do ': self.compile_do() elif self.curr_token == 'return': self.compile_return() else: break self.print_close('compile_statements_end') def compile_let(self): self.print_open('compile_let') # curr_token is let self.__next_token() var_name = self.curr_token # varName kind = self.symbol_table.kind_of(var_name) index = self.symbol_table.index_of(var_name) self.__next_token() if self.curr_token == '[': # push arr self.vmwriter.write_push(kind, index) # VM code for computing and pushing the value of expression1 self.__next_token() self.compile_expression() self.__next_token() # add self.vmwriter.write_arithmetic('add') # VM code for computing and pushing the value of expression2 self.__next_token() # after = self.compile_expression() self.__next_token() # after ; # pop temp 0 self.vmwriter.write_pop('temp', 0) # pop pointer 1 self.vmwriter.write_pop('pointer', 1) # push temp 0 self.vmwriter.write_push('temp', 0) # pop that 0 self.vmwriter.write_pop('that', 0) else: self.__next_token() # after = self.compile_expression() self.__next_token() # after ; self.vmwriter.write_pop(kind, index) self.print_close('compile_let_end') def compile_if(self): self.print_open('compile_if') # curr_token is if index_l = self.__next_label_index() self.__next_token() # ( self.__next_token() # after ( self.compile_expression() self.vmwriter.write_arithmetic('not') self.__next_token() # ) --> { self.__next_token() # { --> ? self.vmwriter.write_if('L1' + str(index_l)) self.compile_statements() self.vmwriter.write_go_to('L2' + str(index_l)) self.__next_token() # } --> ? self.vmwriter.write_label('L1' + str(index_l)) if self.curr_token == 'else': self.__next_token() # else --> { self.__next_token() # { --> ? self.compile_statements() self.__next_token() # } --> ? self.vmwriter.write_label('L2' + str(index_l)) self.print_close('compile_if_end') def compile_while(self): self.print_open('compile_while') # curr_token is while index = self.__next_label_index() self.vmwriter.write_label('L1' + str(index)) self.__next_token() # while --> ( self.__next_token() # ( --> ? self.compile_expression() self.__next_token() # ) --> { self.vmwriter.write_arithmetic('not') self.vmwriter.write_if('L2' + str(index)) self.__next_token() # { --> ? self.compile_statements() self.__next_token() # } --> ? self.vmwriter.write_go_to('L1' + str(index)) self.vmwriter.write_label('L2' + str(index)) self.print_close('compile_while_end') def compile_do(self): self.print_open('compile do') # curr_token is do self.__next_token() # do --> (subroutineName | className | varName) self.subroutine_call() self.vmwriter.write_pop('temp', 0) # because of void call self.__next_token() # ; --> ? self.print_close('compile do_end') def subroutine_call(self, skipped=False, arg_name=''): self.print_open('subroutine_call') name = '' if skipped: name = arg_name else: name = self.curr_token # (subroutineName | className | varName) self.__next_token() function = name args = 0 if self.curr_token == '(': function = self.class_name + '.' + name self.vmwriter.write_push('pointer', 0) args = 1 elif self.curr_token == '.': self.__next_token() # . --> subroutine_name subroutine_name = self.curr_token kind = self.symbol_table.kind_of(name) if kind == None: function = name + '.' + subroutine_name else: var_type = self.symbol_table.type_of(name) function = var_type + '.' + subroutine_name self.vmwriter.write_push(kind, self.symbol_table.index_of(name)) args = 1 self.__next_token() # subroutine_name --> ( self.__next_token() # ( --> ? expression_list_len = self.compile_expression_list() self.__next_token() # ) --> ; self.vmwriter.write_call(function, args + expression_list_len) # self.__next_token() # ; --> ? self.print_close('subroutine_call_end') def compile_return(self): self.print_open('compile_return') # curr_token is return self.__next_token() # return --> ? if self.curr_token != ';': self.compile_expression() else: self.vmwriter.write_push('constant', 0) self.__next_token() # ; --> ? self.vmwriter.write_return() self.print_close('compile_return_end') def compile_expression(self): self.print_open('compile_expression') self.compile_term() while self.curr_token in {'+', '-', '*', '/', '&', '|', '<', '>', '='}: op = self.curr_token self.__next_token() self.compile_term() if op in ['*', '/']: self.vmwriter.write_call(self.translate_dict[op], 2) else: if op in self.translate_dict: self.vmwriter.write_arithmetic(self.translate_dict[op]) self.print_close('compile_expression_end') def compile_term(self): self.print_open('compile_term') if self.curr_token == '(': self.__next_token() # ( --> ? self.compile_expression() self.__next_token() # ) --> ? elif self.curr_token in {'-', '~'}: op = self.curr_token # (-|~) self.__next_token() # (-|~) --> ? self.compile_term() self.vmwriter.write_arithmetic(self.translate_dict['unary' + op]) else: if self.curr_token_type == 'stringConstant': self.vmwriter.write_push('constant', len(self.curr_token)) self.vmwriter.write_call('String.new', 1) for ch in self.curr_token: self.vmwriter.write_push('constant', ord(ch)) self.vmwriter.write_call('String.appendChar', 2) self.__next_token() elif self.curr_token_type == 'integerConstant': self.vmwriter.write_push('constant', self.curr_token) self.__next_token() elif self.curr_token_type == 'keyword': if self.curr_token == 'this': self.vmwriter.write_push('pointer', 0) else: self.vmwriter.write_push('constant', 0) if self.curr_token == 'true': self.vmwriter.write_arithmetic('not') self.__next_token() else: temp = self.curr_token self.__next_token() if self.curr_token == '[': self.vmwriter.write_push(self.symbol_table.kind_of(temp), self.symbol_table.index_of(temp)) self.__next_token() # [ --> ? self.compile_expression() self.__next_token() # ] --> ? # add self.vmwriter.write_arithmetic('add') # pop pointer 1 self.vmwriter.write_pop('pointer', 1) # push that 0 self.vmwriter.write_push('that', 0) elif self.curr_token in ['(', '.']: self.subroutine_call(True, temp) else: # var_name self.vmwriter.write_push(self.symbol_table.kind_of(temp), self.symbol_table.index_of(temp)) # self.__next_token() self.print_close('compile_term_end') def compile_expression_list(self): self.print_open('compile_expression_list') count = 0 while self.curr_token != ')': if self.curr_token == ',': self.__next_token() self.compile_expression() count += 1 self.print_close('compile_expression_list_end') return count #-----------private methods---------------- def __next_token(self): if self.DEBUG: print(' ' * self.depth + 'curr_token: ' + self.curr_token) if self.tokenizer.has_more_tokens(): self.tokenizer.advance() self.curr_token_type = self.tokenizer.token_type() self.curr_token = self.tokenizer.keyword() def __next_label_index(self): index = self.label_index self.label_index += 1 return index def print_open(self, string): if self.DEBUG: print(' ' * self.depth + string) self.depth += 1 def print_close(self, string): if self.DEBUG: self.depth -= 1 print(' ' * self.depth + string)
def compileWhile(self): self.open_tag('whileStatement') while_condition_address = str(randint(200, 500)) while_start_address = str(randint(200, 500)) while_end_address = str(randint(200, 500)) # this is the start address self.compiled.write( VMWriter.write_label(while_condition_address) ) if self.words_exist(['while', 'keyword']): self.format_and_write_line() self.advance() else: raise if self.words_exist(['symbol', '(']): self.format_and_write_line() self.advance() else: raise self.compileExpression() if self.words_exist(['symbol', ')']): self.format_and_write_line() self.advance() else: raise # Stack: true or false # if true go to start self.compiled.write( VMWriter.write_if(while_start_address) ) # if not true then do this one, go to the end self.compiled.write( VMWriter.write_go_to(while_end_address) ) # this is the start address of the while block self.compiled.write( VMWriter.write_label(while_start_address) ) if self.words_exist(['symbol', '{']): self.format_and_write_line() self.advance() else: raise self.compileStatements() if self.words_exist(['symbol', '}']): self.format_and_write_line() self.advance() else: raise # return to beginning self.compiled.write( VMWriter.write_go_to(while_condition_address) ) # this is the end address self.compiled.write( VMWriter.write_label(while_end_address) ) self.close_tag('whileStatement')
class CompilationEngine: all_operators = { "+": "add", "-": "sub", "/": "div", "*": "mul", "&": "and", "|": "or", ">": "gt", "<": "lt", "=": "eq" } def __init__(self, tokens, out_file): """ initializing a new compile engine object :param tokens: the list of tokens created by the tokenizer :param out_file: the output file. """ self.__tokens = tokens self.__file = out_file self.__i = 0 self.__class_symbol = SymbolTable() self.__subroutine_symbol = SymbolTable() self.__cur_token = () self.__class_name = "" self.__writer = VMWriter(out_file) self.__label_count = 0 self.compile_class() self.__writer.close() def eat(self): """ compiling a single token and move to the next one """ self.__cur_token = self.__tokens[self.__i] self.__i += 1 def get_token(self): return self.__cur_token[1] def peek(self): """ checking the current token without compiling :return: the token """ ret_val = self.__tokens[self.__i] return ret_val[1] def peek_type(self): """ checking the current token type without compiling :return: the token type """ ret_val = self.__tokens[self.__i] return ret_val[0] def peek_ll2(self): """ checking two tokens ahead without compiling :return: the token """ ret_val = self.__tokens[self.__i + 1] return ret_val[1] def compile_while_stat(self): # i points to while """ compiling while statement """ self.eat() self.eat() label_true = "L%s" % self.__label_count self.__label_count += 1 label_continue = "L%s" % self.__label_count self.__label_count += 1 self.__writer.write_label(label_true) self.compile_expression() self.__writer.write_arithmetic("not") self.__writer.write_if(label_continue) self.eat() self.eat() self.compile_statements() self.__writer.write_go_to(label_true) self.eat() self.__writer.write_label(label_continue) def compile_return_stat(self): # i points to return """ compiling return statement """ self.eat() if not self.peek() == ";": self.compile_expression() else: self.__writer.write_push("constant", 0) self.__writer.write_return() self.eat() def compile_do_stat(self): """ compiling do statement """ self.eat() self.compile_subroutine_call() self.__writer.write_pop("temp", 0) self.eat() def compile_if_stat(self): """ compiling if statement """ self.eat() self.eat() self.compile_expression() self.__writer.write_arithmetic("not") label_false = "L%s" % self.__label_count self.__label_count += 1 label_continue = "L%s" % self.__label_count self.__label_count += 1 self.__writer.write_if(label_false) self.eat() self.eat() self.compile_statements() self.__writer.write_go_to(label_continue) self.eat() self.__writer.write_label(label_false) if self.peek() == "else": self.eat() self.eat() self.compile_statements() self.eat() self.__writer.write_label(label_continue) def compile_class_var_dec(self): """ compiling class variable declaration """ self.eat() kind = self.get_token() if kind == "var": kind = SymbolTable.VAR self.var_dec_helper(kind, self.__class_symbol) def compile_var_dec(self): """ compiling variable declaration """ self.eat() self.var_dec_helper(SymbolTable.VAR, self.__subroutine_symbol) def var_dec_helper(self, kind, symbol_table): self.eat() type = self.get_token() self.eat() name = self.get_token() symbol_table.add(name, type, kind) cur_stat = self.peek() while cur_stat != ";": self.eat() self.eat() name = self.get_token() symbol_table.add(name, type, kind) cur_stat = self.peek() self.eat() def compile_subroutine_body(self, func_name, func_type): """ compiling subroutine body """ self.eat() cur_stat = self.peek() while cur_stat == "var": self.compile_var_dec() cur_stat = self.peek() self.__writer.write_function( func_name, self.__subroutine_symbol.var_count(SymbolTable.VAR)) self.__subroutine_symbol.add("this", self.__class_name, "pointer") if func_type == "method": self.__writer.write_push(SymbolTable.ARG, 0) self.__writer.write_pop("pointer", 0) elif func_type == "constructor": self.__writer.write_push( "constant", self.__class_symbol.var_count(SymbolTable.FIELD)) self.__writer.write_call("Memory.alloc", 1) self.__writer.write_pop("pointer", 0) self.compile_statements() self.eat() def compile_parameter_list(self): """ compiling parameters list """ cur_stat = self.peek() if cur_stat != ")": self.eat() type = self.get_token() self.eat() name = self.get_token() self.__subroutine_symbol.add(name, type, SymbolTable.ARG) cur_stat = self.peek() while cur_stat == ",": self.eat() self.eat() type = self.get_token() self.eat() name = self.get_token() self.__subroutine_symbol.add(name, type, SymbolTable.ARG) cur_stat = self.peek() def compile_class(self): """ compiling class """ self.eat() self.eat() self.__class_name = self.get_token() self.eat() cur_stat = self.peek() while cur_stat == "static" or cur_stat == "field": self.compile_class_var_dec() cur_stat = self.peek() while cur_stat != "}": self.compile_subroutine_dec() cur_stat = self.peek() self.eat() def compile_expression(self): """ compiling expression """ self.compile_term() cur_stat = self.peek() while cur_stat in CompilationEngine.all_operators.keys(): self.eat() self.compile_term() self.compile_operation(cur_stat) cur_stat = self.peek() def compile_operation(self, op): """ compiling operation :param op: current op """ if op == "*": self.__writer.write_call("Math.multiply", 2) elif op == "/": self.__writer.write_call("Math.divide", 2) else: self.__writer.write_arithmetic(CompilationEngine.all_operators[op]) def compile_statements(self): """ compiling statements """ while self.compile_statement(): continue def compile_subroutine_call(self): """ compiling subroutine call """ self.eat() name = self.get_token() cur_stat = self.peek() if cur_stat == "(": self.eat() self.__writer.write_push("pointer", 0) args = self.compile_expression_list() self.eat() self.__writer.write_call(self.__class_name + "." + name, args + 1) else: self.eat() val = self.find(name) self.eat() var_name = self.get_token() self.eat() if not val: args = 0 else: self.__writer.push_val(val) name = val[0] args = 1 args += self.compile_expression_list() self.__writer.write_call(name + "." + var_name, args) self.eat() def compile_expression_list(self): """ compiling expression list """ args = 0 cur_stat = self.peek() if cur_stat != ")": self.compile_expression() args += 1 cur_stat = self.peek() while cur_stat == ",": self.eat() args += 1 self.compile_expression() cur_stat = self.peek() return args def compile_statement(self): """ compiling statement """ cur_stat = self.peek() if cur_stat == "if": self.compile_if_stat() elif cur_stat == "while": self.compile_while_stat() elif cur_stat == "do": self.compile_do_stat() elif cur_stat == "return": self.compile_return_stat() elif cur_stat == "let": self.compile_let_stat() else: return 0 # when there is no more statements to compile return 1 def compile_let_stat(self): """ compiling let statement """ self.eat() self.eat() name = self.get_token() data = self.find(name) kind = data[1] ind = data[2] if kind == "field": kind = "this" cur_stat = self.peek() if cur_stat == "[": self.compile_array(kind, ind) else: self.eat() self.compile_expression() self.__writer.write_pop(kind, ind) self.eat() # eat ; def compile_subroutine_dec(self): """ compiling subroutine declaration """ self.eat() func_type = self.get_token() self.eat() self.eat() func_name = self.__class_name + "." + self.get_token() self.eat() if func_type == "method": self.__subroutine_symbol.add("this", self.__class_name, SymbolTable.ARG) self.compile_parameter_list() self.eat() self.compile_subroutine_body(func_name, func_type) self.__subroutine_symbol = SymbolTable() def compile_term(self): """ compiling term """ cur_stat = self.peek_type() if cur_stat == JackTokenizer.INT_CONST: self.__writer.write_push("constant", self.peek()) self.eat() return if cur_stat == JackTokenizer.KEYWORD: if self.peek() == "null" or self.peek() == "false": self.__writer.write_push("constant", 0) elif self.peek() == "true": self.__writer.write_push("constant", 0) self.__writer.write_arithmetic("not") elif self.peek() == "this": self.__writer.write_push("pointer", 0) self.eat() return if cur_stat == JackTokenizer.STR_CONST: string1 = self.peek().replace('\t', "\\t") string2 = string1.replace('\n', "\\n") string3 = string2.replace('\r', "\\r") string = string3.replace('\b', "\\b") self.__writer.write_push("constant", len(string)) self.__writer.write_call("String.new", 1) for ch in string: self.__writer.write_push("constant", ord(ch)) self.__writer.write_call("String.appendChar", 2) self.eat() return cur_stat = self.peek() if cur_stat == "(": self.eat() self.compile_expression() self.eat() return if cur_stat == "-": self.eat() self.compile_term() self.__writer.write_arithmetic("neg") return if cur_stat == "~": self.eat() self.compile_term() self.__writer.write_arithmetic("not") return cur_stat = self.peek_ll2() if cur_stat == "[": self.eat() name = self.get_token() self.__writer.push_val(self.find(name)) self.eat() self.compile_expression() self.__writer.write_arithmetic("add") self.__writer.write_pop("pointer", 1) self.__writer.write_push("that", 0) self.eat() return if cur_stat == "." or cur_stat == "(": self.compile_subroutine_call() return self.eat() # varName name = self.get_token() self.__writer.push_val(self.find(name)) return def find(self, name): """ finding a variable name in symbol tables """ val = self.__subroutine_symbol.get_data(name) if not val: val = self.__class_symbol.get_data(name) elif not val: return False return val def compile_array(self, kind, index): """ compiling array assignment :param kind: var kind :param index: var index """ self.eat() self.compile_expression() self.eat() self.__writer.write_push(kind, index) self.__writer.write_arithmetic("add") self.eat() self.compile_expression() self.__writer.write_pop("temp", 0) self.__writer.write_pop("pointer", 1) self.__writer.write_push("temp", 0) self.__writer.write_pop("that", 0)