Example #1
0
class CodeGenVisitor(BaseVisitor, Utils):
    def __init__(self, astTree, env, dir_):
        #astTree: AST
        #env: List[Symbol]
        #dir_: File

        self.astTree = astTree
        self.env = env
        self.className = "MCClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")

    # def visitProgram(self, ast, c):
    #     #ast: Program
    #     #c: Any

    #     self.emit.printout(self.emit.emitPROLOG(self.className, "java.lang.Object"))
    #     e = SubBody(None, self.env)
    #     for x in ast.decl:
    #         e = self.visit(x, e)
    #     # generate default constructor
    #     self.genMETHOD(FuncDecl(Id("<init>"), list(), None, Block(list())), c, Frame("<init>", VoidType))
    #     self.emit.emitEPILOG()
    #     return c

    def VarGlobal(self, ast, c):
        ctxt = c
        nameAttr = ast.variable
        typeAttr = ast.varType
        self.emit.printout(
            self.emit.emitATTRIBUTE(nameAttr, typeAttr, False, ""))
        c.append(Symbol(nameAttr, typeAttr, CName(self.className)))
        return c

    def FuncGlobal(self, ast, c):
        ctxt = c
        nameFunc = ast.name.name
        funcsym = Symbol(nameFunc,
                         MType([x.varType for x in ast.param], ast.returnType),
                         CName(self.className))
        c.append(funcsym)
        return c

    def visitProgram(self, ast, c):
        #ast: Program
        #c: Any
        self.emit.printout(
            self.emit.emitPROLOG(self.className, "java.lang.Object"))
        e = SubBody(None, self.env)
        lsVar = list(filter(lambda x: type(x) is VarDecl, ast.decl))
        lsArray = list(filter(lambda x: type(x.varType) is ArrayType, lsVar))
        lsFunction = list(filter(lambda x: type(x) is FuncDecl, ast.decl))
        #print static field and add to self.env
        reduce(
            lambda x, y: self.VarGlobal(y, x)
            if type(y) is VarDecl else self.FuncGlobal(y, x), ast.decl,
            self.env if self.env else [])
        #visit FuncDecl
        reduce(lambda x, y: self.visit(y, x), lsFunction,
               SubBody(None, self.env))

        #generate defaule constructor
        self.genMETHOD(FuncDecl(Id("<init>"), [], None, Block([])), c,
                       Frame("<init>", VoidType))

        # if lsArray:
        #     self.emit.printout(self.emit.emitCLINIT())
        self.emit.emitEPILOG()
        return c

    def genMETHOD(self, consdecl, o, frame):
        #consdecl: FuncDecl
        #o: Any
        #frame: Frame

        isInit = consdecl.returnType is None
        isMain = consdecl.name.name == "main" and len(
            consdecl.param) == 0 and type(consdecl.returnType) is VoidType
        returnType = VoidType() if isInit else consdecl.returnType
        methodName = "<init>" if isInit else consdecl.name.name
        intype = [ArrayPointerType(StringType())
                  ] if isMain else [x.varType for x in consdecl.param]
        mtype = MType(intype, returnType)

        self.emit.printout(
            self.emit.emitMETHOD(methodName, mtype, not isInit, frame))

        frame.enterScope(True)

        glenv = o

        # Generate code for parameter declarations
        if isInit:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "this",
                                  ClassType(self.className),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
        if isMain:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "args",
                                  ArrayPointerType(StringType()),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))

        glSubBody = SubBody(frame, glenv)
        if (isMain is False) and (intype != []):
            glSubBody = reduce(lambda x, y: self.visit(y, x), consdecl.param,
                               SubBody(frame, glenv))

        body = consdecl.body
        lstvardecl = list(filter(lambda x: type(x) is VarDecl, body.member))
        curenv = reduce(lambda x, y: self.visit(y, x), lstvardecl, glSubBody)
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))

        # Generate code for statements
        if isInit:
            self.emit.printout(
                self.emit.emitREADVAR("this", ClassType(self.className), 0,
                                      frame))
            self.emit.printout(self.emit.emitINVOKESPECIAL(frame))

        lststmt = list(filter(lambda x: not type(x) is VarDecl, body.member))
        # list(map(lambda x: self.visit(x, curenv), lststmt))
        list(map(lambda x: self.printoutStmt(x, curenv),
                 lststmt))  #glSubBody after add vardecl in func

        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if type(returnType) is VoidType or (not returnStmt):
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitVarDecl(self, ast, o):
        #ast: VarDecl
        #o  : SubBody
        env = o.sym
        idx = o.frame.getNewIndex()
        self.emit.printout(
            self.emit.emitVAR(idx, ast.variable, ast.varType,
                              o.frame.getStartLabel(), o.frame.getEndLabel(),
                              o.frame))
        return SubBody(o.frame,
                       env.append(Symbol(ast.variable, ast.varType, Index)))

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any

        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.genMETHOD(ast, subctxt.sym, frame)
        return SubBody(None, [
            Symbol(ast.name, MType(list(), ast.returnType),
                   CName(self.className))
        ] + subctxt.sym)

    def visitArrayType(self, ast, c):
        #ast:
        #c : SubBody

        index = self.lookup(ast.variable, c.sym, lambda x: x.name).value.value
        self.emit.printout(self.emit.emitNEWARRAY(ast.varType, c.frame))
        self.emit.printout(
            self.emit.emitWRITEVAR(ast.variable, ast.varType, index, c.frame))
        return SubBody(c.frame, c.sym)

    def visitBlock(self, ast, c):
        ctxt = c
        frame = c.frame
        sym = c.sym
        frame.EnterScope(False)

        lstvar = list(filter(lambda x: type(x) is VarDecl, ast.member))
        varenv = reduce(lambda x, y: self.visit(y, x), lstvar,
                        SubBody(frame, sym))

        listArrayVarDecl = filter(lambda x: type(x) is ArrayType, lstvar)

        self.emit.printout(self.emit.emitLABEL(frame.getNewLabel(), frame))

        list(map(lambda x: self.visitArrayType(x, varenv), listArrayVarDecl))
        lststmt = list(filter(lambda x: not type(x) is VarDecl, ast.member))
        list(map(lambda x: self.printoutStmt(x, varenv), lststmt))

        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()
        return c

    def printoutStmt(self, ast, c):
        frame = c.frame
        env = c.sym
        if type(ast) is BinaryOp:
            if ast.op == '=':
                self.emit.printout(
                    self.visit(ast, Access(frame, env, True, True, False)))
            else:
                self.emit.printout(
                    self.visit(ast, Access(frame, env, False, True, True)))
                self.emit.printout(self.emit.emitPOP(frame))
        elif type(ast) is CallExpr:
            self.emit.printout(
                self.visit(ast, Access(frame, env, False, True, True)))
            sym = self.lookup(ast.method.name, env, lambda x: x.name)
            returnType = sym.mtype.rettype

            if type(returnType) != VoidType:
                self.emit.printout(self.emit.emitPOP(frame))
        elif (type(ast) is UnaryOp) or (type(ast) is Id) or (type(ast) is ArrayCell) or (type(ast) is IntLiteral) or \
                (type(ast) is FloatLiteral) or (type(ast) is StringLiteral) or (type(ast) is BooleanLiteral):

            self.emit.printout(
                self.visit(ast, Access(frame, newEnv, False, True, True))[0])
            self.emit.printout(self.emit.emitPOP(frame))

        elif (type(ast) is Block) or (type(ast) is If) or (type(ast) is For) or (type(ast) is Break) or \
                (type(ast) is Continue) or (type(ast) is Return) or (type(ast) is Dowhile):

            self.visit(ast, env)
        else:
            pass

    # def printoutStmt(self,ast,env):
    #     #env    : SubBody
    #     frame  = env.frame
    #     newEnv = env.sym
    #     if type(ast) is BinaryOp:
    #         if ast.op == "=":
    #             self.emit.printout(self.visit(ast, Access(frame, newEnv, True, True, False))[0])
    #         else:
    #             self.emit.printout(self.visit(ast, Access(frame, newEnv, False, True, True))[0])
    #             self.emit.printout(self.emit.emitPOP(frame))

    #     elif type(ast) is CallExpr:
    #         self.emit.printout(self.visit(ast, Access(frame, newEnv, False, True, True))[0])
    #         sym = self.lookup(ast.method.name, newEnv, lambda x:x.name)
    #         returnType = sym.mtype.rettype

    #         if type(returnType) != VoidType:
    #             self.emit.printout(self.emit.emitPOP(frame))

    #     elif (type(ast) is UnaryOp) or (type(ast) is Id) or (type(ast) is ArrayCell) or (type(ast) is IntLiteral) or \
    #             (type(ast) is FloatLiteral) or (type(ast) is StringLiteral) or (type(ast) is BooleanLiteral):

    #             self.emit.printout(self.visit(ast, Access(frame, newEnv, False, True, True))[0])
    #             self.emit.printout(self.emit.emitPOP(frame))

    #     elif (type(ast) is Block) or (type(ast) is If) or (type(ast) is For) or (type(ast) is Break) or \
    #             (type(ast) is Continue) or (type(ast) is Return) or (type(ast) is Dowhile):
    #                 # NOTE env hay new env vay cha noi
    #             self.visit(ast, env)
    #     else:
    #         pass
    # def visitIf(self,ast,c):
    #     #c  : SubBody
    #     frame = c.frame
    #     env = c.sym
    #     (resExpr, typeExpr) = ast.expr.accept(self, Access(frame, env, False, True, True))
    #     falseLabel = frame.getNewLabel()

    #     self.emit.printout(resExpr + self.emit.emitIFFALSE(falseLabel, frame))
    #     self.printoutStmt(ast.thenStmt, c)
    #     if not ast.elseStmt:
    #         self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
    #     else:
    #         trueLabel = frame.getNewLabel()
    #         self.emit.printout(self.emit.emitGOTO(trueLabel, frame) + self.emit.emitLABEL(falseLabel, frame)
    #                 )
    #         self.printoutStmt(ast.elseStmt, c)
    #         self.emit.printout(self.emit.emitLABEL(trueLabel, frame))
    def visitIf(self, ast, c):
        #c: SubBody
        frame = c.frame
        env = c.sym
        (resExpr, typeExpr) = self.visit(ast,
                                         Access(frame, env, False, True, True))
        falseLabel = frame.getNewLabel()

        self.emit.printout(resExpr + self.emit.emitIFFALSE(falseLabel, frame))
        self.printoutStmt(ast.thenStmt, c)
        if not ast.elseStmt:
            self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
        else:
            exitLabel = frame.getNewLabel()
            self.emit.printout(
                self.emit.emitGOTO(exitLabel, frame) +
                self.emit.emitLABEL(falseLabel, frame))
            self.printoutStmt(ast.elseStmt, c)
            self.emit.printout(self.emit.emitLABEL(exitLabel, frame))

    # def visitFor(self,ast,c):
    #     #c  : SubBody
    #     frame = c.frame
    #     env = c.sym
    #     beginLabel = frame.getNewLabel()
    #     frame.enterLoop()

    #     self.printoutStmt(ast.expr1, SubBody(frame, env))
    #     self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
    #     (resExpr2, typeExpr2) = ast.expr2.accept(self,Access(frame, env, False, True, False))
    #     self.emit.printout(resExpr2)

    #     self.emit.printout(self.emit.emitIFTRUE(frame.getBreakLabel(), frame))
    #     self.printoutStmt(ast.loop, c)

    #     self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
    #     self.printoutStmt(ast.expr3, SubBody(frame, env))

    #     self.emit.printout(self.emit.emitGOTO(beginLabel, frame))
    #     self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))

    #     frame.exitLoop()

    def visitFor(self, ast, c):
        #c = SubBody
        frame = c.frame
        env = c.sym
        beginLabel = frame.getNewLabel()
        frame.enterLoop()
        # visit expr1
        self.printoutStmt(ast.expr1, SubBody(frame, env))
        # label loop
        self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
        #visit expr2
        (resExpr2,
         typeExpr2) = self.visit(ast.expr2,
                                 Access(frame, env, False, True, False))
        self.emit.printout(resExpr2)

        self.emit.printout(self.emit.emitIFTRUE(frame.getBreakLabel(), frame))
        self.printoutStmt(ast.loop, c)

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))  ###??
        self.printoutStmt(ast.expr3, SubBody(frame, env))

        self.emit.printout(self.emit.emitGOTO(beginLabel, frame))
        self.emit.print(self.emit.emitLABEL(frame.getBreakLabel(), frame))

        frame.exitLoop()

    # def visitDowhile(self,ast,c):
    #     #c  : SubBody
    #     frame = c.frame
    #     env = c.sym
    #     beginLabel = frame.getNewLabel()
    #     frame.enterLoop()

    #     self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
    #     list(map(lambda x:self.printoutStmt(x,c) ,ast.sl))

    #     self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))

    #     (resExpr, typeExpr) = ast.exp.accept(self, Access(frame, env, False, True, True))
    #     self.emit.printout(resExpr)
    #     self.emit.printout(self.emit.emitIFTRUE(frame.getBreakLabel(), frame))
    #     self.emit.printout(self.emit.emitGOTO(beginLabel, frame))
    #     self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
    #     frame.exitLoop()

    def visitDowhile(self, ast, c):
        # c  = SubBody
        frame = c.frame
        env = c.sym
        beignLabel = frame.getNewLabel()
        frame.enterLoop()

        self.visit.printout(self.emit.emitLABEL(beignLabel, frame))
        list(map(self.printoutStmt(x, c), ast.sl))

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))  #?

        (resExpr, typeExpr) = self.visit(ast.exp,
                                         Access(frame, env, False, True, True))
        self.emit.printout(resExpr)
        self.emit.printout(self.emit.emitIFTRUE(frame.getBreakLabel(), frame))
        self.emit.printout(self.emit.emitGOTO(beignLabel, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitBreak(self, ast, c):
        self.emit.printout(self.emit.emitGOTO(c.frame.getBreakLabel(),
                                              c.frame))

    def visitContinue(self, ast, c):
        self.emit.printout(
            self.emit.emitGOTO(c.frame.getContinueLabel(), c.frame))

    # def visitReturn(self,ast,c):
    #     if ast.expr:
    #         (resExpr, resType) = self.visit(ast.expr, Access(c.frame, c.sym, False, True, True))
    #         typeFunc = self.curFunc.mtype.rettype
    #         if type(typeFunc) == FloatType and type(resType) == IntType:
    #             self.emit.printout(resExpr + self.emit.emitI2F(c.frame) + self.emit.emitRETURN(FloatType(), c.frame))
    #         else:
    #             self.emit.printout(resExpr + self.emit.emitRETURN(resType, c.frame))
    #     else:
    #         self.emit.printout(self.emit.emitRETURN(VoidType(), c.frame))
    def visitReturn(self, ast, c):
        if ast.expr:
            (resExpr,
             resType) = self.visit(ast.expr,
                                   Access(c.frame, c.sym, False, True, True))
            typeFunc = self.curFunc.mtype.rettype
            if type(typeFunc) == FloatType and type(resType) == IntType:
                self.emit.printout(resExpr + self.emit.emitI2F(c.frame) +
                                   self.emit.emitRETURN(FloatType(), c.frame))
            else:
                self.emit.printout(resExpr +
                                   self.emit.emitRETURN(resType, c.frame))
        else:
            self.emit.printout(self.emit.emitRETURN(VoidType(), c.frame))

    # def visitUnaryOp(self,ast,c):
    #     ctxt = c
    #     frame = ctxt.frame
    #     env = ctxt.sym
    #     (resExpr, typeExpr) = self.visit(ast.body, Access(frame, env, False, True, True))
    #     if ast.op == "!":
    #         return (resExpr + self.emit.emitNOT(typeExpr, frame), typeExpr)
    #     elif ast.op == "-":
    #         return (resExpr + self.emit.emitNEGOP(typeExpr, frame), typeExpr)

    def visitUnaryOp(self, ast, c):
        frame = c.frame
        env = c.sym
        (resExpr, typeExpr) = self.visit(ast.body,
                                         Access(frame, env, False, True, True))

        if ast.op == "!":
            return (resExpr + self.emit.emitNOT(typeExpr, frame), typeExpr)
        elif ast.op == "-":
            return (resExpr + self.emit.emitNEG(typeExpr, frame), typeExpr)

    # def visitBinaryOp(self,ast,c):
    #     #c  : Access (co the la SubBody)
    #     ctxt = c
    #     frame = ctxt.frame
    #     env = ctxt.sym
    #     op = ast.op
    #     op_Str = ""
    #     str_Dup = ""
    #     str_I2f = ""
    #     resType = IntType()

    #     if op == "=":
    #         (resLeft1, typeLeft1) = self.visit(ast.left, Access(frame, env, True, True, False))
    #         (resRight, typeRight) = self.visit(ast.right,Access(frame, env, False, True, True))

    #         if type(typeLeft1) == FloatType and type(typeRight) == IntType:
    #             str_I2f = self.emit.emitI2F(frame)

    #         if ctxt.isDup == True:
    #             if type(ast.left) is Id:
    #                 str_Dup = self.emit.emitDUP(frame)
    #             else:
    #                 str_Dup = self.emit.emitDUP_X2(frame)

    #         (resLeft2, typeLeft2) = self.visit(ast.left, Access(frame, env, True, False, False))
    #         op_Str = resLeft1 + resRight + str_I2f + str_Dup  + resLeft2

    #         resType = typeLeft1

    #     else:
    #         (resLeft, typeLeft) = self.visit(ast.left, Access(frame, env, False, True, True))
    #         (resRight, typeRight) = self.visit(ast.right, Access(frame, env, False, True, True))

    #         if op == "+" or op == "-":
    #             if type(typeLeft) is FloatType and type(typeRight) is IntType:
    #                 op_Str = resLeft + resRight + self.emit.emitI2F(frame) + self.emit.emitADDOP(op, FloatType(), frame)
    #                 resType = FloatType()
    #             elif type(typeLeft) is IntType and type(typeRight) is FloatType:
    #                 op_Str = resLeft + self.emit.emitI2F(frame) + resRight + self.emit.emitADDOP(op, FloatType(), frame)
    #                 resType = FloatType()
    #             else:
    #                 op_Str = resLeft + resRight + self.emit.emitADDOP(op, typeLeft, frame)
    #                 resType = typeLeft

    #         elif op == "*" or op == "/":
    #             if type(typeLeft) is FloatType and type(typeRight) is IntType:
    #                 op_Str = resLeft + resRight + self.emit.emitI2F(frame) + self.emit.emitMULOP(op, FloatType(), frame)
    #                 resType = FloatType()
    #             elif type(typeLeft) is IntType and type(typeRight) is FloatType:
    #                 op_Str = resLeft + self.emit.emitI2F(frame) + resRight + self.emit.emitMULOP(op, FloatType(), frame)
    #                 resType = FloatType()
    #             else:
    #                 op_Str = resLeft + resRight + self.emit.emitMULOP(op, typeLeft, frame)
    #                 resType = typeLeft
    #         elif op == "%":
    #             op_Str = resLeft + resRight + self.emit.emitMOD(frame)
    #             resType = IntType()
    #         elif (op == "<") or (op == "<=") or (op == ">") or (op == ">="):
    #             if type(typeLeft) is FloatType and type(typeRight) is IntType:
    #                 op_Str = resLeft + resRight + self.emit.emitI2F(frame) + self.emit.emitREOP(op, FloatType(), frame)
    #             elif type(typeLeft) is IntType and type(typeRight) is FloatType:
    #                 op_Str = resLeft + self.emit.emitI2F(frame) + resRight + self.emit.emitREOP(op, FloatType(), frame)
    #             else:
    #                 op_Str = resLeft + resRight + self.emit.emitREOP(op, typeLeft, frame)
    #             resType = BoolType()
    #         elif (op == "==") or (op == "!="):
    #             if type(typeLeft) is BoolType and type(typeRight) is BoolType:
    #                 op_Str = resLeft + resRight + self.emit.emitREOP(op, IntType(), frame)
    #             if type(typeLeft) is IntType and type(typeRight) is IntType:
    #                 op_Str = resLeft + resRight + self.emit.emitREOP(op, IntType(), frame)
    #             else:
    #                 resType = BoolType()
    #         elif (op == "&&") or (op == "||"):
    #             op_Str = self.emit.emitAND_OR_SHORT_CIRCUIT(op, resLeft, resRight, frame)
    #             resType = BoolType()

    #     return (op_Str, resType)
    def visitBinaryOp(self, ast, c):
        ctxt = c
        frame = c.frame
        env = c.sym
        op = ast.op
        op_str = ""
        str_dup = ""
        str_I2F = ""
        resType = IntType()

        if op == "=":
            (resLHS,
             typeLHS) = self.visit(ast.left,
                                   Access(frame, env, True, True, False))
            (resRHS,
             typeRHS) = self.visit(ast.right,
                                   Access(frame, env, False, True, True))

            if type(typeLHS) is FloatType and type(typeRHS) is IntType:
                str_I2F = self.emit.emitI2F(frame)
            if ctxt.isDup == True:
                str_dup = self.emit.emitDUP(frame)
            else:
                str_dup = self.emit.emitDUP_X2(frame)

            (resLHS2,
             typeLHS2) = self.visit(ast.left,
                                    Access(frame, env, True, False, False))
            op_str = resLHS + resRHS + str_I2F + str_dup + resLHS2

            resType = typeLHS
        else:
            (resLHS,
             typeLHS) = self.visit(ast.left,
                                   Access(frame, env, False, True, True))
            (resRHS,
             typeRHS) = self.visit(ast.right,
                                   Access(frame, env, False, True, True))

            if op in ["+", "-"]:
                if type(typeLHS) is FloatType and type(typeRHS) is IntType:
                    op_str = resLHS + resRHS + self.emit.emitI2F(
                        frame) + self.emit.emitADDOP(op, FloatType(), frame)
                    resType = FloatType()
                elif type(typeLHS) is IntType and type(typeRHS) is FloatType:
                    op_str = resLHS + self.emit.emitI2F(
                        frame) + resRHS + self.emit.emitADDOP(
                            op, FloatType(), frame)
                    resType = FloatType()
                else:
                    op_str = resLHS + resRHS + self.emit.emitADDOP(
                        op, typeLHS, frame)
                    resType = typeLHS
            elif op in ["*", "/"]:
                if type(typeLHS) is FloatType and type(typeRHS) is IntType:
                    op_str = resLHS + resRHS + self.emit.emitI2F(
                        frame) + self.emit.emitMULOP(op, FloatType(), frame)
                    resType = FloatType()
                elif type(typeLHS) is IntType and type(typeRHS) is FloatType:
                    op_str = resLHS + self.emit.emitI2F(
                        frame) + resRHS + self.emit.emitMULOP(
                            op, FloatType(), frame)
                    resType = FloatType()
                else:
                    op_str = resLHS + resRHS + self.emit.emitMULOP(
                        op, typeLHS, frame)
                    resType = typeLHS
            elif op == "%":
                op_str = resLHS + resRHS + self.emit.emitMOD(op, resLHS, frame)
                resType = IntType()
            elif op in ["<=", "<", ">=", ">"]:
                if type(typeLHS) is FloatType and type(typeRHS) is IntType:
                    op_str = resLHS + resRHS + self.emit.emitI2F(
                        frame) + self.emit.emitREOP(op, FloatType(), frame)
                elif type(typeLHS) is IntType and type(typeRHS) is FloatType:
                    op_str = resLHS + self.emit.emitI2F(
                        frame) + resRHS + self.emit.emitREOP(
                            op, FloatType(), frame)
                else:
                    op_str = resLHS + resRHS + self.emit.emitREOP(
                        op, typeLHS, frame)
                    resType = BoolType()
            elif op in ["==", "!="]:
                if type(typeLHS) is BoolType and type(typeRHS) is BoolType:
                    op_str = resLHS + resRHS + self.emit.emitREOP(
                        op, IntType(), frame)
                elif type(typeLHS) is IntType and type(typeRHS) is IntType:
                    op_str = resLHS + resRHS + self.emit.emitREOP(
                        op, IntType, frame)
                resType = BoolType()
            elif op in ["||", '&&']:
                op_str = resLHS + resRHS + self.emit.emitREOP(
                    op, BoolType(), frame)
                resType = BooType()
        return (op_str, resType)

    # def visitCallExpr(self, ast, o):
    #     #ast: CallExpr

    #     ctxt = o
    #     frame = ctxt.frame
    #     nenv = ctxt.sym
    #     sym = self.lookup(ast.method.name, nenv, lambda x: x.name)
    #     cname = sym.value.value
    #     ctype = sym.mtype
    #     returnType = ctype.rettype

    #     if ctxt.isLeft is True and ctxt.isFirst is False:
    #         return (self.emit.emitWRITEVAR2(ast.method.name, returnType, frame), returnType)
    #     else:
    #         listParamType = ctype.partype
    #         # zip
    #         checkList=[]
    #         for item in range(len(listParamType)):
    #             checkList.append((ast.param[item],listParamType[item]))

    #         in_ = ("",[])
    #         for x in checkList:
    #             (str1,typ1) = self.visit(x[0],Access(frame,nenv,False,True,True))
    #             if type(typ1) is IntType and type(x[1]) is FloatType:
    #                 in_ = (in_[0] + str1 + self.emit.emitI2F(frame), in_[1].append(typ1))
    #             else:
    #                 in_ = (in_[0] + str1, in_[1] + [typ1])

    #     return (in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame), returnType)
    # def visitCallExpr(self, ast, o):
    #     #ast: CallExpr
    #     #o: Any

    #     ctxt = o
    #     frame = ctxt.frame
    #     nenv = ctxt.sym
    #     sym = self.lookup(ast.method.name, nenv, lambda x: x.name)
    #     cname = sym.value.value

    #     ctype = sym.mtype

    #     in_ = ("", list())
    #     for x in ast.param:
    #         str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
    #         in_ = (in_[0] + str1, in_[1].append(typ1))
    #     self.emit.printout(in_[0])
    #     self.emit.printout(self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame))

    def visitCallExpr(self, ast, o):
        #ast: CallExpr
        #o: Any

        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name, nenv, lambda x: x.name)
        cname = sym.value.value
        ctype = sym.mtype
        returnType = ctype.rettype

        if ctxt.isLeft is True and ctxt.isFirst is False:
            return (self.emit.emitWRITEVAR2(ast.method.name, returnType,
                                            frame))
        else:
            listParamType = ctype.partype
            checkList = zip(ast.param, listParamType)

            in_ = ("", list())
            for x in checkList:
                str1, typ1 = self.visit(x[0], Access(frame, nenv, False, True))
                if type(typ1) is IntType and type(x[1]) is FloatType:
                    in_ = (in_[0] + str1 + self.emit.emitI2F(frame),
                           in_[1].append(typ1))  # not append(x[1])
                else:
                    in_ = (in_[0] + str1, in_[1].append(typ1))
            #self.emit.printout(in_[0])
        return (in_[0] + self.emit.printout(
            self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype,
                                       frame)), returnType)
        #self.emit.printout(self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame))
    def visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()

    def visitFloatLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()

    def visitBoolLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return (self.emit.emitPUSHICONST(str(ast.value), frame), BoolType())

    def visitStringLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHCONST(str(ast.value), StringType(),
                                       frame), StringType()
