def __init__(self, filepath): jt = JackTokenizer(filepath) ce = CompilationEngine(filepath, jt.tokens) self.vmwriter = VMWriter(filepath) self.symbol_table = SymbolTable() self.class_name = None self.generateClass(ce.root)
def __init__(self, parserInput, parserOutput, daSymbolTable): self.tTp = [] #tokens to parse array aka tTp self.tTpcopy = [] #copy to help remove stuff self.tokenCounter = 0 self.indent = 0 # open the input.xml file made by the tokenizer (full of tokens ready to parse) with open(parserInput) as f: for line in f: self.tTpcopy.append(line) self.tTp = self.tTpcopy[1:-1] # remove unwanted stuff from copy self.output1 = open(parserOutput + '.xml', 'w') #output to write to self.theVMWriter = VMWriter(parserOutput) self.currentTokenArr = self.tTp[self.tokenCounter].split(' ') self.currentToken = self.tTp[self.tokenCounter] # first token self.className = '' self.subroutineVoid = False self.iflabel = 0 self.whilelabel = 0 self.constructor = False self.functionType = '' self.subroutineName = '' # get symbol table and everything started self.theSymbolTable = daSymbolTable self.theSymbolTable.classStart() self.compileClass() # start compiling self.output1.close() # close the file when done
def compile_class(self) -> None: """ compiles a class :return: None """ # create VMWriter for current class self.VMWriter = VMWriter(self.file_name) # was class self.tokenizer.advance() # now name # current class name : self.current_class_name = self.tokenizer.get_current_token()[1] # was name self.tokenizer.advance() # now { # was { self.tokenizer.advance() # now class body while self.tokenizer.has_more_tokens(): current_token = self.tokenizer.get_current_token() token_string = current_token[1] if CompilationEngine.is_class_field(token_string): self.compile_class_var_declaration() elif CompilationEngine.is_subroutine(token_string): self.compile_subroutine() # insert last "}" of end of class current_token = self.tokenizer.get_current_token()[1] self.tokenizer.advance()
def __init__(self, file_path): self._tokenizer = JackTokenizer(file_path) self._vm_writer = VMWriter(file_path.replace(".jack", "Compiled.vm")) self._symbol_table = SymbolTable() self.class_name = "" self.label_value = 1 self.compile_class()
def loadFile(self, filepath): self.tokenizer = JackTokenizer(filepath) self._generateTree() self._initializeClassDetails(self.treeRoot) outputFilePath = filepath[:-5] + ".vm" self.writer = VMWriter(outputFilePath)
def __init__(self, tokenizer, output_file): self.tokenizer = tokenizer self.output_file = output_file self.class_symbol_table = SymbolTable() self.subroutine_symbol_table = SymbolTable() self.vm_writer = VMWriter(output_file) self.label_counter = LabelCounter(labels=self.TOKENS_THAT_NEED_LABELS) self.class_name = None
def __init__(self, inputFile, outputFile): self.tokenizer = JackTokenizer(inputFile) self.vmWriter = VMWriter(outputFile) self.symbolTable = SymbolTable() self.classname = "" self.CompileClass() self.whilecounter = 0 self.ifcounter = 0
def __init__(self, input_file): self.st=SymbolTable() self.vmW = VMWriter() self.tknz = JackTokenizer(input_file) self._vm_string = '' self.tknz.advance() self.Op=[] self.Function=[]
def __init__(self, tokenizer, output_vm_file, output_xml_file=None): self.tokenizer = tokenizer self.vmr = VMWriter(output_vm_file) self.output_xml_file = output_xml_file self.indent = "" self.symbol_table = SymbolTable() self.current_class = None self.void_subr = set() self.label_counter = 0
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 __init__(self, _tokens, _in_path, _out_file): self.tokens = iter(_tokens) self.file_name = str(split(_in_path)[1].split('.')[0]) self.out_file = _out_file self.writer = VMWriter(_out_file) self.sym_table = SymbolTable() self.class_name = '' self.curr_subroutine_name = '' self.curr_cond_index = 0
def __init__(self, inpath, outpath): self.tokenizer = Tokenizer(inpath) self.symboltable = SymbolTable() self.vmwriter = VMWriter(outpath) self._class_name = None if self.tokenizer.has_more_tokens(): self.compile_class() self.vmwriter.close() print("{0} completed.".format(outpath))
def __init__(self, tokens_with_tokenType, out_vm_file): self.tokens_with_tokenType = tokens_with_tokenType self.symbol_table = SymbolTable() self.vm_writer = VMWriter(out_vm_file) self.class_name = out_vm_file.stem self.construct_op_dict() self.construct_segment_dict() self.while_label_index = 0 self.if_else_label_index = 0
def __init__(self, tokenizer, outputFile, vmFile): from SymbolTable import SymbolTable from VMWriter import VMWriter self.tokenizer = tokenizer self.outputFile = outputFile self.symbolTable = SymbolTable() self.vmWriter = VMWriter(vmFile) self.labelNum = 0 print(outputFile)
def __init__(self, tokens, fp_out): self.tokens = tokens self.num = 0 #current node in tree self.total = len(tokens) self.crnt_elem = self.tokens[0] self.symbols = SymbolTable()#create symbol table(s) #possibly should call compileclass from outside self.VM = VMWriter(fp_out) self.labels = {} #to create unique labels
def __init__(self, filepath): self._tokenizer = JackTokenizer(filepath) self._writer = VMWriter(filepath) self._classVariables = SymbolTable() self._subroutineVariables = SymbolTable() self._currentToken = None self._preserveCurrentToken = False self._className = '' self._currentCompilingFunction = {'kind': '', 'name': ''} self._numberConditionalsStatementsCurrentFunction = 0
def __init__ (self, path): super().__init__(path) self.xml = str() self.advance() self.st = SymbolTable() self.vm = VMWriter(self.path[:-5]+'.vm') self.className = str() self.labelCounter = 0 self.currentFunctionName = str() self.currentSubroutineType = str()
def __init__(self, tokenizer, out_file_name): ''' Constructor ''' self._tokenizer = tokenizer self._vm_writer = VMWriter(out_file_name) self._class_name = None self._symbol_table = SymbolTable() self._counter = 0 self._subroutine_name = None
def __init__(self, tokenizer, output): """ c'tor :param tokenizer: tokenizer object :param output: output file/stream """ self.tokenizer = tokenizer self.vmWriter = VMWriter(output) self.symbols = SymbolTable() self.className = None self.labelC = 0
def __init__(self, tokenizer: JackTokenizer, jack_file): self.tokenizer = tokenizer self.class_name = '' log_file_name = jack_file.name.replace('.jack', '_engine.xml') self.log_file = open(log_file_name, 'w') log_file_name = jack_file.name.replace('.jack', '.vm') self.output_file = open(log_file_name, 'w') self.symbol_table = SymbolTable() self.vm_writer = VMWriter(self.output_file) self.while_label_index = 0 self.if_label_index = 0
def __init__(self, filename: str, token_list: list): self.token_index = 0 self.identation_level = 0 self.tokens = token_list self.output_file_name = filename self.symbol_table = SymbolTable() self.VMWriter = VMWriter(filename.replace(".jack", ".vm")) self.is_identifier_used = False self.current_if_labels = 0 self.current_while_labels = 0 pass
def __init__(self, filename): self.tokenizer = JackTokenizer(filename) self.types = ['int', 'char', 'boolean'] self.operators = ['+', '-', '*', '/', '&', '|', '<', '>', '='] self.keywordsConstant = ['true', 'false', 'null', 'this'] self.fileName = splitext(filename)[0] self.symbolTable = SymbolTable() self.vm = VMWriter(splitext(filename)[0]) self.whileLabelNum = 0 self.ifLabelNum = 0
def __init__(self, in_address): self.tokenizer = Tokenizer(in_address) self.symbol_table = SymbolTable() self.vm_writer = VMWriter(in_address.replace(".jack", ".vm")) self.curr_token = self.tokenizer.get_current_token() self.out_address = in_address.replace(".jack", ".xml") self.output = "" self.indent = 0 self.label_count = -1 self.class_name = "" self.compile_class()
def make_file(filename): tokenizer = JackTokenizer() tokenizer.read_file(filename) tokenizer.divide_into_tokens() file_to_write = filename[:-5] + "." + "vm" writer = VMWriter(file_to_write) parser = CompilationEngine(tokenizer, writer) parser.void_subroutines() parser.methods_() parser.compile_class() writer.close()
def __init__(self, input_path, output_path): self.class_name = '' self.subroutine_name = '' self.if_counter = -1 self.while_counter = -1 self.subroutine_num_arg = 0 self.tkx = JackTokenizer(input_path) self.class_table = symbolTable() self.subroutine_table = symbolTable() self.vm_writer = VMWriter(output_path) self.compile_class(output_path)
def __init__(self, input_stream, output_stream): """ Creates a new compilation engine with the given input and output. The next routine called must be compileClass(). """ self.__prefix = "" self.__tokenizer = JackTokenizer(input_stream) self.__writer = VMWriter(output_stream) self.__symbol_table = SymbolTable() self.__label_counter = 0 self.__class_name = None
def __init__(self, inFile): self.t = Tokenizer(inFile) self.symTable = SymbolTable() self.vmName = inFile.rstrip('.jack') + '.vm' self.vm = VMWriter(self.vmName) self.className = '' self.types = ['int', 'char', 'boolean', 'void'] self.stmnt = ['do', 'let', 'if', 'while', 'return'] self.subroutType = '' self.whileIndex = 0 self.ifIndex = 0 self.fieldNum = 0
def __init__(self, inputFile, outputFile, outputFile2): # Syntax tokenizer modules self.inF = open(inputFile, 'r') self.opF = open(outputFile, 'w') self.Jt = [] self.JtIndex = 1 # Compilation module self.vmWr = VMWriter(outputFile2) self.symTab = SymbolTable() # parse the result of the tokenizer into a list for line in self.inF: self.Jt.append(line) self.compileProgram()
def __init__(self, source): self.if_counter = 0 self.while_counter = 0 self.tokenizer = Tokenizer(source) self.tokenizer.has_more_tokens() self.tokenizer.advance() self.symbols = SymbolTable() self.writer = VMWriter(source) self.arithmetic_op = {} self.init_op() self.root = Element(CLASS) self.class_name = "" self.compile_class(self.root) self.writer.close()
def compileFiles(self): """Compile each file in the given directory using all modules and generate code.""" verbose = self.parse_arg(sys.argv) for filename in self.filenames: vm_writer = VMWriter(filename) tokenizer = Tokenizer(filename) symbol_table = SymbolTable() tokenizer.tokenize() engine = CompilationEngine(tokens=tokenizer, vm_writer=vm_writer, symbol_table=symbol_table, verbose=verbose) engine.compileClass() vm_writer.close()
def __init__(self, tokenizer, out_file_name): """ Constructor """ self._tokenizer = tokenizer self._vm_writer = VMWriter(out_file_name) self._class_name = None self._symbol_table = SymbolTable() self._counter = 0 self._subroutine_name = None
def __init__(self, inFile, outFile): """Creates a new compilation engine with the given input and output. The next routine called must be compileClass()""" self.tokenizer = JackTokenizer(inFile) self.targetFile = open(outFile, 'w') self.getNext() self.classTable = None self.className = '' self.writer = VMWriter(outFile) self.labelWhile = 1 self.labelIf = 1
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"}
class CompilationEngine(object): def __init__(self, src, output): self.tokenizer = JackTokenizer(src) self.writer = VMWriter(output) self.symbolTable = SymbolTable() self.labelIndex = 0 def _acceptNextToken(self, token): if self.tokenizer.hasMoreToken(): self.tokenizer.advance() typ = self.tokenizer.tokenType() tok = self.tokenizer.tokenValue() if type(token) != list: token = [token] if typ in token or tok in token: return tok raise SyntaxError('Parse Error') def _tryNextToken(self, token): if self.tokenizer.hasMoreToken(): typ, tok = self.tokenizer.next() if type(token) != list: token = [token] if typ in token or tok in token: return True return False def compileClass(self): #'class' className '{' classVarDec* subroutineDec* '}' self._acceptNextToken('class') self.classname = self._acceptNextToken('identifier') self._acceptNextToken('{') while self._tryNextToken(['static', 'field']): self.compileClassVarDec() while self._tryNextToken(['constructor', 'function', 'method']): self.compileSubroutine() self._acceptNextToken('}') self.writer.close() def compileClassVarDec(self): #('static'|'field') type varName (','varName)* ';' kind = self._acceptNextToken(['static', 'field']) type = self._acceptNextToken(['int', 'char', 'boolean', 'identifier']) self.symbolTable.define(self._acceptNextToken('identifier'), type, kind) while self._tryNextToken(','): self._acceptNextToken(',') self.symbolTable.define(self._acceptNextToken('identifier'), type, kind) self._acceptNextToken(';') def compileSubroutine(self): #('constructor'|'function'|'method') #('void'|type)subroutineName'('parameterList')' #subroutineBody self.labelIndex = 0 self.symbolTable.startSubroutine() subroutine = self._acceptNextToken(['constructor', 'function', 'method']) self._acceptNextToken(['void', 'int', 'char', 'boolean', 'identifier']) functionname = self._acceptNextToken('identifier') if subroutine == 'method': self.symbolTable.define('this', self.classname, 'argument') self._acceptNextToken('(') self.compileParameterList() self._acceptNextToken(')') self._acceptNextToken('{') argc = 0 while self._tryNextToken('var'): argc += self.compileVarDec() self.writer.writeFunction(self.classname + '.' + functionname, argc) if subroutine == 'constructor': self.writer.writePush('constant', self.symbolTable.varCount('field')) self.writer.writeCall('Memory.alloc', 1) self.writer.writePop('pointer', 0) elif subroutine == 'method': self.writer.writePush('argument', 0) self.writer.writePop('pointer', 0) while self._tryNextToken(STATEMENT): self.compileStatements() self._acceptNextToken('}') def compileParameterList(self): #((type varName)(','type varName)*)? if self._tryNextToken(TYPE): type = self._acceptNextToken(TYPE) self.symbolTable.define(self._acceptNextToken('identifier'), type, 'argument') while self._tryNextToken(','): self._acceptNextToken(',') type = self._acceptNextToken(TYPE) self.symbolTable.define(self._acceptNextToken('identifier'), type, 'argument') def compileVarDec(self): #'var' type varName (',' varName)*';' argc = 1 self._acceptNextToken('var') type = self._acceptNextToken(TYPE) self.symbolTable.define(self._acceptNextToken('identifier'), type, 'local') while self._tryNextToken(','): self._acceptNextToken(',') argc += 1 self.symbolTable.define(self._acceptNextToken('identifier'), type, 'local') self._acceptNextToken(';') return argc def compileStatements(self): #statement* #letStatement|ifStatement|whileStatement|doStatement|returnStatement while self._tryNextToken(STATEMENT): if self._tryNextToken('let'): self.compileLet() elif self._tryNextToken('if'): self.compileIf() elif self._tryNextToken('while'): self.compileWhile() elif self._tryNextToken('do'): self.compileDo() elif self._tryNextToken('return'): self.compileReturn() def compileDo(self): #'do' subroutineCall ';' #subroutineName '(' expressionList ')' | (className | varName) '.' subroutineName '(' expressionList ')' self._acceptNextToken('do') funcname = self._acceptNextToken('identifier') argc = 0 if self._tryNextToken('.'): self._acceptNextToken('.') type = self.symbolTable.typeOf(funcname) if type != None: argc += 1 self.writer.writePush(self.symbolTable.kindOf(funcname), self.symbolTable.indexOf(funcname)) funcname = type + '.' + self._acceptNextToken('identifier') #game.run() else: funcname = funcname + '.' + self._acceptNextToken('identifier') #Game.run() else: argc += 1 funcname = self.classname + '.' + funcname #run() self.writer.writePush('pointer', 0) self._acceptNextToken('(') argc += self.compileExpressionList() self._acceptNextToken(')') self._acceptNextToken(';') self.writer.writeCall(funcname, argc) self.writer.writePop('temp', 0) def compileLet(self): #'let' varName ('[' expression ']')? '=' expression ';' self._acceptNextToken('let') varName = self._acceptNextToken('identifier') if self._tryNextToken('['): self.writer.writePush(self.symbolTable.kindOf(varName), self.symbolTable.indexOf(varName)) self._acceptNextToken('[') self.compileExpression() self._acceptNextToken(']') self.writer.writeArithmetic('add') self._acceptNextToken('=') self.compileExpression() self._acceptNextToken(';') self.writer.writePop('temp', 0) self.writer.writePop('pointer', 1) self.writer.writePush('temp', 0) self.writer.writePop('that', 0) else: self._acceptNextToken('=') self.compileExpression() self._acceptNextToken(';') self.writer.writePop(self.symbolTable.kindOf(varName), self.symbolTable.indexOf(varName)) def compileWhile(self): #'while' '(' expression ')''{' statements '}' index = str(self.labelIndex) self.labelIndex += 1 self.writer.writeLabel('WHILE' + index) self._acceptNextToken('while') self._acceptNextToken('(') self.compileExpression() self._acceptNextToken(')') self.writer.writeArithmetic('not') self.writer.writeIf('WHILE_END' + index) self._acceptNextToken('{') self.compileStatements() self._acceptNextToken('}') self.writer.writeGoto('WHILE' + index) self.writer.writeLabel('WHILE_END' + index) def compileReturn(self): #'return' expression? ';' self._acceptNextToken('return') if self._tryNextToken(';'): self._acceptNextToken(';') self.writer.writePush('constant', 0) else: self.compileExpression() self._acceptNextToken(';') self.writer.writeReturn() def compileIf(self): #'if' '(' expression ')' '{' statements '}' #('else' '{' statements '}')? index = str(self.labelIndex); self.labelIndex += 1 self._acceptNextToken('if') self._acceptNextToken('(') self.compileExpression() self._acceptNextToken(')') self.writer.writeArithmetic('not') self.writer.writeIf('IF_TRUE' + index) self._acceptNextToken('{') self.compileStatements() self._acceptNextToken('}') self.writer.writeGoto('IF_FALSE' + index) self.writer.writeLabel('IF_TRUE' + index) if self._tryNextToken('else'): self._acceptNextToken('else') self._acceptNextToken('{') self.compileStatements() self._acceptNextToken('}') self.writer.writeLabel('IF_FALSE' + index) def compileExpression(self): #term(op term)* self.compileTerm() while self._tryNextToken(OP): op = self._acceptNextToken(OP) self.compileTerm() if op == '*': self.writer.writeCall('Math.multiply', 2) elif op == '/': self.writer.writeCall('Math.divide', 2) else: self.writer.writeArithmetic(OP_COMMAND[op]) def compileTerm(self): #integerConstant|stringConstant|keywordConstant|varName| if self._tryNextToken('('): #'('expression')' self._acceptNextToken('(') self.compileExpression() self._acceptNextToken(')') elif self._tryNextToken(['-', '~']): #unaryOp term unaryOp = self._acceptNextToken(['-', '~']) self.compileTerm() if unaryOp == '-': self.writer.writeArithmetic('neg') else: self.writer.writeArithmetic('not') else: first_s = self._acceptNextToken(TERM) if self._tryNextToken('['): #varName'['expression']' self.writer.writePush(self.symbolTable.kindOf(first_s), self.symbolTable.indexOf(first_s)) self._acceptNextToken('[') self.compileExpression() self._acceptNextToken(']') self.writer.writeArithmetic('add') self.writer.writePop('pointer', 1) self.writer.writePush('that', 0) elif self._tryNextToken('('): #subroutineCall run() self.writer.writePush('pointer', 0) self._acceptNextToken('(') argc = self.compileExpressionList() + 1 self._acceptNextToken(')') self.writer.writeCall(self.classname + '.' + first_s, argc) elif self._tryNextToken('.'): #subroutineCall game.run() self._acceptNextToken('.') idenfitier = self._acceptNextToken('identifier') type = self.symbolTable.typeOf(first_s) argc = 0 callname = first_s if type != None: argc += 1 callname = type self.writer.writePush(self.symbolTable.kindOf(first_s), self.symbolTable.indexOf(first_s)) self._acceptNextToken('(') argc += self.compileExpressionList() self._acceptNextToken(')') self.writer.writeCall(callname + '.' + idenfitier, argc) else: tokenType = self.tokenizer.tokenType() if tokenType == 'integerConstant': self.writer.writePush('constant', int(first_s)) elif tokenType == 'stringConstant': self.writer.writePush('constant', len(first_s)) self.writer.writeCall('String.new', 1) for c in first_s: self.writer.writePush('constant', ord(c)) self.writer.writeCall('String.appendChar', 2) elif tokenType == 'identifier': self.writer.writePush(self.symbolTable.kindOf(first_s), self.symbolTable.indexOf(first_s)) else: if first_s == 'null' or first_s == 'false': self.writer.writePush('constant', 0) elif first_s == 'true': self.writer.writePush('constant', 1) self.writer.writeArithmetic('neg') elif first_s == 'this': self.writer.writePush('pointer', 0) def compileExpressionList(self): #(expression(','expression)*))? argc = 0 if self._tryNextToken(TERM): self.compileExpression() argc += 1 while self._tryNextToken(','): self._acceptNextToken(',') self.compileExpression() argc += 1 return argc
class CompilationEngine: def __init__(self, inputFile, outputFile): self.tokenizer = JackTokenizer(inputFile) self.vmWriter = VMWriter(outputFile) self.symbolTable = SymbolTable() self.classname = "" self.CompileClass() self.whilecounter = 0 self.ifcounter = 0 def CompileClass(self): #classname self.tokenizer.advance() self.classname = self.tokenizer.identifier() self.tokenizer.advance() # ignore { self.tokenizer.advance() while self.tokenizer.keyWord() == "static" or self.tokenizer.keyWord() == "field": self.CompileClassVarDec() while self.tokenizer.keyWord() == "constructor" or self.tokenizer.keyWord() == "function" or self.tokenizer.keyWord() == "method": self.CompileSubroutine() #ignore } self.tokenizer.advance() def CompileClassVarDec(self): kind = self.tokenizer.keyWord() self.tokenizer.advance() type = self.compileType() name = self.tokenizer.identifier() self.symbolTable.define(name, type, kind) self.tokenizer.advance() # add the rest of var names, if there are while self.tokenizer.symbol() == ",": self.tokenizer.advance() name = self.tokenizer.identifier() self.symbolTable.define(name, type, kind) self.tokenizer.advance() # ignore ; self.tokenizer.advance() def CompileSubroutine(self): self.symbolTable.startSubroutine() self.ifcounter = 0 self.whilecounter = 0 # constructor | function | method functype = self.tokenizer.keyWord() self.tokenizer.advance() if functype == "method": self.symbolTable.define("this", self.classname, "arg") self.tokenizer.advance() subrotineName = self.classname + "." + self.tokenizer.identifier() self.tokenizer.advance() # ( parameterList ) self.tokenizer.advance() self.compileParameterList() self.tokenizer.advance() # subrotineBody # ignore { self.tokenizer.advance() # varDec* while self.tokenizer.keyWord() == "var": self.compileVarDec() self.vmWriter.writeFunction(subrotineName, self.symbolTable.varCount("var")) # allocate memory for constructor # if functype == "constructor": # self.vmWriter.writePush("constant" , self.symbolTable.varCount("field")) # self.vmWriter.writeCall("Memory.alloc", "1") if functype == "constructor" or functype == "method": if functype == "constructor": self.vmWriter.writePush("constant" , self.symbolTable.varCount("field")) self.vmWriter.writeCall("Memory.alloc", "1") else: self.vmWriter.writePush("argument", "0") self.vmWriter.writePop("pointer", "0") # statements self.compileStatements() # ignore } self.tokenizer.advance() def compileParameterList(self): # if not ) if self.tokenizer.tokenType() != 1: # type varName argtype = self.compileType() argname = self.tokenizer.identifier() self.symbolTable.define(argname, argtype, "arg") self.tokenizer.advance() # (, type varName)* while self.tokenizer.symbol() == ",": self.tokenizer.advance() argtype = self.compileType() argname = self.tokenizer.identifier() self.symbolTable.define(argname, argtype, "arg") self.tokenizer.advance() def compileVarDec(self): # var self.tokenizer.advance() # type type = self.compileType() # varName varname = self.tokenizer.identifier() self.symbolTable.define(varname, type, "var") self.tokenizer.advance() # (, varName)* while self.tokenizer.symbol() == ",": self.tokenizer.advance() varname = self.tokenizer.identifier() self.symbolTable.define(varname, type, "var") self.tokenizer.advance() # ignore ; self.tokenizer.advance() def compileStatements(self): while self.tokenizer.tokenType() == 0: if self.tokenizer.keyWord() == "let": self.compileLet() elif self.tokenizer.keyWord() == "if": self.compileIf() elif self.tokenizer.keyWord() == "while": self.compileWhile() elif self.tokenizer.keyWord() == "do": self.compileDo() elif self.tokenizer.keyWord() == "return": self.compileReturn() def compileDo(self): self.tokenizer.advance() self.compileSubRoutineCall() self.vmWriter.writePop("temp", "0") # ignore ; self.tokenizer.advance() def compileLet(self): # let self.tokenizer.advance() # varName varname = self.tokenizer.identifier() varkind = self.symbolTable.kindOf(varname) self.tokenizer.advance() # ([ expression ])? if self.tokenizer.symbol() == "[": self.tokenizer.advance() self.CompileExpression() if varkind == "field": self.vmWriter.writePush("this", self.symbolTable.indexOf(varname)) elif varkind == "var": self.vmWriter.writePush("local", self.symbolTable.indexOf(varname)) elif varkind == "arg": self.vmWriter.writePush("argument", self.symbolTable.indexOf(varname)) elif varkind == "static": self.vmWriter.writePush("static", self.symbolTable.indexOf(varname)) self.vmWriter.writeArithmetic("add") #ignore ] self.tokenizer.advance() #ignore = self.tokenizer.advance() self.CompileExpression() self.vmWriter.writePop("temp", "0") # that self.vmWriter.writePop("pointer", "1") self.vmWriter.writePush("temp", "0") self.vmWriter.writePop("that", "0") self.tokenizer.advance() else: # ignore = self.tokenizer.advance() # expression self.CompileExpression() if varkind == "field": self.vmWriter.writePop("this", self.symbolTable.indexOf(varname)) elif varkind == "var": self.vmWriter.writePop("local", self.symbolTable.indexOf(varname)) elif varkind == "arg": self.vmWriter.writePop("argument", self.symbolTable.indexOf(varname)) elif varkind == "static": self.vmWriter.writePop("static", self.symbolTable.indexOf(varname)) #ignore ; self.tokenizer.advance() def compileWhile(self): # while self.tokenizer.advance() # ( expression ) self.tokenizer.advance() whileindex = self.whilecounter self.whilecounter += 1 self.vmWriter.writeLabel("WHILE_EXP" + str(whileindex)) self.CompileExpression() self.vmWriter.writeArithmetic("not") self.vmWriter.writeIf("WHILE_END" + str(whileindex)) self.tokenizer.advance() # ignore { self.tokenizer.advance() # statements self.compileStatements() # ignore } self.tokenizer.advance() self.vmWriter.writeGoto("WHILE_EXP" + str(whileindex)) self.vmWriter.writeLabel("WHILE_END" + str(whileindex)) def compileReturn(self): # return self.tokenizer.advance() # expression? if self.isTerm(): self.CompileExpression() self.vmWriter.writeReturn() else: self.vmWriter.writePush("constant", "0") self.vmWriter.writeReturn() # ignore; self.tokenizer.advance() def compileIf(self): #if self.tokenizer.advance() # ( expression ) self.tokenizer.advance() self.CompileExpression() ifindex = self.ifcounter self.ifcounter += 1 self.vmWriter.writeIf("IF_TRUE" + str(ifindex)) self.vmWriter.writeGoto("IF_FALSE" + str(ifindex)) self.vmWriter.writeLabel("IF_TRUE" + str(ifindex)) self.tokenizer.advance() # { statements } self.tokenizer.advance() self.compileStatements() self.tokenizer.advance() if self.tokenizer.tokenType() == 0 and self.tokenizer.keyWord() == "else": # else self.vmWriter.writeGoto("IF_END" + str(ifindex)) self.vmWriter.writeLabel("IF_FALSE" + str(ifindex)) self.tokenizer.advance() # { statements } self.tokenizer.advance() self.compileStatements() self.tokenizer.advance() self.vmWriter.writeLabel("IF_END" + str(ifindex)) else: self.vmWriter.writeLabel("IF_FALSE" + str(ifindex)) def CompileExpression(self): #term self.CompileTerm() # (op term)* op = self.tokenizer.symbol() while self.tokenizer.tokenType() == 1 and op in operators: self.tokenizer.advance() self.CompileTerm() if op == "=": self.vmWriter.writeArithmetic("eq") elif op == "+": self.vmWriter.writeArithmetic("add") elif op == "-": self.vmWriter.writeArithmetic("sub") elif op == "*": self.vmWriter.writeCall("Math.multiply", "2") elif op == "/": self.vmWriter.writeCall("Math.divide", "2") elif op == "&": self.vmWriter.writeArithmetic("and") elif op == "|": self.vmWriter.writeArithmetic("or") elif op == "<": self.vmWriter.writeArithmetic("lt") elif op == ">": self.vmWriter.writeArithmetic("gt") op = self.tokenizer.symbol() def CompileTerm(self): if self.tokenizer.tokenType() == 3: self.vmWriter.writePush("constant", self.tokenizer.intVal()) self.tokenizer.advance() elif self.tokenizer.tokenType() == 4: conststring = self.tokenizer.stringVal() self.vmWriter.writePush("constant", str(len(conststring))) self.vmWriter.writeCall("String.new", "1") for i in range(len(conststring)): self.vmWriter.writePush("constant", str(ord(conststring[i]))) self.vmWriter.writeCall("String.appendChar", "2") self.tokenizer.advance() elif self.tokenizer.tokenType() == 0: keywordconst = self.tokenizer.keyWord() if keywordconst == "true": self.vmWriter.writePush("constant", "0") self.vmWriter.writeArithmetic("not") elif keywordconst == "false" or keywordconst == "null": self.vmWriter.writePush("constant", "0") elif keywordconst == "this": self.vmWriter.writePush("pointer", "0") self.tokenizer.advance() elif self.tokenizer.tokenType() == 2: # varName [ expression] if self.tokenizer.tokens[self.tokenizer.currentToken +1] == '[': varname = self.tokenizer.identifier() varkind = self.symbolTable.kindOf(varname) self.tokenizer.advance() # [ expression ] self.tokenizer.advance() self.CompileExpression() if varkind == "field": self.vmWriter.writePush("this", self.symbolTable.indexOf(varname)) elif varkind == "var": self.vmWriter.writePush("local", self.symbolTable.indexOf(varname)) elif varkind == "arg": self.vmWriter.writePush("argument", self.symbolTable.indexOf(varname)) elif varkind == "static": self.vmWriter.writePush("static", self.symbolTable.indexOf(varname)) self.vmWriter.writeArithmetic("add") # that self.vmWriter.writePop("pointer", "1") self.vmWriter.writePush("that", "0") self.tokenizer.advance() # subrutine call elif self.tokenizer.tokens[self.tokenizer.currentToken +1] == '(' or self.tokenizer.tokens[self.tokenizer.currentToken +1] == '.': self.compileSubRoutineCall() # varname else: varname = self.tokenizer.identifier() varkind = self.symbolTable.kindOf(varname) if varkind == "field": self.vmWriter.writePush("this", self.symbolTable.indexOf(varname)) elif varkind == "var": self.vmWriter.writePush("local", self.symbolTable.indexOf(varname)) elif varkind == "arg": self.vmWriter.writePush("argument", self.symbolTable.indexOf(varname)) elif varkind == "static": self.vmWriter.writePush("static", self.symbolTable.indexOf(varname)) self.tokenizer.advance() elif self.tokenizer.tokenType() == 1 and self.tokenizer.symbol() == '(': # ( expression ) self.tokenizer.advance() self.CompileExpression() self.tokenizer.advance() else: #unary!!! op = self.tokenizer.symbol() self.tokenizer.advance() self.CompileTerm() if op == "-": self.vmWriter.writeArithmetic("neg") elif op == "~": self.vmWriter.writeArithmetic("not") def compileSubRoutineCall(self): # subroutineName | (className | varName) identifier = self.tokenizer.identifier() self.tokenizer.advance() #no "." only name if self.tokenizer.symbol() == '(': # ( expressionList ) -- subroutine of type method self.tokenizer.advance() self.vmWriter.writePush("pointer", "0") argnum = self.CompileExpressionList() self.vmWriter.writeCall(self.classname + "." + identifier, str(argnum +1)) self.tokenizer.advance() else: # . -- class.function or var.method self.tokenizer.advance() # subroutineName subname = self.tokenizer.identifier() self.tokenizer.advance() self.tokenizer.advance() if identifier in self.symbolTable.classtable or identifier in self.symbolTable.subroutinetable: # varname!!! if identifier in self.symbolTable.subroutinetable: if self.symbolTable.kindOf(identifier) == "var": self.vmWriter.writePush("local", self.symbolTable.indexOf(identifier)) else: self.vmWriter.writePush("argument", self.symbolTable.indexOf(identifier)) else: if self.symbolTable.kindOf(identifier) == "static": self.vmWriter.writePush("static", self.symbolTable.indexOf(identifier)) else: self.vmWriter.writePush("this", self.symbolTable.indexOf(identifier)) argnum = self.CompileExpressionList() identifierclass = self.symbolTable.typeOf(identifier) self.vmWriter.writeCall(identifierclass + "." + subname, str(argnum +1)) else: argnum = self.CompileExpressionList() self.vmWriter.writeCall(identifier + "." + subname, str(argnum)) self.tokenizer.advance() def CompileExpressionList(self): # (expression i = 0 if self.isTerm(): i += 1 # (, expression) self.CompileExpression() while self.tokenizer.symbol() == ',': i+= 1 self.tokenizer.advance() self.CompileExpression() return i def isTerm(self): if self.tokenizer.tokenType() == 3 or self.tokenizer.tokenType() == 4: return True if self.tokenizer.tokenType() == 0 and self.tokenizer.keyWord() in keyword_const: return True if self.tokenizer.tokenType() == 1 and self.tokenizer.symbol() == '(' : return True if self.tokenizer.tokenType() == 1 and (self.tokenizer.symbol() == '-' or self.tokenizer.symbol() == '~'): return True if self.tokenizer.tokenType() == 2: return True return False def compileType(self): if self.tokenizer.tokenType() == 0: typen = self.tokenizer.keyWord() else: typen = self.tokenizer.identifier() self.tokenizer.advance() return typen
def __init__(self, src, output): self.tokenizer = JackTokenizer(src) self.writer = VMWriter(output) self.symbolTable = SymbolTable() self.labelIndex = 0
class CompliationEngine(object): """ Effects the actual compilation output. Gets its input from a JackTokenizer and emits its parsed structure into an output file/stream """ MAP = {"<": "<", ">": ">", '"': """, "&": "&"} def __init__(self, tokenizer, out_file_name): """ Constructor """ self._tokenizer = tokenizer self._vm_writer = VMWriter(out_file_name) self._class_name = None self._symbol_table = SymbolTable() self._counter = 0 self._subroutine_name = None def Compile(self): token = str(self._tokenizer.next_token()) if token == "class": self.CompileClass(token) def CompileClass(self, token): """ takes 'class' as token and end the compilation """ self._class_name = self._tokenizer.next_token() # got the class name str(self._tokenizer.next_token()) # '{' token = self._tokenizer.next_token() # field declarations # For declaring Class Level Variable while token in ["field", "static"]: token = self.CompileClassVarDec(token) # Class Methods while token in ["function", "method", "constructor"]: token = self.CompileSubroutine(token) self._vm_writer.writer_close() self._symbol_table.printSymbolTables() def CompileSubroutine(self, token): """ Takes any among 'function', 'method', 'constructor' and return token after end of subroutine '}' or simple next subroutine token """ function_modifier = token str(self._tokenizer.next_token()) # return type function_name = str(self._tokenizer.next_token()) # name of function self._subroutine_name = function_name self._symbol_table.startSubRoutine(function_name) if function_modifier == "method": self._symbol_table.define(["this", self._class_name, "argument"]) str(self._tokenizer.next_token()) # '(' token = str(self._tokenizer.next_token()) # 'arguments' while token != ")": token = self.CompileParamList(token) str(self._tokenizer.next_token()) # '{' token = str(self._tokenizer.next_token()) # Statements or '}' while token == "var": token = self.CompileVarDec(token) local_variables = self._symbol_table.varCount("local") # Writing Function VM self._vm_writer.write_subroutine(self._class_name, function_name, local_variables) if function_name == "new": no_of_fields = self._symbol_table.varCount("field") self._vm_writer.write_push("constant", no_of_fields) self._vm_writer.write_call("Memory", "alloc", 1) self._vm_writer.write_pop("pointer", 0) if function_modifier == "method": self._vm_writer.write_push("argument", 0) self._vm_writer.write_pop("pointer", 0) """temp_buffer = "" while local_variables > 0: temp_buffer += 'push constant 0\n' local_variables -= 1 self._out_file_object.write(temp_buffer) self._out_file_object.flush()""" while token != "}": token = self.CompileStatements(token) token = str(self._tokenizer.next_token()) # next subroutine return token def CompileStatements(self, token): if token == "return": return self.CompileReturn(token) if token == "do": return self.CompileDo(token) if token == "let": return self.CompileLet(token) if token == "while": return self.CompileWhile(token) if token == "if": return self.CompileIf(token) def CompileIf(self, token): """ Takes 'if' keyword and returns next statement token """ self._counter += 1 # for linear label names str(self._tokenizer.next_token()) # '(' token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) # returns ')' self._vm_writer.write_arithmatic("~") label = self._class_name + "." + "if." + str(self._counter) + ".L1" self._vm_writer.write_if_goto(label) str(self._tokenizer.next_token()) # '}' token = str(self._tokenizer.next_token()) goto_label = self._class_name + "." + "if." + str(self._counter) + ".L2" while token != "}": token = self.CompileStatements(token) self._vm_writer.write_goto(goto_label) self._vm_writer.write_label(label) # optional else Command token = str(self._tokenizer.next_token()) if token == "else": token = self.CompileElse(token) self._vm_writer.write_label(goto_label) return token def CompileElse(self, token): """ Takes 'else' token and return next statement token """ str(self._tokenizer.next_token()) # '{' token = str(self._tokenizer.next_token()) while token != "}": token = self.CompileStatements(token) token = str(self._tokenizer.next_token()) return token def CompileWhile(self, token): """ Takes 'while' token and returns next statement token """ self._counter += 1 # for linear label names label = self._class_name + "." + "while." + str(self._counter) + ".L1" self._vm_writer.write_label(label) str(self._tokenizer.next_token()) # '(' token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) # 'returns ')' self._vm_writer.write_arithmatic("~") # ~cond if_label = self._class_name + "." + "while." + str(self._counter) + ".L2" self._vm_writer.write_if_goto(if_label) str(self._tokenizer.next_token()) # '{' token = str(self._tokenizer.next_token()) while token != "}": token = self.CompileStatements(token) self._vm_writer.write_goto(label) # 'goto label' self._vm_writer.write_label(if_label) # label for next statement token = str(self._tokenizer.next_token()) return token def CompileDo(self, token): identifier = str(self._tokenizer.next_token()) # identifer or class name token = str(self._tokenizer.next_token()) class_name = identifier no_of_arguments = 0 if token == ".": method_or_function = str(self._tokenizer.next_token()) str(self._tokenizer.next_token()) # '(' id_type = self._symbol_table.typeOf(identifier) else: class_name = self._class_name method_or_function = identifier no_of_arguments += 1 self._vm_writer.write_push("pointer", "0") id_type = None token = str(self._tokenizer.next_token()) if id_type != None: segment = self._symbol_table.kindOf(identifier) index = self._symbol_table.indexOf(identifier) self._vm_writer.write_push(segment, index) no_of_arguments += 1 class_name = id_type no_arguments = 0 if token != ")": token, no_arguments = self.CompilerExpressionList(token) # return value is ')' no_of_arguments += no_arguments self._vm_writer.write_call(class_name, method_or_function, no_of_arguments) str(self._tokenizer.next_token()) # ';' # 'void functions will return constant 0 which should be discarded' self._vm_writer.write_pop("temp", "0") token = str(self._tokenizer.next_token()) return token def CompileLet(self, token): """ Function receiver 'let' and return ';' """ identifier = str(self._tokenizer.next_token()) # left hand side identifier segment = self._symbol_table.kindOf(identifier) index = str(self._symbol_table.indexOf(identifier)) token = str(self._tokenizer.next_token()) # = or [ if_array = False if token == "[": if_array = True token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) # ']' self._vm_writer.write_push(segment, index) self._vm_writer.write_arithmatic("+") # Equal Expression token = str(self._tokenizer.next_token()) # Right Hand Side Expression token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) # End Statements if if_array: self._vm_writer.write_pop("temp", 0) self._vm_writer.write_pop("pointer", 1) self._vm_writer.write_push("temp", 0) self._vm_writer.write_pop("that", 0) else: self._vm_writer.write_pop(segment, index) token = str(self._tokenizer.next_token()) return token def CompileReturn(self, token): """ Takes 'return' token if simple return pushes dummy constant and returns 0 """ token = str(self._tokenizer.next_token()) # ';'? if token == ";": self._vm_writer.write_push("constant", "0") else: token = self.CompileExpression(token) # ';' self._vm_writer.write_return() return str(self._tokenizer.next_token()) def CompilerExpressionList(self, token): no_of_argument = 1 token = self.CompileExpression(token) # returns ',' while token == ",": no_of_argument += 1 token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) return token, no_of_argument def CompileExpression(self, token): """ Expression """ token = self.CompileTerm(token) if token in Lexical.OP: operator = token token = str(self._tokenizer.next_token()) # Next term token = self.CompileTerm(token) self._vm_writer.write_arithmatic(operator) return token def CompileTerm(self, token): """ Takes the term token and returns the token after the term """ if token.isdigit(): self._vm_writer.write_push("constant", token) elif token[0] == '"': no_of_character = len(token) - 2 # removing " self._vm_writer.write_push("constant", no_of_character) self._vm_writer.write_call("String", "new", 1) for idx in range(1, len(token) - 1): self._vm_writer.write_push("constant", ord(token[idx])) self._vm_writer.write_call("String", "appendChar", 2) elif token == "true": self._vm_writer.write_push("constant", "1") self._vm_writer.write_arithmatic("-", "NEG") elif token in ["false", "null"]: self._vm_writer.write_push("constant", "0") elif token == "this": self._vm_writer.write_push("pointer", "0") elif token == "-": return self.CompileNegOperator(token) elif token == "~": return self.CompileNotOperator(token) elif token == "(": token = str(self._tokenizer.next_token()) # Term token token = self.CompileExpression(token) # Returns ')' elif self._tokenizer.expected_token() == "[": identifier = token index = self._symbol_table.indexOf(identifier) segment = self._symbol_table.kindOf(identifier) self._vm_writer.write_push(segment, index) str(self._tokenizer.next_token()) # '[' token = str(self._tokenizer.next_token()) token = self.CompileExpression(token) # return value is ']' self._vm_writer.write_arithmatic("+") self._vm_writer.write_pop("pointer", "1") self._vm_writer.write_push("that", "0") elif self._tokenizer.expected_token() == ".": identifier = token str(self._tokenizer.next_token()) # '.' method_or_function = str(self._tokenizer.next_token()) str(self._tokenizer.next_token()) # '(' token = str(self._tokenizer.next_token()) no_of_arguments = 0 class_name = identifier id_type = self._symbol_table.typeOf(identifier) print identifier, id_type if id_type != None: segment = self._symbol_table.kindOf(identifier) index = self._symbol_table.indexOf(identifier) self._vm_writer.write_push(segment, index) no_of_arguments += 1 class_name = id_type no_arguments = 0 if token != ")": token, no_arguments = self.CompilerExpressionList(token) no_of_arguments += no_arguments self._vm_writer.write_call(class_name, method_or_function, no_of_arguments) else: identifier = token index = self._symbol_table.indexOf(identifier) segment = self._symbol_table.kindOf(identifier) self._vm_writer.write_push(segment, index) token = str(self._tokenizer.next_token()) return token def CompileNegOperator(self, token): token = str(self._tokenizer.next_token()) token = self.CompileTerm(token) self._vm_writer.write_arithmatic("-", "NEG") return token def CompileNotOperator(self, token): """ Takes '~' as argument as return ')' """ token = str(self._tokenizer.next_token()) # '('? if token != "(": token = self.CompileTerm(token) else: token = str(self._tokenizer.next_token()) # token = self.CompileExpression(token) # returns inner ')' res token = str(self._tokenizer.next_token()) # outer ')' self._vm_writer.write_arithmatic("~") return token def CompileParamList(self, token): """ Takes type of the first argument of the subroutine """ id_type = token # type of var variable kind = "argument" identifier = str(self._tokenizer.next_token()) # identifier name identifier_details = [identifier, id_type, kind] self._symbol_table.define(identifier_details) token = str(self._tokenizer.next_token()) if token == ",": token = str(self._tokenizer.next_token()) return self.CompileParamList(token) return token def CompileVarDec(self, token): """ Takes either of 'field' or 'static' as token return next statement either 'var' or do, let, if, while """ id_type = str(self._tokenizer.next_token()) # type of var variable kind = "local" identifier = str(self._tokenizer.next_token()) # identifier name identifier_details = [identifier, id_type, kind] self._symbol_table.define(identifier_details) token = str(self._tokenizer.next_token()) # ',' or '; while token == ",": identifier_details = [] identifier = str(self._tokenizer.next_token()) # identifier name identifier_details = [identifier, id_type, kind] self._symbol_table.define(identifier_details) token = str(self._tokenizer.next_token()) # ',' or '; return str(self._tokenizer.next_token()) def CompileClassVarDec(self, token): class_var_modifer = str(token) # 'field' or 'static' # primitive or user defined class class_var_type = str(self._tokenizer.next_token()) identifier = str(self._tokenizer.next_token()) identifier_details = [identifier, class_var_type, class_var_modifer] self._symbol_table.define(identifier_details) token = self._tokenizer.next_token() while token == ",": identifier = str(self._tokenizer.next_token()) identifier_details = [identifier, class_var_type, class_var_modifer] self._symbol_table.define(identifier_details) token = str(self._tokenizer.next_token()) token = self._tokenizer.next_token() if token in ["field", "static"]: return self.CompileClassVarDec(token) return token
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)
class CompilationEngine: """Recursive top-down parser""" def __init__(self, inFile, outFile): """Creates a new compilation engine with the given input and output. The next routine called must be compileClass()""" self.tokenizer = JackTokenizer(inFile) self.targetFile = open(outFile, 'w') self.getNext() self.classTable = None self.className = '' self.writer = VMWriter(outFile) self.labelWhile = 1 self.labelIf = 1 def getNext(self): if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() def compileClass(self): """Compiles a complete class""" self.classTable = SymbolTable() # 'class' className '{' classVarDec* subroutineDec* '}' # class self.getNext() # className self.className = self.tokenizer.getToken() self.getNext() # { self.getNext() token = self.tokenizer.getToken() while token in ["static", "field"]: self.compileDec() token = self.tokenizer.getToken() token = self.tokenizer.getToken() while token in ["constructor", "function", "method"]: self.compileSubroutine() token = self.tokenizer.getToken() # } self.getNext() def compileSubroutine(self): """Compiles a complete method, function, or constructor.""" # subroutine dec self.classTable.startSubroutine() # ('constructor' | 'function' | 'method') ('void' | type) subroutineName '(' parameterList ')' subroutineBody # ('constructor' | 'function' | 'method') subroutineType = self.tokenizer.getToken() self.getNext() # ('void' | type) self.getNext() # subroutineName name = self.tokenizer.getToken() self.getNext() # ( self.getNext() # parameterList self.compileParameterList(subroutineType == 'method') # ) self.getNext() # subroutine body # '{' varDec* statements '}' # { self.getNext() # varDec* while self.tokenizer.getToken() == 'var': self.compileDec() numOfVars = self.classTable.varCount(Toolbox.VAR) if subroutineType == 'function': self.writer.writeFunction(self.className + "." + name, numOfVars) elif subroutineType == 'constructor': self.writer.writeFunction(self.className + "." + name, numOfVars) # push constant (num of fields) # call Memory.alloc 1 # pop pointer 0 fields = self.classTable.varCount(Toolbox.FIELD) self.writer.writePush(Toolbox.CONST, fields) self.writer.writeCall('Memory.alloc', 1) self.writer.writePop(Toolbox.POINTER, 0) else: # method self.writer.writeFunction(self.className + "." + name, numOfVars) # push argument 0 # pop pointer 0 self.writer.writePush(Toolbox.SEG_ARG, 0) self.writer.writePop(Toolbox.POINTER, 0) # statements self.compileStatements() # } self.getNext() def compileParameterList(self, method=False): """Compiles a (possibly empty) parameter list, not including the enclosing "()".""" tokenType, name = '', '' if method: # Add this to method's var list. self.classTable.define(None, None, Toolbox.ARG) if self.tokenizer.tokenType() != self.tokenizer.SYMBOL: # param list not empty while True: tokenType = self.tokenizer.getToken() self.getNext() name = self.tokenizer.getToken() self.classTable.define(name, tokenType, Toolbox.ARG) self.getNext() if self.tokenizer.getToken() == ')': break self.getNext() # ',' def compileStatements(self): # (letStatement | ifStatement | whileStatement | doStatement | returnStatement)* """Compiles a sequence of statements, not including the enclosing "{}".""" token = self.tokenizer.getToken() while token in ["let", "if", "while", "do", "return"]: if token == 'let': self.compileLet() elif token == 'if': self.compileIf() elif token == 'while': self.compileWhile() elif token == 'do': self.compileDo() elif token == 'return': self.compileReturn() token = self.tokenizer.getToken() def compileSubroutineCall(self, name, printIdentifier=True): # subroutineName '(' expressionList ') ' | ( className | varName) '.' subroutineName '(' expressionList ') ' var = None nArgs = 0 if printIdentifier: # subroutineName | ( className | varName) self.getNext() var = self.classTable.searchScope(name) if self.tokenizer.getToken() == '.': if var: # push <this> self.writer.writePush(var[0], var[1]) nArgs += 1 className = var[2] # Use the type instead of the variable name else: className = name self.getNext() subroutineName = self.tokenizer.getToken() self.getNext() else: # push <this> self.writer.writePush(Toolbox.POINTER, 0) nArgs += 1 className = self.className subroutineName = name name = className + '.' + subroutineName # '(' self.getNext() nArgs += self.compileExpressionList() self.writer.writeCall(name, nArgs) # ')' self.getNext() def compileDo(self): # 'do' subroutineCall ';' """Compiles a do statement""" # do self.getNext() # subroutineCall self.compileSubroutineCall(self.tokenizer.getToken()) self.writer.writePop(Toolbox.TEMP, 0) # ; if self.tokenizer.getToken() == ';': self.getNext() def compileLet(self): # 'let' varName ('[' expression ']')? '=' expression ';' """Compiles a let statement""" # let # self.targetFile.write(T_LET) self.getNext() # var name name = self.tokenizer.getToken() # search scope segment, index, type = self.classTable.searchScope(name) self.getNext() # [ array = False if self.tokenizer.getToken() == '[': array = True self.writer.writePush(segment, index) self.getNext() # expression self.compileExpression() # ] self.getNext() self.writer.writeArithmetic('add') # = self.getNext() # expression self.compileExpression() if array: self.writer.writePop(Toolbox.TEMP, 0) self.writer.writePop(Toolbox.TEMP, 1) self.writer.writePush(Toolbox.TEMP, 0) self.writer.writePush(Toolbox.TEMP, 1) self.writer.writePop(Toolbox.POINTER, 1) self.writer.writePop(Toolbox.THAT, 0) else: self.writer.writePop(segment, index) # ; token = self.tokenizer.getToken() if token == ';': self.getNext() def compileWhile(self): # while' '(' expression ')' '{' statements '}' """Compiles a while statement""" # while label = str(self.labelWhile) self.labelWhile += 1 self.writer.writeLabel('while' + label) self.getNext() # ( self.getNext() # expression self.compileExpression() # ) self.getNext() self.writer.writeArithmetic('not') self.writer.writeIf('endwhile' + label) # { self.getNext() # statements self.compileStatements() # } self.getNext() self.writer.writeGoto('while' + label) self.writer.writeLabel('endwhile' + label) def compileReturn(self): # 'return' expression? ';' """Compiles a return statement""" # return self.getNext() # expression if not (self.tokenizer.getToken() == ";"): self.compileExpression() else: self.writer.writePush(Toolbox.CONST, 0) self.writer.writeReturn() # ; self.getNext() def compileIf(self): # 'if' '(' expression ')' '{' statements '}' ( 'else' '{' statements '}' )? """Compiles an if statement, possibly with a trailing else clause""" # if label = 'if' + str(self.labelIf) self.labelIf += 1 self.getNext() # ( self.getNext() # expression self.compileExpression() # ) self.getNext() self.writer.writeArithmetic('not') self.writer.writeIf('else' + label) # { self.getNext() # statements self.compileStatements() # } self.getNext() self.writer.writeGoto('end' + label) self.writer.writeLabel('else' + label) # else if self.tokenizer.getToken() == 'else': self.getNext() # { self.getNext() # expression self.compileStatements() # } self.getNext() self.writer.writeLabel('end' + label) def compileExpression(self): """Compiles an expression""" # term (op term)* self.compileTerm() token = self.tokenizer.getToken() while token in ['+', '/', '-', '*', '&', '|', '>', '<', '=']: self.getNext() self.compileTerm() self.writer.writeArithmetic(token) token = self.tokenizer.getToken() def compileTerm(self): #integerConstant | stringConstant | keywordConstant | varName | varName '[' expression']' | # subroutineCall | '(' expression ')' | unaryOp term """Compiles a term""" token = self.tokenizer.getToken() tokenType = self.tokenizer.tokenType() if tokenType == self.tokenizer.INT_CONST: self.writer.writePush(Toolbox.CONST, token) self.getNext() elif tokenType == self.tokenizer.STRING_CONST: self.writer.writePush(Toolbox.CONST, len(token)) self.writer.writeCall('String.new', 1) for c in token: self.writer.writePush(Toolbox.CONST, ord(c)) self.writer.writeCall('String.appendChar', 2) self.getNext() elif tokenType == self.tokenizer.KEYWORD: # true | false | null | this self.compileKeywordConstant(token) elif tokenType == self.tokenizer.IDENTIFIER: name = token self.getNext() token = self.tokenizer.getToken() if token == '[': self.compileVarName(name) self.getNext() self.compileExpression() self.getNext() self.writer.writeArithmetic('add') self.writer.writePop(Toolbox.POINTER, 1) self.writer.writePush(Toolbox.THAT, 0) elif token in ['(', '.']: self.compileSubroutineCall(name, False) else: self.compileVarName(name) elif token == '(': self.getNext() self.compileExpression() self.getNext() elif token in ['-', '~']: self.compileUnary(token) def compileExpressionList(self): """Compiles a (possibly empty) comma separated list of expressions""" nArgs = 0 if self.tokenizer.getToken() != ')': self.compileExpression() nArgs += 1 while self.tokenizer.getToken() == ',': self.getNext() self.compileExpression() nArgs += 1 return nArgs def compileDec(self): # 'var' type varName (',' varName)* ';' """Compiles a var declaration""" # keyword 'var' token = self.tokenizer.getToken() kind = None if token == 'var': kind = Toolbox.VAR elif token == 'field': kind = Toolbox.FIELD elif token == 'static': kind = Toolbox.STATIC self.getNext() tokenType = self.tokenizer.getToken() # type can be an identifier or a keyword self.getNext() # var name name = self.tokenizer.getToken() self.classTable.define(name, tokenType, kind) self.getNext() while self.tokenizer.tokenType() == self.tokenizer.SYMBOL and self.tokenizer.getToken() == ',': # , self.getNext() name = self.tokenizer.getToken() self.classTable.define(name, tokenType, kind) # var name self.getNext() # ; self.getNext() def compileVarName(self, name): segment, index, type = self.classTable.searchScope(name) self.writer.writePush(segment, index) def compileKeywordConstant(self, keyword): if keyword == 'false' or keyword == 'null': self.writer.writePush(Toolbox.CONST, 0) if keyword == 'true': self.writer.writePush(Toolbox.CONST, 0) self.writer.writeArithmetic('not') if keyword == 'this': self.writer.writePush(Toolbox.POINTER, 0) self.getNext() def compileUnary(self, token): """ Compiles an unary operator with its operand (term) :param token: unary token """ self.getNext() # '~' or '-' self.compileTerm() # operand if token == '-': self.writer.writeArithmetic('neg') else: # token is '~' self.writer.writeArithmetic('not')
class CompilationEngine: keywordConsts = ["null", "true", "false", "this"] def __init__(self, tokenizer, outputFile, vmFile): from SymbolTable import SymbolTable from VMWriter import VMWriter self.tokenizer = tokenizer self.outputFile = outputFile self.symbolTable = SymbolTable() self.vmWriter = VMWriter(vmFile) self.labelNum = 0 print(outputFile) def compileClass(self): from JackTokenizer import JackTokenizer self.indentLevel = 0 NUM_OPENING_STATEMENTS = 3 classVarOpenings = ['static', 'field'] subOpenings = ['constructor', 'function', 'method'] if self.tokenizer.currentToken != "class": raise Exception("Keyword 'class' expected") self.writeFormatted("<class>") self.indentLevel += 1 self.printToken() #Should print 'class' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print class name self.className = self.tokenizer.identifier() self.writeClassOrSubInfo("class", False) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print '{' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.fieldCount = 0 while self.tokenizer.hasMoreTokens() and self.tokenizer.keyWord() in classVarOpenings: if self.tokenizer.keyWord() == "field": self.fieldCount += 1 self.compileClassVarDec() while(self.tokenizer.hasMoreTokens() and self.tokenizer.tokenType == JackTokenizer.KEYWORD and self.tokenizer.keyWord() in subOpenings): self.compileSubroutine() self.printToken() self.writeFormatted("</class>") self.indentLevel -= 1 def compileClassVarDec(self): from JackTokenizer import JackTokenizer from SymbolTable import SymbolTable self.writeFormatted("<classVarDec>") self.indentLevel += 1 self.printToken() #Should print static or field if self.tokenizer.tokenType == JackTokenizer.KEYWORD: if self.tokenizer.keyWord() == "static": kind = SymbolTable.STATIC elif self.tokenizer.keyWord() == "field": kind = SymbolTable.FIELD else: raise Exception("Invalid kind of class variable " + self.tokenizer.keyWord()) else: raise Exception("Keyword expected") if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the variable type identifierType = self.tokenizer.currentToken isKeyword = self.tokenizer.tokenType == JackTokenizer.KEYWORD if not isKeyword: self.writeClassOrSubInfo("class", True) varNames = [] if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print variable name varNames.append(self.tokenizer.currentToken) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() while self.tokenizer.symbol() != ";" and self.tokenizer.hasMoreTokens(): if self.tokenizer.symbol() != ",": raise Exception("Invalid variable list") self.printToken() #Should print ',' self.tokenizer.advance() self.printToken() #Should print variable name varNames.append(self.tokenizer.currentToken) if kind == SymbolTable.FIELD: self.fieldCount += 1 if not self.tokenizer.hasMoreTokens(): raise Exception("More tokens expected") self.tokenizer.advance() self.printToken() for name in varNames: self.symbolTable.define(name, identifierType, kind) self.writeVarInfo(name, False) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</classVarDec>") def compileSubroutine(self): from JackTokenizer import JackTokenizer from SymbolTable import SymbolTable self.writeFormatted("<subroutineDec>") self.symbolTable.startSubroutine() self.indentLevel += 1 NUM_OPENING_STATEMENTS = 4 self.printToken() #Should print 'constructor', 'function', or 'method' self.isConstructor = False self.isMethod = False if self.tokenizer.keyWord() == "constructor": self.isConstructor = True elif self.tokenizer.keyWord() == "method": self.isMethod = True self.symbolTable.define("this", self.className, SymbolTable.ARG) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the type or 'void' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the subroutine name self.subName = self.tokenizer.identifier() if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print opening '(' before parameter list if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileParameterList() self.printToken() #Should print closing ")" after parameter list if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.numLocalVariables = 0 self.compileSubroutineBody() self.indentLevel -= 1 self.writeFormatted("</subroutineDec>") def compileSubroutineBody(self): from JackTokenizer import JackTokenizer from SymbolTable import SymbolTable from VMWriter import VMWriter self.writeFormatted("<subroutineBody>") self.indentLevel += 1 self.printToken() #Should print "{" if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() while(self.tokenizer.hasMoreTokens() and self.tokenizer.tokenType == JackTokenizer.KEYWORD and self.tokenizer.keyWord() == "var"): self.compileVarDec() self.vmWriter.writeFunction(self.className + "." + self.subName, self.numLocalVariables) if self.isConstructor: self.vmWriter.writePush("constant", self.fieldCount) self.vmWriter.writeCall("Memory.alloc", 1) #allocate space for this object self.vmWriter.writePop("pointer", 0) #assign object to 'this' elif self.isMethod: self.vmWriter.writePush(SymbolTable.ARG, 0) self.vmWriter.writePop("pointer", VMWriter.THIS_POINTER) self.compileStatements() self.printToken() #Should print closing "}" if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</subroutineBody>") def compileParameterList(self): from JackTokenizer import JackTokenizer from SymbolTable import SymbolTable self.writeFormatted("<parameterList>") self.indentLevel += 1 if self.tokenizer.currentToken != ")": self.printToken() #Should print the type argType = self.tokenizer.currentToken self.tokenizer.advance() self.printToken() #Should print the name argName = self.tokenizer.currentToken self.symbolTable.define(argName, argType, SymbolTable.ARG) self.writeVarInfo(argName, False) self.tokenizer.advance() while self.tokenizer.tokenType != JackTokenizer.SYMBOL or self.tokenizer.symbol() != ")": self.printToken() #Should print a comma if self.tokenizer.currentToken != ",": raise Exception("Comma expected") if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the argument type argType = self.tokenizer.currentToken if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the argument name argName = self.tokenizer.currentToken self.symbolTable.define(argName, argType, SymbolTable.ARG) self.writeVarInfo(argName, False) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</parameterList>") def compileVarDec(self): from JackTokenizer import JackTokenizer from SymbolTable import SymbolTable self.numLocalVariables += 1 self.writeFormatted("<varDec>") self.indentLevel += 1 varNames = [] self.printToken() #Should print 'var' if self.tokenizer.currentToken != "var": raise Exception("'var' keyword expected") if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the type varType = self.tokenizer.currentToken isKeyword = self.tokenizer.tokenType == JackTokenizer.KEYWORD if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print the var name varNames.append(self.tokenizer.currentToken) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() while(self.tokenizer.hasMoreTokens() and (self.tokenizer.tokenType != JackTokenizer.SYMBOL or self.tokenizer.symbol() != ";")): self.printToken() #Should print ',' self.tokenizer.advance() self.printToken() #Should print the var name varNames.append(self.tokenizer.currentToken) self.tokenizer.advance() self.numLocalVariables += 1 #If the type is not a keyword (e.g. int) that means it's a class and we should print identifier info if not isKeyword: self.writeClassOrSubInfo("class", "True") for name in varNames: self.symbolTable.define(name, varType, SymbolTable.VAR) self.writeVarInfo(name, False) self.printToken() #Should print ';' self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</varDec>") def compileStatements(self): from JackTokenizer import JackTokenizer self.writeFormatted("<statements>") self.indentLevel += 1 stmtStarts = ['do', 'while', 'let', 'if', 'return'] while(self.tokenizer.hasMoreTokens() and self.tokenizer.tokenType == JackTokenizer.KEYWORD and self.tokenizer.keyWord() in stmtStarts): if self.tokenizer.keyWord() == "do": self.compileDo() elif self.tokenizer.keyWord() == "while": self.compileWhile() elif self.tokenizer.keyWord() == "let": self.compileLet() elif self.tokenizer.keyWord() == "if": self.compileIf() elif self.tokenizer.keyWord() == "return": self.compileReturn() self.indentLevel -= 1 self.writeFormatted("</statements>") def compileDo(self): from JackTokenizer import JackTokenizer self.writeFormatted("<doStatement>") self.indentLevel += 1 if self.tokenizer.keyWord() != "do": raise Exception("'do' keyword expected") self.printToken() if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileSubroutineCall() self.vmWriter.writePop("temp", 0) #This pops and ignores the returned value self.printToken() #Print ';' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</doStatement>") def compileLet(self): from SymbolTable import SymbolTable from VMWriter import VMWriter self.writeFormatted("<letStatement>") self.indentLevel += 1 isArray = False if self.tokenizer.keyWord() != "let": raise Exception("Let keyword expected") self.printToken() #Should print "let" if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print varname varName = self.tokenizer.identifier() self.writeVarInfo(self.tokenizer.identifier(), True) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print '[' or '=' print("compileLet - [ or = " + self.tokenizer.currentToken) if self.tokenizer.currentToken == "[": isArray = True self.tokenizer.advance() if self.symbolTable.isDefined(varName): varKind = self.symbolTable.kindOf(varName) self.vmWriter.writePush(varKind, self.symbolTable.indexOf(varName)) self.compileExpression() self.printToken() #Should print ']' self.vmWriter.writeArithmetic("add") segment = "that" index = 0 else: raise Exception("Symbol " + varName + " is not defined") if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print '=' else: #If it goes down this path this is just a regular variable not an array varKind = self.symbolTable.kindOf(varName) segment = varKind index = self.symbolTable.indexOf(varName) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() print("compileLet - after equals " + self.tokenizer.currentToken) self.compileExpression() if isArray: self.vmWriter.writePop("temp", 0) self.vmWriter.writePop("pointer", VMWriter.THAT_POINTER) self.vmWriter.writePush("temp", 0) self.vmWriter.writePop(segment, index) self.printToken() #print ";" if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</letStatement>") def compileWhile(self): from JackTokenizer import JackTokenizer self.writeFormatted("<whileStatement>") self.indentLevel += 1 self.labelNum += 1 firstLabel = "W" + str(self.labelNum) self.labelNum += 1 secondLabel = "W" + str(self.labelNum) if not(self.tokenizer.tokenType == JackTokenizer.KEYWORD and self.tokenizer.keyWord() == "while"): raise Exception("'while' keyword was expected") self.printToken() #print 'while' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #print '(' self.vmWriter.writeLabel(firstLabel) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileExpression() self.vmWriter.writeArithmetic("not") self.vmWriter.writeIf(secondLabel) self.printToken() #print ')' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #print '{' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileStatements() self.vmWriter.writeGoto(firstLabel) self.printToken() #print '}' self.vmWriter.writeLabel(secondLabel) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</whileStatement>") def compileReturn(self): from JackTokenizer import JackTokenizer self.writeFormatted("<returnStatement>") self.indentLevel += 1 if self.tokenizer.keyWord() != "return": raise Exception("'return' keyword was expected") self.printToken() #print 'return' keyword if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() if not(self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() == ";"): self.compileExpression() else: #When the function's return type is void it should always return 0 self.vmWriter.writePush("constant", 0) self.printToken() #print ";" self.vmWriter.writeReturn() if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</returnStatement>") def compileIf(self): from JackTokenizer import JackTokenizer self.writeFormatted("<ifStatement>") self.indentLevel += 1 trueLabel = "IF-TRUE" + str(self.labelNum) falseLabel = "IF-FALSE" + str(self.labelNum) endLabel = "END-IF" + str(self.labelNum) self.labelNum += 1 if self.tokenizer.keyWord() != "if": raise Exception("'if' keyword was expected") self.printToken() #print 'if' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #print '(' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileExpression() self.printToken() #print ')' self.vmWriter.writeIf(trueLabel) self.vmWriter.writeGoto(falseLabel) self.vmWriter.writeLabel(trueLabel) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #print '{' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileStatements() self.printToken() #print '}' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() if self.tokenizer.tokenType == JackTokenizer.KEYWORD and self.tokenizer.keyWord() == "else": self.vmWriter.writeGoto(endLabel) self.vmWriter.writeLabel(falseLabel) self.printToken() #print 'else' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #print '{' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileStatements() self.printToken() #print '}' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.vmWriter.writeLabel(endLabel) else: #In this case the if statement doesn't have an else so we #don't need the end label self.vmWriter.writeLabel(falseLabel) self.indentLevel -= 1 self.writeFormatted("</ifStatement>") def compileExpression(self): from JackTokenizer import JackTokenizer #There are 2 symbol arrays which each correspond to a different array with #the commands/functions to call for the given operator in the same index functionSymbols = [ '*', '/'] functionNames = ["Math.multiply", "Math.divide"] builtInCommands = ["add", "sub", "and", "or", "lt", "gt", "eq"] builtInSymbols = ['+', '-', '&', '|', '<', '>', '='] self.writeFormatted("<expression>") self.indentLevel += 1 print("About to call compile term current token is " + self.tokenizer.currentToken) self.compileTerm() while(self.tokenizer.tokenType == JackTokenizer.SYMBOL and (self.tokenizer.symbol() in builtInSymbols or self.tokenizer.symbol() in functionSymbols)): self.printToken() operator = self.tokenizer.symbol() print("Current operator " + self.tokenizer.currentToken) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileTerm() if operator in builtInSymbols: self.vmWriter.writeArithmetic(builtInCommands[builtInSymbols.index(operator)]) else: #Both multiply and divide take two arguments self.vmWriter.writeCall(functionNames[functionSymbols.index(operator)], 2) self.indentLevel -= 1 self.writeFormatted("</expression>") def compileTerm(self): from JackTokenizer import JackTokenizer from VMWriter import VMWriter print("Opening token is " + self.tokenizer.currentToken) unaryOps = ['-', '~'] unaryCommands = ["neg", "not"] self.writeFormatted("<term>") self.indentLevel += 1 self.printToken() if self.tokenizer.tokenType == JackTokenizer.IDENTIFIER: name = self.tokenizer.identifier() self.tokenizer.advance() print("second token in IDENTIFIER " + self.tokenizer.currentToken) if self.tokenizer.tokenType == JackTokenizer.SYMBOL: if self.tokenizer.symbol() == ".": if self.symbolTable.isDefined(name): self.writeVarInfo(name, True) else: self.writeClassOrSubInfo("class", True) self.printToken() #Should print '.' self.tokenizer.advance() self.printToken() #Should print subroutine name subName = self.tokenizer.identifier() self.tokenizer.advance() self.printToken() #Should print '(' #If the subroutine is a method call we must first push the object before #pushing the rest of the arguments if self.symbolTable.isDefined(name): self.vmWriter.writePush(self.symbolTable.kindOf(name), self.symbolTable.indexOf(name)) self.numExpressions = 0 self.tokenizer.advance() self.compileExpressionList() self.printToken() #Should print ')' if self.symbolTable.isDefined(name): #Must add 1 to the number of arguments since we pushed the object that the method is operating on self.vmWriter.writeCall(self.symbolTable.typeOf(name) + "." + subName, self.numExpressions + 1) else: self.vmWriter.writeCall(name + "." + subName, self.numExpressions) self.tokenizer.advance() elif self.tokenizer.symbol() == "(": self.printToken() self.writeClassOrSubInfo("subroutine", True) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.vmWriter.writePush("pointer", VMWriter.THIS_POINTER) self.compileExpressionList() self.numExpressions += 1 self.printToken() #Print ')' self.vmWriter.writeCall(self.className + "." + name, self.numExpressions) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() elif self.tokenizer.symbol() == "[": self.writeVarInfo(name, True) self.printToken() self.vmWriter.writePush(self.symbolTable.kindOf(name), self.symbolTable.indexOf(name)) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.compileExpression() self.printToken() #Should print ']' self.vmWriter.writeArithmetic("add") self.vmWriter.writePop("pointer", VMWriter.THAT_POINTER) self.vmWriter.writePush("that", 0) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() else: self.vmWriter.writePush(self.symbolTable.kindOf(name), self.symbolTable.indexOf(name)) self.writeVarInfo(name, True) elif self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() == "(": self.tokenizer.advance() print("second token in (expression)" + self.tokenizer.currentToken) self.compileExpression() self.printToken() #print ')' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() elif self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() in unaryOps: op = self.tokenizer.symbol() self.tokenizer.advance() print("second token in unary " + self.tokenizer.currentToken) self.compileTerm() self.vmWriter.writeArithmetic(unaryCommands[unaryOps.index(op)]) elif self.tokenizer.tokenType == JackTokenizer.INT_CONST: self.vmWriter.writePush("constant", self.tokenizer.intVal()) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() elif self.tokenizer.currentToken in CompilationEngine.keywordConsts: if self.tokenizer.keyWord() == "null" or self.tokenizer.keyWord() == "false": self.vmWriter.writePush("constant", 0) elif self.tokenizer.keyWord() == "true": self.vmWriter.writePush("constant", 1) self.vmWriter.writeArithmetic("neg") #Value of true is -1 elif self.tokenizer.keyWord() == "this": self.vmWriter.writePush("pointer", VMWriter.THIS_POINTER) else: raise Exception("Invalid keyword constant " + self.tokenizer.keyWord()) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() elif self.tokenizer.tokenType == JackTokenizer.STRING_CONST: self.vmWriter.writePush("constant", len(self.tokenizer.stringVal())) self.vmWriter.writeCall("String.new", 1) for char in self.tokenizer.stringVal(): self.vmWriter.writePush("constant", ord(char)) self.vmWriter.writeCall("String.appendChar", 2) if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() else: raise Exception("Invalid term provided") print("The current token is " + self.tokenizer.currentToken) self.indentLevel -= 1 self.writeFormatted("</term>") def compileExpressionList(self): from JackTokenizer import JackTokenizer self.writeFormatted("<expressionList>") self.indentLevel += 1 self.numExpressions = 0 #The number of expressions in this list #I sort of feel guilty for doing this since this relies on knowing that #the expression list is surrounded by parenthesis and according to the spec #it should not know that (it would require modifying this message if I wanted to use an expression list anywhere else). #However, also according to the spec I should create a <subroutineCall> XML element or I shouldn't depending #on which part of the spec you trust. while not(self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() == ")"): self.compileExpression() self.numExpressions += 1 if self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() == ",": self.printToken() #print ',' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.indentLevel -= 1 self.writeFormatted("</expressionList>") def compileSubroutineCall(self): from JackTokenizer import JackTokenizer from VMWriter import VMWriter self.printToken() #Should print either the subroutine name or the class/object the #subroutine is a member of firstToken = self.tokenizer.currentToken secondToken = "" isClassOrObj = False if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print '.' or '(' if self.tokenizer.tokenType == JackTokenizer.SYMBOL and self.tokenizer.symbol() == ".": isClassOrObj = True if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print subroutine name secondToken = self.tokenizer.currentToken if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() self.printToken() #Should print opening '(' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() #If the subroutine is a method call we must first push the object before #pushing the rest of the arguments if secondToken != "" and self.symbolTable.isDefined(firstToken): self.vmWriter.writePush(self.symbolTable.kindOf(firstToken), self.symbolTable.indexOf(firstToken)) if secondToken == "": self.vmWriter.writePush("pointer", VMWriter.THIS_POINTER) self.compileExpressionList() self.printToken() #Should print ')' if self.tokenizer.hasMoreTokens(): self.tokenizer.advance() if secondToken != "": if self.symbolTable.isDefined(firstToken): callName = self.symbolTable.typeOf(firstToken) + "." + secondToken self.numExpressions += 1 else: callName = firstToken + "." + secondToken else: self.numExpressions += 1 callName = self.className + "." + firstToken self.vmWriter.writeCall(callName, self.numExpressions) if isClassOrObj and self.symbolTable.isDefined(firstToken): self.writeVarInfo(firstToken, True) #Writing information about an object elif isClassOrObj: self.writeClassOrSubInfo("class", True) #Writing information about a class self.writeClassOrSubInfo("subroutine", True) def printToken(self): from JackTokenizer import JackTokenizer if self.tokenizer.tokenType == JackTokenizer.KEYWORD: self.writeFormatted("<keyword>" + self.tokenizer.keyWord() + "</keyword>") elif self.tokenizer.tokenType == JackTokenizer.SYMBOL: self.writeFormatted("<symbol>" + self.tokenizer.symbol() + "</symbol>") elif self.tokenizer.tokenType == JackTokenizer.IDENTIFIER: self.writeFormatted("<identifier>" + self.tokenizer.identifier() + "</identifier>") elif self.tokenizer.tokenType == JackTokenizer.INT_CONST: self.writeFormatted("<integerConstant>" + self.tokenizer.intVal() + "</integerConstant>") elif self.tokenizer.tokenType == JackTokenizer.STRING_CONST: self.writeFormatted("<stringConstant>" + self.tokenizer.stringVal() + "</stringConstant>") def writeFormatted(self, string): self.outputFile.write(" " * self.indentLevel + string + "\n") def writeVarInfo(self, varName, inUse): from SymbolTable import SymbolTable self.writeFormatted("<IdentifierInfo>") self.indentLevel += 1 self.writeFormatted("<type>" + self.symbolTable.typeOf(varName) + "</type>") self.writeFormatted("<kind>" + self.symbolTable.stringKindOf(varName) + "</kind>") self.writeFormatted("<index>" + str(self.symbolTable.indexOf(varName)) + "</index>") self.writeFormatted("<inUse>" + str(inUse) + "</inUse>") self.indentLevel -= 1 self.writeFormatted("</IdentifierInfo>") def writeClassOrSubInfo(self, kind, inUse): self.writeFormatted("<IdentifierInfo>") self.indentLevel += 1 self.writeFormatted("<kind>" + kind + "</kind>") self.writeFormatted("<inUse>" + str(inUse) + "</inUse>") self.indentLevel -= 1 self.writeFormatted("</IdentifierInfo>")