class FuncStat: def __init__(self, block: Block): self.proto = Protocol() self.prev = None self.block = block self.pc = 0 self.number_constant = 0 self.number_active_var = 0 self.number_up_value = 0 # symbol table stack if self.prev is not None: self.symbol_table = SymbolTable(self.prev.symbol_table) else: self.symbol_table = SymbolTable() self.constant_pool = ConstantPool() def get_main_proto(self): if self.prev is None: return self.proto return None def enter_func_stat(self): pass def leave_func_stat(self): pass def generate_opcode(self): self.generate_block(self.block) def generate_block(self, block: Block): self.generate_chuck_stmt(block.chunk) self.proto.add_instruction(Instruction(OpCode.RETURN, 0, 1)) def generate_chuck_stmt(self, chunk: Chunk): for stmt in chunk.stat_arr: self.generate_stmt(stmt) def generate_stmt(self, stmt: Stmt): if stmt.kind is StmtEnum.LOCAL_ASSIGN: self.generate_local_assign(stmt.value) # TODO: other stmt def generate_const(self, term: Terminal): idx = self.constant_pool.add(term) return idx def generate_name(self, register, term: TermName): """ 1) local variable 2) up values 3) top variable :param register: :param term: :return: """ lookup = self.symbol_table.lookup(term.value) # _ENV variable if -1 == lookup.level: # add symbol to constant pool idx = self.constant_pool.add(term) self.proto.add_instruction(Instruction(OpCode.GETTABUP, register, 0, idx)) return register def _back_path(self, lst): pc = self.proto.pc() for p in lst: self.proto.change_instruction(p, Instruction(OpCode.JMP, 0, pc - p + 1)) def generate_login_and_expr(self, register, expr: BinOpExpr): self.generate_expr(register, expr.left) # B1 AND B2 => if B1 = true jump to B2 self.proto.add_instruction(Instruction(OpCode.TEST, register, 0)) # if B1 false jump to end self.proto.add_instruction(Instruction(OpCode.JMP, 0, 0)) jump_index = self.proto.pc() # record left expr false list expr.left.false_list.append(jump_index) self.generate_expr(register, expr.right) # record right expr true list jump_index = self.proto.pc() expr.right.false_list.append(jump_index) def generate_login_or_expr(self, register, expr: BinOpExpr): self.generate_expr(register, expr.left) # B1 or B2 => if B1 = false jump to B2 self.proto.add_instruction(Instruction(OpCode.TEST, register, 1)) # if B1 true jump to end self.proto.add_instruction(Instruction(OpCode.JMP, 0, 0)) # record left expr true list expr.left.true_list.append(self.proto.pc()) self.generate_expr(register, expr.right) # record right expr true list expr.right.true_list.append(self.proto.pc()) def generate_equal_expr(self, register, expr: BinOpExpr): self._generate_equal_expr(register, OpCode.EQ, expr) def generate_not_equal_expr(self, register, expr: BinOpExpr): self._generate_not_equal_expr(register, OpCode.EQ, expr) def generate_less_then_expr(self, register, expr: BinOpExpr): self._generate_equal_expr(register, OpCode.LT, expr) def generate_less_equal_expr(self, register, expr: BinOpExpr): self._generate_equal_expr(register, OpCode.LE, expr) def generate_greater_then_expr(self, register, expr: BinOpExpr): self._generate_not_equal_expr(register, OpCode.LE, expr) def generate_greater_equal_expr(self, register, expr: BinOpExpr): self._generate_not_equal_expr(register, OpCode.LT, expr) def _generate_not_equal_expr(self, register, opcode: OpCode, expr: BinOpExpr): left_reg = self.symbol_table.add_temp_var() self.generate_expr(left_reg, expr.left) right_reg = self.symbol_table.add_temp_var() self.generate_expr(right_reg, expr.right) self.proto.add_instruction(Instruction(opcode, 0, left_reg, right_reg)) self.proto.add_instruction(Instruction(OpCode.JMP, 0, 1)) self.proto.add_instruction(Instruction(OpCode.LOADBOOL, register, 0, 1)) self.proto.add_instruction(Instruction(OpCode.LOADBOOL, register, 1, 0)) def _generate_equal_expr(self, register, opcode: OpCode, expr: BinOpExpr): left_reg = self.symbol_table.add_temp_var() self.generate_expr(left_reg, expr.left) right_reg = self.symbol_table.add_temp_var() self.generate_expr(right_reg, expr.right) self.proto.add_instruction(Instruction(opcode, 1, left_reg, right_reg)) self.proto.add_instruction(Instruction(OpCode.JMP, 0, 1)) self.proto.add_instruction(Instruction(OpCode.LOADBOOL, register, 1, 1)) self.proto.add_instruction(Instruction(OpCode.LOADBOOL, register, 0, 0)) def _generate_binary_common(self, opcode: OpCode, register, binop: BinOpExpr): left_reg = self.generate_expr(register, binop.left) right_reg = self.symbol_table.add_temp_var() right_reg = self.generate_expr(right_reg, binop.right) self.proto.add_instruction(Instruction(opcode, register, left_reg, right_reg)) self.symbol_table.pop_temp_var() return register def generate_binary_expr(self, register, binop: BinOpExpr): if BinOpEnum.ADD == binop.operator: return self._generate_binary_common(OpCode.ADD, register, binop) elif BinOpEnum.SUB == binop.operator: return self._generate_binary_common(OpCode.SUB, register, binop) elif BinOpEnum.MUL == binop.operator: return self._generate_binary_common(OpCode.MUL, register, binop) elif BinOpEnum.DIV == binop.operator: return self._generate_binary_common(OpCode.DIV, register, binop) elif BinOpEnum.XOR == binop.operator: return self._generate_binary_common(OpCode.BXOR, register, binop) elif BinOpEnum.MOD == binop.operator: return self._generate_binary_common(OpCode.MOD, register, binop) elif BinOpEnum.CONCAT == binop.operator: return self._generate_binary_common(OpCode.CONCAT, register, binop) elif BinOpEnum.LT == binop.operator: self.generate_less_then_expr(register, binop) elif BinOpEnum.LTE == binop.operator: self.generate_less_equal_expr(register, binop) elif BinOpEnum.GT == binop.operator: self.generate_greater_then_expr(register, binop) elif BinOpEnum.GTE == binop.operator: self.generate_greater_equal_expr(register, binop) elif BinOpEnum.EQ == binop.operator: self.generate_equal_expr(register, binop) elif BinOpEnum.AND == binop.operator: self.generate_login_and_expr(register, binop) elif BinOpEnum.OR == binop.operator: self.generate_login_or_expr(register, binop) def generate_prefix_expr(self, register, expr: PrefixExpr): if PrefixExpr.VAR == expr.kind: return self.generate_name(register, expr.var.name) return register def generate_expr(self, register, expr: Expr) -> int: res = register if ExprEnum.CONSTANT == expr.kind: res = self.generate_const(expr.value) # self.proto.add_instruction(Instruction(OpCode.LOADK, register, k)) elif ExprEnum.BINOP == expr.kind: if BinOpEnum.AND == expr.value.operator: self.generate_login_and_expr(register, expr.value) expr.false_list = expr.value.left.false_list elif BinOpEnum.OR == expr.value.operator: self.generate_login_or_expr(register, expr.value) expr.true_list = expr.value.left.true_list elif expr.value.operator in [BinOpEnum.GT, BinOpEnum.GTE, BinOpEnum.LT, BinOpEnum.LTE]: self.generate_binary_expr(register, expr.value) else: self.generate_binary_expr(register, expr.value) return register elif ExprEnum.PREFIX == expr.kind: res = self.generate_prefix_expr(register, expr.value) return res def generate_local_assign(self, assign: LocalAssignStmt): left = assign.left.name_list right = assign.right.expr_list # left -- add local variable # for name in left: # right -- calc value and assign to left variable for idx, name in enumerate(left): register = self.symbol_table.insert(name.value, name) # res = self.symbol_table.lookup(name.value) val = right[idx] res = self.generate_expr(register, val) if ExprEnum.BINOP == val.kind and BinOpEnum.AND == val.value.operator: self._back_path(val.false_list) elif ExprEnum.BINOP == val.kind and BinOpEnum.OR == val.value.operator: self._back_path(val.true_list) if res < 0 and (type(self.constant_pool.index(res)) == TermFalse or type(self.constant_pool.index(res)) == TermTrue): self.proto.add_instruction(Instruction(OpCode.LOADBOOL, register, 0 if type(self.constant_pool.index(res)) == TermFalse else 1)) else: # same register not generate opcode if register != res: self.proto.add_instruction(Instruction(OpCode.LOADK, register, res)) # code = Instruction(OpCode.LOADK, res.index, reg_right) # self.add_instruction(code) def print(self): print('--------Instruction array-------') self.proto.print() print('--------symbol stack-------') self.symbol_table.print() print('--------constant pool-------') self.constant_pool.print()