Example #2
0
class CodeGenVisitor(BaseVisitor, Utils):
    def __init__(self, astTree, env, dir_):
        #astTree: AST
        #env: List[Symbol]
        #dir_: File

        self.astTree = astTree
        self.env = env
        self.className = "MCClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.curFunc = Symbol("null", MType([], VoidType()),
                              CName(self.className))

    def VarGlobal(self, ast, c):
        ctxt = c
        nameAtt = ast.variable
        typeAtt = ast.varType
        self.emit.printout(self.emit.emitATTRIBUTE(nameAtt, typeAtt, False,
                                                   ""))
        symbol = Symbol(ast.variable, typeAtt, CName(self.className))
        c.append(symbol)
        return c

    def FuncGlobal(self, ast, c):
        ctxt = c
        nameFunc = ast.name.name
        typeFunc = MType([x.varType for x in ast.param], ast.returnType)
        symbol = Symbol(nameFunc, typeFunc, CName(self.className))
        c.append(symbol)
        return c

    def visitProgram(self, ast, c):
        #ast: Program
        #c: Any

        self.emit.printout(
            self.emit.emitPROLOG(self.className, "java.lang.Object"))

        lsVar = list(filter(lambda x: type(x) is VarDecl, ast.decl))
        lsArrayVar = list(filter(lambda x: type(x.varType) is ArrayType,
                                 lsVar))
        lsFun = list(filter(lambda x: type(x) is FuncDecl, ast.decl))

        # printout static field and add them to self.env
        functools.reduce(lambda x,y: self.VarGlobal(y,x) if type(y) is VarDecl else self.FuncGlobal(y,x), \
                ast.decl, self.env if self.env else [])

        # visit func decl
        functools.reduce(lambda a, b: self.visit(b, a), lsFun,
                         SubBody(None, self.env))

        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), [], None, Block([])), c,
                       Frame("<init>", VoidType()))
        if lsArrayVar:
            self.emit.printout(
                self.emit.emitCLINIT(self.className, lsArrayVar,
                                     Frame("<clinit>", VoidType())))
        self.emit.emitEPILOG()
        return c

    def visitVarDecl(self, ast, c):
        #ast: VarDecl
        #c  : SubBody
        env = c.sym if type(c) is SubBody else []
        indx = c.frame.getNewIndex()
        self.emit.printout(
            self.emit.emitVAR(indx, ast.variable, ast.varType,
                              c.frame.getStartLabel(), c.frame.getEndLabel(),
                              c.frame))
        return SubBody(c.frame,
                       [Symbol(ast.variable, ast.varType, Index(indx))] + env)

    def arrayTypeDecl(self, ast, c):
        #ast : VarDecl
        #c   : any

        # coi lai
        index = (self.lookup(ast.variable, c.sym,
                             lambda x: x.name)).value.value
        self.emit.printout(self.emit.emitNEWARRAY(ast.varType, c.frame))
        self.emit.printout(
            self.emit.emitWRITEVAR(ast.variable, ast.varType, index, c.frame))
        return SubBody(c.frame, c.sym)

    def genMETHOD(self, consdecl, o, frame):
        #consdecl: FuncDecl
        #o: Any
        #frame: Frame

        isInit = consdecl.returnType is None
        isMain = consdecl.name.name == "main" and len(
            consdecl.param) == 0 and type(consdecl.returnType) is VoidType
        returnType = VoidType() if isInit else consdecl.returnType
        methodName = "<init>" if isInit else consdecl.name.name
        intype = [ArrayPointerType(StringType())
                  ] if isMain else [x.varType for x in consdecl.param]
        mtype = MType(intype, returnType)

        self.emit.printout(
            self.emit.emitMETHOD(methodName, mtype, not isInit, frame))

        frame.enterScope(True)

        glenv = o

        # Generate code for parameter declarations
        if isInit:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "this",
                                  ClassType(self.className),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
        if isMain:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "args",
                                  ArrayPointerType(StringType()),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))

        glSubBody = SubBody(frame, glenv)
        if (isMain is False) and (intype != []):
            glSubBody = functools.reduce(lambda a, b: self.visit(b, a),
                                         consdecl.param, SubBody(frame, glenv))

        body = consdecl.body
        lstdecl = list(filter(lambda x: type(x) is VarDecl, body.member))
        curenv = functools.reduce(lambda a, b: self.visit(b, a), lstdecl,
                                  glSubBody)

        lsArrVarDecl = list(
            filter(lambda x: type(x.varType) is ArrayType, lstdecl))
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))

        for x in lsArrVarDecl:
            self.arrayTypeDecl(x, curenv)

        # Generate code for statements
        if isInit:
            self.emit.printout(
                self.emit.emitREADVAR("this", ClassType(self.className), 0,
                                      frame))
            self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        lststmt = list(filter(lambda x: not type(x) is VarDecl, body.member))
        returnStmt = list(filter(lambda x: type(x) is Return, lststmt))

        list(map(lambda x: self.printoutStmt(x, curenv), lststmt))

        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if (type(returnType) is VoidType) or (not returnStmt):
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def printoutStmt(self, ast, env):
        #env    : SubBody
        frame = env.frame
        newEnv = env.sym
        if type(ast) is BinaryOp:
            if ast.op == "=":
                self.emit.printout(
                    self.visit(ast, Access(frame, newEnv, True, True,
                                           False))[0])
            else:
                self.emit.printout(
                    self.visit(ast, Access(frame, newEnv, False, True,
                                           True))[0])
                self.emit.printout(self.emit.emitPOP(frame))

        elif type(ast) is CallExpr:
            self.emit.printout(
                self.visit(ast, Access(frame, newEnv, False, True, True))[0])
            sym = self.lookup(ast.method.name, newEnv, lambda x: x.name)
            returnType = sym.mtype.rettype

            if type(returnType) != VoidType:
                self.emit.printout(self.emit.emitPOP(frame))

        elif (type(ast) is UnaryOp) or (type(ast) is Id) or (type(ast) is ArrayCell) or (type(ast) is IntLiteral) or \
                (type(ast) is FloatLiteral) or (type(ast) is StringLiteral) or (type(ast) is BooleanLiteral):

            self.emit.printout(
                self.visit(ast, Access(frame, newEnv, False, True, True))[0])
            self.emit.printout(self.emit.emitPOP(frame))

        elif (type(ast) is Block) or (type(ast) is If) or (type(ast) is For) or (type(ast) is Break) or \
                (type(ast) is Continue) or (type(ast) is Return) or (type(ast) is Dowhile):
            # NOTE env hay new env vay cha noi
            self.visit(ast, env)  #vi la stmt nen truyen vao SubBody
        else:
            pass

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl

        subctxt = o
        frame = Frame(ast.name.name, ast.returnType)
        self.curFunc = self.lookup(ast.name.name, subctxt.sym,
                                   lambda x: x.name)
        self.genMETHOD(ast, subctxt.sym, frame)

        return o
        #return SubBody(None, [Symbol(ast.name, MType(list(), ast.returnType), CName(self.className))] + subctxt.sym)

    def visitBlock(self, ast, c):
        #c  : SubBody
        ctxt = c
        frame = ctxt.frame
        newEnv = ctxt.sym

        frame.enterScope(False)
        #varEnv = ast.decl.foldLeft(SubBody(frame, newEnv))((x, e) => visit(e, x).asInstanceOf[SubBody])
        lstdecl = list(filter(lambda x: type(x) is VarDecl, ast.member))
        varEnv = functools.reduce(lambda a, b: self.visit(b, a), lstdecl,
                                  SubBody(frame, newEnv))

        # list Vardecl
        listVarDecl = ast.member
        listArrayVarDecl = filter(lambda x: type(x) is ArrayType, listVarDecl)

        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        list(map(lambda x: self.arrayTypeDecl(x, varEnv), listArrayVarDecl))
        lststmt = list(filter(lambda x: not type(x) is VarDecl, ast.member))
        list(map(lambda x: self.printoutStmt(x, varEnv), lststmt))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()
        return c

    def visitIf(self, ast, c):
        #c  : SubBody
        frame = c.frame
        env = c.sym
        (resExpr,
         typeExpr) = ast.expr.accept(self, Access(frame, env, False, True,
                                                  True))
        falseLabel = frame.getNewLabel()

        self.emit.printout(resExpr + self.emit.emitIFFALSE(falseLabel, frame))
        self.printoutStmt(ast.thenStmt, c)
        if not ast.elseStmt:
            self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
        else:
            trueLabel = frame.getNewLabel()
            self.emit.printout(
                self.emit.emitGOTO(trueLabel, frame) +
                self.emit.emitLABEL(falseLabel, frame))
            self.printoutStmt(ast.elseStmt, c)
            self.emit.printout(self.emit.emitLABEL(trueLabel, frame))

    def visitFor(self, ast, c):
        #c  : SubBody
        frame = c.frame
        env = c.sym
        beginLabel = frame.getNewLabel()
        frame.enterLoop()

        self.printoutStmt(ast.expr1, SubBody(frame, env))
        self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
        (resExpr2,
         typeExpr2) = ast.expr2.accept(self,
                                       Access(frame, env, False, True, False))
        self.emit.printout(resExpr2)

        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))
        self.printoutStmt(ast.loop, c)

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        self.printoutStmt(ast.expr3, SubBody(frame, env))

        self.emit.printout(self.emit.emitGOTO(beginLabel, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))

        frame.exitLoop()

    def visitDowhile(self, ast, c):
        #c  : SubBody
        frame = c.frame
        env = c.sym
        beginLabel = frame.getNewLabel()
        frame.enterLoop()

        self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
        list(map(lambda x: self.printoutStmt(x, c), ast.sl))

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))

        (resExpr, typeExpr) = self.visit(ast.exp,
                                         Access(frame, env, False, True, True))

        self.emit.printout(resExpr)
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))
        self.emit.printout(self.emit.emitGOTO(beginLabel, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitBreak(self, ast, c):
        self.emit.printout(self.emit.emitGOTO(c.frame.getBreakLabel(),
                                              c.frame))

    def visitContinue(self, ast, c):
        self.emit.printout(
            self.emit.emitGOTO(c.frame.getContinueLabel(), c.frame))

    def visitReturn(self, ast, c):
        if ast.expr:
            (resExpr,
             resType) = self.visit(ast.expr,
                                   Access(c.frame, c.sym, False, True, True))
            typeFunc = self.curFunc.mtype.rettype
            if type(typeFunc) == FloatType and type(resType) == IntType:
                self.emit.printout(resExpr + self.emit.emitI2F(c.frame) +
                                   self.emit.emitRETURN(FloatType(), c.frame))
            else:
                self.emit.printout(resExpr +
                                   self.emit.emitRETURN(resType, c.frame))
        else:
            self.emit.printout(self.emit.emitRETURN(VoidType(), c.frame))

    def visitBinaryOp(self, ast, c):
        #c  : Access (co the la SubBody)
        ctxt = c
        frame = ctxt.frame
        env = ctxt.sym
        op = ast.op
        op_Str = ""
        str_Dup = ""
        str_I2f = ""
        resType = IntType()

        if op == "=":
            (resLeft1,
             typeLeft1) = self.visit(ast.left,
                                     Access(frame, env, True, True, False))
            (resRight,
             typeRight) = self.visit(ast.right,
                                     Access(frame, env, False, True, True))

            if type(typeLeft1) == FloatType and type(typeRight) == IntType:
                str_I2f = self.emit.emitI2F(frame)
            if ctxt.isDup == True:
                if type(ast.left) is Id:
                    str_Dup = self.emit.emitDUP(frame)
                else:
                    str_Dup = self.emit.emitDUP_X2(frame)

            (resLeft2,
             typeLeft2) = self.visit(ast.left,
                                     Access(frame, env, True, False, False))
            op_Str = resLeft1 + resRight + str_I2f + str_Dup + resLeft2

            resType = typeLeft1

        else:
            (resLeft,
             typeLeft) = self.visit(ast.left,
                                    Access(frame, env, False, True, True))
            (resRight,
             typeRight) = self.visit(ast.right,
                                     Access(frame, env, False, True, True))

            if op == "+" or op == "-":
                if type(typeLeft) is FloatType and type(typeRight) is IntType:
                    op_Str = resLeft + resRight + self.emit.emitI2F(
                        frame) + self.emit.emitADDOP(op, FloatType(), frame)
                    resType = FloatType()
                elif type(typeLeft) is IntType and type(
                        typeRight) is FloatType:
                    op_Str = resLeft + self.emit.emitI2F(
                        frame) + resRight + self.emit.emitADDOP(
                            op, FloatType(), frame)
                    resType = FloatType()
                else:
                    op_Str = resLeft + resRight + self.emit.emitADDOP(
                        op, typeLeft, frame)
                    resType = typeLeft

            elif op == "*" or op == "/":
                if type(typeLeft) is FloatType and type(typeRight) is IntType:
                    op_Str = resLeft + resRight + self.emit.emitI2F(
                        frame) + self.emit.emitMULOP(op, FloatType(), frame)
                    resType = FloatType()
                elif type(typeLeft) is IntType and type(
                        typeRight) is FloatType:
                    op_Str = resLeft + self.emit.emitI2F(
                        frame) + resRight + self.emit.emitMULOP(
                            op, FloatType(), frame)
                    resType = FloatType()
                else:
                    op_Str = resLeft + resRight + self.emit.emitMULOP(
                        op, typeLeft, frame)
                    resType = typeLeft
            elif op == "%":
                op_Str = resLeft + resRight + self.emit.emitMOD(frame)
                resType = IntType()
            elif (op == "<") or (op == "<=") or (op == ">") or (op == ">="):
                if type(typeLeft) is FloatType and type(typeRight) is IntType:
                    op_Str = resLeft + resRight + self.emit.emitI2F(
                        frame) + self.emit.emitREOP(op, FloatType(), frame)
                elif type(typeLeft) is IntType and type(
                        typeRight) is FloatType:
                    op_Str = resLeft + self.emit.emitI2F(
                        frame) + resRight + self.emit.emitREOP(
                            op, FloatType(), frame)
                else:
                    op_Str = resLeft + resRight + self.emit.emitREOP(
                        op, typeLeft, frame)
                resType = BoolType()
            elif (op == "==") or (op == "!="):
                if type(typeLeft) is BoolType and type(typeRight) is BoolType:
                    op_Str = resLeft + resRight + self.emit.emitREOP(
                        op, IntType(), frame)
                if type(typeLeft) is IntType and type(typeRight) is IntType:
                    op_Str = resLeft + resRight + self.emit.emitREOP(
                        op, IntType(), frame)
                else:
                    resType = BoolType()
            elif (op == "&&") or (op == "||"):
                op_Str = self.emit.emitAND_OR_SHORT_CIRCUIT(
                    op, resLeft, resRight, frame)
                resType = BoolType()

        return (op_Str, resType)

    def visitUnaryOp(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        env = ctxt.sym
        (resExpr, typeExpr) = self.visit(ast.body,
                                         Access(frame, env, False, True, True))
        if ast.op == "!":
            return (resExpr + self.emit.emitNOT(typeExpr, frame), typeExpr)
        elif ast.op == "-":
            return (resExpr + self.emit.emitNEGOP(typeExpr, frame), typeExpr)

    def visitCallExpr(self, ast, o):
        #ast: CallExpr

        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name, nenv, lambda x: x.name)
        cname = sym.value.value
        ctype = sym.mtype
        returnType = ctype.rettype

        if ctxt.isLeft is True and ctxt.isFirst is False:
            return (self.emit.emitWRITEVAR2(ast.method.name, returnType,
                                            frame), returnType)
        else:
            listParamType = ctype.partype
            # zip
            checkList = []
            for item in range(len(listParamType)):
                checkList.append((ast.param[item], listParamType[item]))

            in_ = ("", [])
            for x in checkList:
                (str1,
                 typ1) = self.visit(x[0], Access(frame, nenv, False, True,
                                                 True))
                if type(typ1) is IntType and type(x[1]) is FloatType:
                    in_ = (in_[0] + str1 + self.emit.emitI2F(frame),
                           in_[1].append(typ1))
                else:
                    in_ = (in_[0] + str1, in_[1] + [typ1])

        return (in_[0] + self.emit.emitINVOKESTATIC(
            cname + "/" + ast.method.name, ctype, frame), returnType)

        #in_ = ("", list())
        #for x in ast.param:
        #    str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
        #    in_ = (in_[0] + str1, in_[1].append(typ1))
        #self.emit.printout(in_[0])
        #self.emit.printout(self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame))

    def visitId(self, ast, o, fl=False):
        # o : Access (co the la SubBody)
        if type(o) != SubBody:
            sym = self.lookup(ast.name, o.sym, lambda x: x.name)

            code = ""
            if o.isLeft is True and o.isFirst is True:
                pass
            elif o.isLeft is True and o.isFirst is False:
                if type(sym.mtype) is ArrayType or type(
                        sym.mtype) is ArrayPointerType:
                    code = self.emit.emitWRITEVAR2(ast.name, sym.mtype,
                                                   o.frame)
                else:
                    if type(sym.value) is CName:
                        code = self.emit.emitPUTSTATIC(
                            sym.value.value + "." + ast.name, sym.mtype,
                            o.frame)
                    elif type(sym.value) is Index:
                        code = self.emit.emitWRITEVAR(ast.name, sym.mtype,
                                                      sym.value.value, o.frame)

            elif o.isLeft is False:
                if type(sym.value) is CName:
                    code = self.emit.emitGETSTATIC(
                        sym.value.value + "." + ast.name, sym.mtype, o.frame)
                elif type(sym.value) is Index:
                    code = self.emit.emitREADVAR(ast, sym.mtype,
                                                 sym.value.value, o.frame)

            return (code, sym.mtype)
        else:
            sym = self.lookup(ast.name, o.sym, lambda x: x.name)
            return ("", sym.mtype)

    def visitArrayCell(self, ast, o):

        # if in body expression
        if type(o) != SubBody:
            frame = o.frame
            lsSym = o.sym
            if o.isLeft is True and o.isFirst is True:
                (resArr, typeArr) = self.visit(
                    ast.arr, Access(frame, lsSym, False, True, False))
                (resIdx,
                 typIdx) = self.visit(ast.idx,
                                      Access(frame, lsSym, False, True, True))
                return (resArr + resIdx, typeArr.eleType)

            elif o.isLeft is True and o.isFirst is False:
                (resArr, typeArr) = self.visit(
                    ast.arr, Access(frame, lsSym, True, False, False))
                return (resArr, typeArr)

            elif o.isLeft is False:
                (resArr, typeArr) = self.visit(
                    ast.arr, Access(frame, lsSym, False, True, False))
                (resIdx,
                 typIdx) = self.visit(ast.idx,
                                      Access(frame, lsSym, False, True, True))
                if type(typeArr) is ArrayType:
                    arrayType = typeArr.eleType
                    aload = self.emit.emitALOAD(arrayType, frame)
                    return (resArr + resIdx + aload, arrayType)
                elif type(typeArr) is ArrayPointerType:
                    arrayPointerType = typeArr.eleType
                    aload = self.emit.emitALOAD(arrayPointerType, frame)
                    return (resArr + resIdx + aload, arrayPointerType)
        else:
            # ko o trong body expr thi o dau ta. o ngoai, vi du: a[6] = 4;
            frame = o.frame
            lsSym = o.sym
            (resArr,
             typeArr) = self.visit(ast.arr,
                                   Access(frame, lsSym, False, True, False))
            arrayType = typeArr.eleType
            return ("", arrayType)

    def visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()

    def visitFloatLiteral(self, ast, o):
        #ast: FloatLiteral
        #o: Any
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()

    def visitStringLiteral(self, ast, o):
        #ast: StringLiteral
        #o: Any
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHCONST(ast.value, StringType(),
                                       frame), StringType()

    def visitBooleanLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return (self.emit.emitPUSHICONST(str(ast.value), frame), BoolType())