def gen_asm(self): """ returns a list of 'Instruction' and 'JumpFlag' """ jump_id = Memory.gen_jump_name() inst = [Instruction("BRA", jump=jump_id, comment="jump over memory")] for idx, m in enumerate(self.memory): ref = self.memory[m] i = Instruction("MEM", adr=ref["value"], comment="<{0}>".format(m)) inst.append(i) # Update the memory table so that we can use it # as a lookup table with for it's location in the file. # # Memory is always the first thing in the file, so # we can safely say the first index + 1 (jump over the BRA instruction) # will make it align properly. # ref["line"] = idx + 1 self.memory[m] = ref inst.append(JumpFlag(jump_id)) return inst
def visit_Assign(self, node): if isinstance(node.value, ast.Dict): variable = self.fp.get_variable(node.targets[0].id, True) variable.type = 'map' if len(variable.value) == 0: variable.value = {} # if self.context is None: # variable.isGlobal = True self.fp.add_variable(variable) elif isinstance(node.targets[0], ast.Subscript): # assign to map item gv = self.fp.new_guard_variable() inst = Instruction( self.guardStack[-1], [self.visit(node.value), self.visit(node.targets[0])], [gv], 'neq') self.fp.add_instruction(inst) self.guardStack.append(gv) var = self.fp.new_variable() inst = Instruction(self.guardStack[-1], [ self.fp.get_variable(node.targets[0].value.id), self.visit(node.targets[0].slice.value) ], [var], 'varof') self.fp.add_instruction(inst) inst = Instruction(self.guardStack[-1], [self.fp.get_variable(node.value.id)], [var], 'assign') self.fp.add_instruction(inst) self.guardStack.pop() else: var = self.fp.get_variable(node.targets[0].id, True) inst = Instruction(self.guardStack[-1], [self.visit(node.value)], [var], 'assign') self.fp.add_instruction(inst)
def gen_runtime_expression(self, tokens, memory, functions=None, *, result_var=None): rpn_notation = self._apply_shunting_yard(tokens, None, substitute_vars=False) stack = Stack() asm = AsmExpressionContainer(tokens) # print("rpn_notation: " + str([str(t.value) for t in rpn_notation])) # debug temp = Memory.gen_temp_name() memory.add_reference(temp) for t in rpn_notation: if t.token == TokenType.Identifier: stack.push(t) elif self._is_operator(t): # take N arguments off the stack # TODO: Expand to include functions var2 = stack.pop() var1 = stack.pop() if var1.value.isdigit(): #var1.token == TokenType.IntValue: var1_name = Memory.gen_temp_name() memory.add_reference(var1_name, var1.value) else: var1_name = var1.value if var2.value.isdigit(): #.token == TokenType.IntValue: var2_name = Memory.gen_temp_name() memory.add_reference(var2_name, var2.value) else: var2_name = var2.value if t.token == TokenType.Add: asm.load(var1_name) asm.add(Instruction("ADD", variable=var2_name)) asm.store(temp) elif t.token == TokenType.Sub: asm.load(var1_name) asm.add(Instruction("SUB", variable=var2_name)) asm.store(temp) stack.push(Token(temp, TokenType.Identifier)) else: print("ERROR: " + token.value) asm.load(temp) asm.store(result_var) return asm
def visit_Return(self, node): ret_val = self.fp.get_variable('return') if ret_val is None: ret_val = self.fp.new_variable('return') if isinstance(node.value, ast.Subscript): inst = Instruction(self.guardStack[-1], [ self.fp.get_variable(node.value.value.id), self.visit(node.value.slice.value) ], [ret_val], 'varof') else: inst = Instruction(self.guardStack[-1], [self.visit(node.value)], [ret_val], 'assign') self.fp.add_instruction(inst)
def visit_Subscript(self, node): var = self.fp.new_variable() inst = Instruction(self.guardStack[-1], [ self.fp.get_variable(node.value.id), self.visit(node.slice.value) ], [var], 'varof') self.fp.add_instruction(inst) return var
def _handle_if(self, ex): # skip the identifier and the '=' char relevant_tokens = ex.tokens[2:len(ex.tokens) - 1] asm = AsmExpressionContainer(ex) result_var = "" if len(relevant_tokens) == 1 and relevant_tokens[0].token == TokenType.Identifier \ and not relevant_tokens[0].value.isdigit(): # single token with a value, should be dynamic #print("IT'S AN IDENTIFIER") var_name = str(relevant_tokens[0].value) result_var = var_name #self.mem.add_reference(temp, self.mem.get_reference(relevant_tokens[0].value)) else: temp = Memory.gen_temp_name() #val = int(self.solver.solve_expr(ex.tokens[2:len(ex.tokens)-1], self.mem, None)) #ex.value = val #var_name = add_mem_ref(val) if len(relevant_tokens) == 1 and relevant_tokens[0].value.isdigit( ): # one token that is an int value self.mem.add_reference(temp, relevant_tokens[0].value) elif len(relevant_tokens) == 1 and self.mem.has_reference( relevant_tokens[0].value): # one token that is an identifier #self.mem.add_reference(temp, self.mem.get_reference(relevant_tokens[0].value)) temp = relevant_tokens[0].value else: # several tokens, let's solve it self.mem.add_reference(temp) instructions = self.solver.gen_runtime_expression( relevant_tokens, self.mem, result_var=temp) asm.merge(instructions) result_var = temp asm.load(result_var) #print("a.load(var_name); == " + var_name) jp_name = Memory.gen_jump_name() #asm.load(temp) asm.add(Instruction("BRZ", jump=jp_name, comment="jump if zero")) for e in ex.expressions: ae = self._handle_expr(e) if ae is not None: asm.asm_expressions.append(ae) for aa in asm.asm_expressions: instrs = aa.get_instructions() for i in instrs: asm.add(i) asm.add(JumpFlag(jp_name)) return asm
def visit_If(self, node): gv = self.fp.new_guard_variable() mapping = self.get_mapping(node.test.ops[0]) inst = Instruction( self.guardStack[-1], [self.visit(node.test.left), self.visit(node.test.comparators[0])], [gv], mapping) self.fp.add_instruction(inst) self.guardStack.append(gv) for b in node.body: self.visit(b) o = self.guardStack.pop() if len(node.orelse) > 0: elsegv = self.fp.new_guard_variable() inst = Instruction(self.guardStack[-1], [o], [elsegv], 'not') self.fp.add_instruction(inst) self.guardStack.append(elsegv) self.visit(node.orelse[0]) self.guardStack.pop()
def visit_Call(self, node): if isinstance(node.func, ast.Attribute): if node.func.attr == 'insert': gv = self.fp.new_guard_variable() var = self.fp.new_variable() inst = Instruction( self.guardStack[-1], [self.visit(node.func.value), self.visit(node.args[0])], [var], 'varof') self.fp.add_instruction(inst) inst = Instruction(self.guardStack[-1], [var, self.visit(node.args[1])], [gv], 'neq') self.fp.add_instruction(inst) self.guardStack.append(gv) inst = Instruction(self.guardStack[-1], [ self.fp.get_variable('pkt'), self.fp.get_variable('inport') ], [var], 'toController') self.fp.add_instruction(inst) self.guardStack.pop() elif node.func.attr == 'lpm': var = self.fp.new_variable() inst = Instruction(self.guardStack[-1], [ self.fp.get_variable(node.func.value.id, True), self.visit(node.args[0]) ], [var], 'lpmvarof') self.fp.add_instruction(inst) return var else: var = self.fp.new_variable() args = [] for arg in node.args: args.append(self.visit(arg)) inst = Instruction(self.guardStack[-1], args, [var], node.func.id) self.fp.add_instruction(inst) return var
def _handle_func_call(self, ex): # TODO: function lookup table with arument count and such # cause right now all we have is "print" and "read" identifier = str(ex.tokens[2].value) a = AsmExpressionContainer(ex) name = str(ex.tokens[0].value) if name == "print": # identifier is a constant # so we just print it if identifier.isdigit(): temp = Memory.gen_temp_name() self.mem.add_reference(temp, identifier) a.load(temp) a.do_print() else: a.load(identifier) a.do_print() elif name == "read": a.do_read() if self.mem.has_reference(identifier): temp = Memory.gen_temp_name() self.mem.add_reference(temp) a.add(Instruction("STA", variable=temp, comment="store input")) a.add( Instruction("LDA", variable=temp, comment="variable 're-assignment'")) a.add(Instruction("STA", variable=identifier)) else: print("im so done with this shit") return a
def visit_FunctionDef(self, node): if node.name == 'on_packet': for arg in node.args.args: variable = Variable(arg.arg) self.fp.add_variable(variable) gv = self.fp.new_guard_variable() var = self.visit(node.args.args[1].annotation) inst = Instruction(self.guardStack[-1], [self.fp.new_variable('inport_label'), var], [gv], 'eq') self.fp.add_instruction(inst) self.guardStack.append(gv) self.generic_visit(node) self.guardStack.pop()
def _parse(self, tokens): exprs = self._parse_expr_recursive(tokens) asm_list = [] # AsmExpression for ex in exprs: asm_expr = self._handle_expr(ex) if Utils.check_none_critical(asm_expr): Utils.debug("Compiler Error!: 'asm_expr' cannot be None.") asm_list.append(asm_expr) g = [] mem_asm = self.mem.gen_asm() g.extend(mem_asm) # get the rest of the instructions for expr in asm_list: g.extend(expr.get_instructions()) g.append(Instruction("HLT", comment="exit")) print("\nDebug preview:\n") for idx, gg in enumerate(g): print(str(idx) + ": " + str(gg)) instructions = self._merge_jumps(g) instructions = self.mem.bind_mem(instructions) if instructions is None: print("Critical Error!: Memory bindings.") return None instructions = self._bind_jumps(instructions) if Utils.check_none_critical(instructions): print("Critical Error!: Jump bindings.") return None assembly = "\n".join([a.asm() for a in instructions]) print("\nCompiled:\n") for idx, gg in enumerate(instructions): print(str(idx) + ": " + str(gg)) return [], assembly
def _handle_assignment(self, ex): """ if the identifier does not exist, create a reference, solve the expression with the 'result_var' set to this identifier. if the identifier exists, create a temp reference to add the expression result into, then add the instructions to move the temp result variable into the reference. """ identifier = str(ex.tokens[0].value) # skip the identifier and the '=' char relevant_tokens = ex.tokens[2:] asm = AsmExpressionContainer(ex) # reference does not exist if not self.mem.has_reference(identifier): if len(relevant_tokens) == 1 and relevant_tokens[0].value.isdigit( ): # one token that is an int value self.mem.add_reference(identifier, relevant_tokens[0].value) elif len(relevant_tokens) == 1 and self.mem.has_reference( relevant_tokens[0].value): # one token that is an identifier self.mem.add_reference( identifier, self.mem.get_reference(relevant_tokens[0].value)) else: # several tokens, let's solve it self.mem.add_reference(identifier) instructions = self.solver.gen_runtime_expression( relevant_tokens, self.mem, result_var=identifier) asm.merge(instructions) # reference exists else: temp = Memory.gen_temp_name() #self.mem.add_reference(temp) if len(relevant_tokens) == 1 and relevant_tokens[0].value.isdigit( ): # one token that is an int value self.mem.add_reference(temp, relevant_tokens[0].value) elif len(relevant_tokens) == 1 and self.mem.has_reference( relevant_tokens[0].value): # one token that is an identifier self.mem.add_reference( temp, self.mem.get_reference(relevant_tokens[0].value)) else: # several tokens, let's solve it self.mem.add_reference(temp) instructions = self.solver.gen_runtime_expression( relevant_tokens, self.mem, result_var=temp) asm.merge(instructions) # the 'temp' variabel may be loaded in the # AC, but just to be sure we do it again. asm.add( Instruction("LDA", variable=temp, comment="variable 're-assignment'")) asm.add(Instruction("STA", variable=identifier)) return asm