def _token_from_name(token_string:str, table:SymbolTable, line_number:int=None) -> Token: """Returns the correct token from the name """ if table.is_keyword(token_string): token_id = "keyword" elif table.is_operator(token_string): token_id = "operator" elif table.is_constant(token_string): token_id = "constant" elif token_string[0].lower() == "r": token_id = "identifier" else: token_id = "label" return Token(token_id, token_string, line_number=line_number)
def __init__(self, tokenizer): """ Creates a new compilation engine with the given tokenizer. """ if not tokenizer or not tokenizer.filename: raise TypeError('Tokenizer not valid.') filename = re.sub('.jack$', '.vm', tokenizer.filename) self.tokenizer = tokenizer self.vm_writer = VMWriter(filename) self.symbol_table = SymbolTable(filename) self.classname = self.get_classname(filename) self.tokenizer.seperate_all() # Different keywords and operators partition to digest # the structure of program. self.class_var_dec = ['static', 'field'] self.subroutines = ['constructor', 'function', 'method'] self.statements = ['let', 'do', 'if', 'while', 'return'] self.ops = ['+', '-', '*', '/', '&', '|', '<', '>', '='] self.unary_ops = ['~', '-'] # Determines the current subroutine in use. self.current_fn_type = None self.current_fn_name = None self.if_idx = 0 self.while_idx = 0 self.verbal_arithemtic = { '>': 'GT', '<': 'LT', '=': 'EQ', '|': 'OR', '-': 'SUB', '+': 'ADD', '&': 'AND' } self.verbal_unary = {'~': 'NOT', '-': 'NEG'}
def __init__(self): il.Symbol.IDC = 0 il.Type.IDC = 0 self.fcount = 0 self.tcount = 0 self.bcount = 0 self.blocks = dict() self.functions = dict() self.fstack = list() self.objs = SymbolTable()
def test_pushpop(): table = SymbolTable() t1 = Symbol("t1", Int(0, 1)) t2_1 = Symbol("t2", Int(0, 2)) t3 = Symbol("t3", Int(0, 3)) t2_2 = Symbol("t2", Int(0, 4)) t4_1 = Symbol("t4", FuncPointer(0, 5)) t4_2 = Symbol("t4", FuncPointer(0, 6)) t5 = Symbol("t5", FuncPointer(0, 7)) table.add(t1) table.add(t2_1) assert table == {"t1": t1, "t2": t2_1} table = table.push() assert table == {"t1": t1, "t2": t2_1} table.update({"t3": t3, "t2": t2_2}) assert table == {"t1": t1, "t3": t3, "t2": t2_2} table = table.push() assert table == {"t1": t1, "t3": t3, "t2": t2_2} table.update({"t4": t4_1}) assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table = table.push() assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table.update({"t4": t4_2, "t5": t5}) assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_2, "t5": t5} table = table.pop() assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table = table.pop() assert table == {"t1": t1, "t3": t3, "t2": t2_2} table = table.pop() assert table == {"t1": t1, "t2": t2_1} assert_raises(Exception, table.pop)
class CompilationEngine: """ Recursive top-down compilation engine for the Jack langauge. Using a Tokenizer object, this module will process different Jack tokens and compile it to VM code using the VMWriter. While at it, invalid Jack syntax will raise SyntaxError. """ def __init__(self, tokenizer): """ Creates a new compilation engine with the given tokenizer. """ if not tokenizer or not tokenizer.filename: raise TypeError('Tokenizer not valid.') filename = re.sub('.jack$', '.vm', tokenizer.filename) self.tokenizer = tokenizer self.vm_writer = VMWriter(filename) self.symbol_table = SymbolTable(filename) self.classname = self.get_classname(filename) self.tokenizer.seperate_all() # Different keywords and operators partition to digest # the structure of program. self.class_var_dec = ['static', 'field'] self.subroutines = ['constructor', 'function', 'method'] self.statements = ['let', 'do', 'if', 'while', 'return'] self.ops = ['+', '-', '*', '/', '&', '|', '<', '>', '='] self.unary_ops = ['~', '-'] # Determines the current subroutine in use. self.current_fn_type = None self.current_fn_name = None self.if_idx = 0 self.while_idx = 0 self.verbal_arithemtic = { '>': 'GT', '<': 'LT', '=': 'EQ', '|': 'OR', '-': 'SUB', '+': 'ADD', '&': 'AND' } self.verbal_unary = {'~': 'NOT', '-': 'NEG'} def compile_class(self): """ Compiles a complete class. """ if not self.tokenizer.has_more_tokens(): raise SyntaxError('No tokens available to compile.') # Advance to the first token. self.tokenizer.advance() self.process('class') self.get_token() # class name self.process('{') # Reached a variable declaration or a subroutine, # there might be more than one. while self.tokenizer.current_token in self.class_var_dec: self.compile_class_var_dec() # Keep on writing subroutines until end of class. while self.tokenizer.current_token in self.subroutines: self.compile_subroutine_dec() # Validates the closing bracket of a class. self.process('}') self.vm_writer.close() def compile_class_var_dec(self): """ Compiles a static variable declaration, or a field declaration. """ kind = self.get_token() type = self.get_token() # Iterate tokens until reaching a command break (';'). while self.tokenizer.current_token != ';': name = self.get_token() self.symbol_table.define(name, type, kind) if self.tokenizer.current_token == ',': self.process() self.process(';') def compile_subroutine_dec(self): """ Compiles a complete method, function, or constructor. """ self.current_fn_type = self.get_token( ) # static function, method or constructor. self.current_fn_return = self.get_token() # void or type. self.current_fn_name = self.get_token() # name of the subroutine. # Reset symbol table for current scope. self.symbol_table.start_subroutine() if self.current_fn_type == 'method': # The type of 'this' is the class name (for exmaple, 'Point'). self.symbol_table.define('this', self.classname, 'arg') # Parameters list, e.g, (int Ax, int Ay, int Asize) self.process('(') self.compile_parameter_list() self.process(')') # Subroutine body self.compile_subroutine_body() def compile_parameter_list(self): """ Compiles a (possibly empty) parameter list. """ while self.tokenizer.current_token != ')': type = self.get_token() name = self.get_token() self.symbol_table.define(name, type, 'arg') if self.tokenizer.current_token == ',': self.process() def compile_subroutine_body(self): """ Compiles a subroutine's body. """ self.process('{') # Before proceeding to the routine's statements, # check if there are any variable declarations. while self.tokenizer.current_token not in self.statements: self.compile_var_dec() # Ouput the subroutine's declaration VM code. subroutine_name = '{}.{}'.format(self.classname, self.current_fn_name) nlocals = self.symbol_table.var_count('var') self.vm_writer.write_function(subroutine_name, nlocals) # Constructors require allocating memory to object fields. if self.current_fn_type == 'constructor': nargs = self.symbol_table.var_count('field') self.vm_writer.write_push('constant', nargs) self.vm_writer.write_call('Memory.alloc', 1) self.vm_writer.write_pop('pointer', 0) # THIS = argument 0 for class methods. if self.current_fn_type == 'method': self.vm_writer.write_push('argument', 0) self.vm_writer.write_pop('pointer', 0) # The subroutine body contains statements. For example, # let x = Ax; let statement # do draw(); do statement # return x; return statement self.compile_statements() self.process('}') def compile_var_dec(self): """ Compiles a var declaration. """ kind = self.get_token() type = self.get_token() while self.tokenizer.current_token != ';': name = self.get_token() self.symbol_table.define(name, type, kind) if self.tokenizer.current_token == ',': self.process(',') self.process(';') def compile_statements(self): """ Compiles a sequence of statements. """ # Write statements until ending closing bracket of parent subroutine. while self.tokenizer.current_token != '}': # Explicitly validate statement statement = self.get_token() if statement not in self.statements: s = ', '.join(self.statements) raise SyntaxError('Statement should start with one of ' + s) # Compile full statement. method = getattr(self, 'compile_' + statement) method() def compile_let(self): """ Compiles a let statement. """ if self.tokenizer.current_type != 'IDENTIFIER': raise SyntaxError('Let statement must proceed with an identifier.') identifier = self.get_token() index = self.get_index(identifier) segment = self.get_kind(identifier) # Placement might be an array entring. if self.tokenizer.current_token == '[': self.compile_array_entry() self.vm_writer.write_push(segment, index) self.vm_writer.write_arithmetic('ADD') self.vm_writer.write_pop('TEMP', 0) self.process('=') self.compile_expression() self.vm_writer.write_push('TEMP', 0) self.vm_writer.write_pop('POINTER', 1) self.vm_writer.write_pop('THAT', 0) else: # Regular assignment. self.process('=') self.compile_expression() self.vm_writer.write_pop(segment, index) self.process(';') def compile_do(self): """ Compiles a do statement. """ self.compile_subroutine_invoke() self.vm_writer.write_pop('TEMP', 0) self.process(';') # end of do statement. def compile_subroutine_invoke(self): """ Compiles a subroutine invokation. """ identifier = self.get_token() args_count = 0 # Either a static (outer) class funciton or an instance function call. if self.tokenizer.current_token == '.': self.process('.') subroutine_name = self.get_token() inst_type = self.symbol_table.type_of(identifier) if inst_type: # It's an instance. inst_kind = self.get_kind(identifier) inst_indx = self.get_index(identifier) self.vm_writer.write_push(inst_kind, inst_indx) fn_name = '{}.{}'.format(inst_type, subroutine_name) args_count += 1 # Pass 'this' as an argument. else: # Static function of a class. fn_name = '{}.{}'.format(identifier, subroutine_name) else: # Local method call. fn_name = '{}.{}'.format(self.classname, identifier) args_count += 1 # Pass 'this' as an argument. self.vm_writer.write_push('POINTER', 0) self.process('(') args_count += self.compile_expression_list() self.process(')') self.vm_writer.write_call(fn_name, args_count) def compile_if(self): """ Compiles an if statement, possibly with a trailing else clause. """ self.process('(') self.compile_expression() # E.g., x > 2 self.vm_writer.write_arithmetic('NOT') self.process(')') # End of if condition statement. # if statement body self.process('{') idx = self.if_idx self.if_idx += 1 label_false = '{}.if_false.{}'.format(self.current_fn_name, idx) label_proceed = '{}.{}'.format(self.current_fn_name, idx) self.vm_writer.write_if(label_false) self.compile_statements() self.vm_writer.write_goto(label_proceed) self.process('}') # Lables statements. self.vm_writer.write_label(label_false) if self.tokenizer.current_token == 'else': # We have a proceeding else. self.process('else') self.process('{') self.compile_statements() self.process('}') self.vm_writer.write_label(label_proceed) def compile_while(self): """ Compiles a while statement. """ self.process('(') fn_name = self.current_fn_name idx = self.while_idx self.while_idx += 1 while_start_label = '{}.while_start.{}'.format(fn_name, idx) while_end_label = '{}.while_end.{}'.format(fn_name, idx) self.vm_writer.write_label(while_start_label) self.compile_expression() self.vm_writer.write_arithmetic('NOT') self.process(')') # while's body. self.process('{') self.vm_writer.write_if(while_end_label) self.compile_statements() self.vm_writer.write_goto(while_start_label) self.vm_writer.write_label(while_end_label) self.process('}') # We're done def compile_return(self): """ Compiles a return statement. """ if self.tokenizer.current_token != ';': self.compile_expression() else: # Return VOID. self.vm_writer.write_push('CONSTANT', 0) self.vm_writer.write_return() self.process(';') def compile_expression(self): """ Compiles an expression. """ self.compile_term() while self.tokenizer.current_token in self.ops: op = self.get_token() self.compile_term() # Push is done by compile_term # Explicitly use Math.multiply or Math.divide. if op == '*': self.vm_writer.write_call('Math.multiply', 2) elif op == '/': self.vm_writer.write_call('Math.divide', 2) else: name = self.verbal_arithemtic.get(op) self.vm_writer.write_arithmetic(name) def compile_term(self): """ Compiles a term. If the current token is an identifier, the routine must resolve it into a variable, an array entry, or a subroutine call. A single lookahead token, which may be [, (, or ., suffices to distinguish between the possibilities. Any other token is not part of this term and should not be advanced over. """ current_token = self.tokenizer.current_token token_type = self.get_current_type() if current_token == '(': self.process('(') self.compile_expression() self.process(')') elif self.tokenizer.peek() == '[': arr_identifier = self.get_token() self.compile_array_entry() index = self.get_index(arr_identifier) segment = self.get_kind(arr_identifier) self.vm_writer.write_push(segment, index) self.vm_writer.write_arithmetic('ADD') self.vm_writer.write_pop('POINTER', 1) self.vm_writer.write_push('THAT', 0) elif current_token in self.unary_ops: unary_op = self.get_token() self.compile_term() name = self.verbal_unary.get(unary_op) self.vm_writer.write_arithmetic(name) elif self.peek() in ['.', '(']: self.compile_subroutine_invoke() elif token_type == 'INT_CONST': self._compile_integer() elif token_type == 'STRING_CONST': self._compile_string() elif token_type == 'KEYWORD': self._compile_keyword() else: self._compile_identifier() def _compile_integer(self): """Compiles the current token as an integer.""" token = self.get_token() self.vm_writer.write_push('CONSTANT', abs(token)) if token < 0: self.vm_writer.write_arithmetic('NEG') def _compile_string(self): """Compiles the current token as a string.""" current_token = self.tokenizer.current_token self.vm_writer.write_push('CONSTANT', len(current_token)) self.vm_writer.write_call('String.new', 1) # String assignments are handled using a series of calls # to String.appendChar(c), when c is the integer representing # unicode code point. for c in current_token: self.vm_writer.write_push('CONSTANT', ord(c)) self.vm_writer.write_call('String.appendChar', 2) self.process() # Finished compiling string. def _compile_keyword(self): """Compiles the current token as a keyword.""" current_token = self.get_token() if current_token == 'this': self.vm_writer.write_push('POINTER', 0) return if current_token == 'true': self.vm_writer.write_push('CONSTANT', 1) self.vm_writer.write_arithmetic('NEG') return # null or false. self.vm_writer.write_push('CONSTANT', 0) def _compile_identifier(self): """Compiles the current token as an identifier.""" current_token = self.get_token() index = self.get_index(current_token) segment = self.get_kind(current_token) self.vm_writer.write_push(segment, index) def get_current_type(self): """Returns the type of the current token.""" return self.tokenizer.current_type def compile_expression_list(self): """ Compiles a (possibly empty) comma- separated list of expressions and returns the number of arguments in this expression list. """ args_count = 0 while self.tokenizer.current_token != ')': args_count += 1 self.compile_expression() if self.tokenizer.current_token == ',': self.process(',') return args_count def process(self, string=None): """ A helper routine that validates the current token, and advances to get the next token. """ t = self.tokenizer.current_token if string and t != string: caller = inspect.stack()[1][3] msg = 'Invalid token rasied from {}. Got {} when expected: {}'.format( caller, string, t) raise SyntaxError(msg) if self.tokenizer.has_more_tokens(): self.tokenizer.advance() def get_token(self): """ Helper method to get the current token and advance to the next one. """ token = self.tokenizer.current_token if self.tokenizer.has_more_tokens(): self.tokenizer.advance() return token def peek(self): """Peeks into the toknes deque.""" return self.tokenizer.peek() def compile_array_entry(self): """ A helper routine to compile an array entry. """ self.process('[') self.compile_expression() self.process(']') def is_int(self, input): try: input = int(input) return True except ValueError: return None def get_kind(self, name): """Returns the kind value of a symbol table value.""" segment = self.symbol_table.kind_of(name) segment = segment.lower() if segment == 'field': return 'this' if segment == 'var': return 'local' if segment == 'arg': return 'argument' return segment def get_index(self, name): """Returns the index value of a symbol table value.""" return self.symbol_table.index_of(name) def get_classname(self, filename): """Returns the clean class name.""" return filename.split('/')[-1].split('.')[0] def close(self): """ Closes the vm stream. """ self.vm_writer.close()
class generate(object): def __new__(cls, root, debug=False): self = super(generate, cls).__new__(cls) self.__init__() self.debug = debug self.push_func("main") self.cfunc.scope_depth = 1 entry = self.block() blk = self.Stmts(root, entry) main = self.pop_func() main.entry = entry main.exit = blk if debug: print_blks(self.blocks.values()) print "Functions:" for name, f in sorted(self.functions.iteritems(), key=lambda x: x[0]): print f print print return self.objs, self.blocks, self.functions def __init__(self): il.Symbol.IDC = 0 il.Type.IDC = 0 self.fcount = 0 self.tcount = 0 self.bcount = 0 self.blocks = dict() self.functions = dict() self.fstack = list() self.objs = SymbolTable() def tmp(self): self.tcount += 1 return "t%i" % self.tcount def block(self): self.bcount += 1 name = "b%i" % self.bcount blk = il.Block(name) self.blocks[name] = blk self.cfunc.blks.append(blk) return blk def push_func(self, name=None): self.fcount += 1 if name is None: name = "f%i" % self.fcount self.functions[name] = il.Function(name) self.fstack.append(self.functions[name]) self.cfunc.scope_depth = self.objs.depth + 1 def pop_func(self): return self.fstack.pop() @property def cfunc(self): return self.fstack[-1] def Stmts(self, node, blk): assert node.label == "Stmts" for c in node.children: if c.label == "Assign": self.PreAssign(c) elif c.label == "Var": self.PreVar(c) for c in node.children: # print c.label if c.label == "Assign": blk = self.Assign(c, blk) elif c.label == "Var": blk = self.Var(c, blk) elif c.label == "Call": blk = self.Call(c, None, blk) elif c.label == "Print": blk = self.Print(c, blk) elif c.label == "If": blk = self.If(c, blk) else: raise Exception, c.label return blk def If(self, node, blk): assert node.label == "If" thenblk = self.block() finalblk = self.block() elseblk = None if len(node.children) == 3: elseblk = self.block() blk = self.BooleanExpr(node.children[0], blk, thenblk, elseblk) else: blk = self.BooleanExpr(node.children[0], blk, thenblk, finalblk) thenblk = self.Stmts(node.children[1], thenblk) thenblk.link(finalblk, il.UNCONDITIONAL) thenblk.insts += [il.Inst(il.J, finalblk, 0, 0)] if len(node.children) == 3: # blk.insts += [ il.Inst(il.J, elseblk, 0, 0) ] ## This line must go here. subtle bug elseblk = self.Stmts(node.children[2], elseblk) elseblk.link(finalblk, il.UNCONDITIONAL) elseblk.insts += [il.Inst(il.J, finalblk, 0, 0)] return finalblk def Print(self, node, blk): assert node.label == "Print" c = node.children[0] if c.label == "Expr": result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c, result, blk) else: raise Exception, c.label blk.insts += [il.Inst(il.PRNT, result, 0, 0)] return blk def PreAssign(self, node): assert node.label == "Assign" name = node.children[0] c = node.children[1] if c.label == "Func": s = il.Symbol(name, il.Func(None)) if name in self.objs.myscope: self.objs.add(s) elif name in self.objs: raise TypeError, "Cannot assign a function to a non local var." else: raise TypeError, "Variable name %s not declared." % (name) def PreVar(self, node): assert node.label == "Var" name = node.children[0] if len(node.children) == 2: c = node.children[1] if c.label == "Func": s = il.Symbol(name, il.Func(None)) if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name self.objs.add(s) def Assign(self, node, blk): assert node.label == "Assign" name = node.children[0] c = node.children[1] if name in self.objs: result = self.objs[name] else: raise TypeError, "Use of name %s without prior declaration" % name if c.label == "Expr": if isinstance(result.type, il.Null): result.type = il.Int() blk = self.Expr(c, result, blk, toplevel=True) elif c.label == "Func": if isinstance(result.type, il.Null): result.type = il.Func(None) blk = self.Func(c, name, blk) else: raise Exception, c.label return blk def Var(self, node, blk): assert node.label == "Var" name = node.children[0] if len(node.children) == 1: if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name self.objs.add(il.Symbol(name, il.Null())) else: c = node.children[1] if c.label == "Expr": if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name result = il.Symbol(name, il.Int()) self.objs.add(result) blk = self.Expr(c, result, blk, toplevel=True) elif c.label == "Func": blk = self.Func(c, name, blk) else: raise Exception, c.label return blk def Func(self, node, name, blk): assert node.label == "Func" parent_blk = blk self.push_func() blk = self.block() self.cfunc.entry = blk self.objs[name].type.entry = self.cfunc.name self.objs = self.objs.push() for c in node.children: if c.label == "DParams": blk = self.DParams(node.children[0], blk) elif c.label == "Stmts": blk = self.Stmts(c, blk) elif c.label == "Return": blk = self.Return(c, blk) else: raise Exception, c.label self.cfunc.exit = blk self.objs = self.objs.pop() self.pop_func() return parent_blk def Return(self, node, blk): assert node.label == "Return" if node.children: if node.children[0].label == "Expr": result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(node.children[0], result, blk) blk.insts += [il.Inst(il.OPRM, 0, result, 0)] self.cfunc.oparam_count += 1 else: raise Exception, "Expected Expr got %s" % node.children[0].label blk.insts += [il.Inst(il.RTRN, 0, 0, 0)] return blk def DParams(self, node, blk): assert node.label == "DParams" for i, c in enumerate(node.children): t = il.Symbol(c, il.Int()) self.objs.add(t) self.cfunc.params.append(c) blk.insts += [il.Inst(il.GPRM, i, 0, t)] return blk def Expr(self, node, result, blk, toplevel=False): if node.label == "Expr": c = node.children[0] else: c = node if c.label == "INT": blk = self.Int(c.children[0], result, blk) elif c.label == "/" or c.label == "*" or c.label == "-" or c.label == "+": blk = self.Op(c, result, blk) elif c.label == "NAME": ## If it this is a top level expression (eg. c = a) then ## this is a copy instruction. Otherwise, this is a reference ## instruction, (eg. c = a + 2) ## c = a ## MV A, 0, C ## c = a + 2 ## IMM 2, 0, tmp ## ADD a, tmp, c if toplevel: blk.insts += [il.Inst(il.MV, self.objs[c.children[0]], 0, result)] else: result.clone(self.objs[c.children[0]]) elif c.label == "Call": blk = self.Call(c, result, blk) else: raise Exception, "Unexpected Node %s" % str(c) return blk def BooleanExpr(self, node, blk, thenblk, elseblk): assert node.label == "BooleanExpr" c = node.children[0] return self.BooleanOp(c, blk, thenblk, elseblk) def BooleanOp(self, c, blk, thenblk, elseblk, negate=False): if c.label == "BooleanExpr": return self.BooleanOp(c.children[0], blk, thenblk, elseblk, negate) elif c.label in ["==", "!=", "<", "<=", ">", ">="]: Ar = il.Symbol("r" + self.tmp(), il.Int()) Br = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c.children[0], Ar, blk) blk = self.Expr(c.children[1], Br, blk) inst = self.CmpOp(c, negate) blk.insts += [il.Inst(inst, Ar, Br, thenblk), il.Inst(il.J, elseblk, 0, 0)] blk.link(thenblk, il.TRUE) blk.link(elseblk, il.FALSE) elif c.label in ("Or", "And"): ## the blk become the A expressions block ## we allocate a new blk for B, the previous block is blk a = c.children[0] b = c.children[1] ablk = blk bblk = self.block() op = c.label bresult = self.BooleanOp(b, bblk, thenblk, elseblk, negate) if negate: if op == "Or": op = "And" elif op == "And": op = "Or" if op == "Or": aresult = self.BooleanOp(a, ablk, thenblk, bresult, negate) elif op == "And": aresult = self.BooleanOp(a, ablk, bresult, elseblk, negate) blk = aresult elif c.label == "Not": blk = self.BooleanOp(c.children[0], blk, thenblk, elseblk, not negate) else: raise Exception, "Unexpected Node %s" % c.label return blk def CmpOp(self, node, negate=False): ops = {"==": il.IFEQ, "!=": il.IFNE, "<": il.IFLT, "<=": il.IFLE, ">": il.IFGT, ">=": il.IFGE} ops_ = {"==": il.IFNE, "!=": il.IFEQ, "<": il.IFGE, "<=": il.IFGT, ">": il.IFLE, ">=": il.IFLT} if negate: return ops_[node.label] else: return ops[node.label] def Op(self, node, result, blk): ops = {"/": "DIV", "*": "MUL", "-": "SUB", "+": "ADD"} Ar = il.Symbol("r" + self.tmp(), il.Int()) Br = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(node.children[0], Ar, blk) blk = self.Expr(node.children[1], Br, blk) blk.insts += [il.Inst(il.ops[ops[node.label]], Ar, Br, result)] return blk def Call(self, node, result, blk): assert node.label == "Call" fun = self.objs[node.children[0]] # print self.objs, fun, node.children[0], self.objs['f'] if isinstance(fun.type, il.Int): fun.type = fun.type.cast(il.FuncPointer) # print fun # print repr(fun) if len(node.children) != 1: blk = self.Params(node.children[1], blk) blk.insts += [il.Inst(il.CALL, fun, 0, 0)] if result is not None: blk.insts += [il.Inst(il.RPRM, 0, 0, result)] return blk def Params(self, node, blk): assert node.label == "Params" params = list() for c in node.children: result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c, result, blk) params.append(result) params.reverse() for i, p in enumerate(params): blk.insts += [il.Inst(il.IPRM, len(params) - 1 - i, p, 0)] return blk def Int(self, node, result, blk): blk.insts += [il.Inst(il.IMM, node, 0, result)] return blk