Exemple #1
0
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()