Example #1
0
 def __init__(self, astTree, env, dir_):
     self.astTree = astTree
     self.env = env
     self.className = "MPClass"
     self.path = dir_
     self.emit = Emitter(self.path + "/" + self.className + ".j")
     self.arrayGlobals = list()
Example #2
0
 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")
Example #3
0
 def __init__(self, astTree, env, dir_):
     #astTree: AST
     #env: List[Symbol]
     #dir_: File
     self.astTree = astTree
     self.className = "MCClass"
     self.env = [Symbol(sym.name, sym.mtype, CName(self.className)) if sym.value is None else sym for sym in env]
     self.path = dir_
     self.emit = Emitter(self.path + "/" + self.className + ".j")
  def __init__(self, astTree, env, dir_):
    #astTree: AST
    #env: List[Symbol] built in function from codegenerator
    #dir_: File

    self.astTree = astTree
    self.env = env
    self.className = "MCClass"
    self.path = dir_
    self.emit = Emitter(self.path + "/" + self.className + ".j")
    self.globalArrayVarList = []
Example #5
0
    def __init__(self, astTree, env, dir_):
        #astTree: AST
        #env: List[Symbol]
        #dir_: File

        self.astTree = astTree
        self.env = env
        self.className = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.current_function = None  #Symbol("",MType([],VoidType()),CName(self.className))
    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")
            # not in original version
        self.listGlobalArray = [] # list(VarDecl: array declare global)
Example #7
0
    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.listGlobalArray = []
        self.function = []
        self.visitFunc = []
        self.paramMain = []
        self.visitedPara = []
        self.inferType = []
Example #8
0
    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.static = []
        self.initVar = []
        self.ret = []
        self.envFuncNum = 0
        self.staticFunction = []
        self.initStatic = []
        self.clinitStackSize = 0
Example #9
0
    def __init__(self):
        self.t = 0.0
        self.t = 0
        self.x = 0.0
        self.y = 0
        self.z = 0
        self.scale = 1.0
        self.rz = 0.0

        #initialise glut
        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
        self.width = 1000
        self.height = 1000
        self.aspect = self.width / float(self.height)
        glutInitWindowSize(1000, 1000)
        glutCreateWindow("The return of the Bunny")

        self.init()
        #initialize GL
        glutReshapeFunc(self.reshape)
        glutDisplayFunc(self.display)
        glutKeyboardFunc(self.keyboard)
        #glutSpecialFunc(self.glutSpecialKey)

        # load all the required textures here
        self.texid_sawblade = glutils.loadTexture('../assets/sawblade.jpg')
        self.texid_ground = glutils.loadTexture('../assets/ground_tile.jpg')
        self.texid_slab = glutils.loadTexture('../assets/slab.jpg')
        self.texid_star = glutils.loadTextureWithTransparency(
            '../assets/new_spark2.png')

        self.texid_cube = glutils.loadTexture('../assets/wood.jpg')
        self.texid_cone = glutils.loadTexture('../assets/blue.jpg')
        self.texid_sphere = glutils.loadTextureWithTransparency(
            '../assets/sphere.png')
        self.texid_bunny = glutils.loadTextureWithTransparency(
            '../assets/bunny.png')

        #create an emitter for the particle system
        self.emitter = Emitter(self.texid_star)
        self.frame = 0
        self.time = 0
        self.timebase = 0
        glutMainLoop()
Example #10
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 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 list()
        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))

        body = consdecl.body
        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))
        list(map(lambda x: self.visit(x, SubBody(frame, glenv)), body.member))

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

    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 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 visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()
Example #11
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.currentFunc = Symbol("null", MType([], VoidType()),
                                  CName(self.className))

    def visitVarGlobal(self, ast, c):
        _ctxt = c
        _name = ast.variable
        _type = ast.varType
        self.emit.printout(self.emit.emitATTRIBUTE(_name, _type, False, ""))
        _sym = Symbol(_name, _type, CName(self.className))
        _ctxt.append(_sym)
        return _ctxt

    def visitFunGlobal(self, ast, c):
        _ctxt = c
        _name = ast.name.name
        _type = MType([x.varType for x in ast.param], ast.returnType)
        _sym = Symbol(_name, _type, CName(self.className))
        _ctxt.append(_sym)
        return _ctxt

    def visitProgram(self, ast, c):
        self.emit.printout(
            self.emit.emitPROLOG(self.className, 'java.lang.Object'))
        lstVarDecl = []
        lstFuncDecl = []

        for x in ast.decl:
            if type(x) is VarDecl:
                lstVarDecl += [x]
            elif type(x) is FuncDecl:
                lstFuncDecl += [x]
        for x in ast.decl:
            self.env += self.visitVarGlobal(
                x, self.env) if type(x) is VarDecl else self.visitFunGlobal(
                    x, self.env)
        for funDecl in lstFuncDecl:
            self.visit(funDecl, SubBody(None, self.env))
        self.genMETHOD(FuncDecl(Id("<init>"), [], None, []), c,
                       Frame("<init>", VoidType))
        lstArrayType = []
        for item in lstVarDecl:
            if type(item.varType) is ArrayType:
                lstArrayType += [item]

        if lstArrayType:
            self.emit.printout(
                self.emit.emitCLINIT(self.className, lstArrayType,
                                     Frame("<clinit>", VoidType())))
        self.emit.emitEPILOG()
        return c

    def genMETHOD(self, decl, c, frame):
        IsInit = True if decl.returnType is None else False
        IsMain = True if decl.name.name == "main" else False
        nameMethod = "<init>" if IsInit else decl.name.name
        typePara = [ArrayPointerType(StringType())
                    ] if IsMain else [x.varType for x in decl.param]
        returntype = VoidType() if IsInit else decl.returnType
        mtype = MType(typePara, returntype)
        self.emit.printout(
            self.emit.emitMETHOD(nameMethod, mtype, not IsInit, frame))

        frame.enterScope(True)

        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))
        subBody = SubBody(frame, c)
        if not IsMain and len(decl.param) != 0:
            for param in decl.param:
                subBody = self.visit(param, subBody)
        body = decl.body
        if not IsInit:
            for member in body.member:
                if type(member) is VarDecl:
                    subBody = self.visit(member, subBody)

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

        if IsInit:
            self.emit.printout(
                self.emit.emitREADVAR('this', ClassType(self.className), 0,
                                      frame))
            self.emit.printout(self.emit.emitINVOKESPECIAL(frame))

        lstReturnStmt = []
        lstVarArrayType = []
        if not IsInit:
            for member in decl.body.member:
                if type(member) is VarDecl:
                    if type(member.varType) is ArrayType:
                        lstVarArrayType += [member]
        [self.ArrayTypeDecl(x, subBody) for x in lstVarArrayType]
        if not IsInit:
            for member in decl.body.member:
                if not type(member) is VarDecl:
                    if type(member) is Return:
                        lstReturnStmt += [member]
                    self.visit(member, subBody)

        for i in range(0, frame.getStackSize(), 1):
            self.emit.printout(self.emit.emitPOP(frame))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))

        if (type(returntype) is VoidType or len(lstReturnStmt) == 0):
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))

        self.emit.printout(self.emit.emitENDMETHOD(frame))

        frame.exitScope()

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

    def visitFuncDecl(self, ast, c):
        frame = Frame(ast.name.name, ast.returnType)
        lstSym = c.sym
        self.currentFunc = self.lookup(ast.name.name, lstSym, lambda x: x.name)
        self.genMETHOD(ast, lstSym, frame)
        return c

    def genBinString(self, frame, retLeft, typeLeft, retRight, typeRight):
        if type(typeLeft) is IntType and type(typeRight) is FloatType:
            return retLeft + self.emit.emitI2F(frame) + retRight, FloatType()
        if type(typeLeft) is FloatType and type(typeRight) is IntType:
            return retLeft + retRight + self.emit.emitI2F(frame), FloatType()
        if type(typeLeft) is FloatType and type(typeRight) is FloatType():
            return retLeft + self.emit.emitI2F(
                frame) + retRight + self.emit.emitI2F(frame), FloatType()
        stringReturn = retLeft + retRight, typeLeft
        # print(stringReturn)
        return stringReturn

    def visitUnaryOp(self, ast, c):
        op = ast.op
        frame = c.frame
        lstSym = c.sym
        (retExpr, typeExpr) = self.visit(ast.body,
                                         Access(frame, lstSym, False, True))
        if op == '-':
            return retExpr + self.emit.emitNEGOP(typeExpr, frame), typeExpr
        elif op == '!':
            return retExpr + self.emit.emitNOT(BoolType(), frame), BoolType()

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

    def visitBlock(self, ast, c):
        frame = c.frame
        oldEnv = c.sym
        frame.enterScope(False)
        varDeclInBlock = SubBody(frame, oldEnv)
        arrayDecl = []
        lstStmt = []
        for item in ast.member:
            if type(item) is VarDecl:
                varDeclInBlock = self.visit(item, c)
            else:
                lstStmt += [item]
            if type(item.varType) is ArrayType:
                arrayDecl += [item]

        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        [self.ArrayTypeDecl(x, varDeclInBlock) for x in arrayDecl]
        [self.visit(x, varDeclInBlock) for x in lstStmt]
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()
        return None

    def visitIf(self, ast, c):
        frame = c.frame
        lstSym = c.sym

        stringReturn, typeReturn = self.visit(
            ast.expr, Access(frame, lstSym, False, True))
        falseLabel = frame.getNewLabel()
        self.emit.printout(stringReturn +
                           self.emit.emitIFFALSE(falseLabel, frame))
        if not type(ast.thenStmt) is Block:
            [self.visit(ast.thenStmt, c)]
        else:
            [self.visit(x, c) for x in ast.thenStmt.member]
        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.printout(self.emit.emitLABEL(falseLabel, frame))
            if not type(ast.elseStmt) is Block:
                [self.visit(ast.elseStmt, c)]
            else:
                [self.visit(x, c) for x in ast.elseStmt.member]
            self.emit.printout(self.emit.emitLABEL(trueLabel, frame))
        return None

    def visitDowhile(self, ast, c):
        frame = c.frame
        lstSym = c.sym
        loopLabel = frame.getNewLabel()
        frame.enterLoop()
        self.emit.printout(self.emit.emitLABEL(loopLabel, frame))
        [self.visit(x, c) for x in ast.sl]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        stringReturn, typeReturn = self.visit(
            ast.exp, Access(frame, lstSym, False, True))
        self.emit.printout(stringReturn)
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))
        self.emit.printout(self.emit.emitGOTO(loopLabel, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()
        return None

    def visitFor(self, ast, c):
        frame = c.frame
        lstSym = c.sym
        loopLabel = frame.getNewLabel()
        frame.enterLoop()
        self.visit(ast.expr1, Access(frame, lstSym, False, True))
        self.emit.printout(self.emit.emitLABEL(loopLabel, frame))
        stringReturn, typeReturn = self.visit(
            ast.expr2, Access(frame, lstSym, False, True))
        self.emit.printout(stringReturn)
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))
        if (type(ast.loop) is Block):
            [self.visit(x, c) for x in ast.loop.member]
        else:
            [self.visit(ast.loop, c)]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        self.visit(ast.expr3, Access(frame, lstSym, False, True))
        self.emit.printout(self.emit.emitGOTO(loopLabel, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()
        return None

    def visitCallExpr(self, ast, c):
        lstSym = c.sym
        frame = c.frame
        sym = self.lookup(ast.method.name, lstSym, lambda x: x.name)
        cname = sym.value.value
        ctype = sym.mtype
        lstParaType = ctype.partype

        if type(c) is Access:
            if c.isLeft and not c.isFirst:
                return self.emit.emitWRITEVAR2(ast.method.name, ctype.rettype,
                                               frame), ctype.rettype
        _in = ("", [])
        lstCheck = []
        for item in range(len(lstParaType)):
            lstCheck.append((ast.param[item], lstParaType[item]))
        for x in lstCheck:
            (stringReturn,
             typeReturn) = self.visit(x[0], Access(frame, lstSym, False, True))
            if type(x[1]) is FloatType and type(typeReturn) is IntType:
                _in = (_in[0] + stringReturn + self.emit.emitI2F(frame),
                       _in[1] + [typeReturn])
            else:
                _in = (_in[0] + stringReturn, _in[1] + [typeReturn])

        self.emit.printout(_in[0])
        self.emit.printout(
            self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame))
        return "", ctype.rettype

    def visitArrayCell(self, ast, c):

        frame = c.frame
        lstSym = c.sym
        if type(c) != SubBody:
            if c.isLeft == True and c.isFirst == True:
                arrStringReturn, arrTypeReturn = self.visit(
                    ast.arr, Access(frame, lstSym, False, True))
                idxStringReturn, idxTypeReturn = self.visit(
                    ast.idx, Access(frame, lstSym, False, True))
                return arrStringReturn + idxStringReturn, arrTypeReturn.eleType
            elif c.isLeft == True and c.isFirst == False:
                arrStringReturn, arrTypeReturn = self.visit(
                    ast.arr, Access(frame, lstSym, True, False))
                return arrStringReturn, arrTypeReturn
            elif c.isLeft == False:
                arrStringReturn, arrTypeReturn = self.visit(
                    ast.arr, Access(frame, lstSym, False, True))
                idxStringReturn, idxTypeReturn = self.visit(
                    ast.idx, Access(frame, lstSym, False, True))
                if type(arrTypeReturn) is ArrayType:
                    arrayType = arrTypeReturn.eleType
                    aload = self.emit.emitALOAD(arrayType, frame)
                    return arrStringReturn + idxStringReturn + aload, arrayType
                elif type(arrTypeReturn) is ArrayPointerType:
                    arrayPointerType = arrTypeReturn.eleType
                    aload = self.emit.emitALOAD(arrayPointerType, frame)
                    return arrStringReturn + idxStringReturn + aload, arrayPointerType
        else:
            arrStringReturn, arrTypeReturn = self.visit(
                ast.arr, Access(frame, lstSym, False, True))
            arrType = arrTypeReturn.eleType
            return "", arrTypeReturn
        return None

    def visitBinaryOp(self, ast, c):
        frame = c.frame
        lstSym = c.sym
        op = ast.op
        if op != '=':
            (retLeft,
             typeLeft) = self.visit(ast.left, Access(frame, lstSym, False,
                                                     True))
            (retRight,
             typeRight) = self.visit(ast.right,
                                     Access(frame, lstSym, False, True))
            stringExp, typeExp = self.genBinString(frame, retLeft, typeLeft,
                                                   retRight, typeRight)
            if (op in ['+', '-']):
                stringOp = self.emit.emitADDOP(op, typeExp, frame)
            elif op in ['*', '/']:
                stringOp = self.emit.emitMULOP(op, typeExp, frame)
            elif op in ['>', '>=', '<', '<=', '!=', '==']:
                stringOp = self.emit.emitREOP(op, typeExp, frame)
                typeExp = BoolType()
            elif op == '%':
                stringOp = self.emit.emitMOD(frame)
            elif op == '||':
                stringOp = self.emit.emitOROP(frame)
                typeExp = BoolType()
            elif op == '&&':
                stringOp = self.emit.emitANDOP(frame)
                typeExp = BoolType()
            return stringExp + stringOp, typeExp
        elif op == '=':
            # print(ast)
            strDup = ""
            strForI2F = ""
            stringReturn = ""
            (retFirstLeft,
             typeFirstLeft) = self.visit(ast.left,
                                         Access(frame, lstSym, True, True))
            (retRight,
             typeRight) = self.visit(ast.right,
                                     Access(frame, lstSym, False, True, True))

            if type(typeFirstLeft) is FloatType and type(typeRight) is IntType:
                strForI2F = self.emit.emitI2F(frame)
            if (type(c) is Access) and (c.isDup == True):
                strDup = self.emit.emitDUP(frame)
                self.emit.printout(retRight)
            stringReturn = retFirstLeft + strForI2F
            self.emit.printout(stringReturn + strDup)

            (retSecondLeft,
             typeSecondLeft) = self.visit(ast.left,
                                          Access(frame, lstSym, True, False))

            self.emit.printout(retSecondLeft)
            return (stringReturn, typeSecondLeft)

    def visitId(self, ast, c):
        if not type(c) is SubBody:
            frame = c.frame
            lstSym = c.sym
            sym = self.lookup(ast.name, lstSym, lambda x: x.name)
            stringReturn = ""
            if c.isLeft == True and c.isFirst == True:
                pass
            elif c.isLeft == True and c.isFirst == False:
                if type(sym.mtype) is ArrayType or type(
                        sym.mtype) is ArrayPointerType:
                    stringReturn = self.emit.emitWRITEVAR2(
                        sym.name, sym.mtype, frame)
                else:
                    if type(sym.value) is CName:
                        stringReturn = self.emit.emitPUTSTATIC(
                            sym.value.value + "." + sym.name, sym.mtype, frame)
                    elif type(sym.value) is Index:
                        stringReturn = self.emit.emitWRITEVAR(
                            sym.name, sym.mtype, sym.value.value, frame)
            elif c.isLeft == False:
                if type(sym.value) is CName:
                    stringReturn = self.emit.emitGETSTATIC(
                        sym.value.value + "." + sym.name, sym.mtype, frame)
                elif type(sym.value) is Index:
                    stringReturn = self.emit.emitREADVAR(
                        sym.name, sym.mtype, sym.value.value, frame)
            return stringReturn, sym.mtype
        else:

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

    def visitReturn(self, ast, c):
        frame = c.frame
        lstSym = c.sym
        if ast.expr:
            stringReturn, typeReturn = self.visit(
                ast.expr, Access(frame, lstSym, False, True))
            typeFuncReturn = self.currentFunc.mtype.rettype
            if (type(typeFuncReturn) is FloatType
                    and type(typeReturn) is IntType):
                self.emit.printout(stringReturn + self.emit.emitI2F(frame) +
                                   self.emit.emitRETURN(FloatType(), frame))
            else:
                self.emit.printout(stringReturn +
                                   self.emit.emitRETURN(typeReturn, frame))
        else:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))

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

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

    def visitIntLiteral(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()

    def visitFloatLiteral(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()

    def visitStringLiteral(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        return self.emit.emitPUSHCONST(ast.value, StringType(),
                                       frame), StringType()

    def visitBooleanLiteral(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(str(ast.value).lower(),
                                        frame), BoolType()
Example #12
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 = "MPClass"
        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, True))  # get name global
        for x in ast.decl:
            self.visit(x, (e, False))  # generate code
        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None),
                       e.sym, Frame("<init>", VoidType))
        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))
        glenv = reduce(lambda x, y: [self.visit(y, (frame, "decl"))] + x,
                       consdecl.param, glenv)
        glenv = reduce(lambda x, y: [self.visit(y, (frame, "decl"))] + x,
                       consdecl.local, glenv)
        body = consdecl.body
        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))
        list(map(lambda x: self.visit(x, SubBody(frame, glenv)), body))

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

        # if type(returnType) is VoidType:
        self.emit.printout(self.emit.emitRETURN(returnType, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any
        subctxt = o[0]
        if o[1] is True:
            retType = MType([x.varType for x in ast.param], ast.returnType)
            return SubBody(
                None, [Symbol(ast.name.name, retType, CName(self.className))] +
                subctxt.sym)
        # o[1] is False
        frame = Frame(ast.name, ast.returnType)
        self.genMETHOD(ast, subctxt.sym, frame)

    def visitVarDecl(self, ast, o):
        subctxt = o[0]
        if o[1] is True:
            retType = ast.varType
            self.emit.printout(
                self.emit.emitATTRIBUTE(ast.variable.name, retType, False,
                                        None))
            return SubBody(
                None,
                [Symbol(ast.variable.name, retType, CName(self.className))] +
                subctxt.sym)
        elif o[1] == "decl":  # o[0] is frame
            retType = ast.varType
            frame = o[0]
            index = frame.getNewIndex()
            self.emit.printout(
                self.emit.emitVAR(index, ast.variable.name, retType,
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
            return Symbol(ast.variable.name, retType, Index(index))

    def visitWith(self, ast, o):
        subctxt = o
        frame = subctxt.frame
        frame.enterScope(False)

        nenv = reduce(lambda x, y: [self.visit(y, (frame, "decl"))] + x,
                      ast.decl, subctxt.sym)

        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        # generate code for body
        for x in ast.stmt:
            self.visit(x, SubBody(frame, nenv))

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

    def visitIf(self, ast, o):
        subctxt = o
        frame = subctxt.frame
        sym = subctxt.sym
        elseLb = frame.getNewLabel()
        endLb = frame.getNewLabel()

        expcode, expType = self.visit(ast.expr, Access(frame, sym, False,
                                                       True))

        self.emit.printout(expcode)
        # generate code for thenstmt
        self.emit.printout(self.emit.emitIFFALSE(elseLb, frame))
        list(map(lambda x: self.visit(x, subctxt), ast.thenStmt))
        self.emit.printout(self.emit.emitGOTO(endLb, frame))
        # generate code for elsestmt
        self.emit.printout(self.emit.emitLABEL(elseLb, frame))
        list(map(lambda x: self.visit(x, subctxt), ast.elseStmt))
        self.emit.printout(self.emit.emitLABEL(endLb, frame))

    def visitFor(self, ast, o):
        frame = o.frame
        sym = o.sym
        code_expr1, typeExpr1 = self.visit(ast.expr1,
                                           Access(frame, sym, False, True))
        idStore, _ = self.visit(ast.id, Access(frame, sym, True, False))
        self.emit.printout(code_expr1 + idStore)

        frame.enterLoop()
        strLabel = frame.getNewLabel()
        ConLabel = frame.getContinueLabel()
        BrkLabel = frame.getBreakLabel()

        self.emit.printout(self.emit.emitLABEL(strLabel, frame))
        idLoad, _ = self.visit(ast.id, Access(frame, sym, False, False))
        code_expr2, typeExpr2 = self.visit(ast.expr2,
                                           Access(frame, sym, False, True))
        if ast.up:
            self.emit.printout(idLoad + code_expr2 +
                               self.emit.emitREOP("<=", typeExpr2, frame))
        else:
            self.emit.printout(idLoad + code_expr2 +
                               self.emit.emitREOP(">=", typeExpr2, frame))
        self.emit.printout(self.emit.emitIFFALSE(BrkLabel, frame))
        for x in ast.loop:
            self.visit(x, Access(frame, sym, False, True))

        self.emit.printout(self.emit.emitLABEL(ConLabel, frame))
        self.emit.printout(
            self.emit.emitINCREASE(idStore, idLoad, ast.up, frame))
        self.emit.printout(self.emit.emitGOTO(strLabel, frame))
        self.emit.printout(self.emit.emitLABEL(BrkLabel, frame))
        frame.exitLoop()

    def visitWhile(self, ast, o):
        ctxt = o
        sym = o.sym
        frame = o.frame

        frame.enterLoop()
        continueLabel = frame.getContinueLabel()
        breakLabel = frame.getBreakLabel()

        #generate code for continue label
        self.emit.printout(self.emit.emitLABEL(continueLabel, frame))

        #generate code for expr
        code, ret = self.visit(ast.exp, Access(frame, sym, False, True))
        self.emit.printout(code)

        #generate code for break label
        self.emit.printout(self.emit.emitIFFALSE(breakLabel, frame))

        #generate code for listStmt
        list(map(lambda x: self.visit(x, o), ast.sl))

        self.emit.printout(self.emit.emitGOTO(continueLabel, frame))
        self.emit.printout(self.emit.emitLABEL(breakLabel, frame))
        frame.exitLoop()

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

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

    def visitReturn(self, ast, o):
        frame = o.frame
        retType = frame.returnType
        expcode, expType = "", []
        if ast.expr:
            expcode, expType = self.visit(ast.expr,
                                          Access(frame, o.sym, False, True))
            if type(retType) != type(expType):
                expcode = expcode + self.emit.emitI2F(frame)
        self.emit.printout(expcode)
        self.emit.printout(self.emit.emitGOTO(frame.getEndLabel(), frame))

    def visitAssign(self, ast, o):
        cRight, retRight = self.visit(ast.exp,
                                      Access(o.frame, o.sym, False, True))
        cLeft, retLeft = self.visit(ast.lhs, Access(o.frame, o.sym, True,
                                                    False))
        code = cRight + cLeft
        if type(retRight) != type(retLeft):
            code = cRight + self.emit.emitI2F(o.frame) + cLeft
        self.emit.printout(code)

    def visitId(self, ast, o):
        sym = o.sym
        frame = o.frame
        sym = self.lookup(ast.name.lower(), sym, lambda x: x.name.lower())
        reType = sym.mtype
        cname = sym.value
        idx = sym.value.value
        id_code = ""
        # id is left not first
        if o.isLeft == True and o.isFirst == False:
            if type(cname) is CName:
                id_code = self.emit.emitPUTSTATIC(cname.value + "." + ast.name,
                                                  reType, frame)
            else:
                id_code = self.emit.emitWRITEVAR(ast.name, reType, idx, frame)
        elif o.isLeft == False:
            if type(cname) is CName:
                id_code = self.emit.emitGETSTATIC(cname.value + "." + ast.name,
                                                  reType, frame)
            else:
                id_code = self.emit.emitREADVAR(ast.name, reType, idx, frame)
        return id_code, reType

    def visitCallStmt(self, ast, o):
        #ast: CallStmt
        #o: Any

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

        in_ = ("", [])
        for x in ast.param:
            str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
            in_ = (in_[0] + str1, in_[1] + [typ1])
        self.emit.printout(in_[0])
        self.emit.printout(
            self.emit.emitINVOKESTATIC(cname + "/" + sym.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.lower(), nenv,
                          lambda x: x.name.lower())
        cname = sym.value.value
        ctype = sym.mtype

        in_ = ("", [])
        for x in ast.param:
            str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
            in_ = (in_[0] + str1, in_[1] + [typ1])

        return in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name,
                                                   ctype, frame), ctype.rettype

    def visitBinaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame

        lc, lt = self.visit(ast.left, o)
        rc, rt = self.visit(ast.right, o)
        retType = None

        if type(lt) == type(rt):
            if ast.op == '/':
                lc += self.emit.emitI2F(frame)
                rc += self.emit.emitI2F(frame)
                retType = FloatType()
            else:
                retType = lt
        elif type(lt) is IntType:
            lc += self.emit.emitI2F(frame)
            retType = FloatType()
        else:
            rc += self.emit.emitI2F(frame)
            retType = FloatType()
        if ast.op in ["+", "-"]:
            return lc + rc + self.emit.emitADDOP(ast.op, retType,
                                                 frame), retType
        elif ast.op in ["*", "/"]:
            return lc + rc + self.emit.emitMULOP(ast.op, retType,
                                                 frame), retType
        elif ast.op.lower() == "div":
            return lc + rc + self.emit.emitDIV(frame), retType
        elif ast.op.lower() == "mod":
            return lc + rc + self.emit.emitMOD(frame), retType
        elif ast.op.lower() == "and":  # and
            return lc + rc + self.emit.emitANDOP(frame), retType
        elif ast.op.lower() == "or":
            return lc + rc + self.emit.emitOROP(frame), retType
        elif ast.op.lower() in ["andthen", "orelse"]:
            pass
        else:  #( >, <, <>, =, >=, <=)
            return lc + rc + self.emit.emitREOP(ast.op, retType,
                                                frame), BoolType()

    def visitUnaryOp(self, ast, o):
        frame = o.frame
        op = ast.op.lower()
        cExp, retType = self.visit(ast.body, o)
        code = ""
        if op == "not":
            code = cExp + self.emit.emitNOT(retType, frame)
            retType = BoolType()
        elif op == "-":
            code = cExp + self.emit.emitNEGOP(retType, frame)
        return code, retType

    def visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any
        return self.emit.emitPUSHICONST(ast.value, o.frame), IntType()

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

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

    def visitStringLiteral(self, ast, o):
        return self.emit.emitPUSHCONST(ast.value, StringType(),
                                       o.frame), StringType()
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)
        list_vardecl=[]
        for item in ast.decl:
            if type(item) is VarDecl:
                self.visit(item, e)
                list_vardecl.insert(0,Symbol(item.variable,self.visit(item.varType,c),CName(self.className)))
            else:
                isMain= item.name.name == "main" and len(item.param)==0 and type(item.returnType) is VoidType
                intype=[ArrayPointerType(StringType())] if isMain else [self.visit(x.varType,c) for x in item.param]
                self.env.insert(0,Symbol(item.name.name,MType(intype,item.returnType),CName(self.className)))
        list(map(lambda x:self.visit(x,SubBody(None,self.env)) if type(x) is not VarDecl else None,ast.decl))
        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), None, Block(list())), c, Frame("<init>", VoidType))
        #generate function for static array global
        self.genMETHOD(FuncDecl(Id("<clinit>"), list(),None , Block(list())), list_vardecl, Frame("<clinit>", VoidType))
        self.emit.emitEPILOG()
        
        return c

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

        isInit = consdecl.returnType is None and consdecl.name.name=="<init>"
        # isMain = consdecl.name.name == "main" and len(consdecl.param) == 0 and type(consdecl.returnType) is VoidType
        isMain=consdecl.name.name == "main" and len(consdecl.param)==0 and type(consdecl.returnType) is VoidType

        isClinit=consdecl.name.name == "<clinit>"

        isFunc =(not isInit) and (not isMain) and (not isClinit)

        returnType = VoidType() if isInit else consdecl.returnType
        methodName = "<init>" if isInit else consdecl.name.name
        intype = [ArrayPointerType(StringType())] if isMain else [self.visit(x.varType,o) for x in consdecl.param]
        mtype = MType(intype, returnType)
        if isClinit:
            self.emit.printout(self.emit.emitMETHOD("<clinit>", MType([],VoidType()), isClinit, frame))
        else:
            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))
            [self.visit(x,SubBody(frame,glenv)) for x in [ivar for ivar in consdecl.body.member if type(ivar) is VarDecl]]
        if isFunc:
            [self.visit(x,SubBody(frame,glenv)) for x in (consdecl.param+[ivar for ivar in consdecl.body.member if type(ivar) is VarDecl])]

        body = consdecl.body
        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))
        if isClinit:
            for item in glenv:
                if type(item.mtype) is ArrayType:
                    get_dimen=item.mtype.dimen
                    # self.emit.printout(self.emit.emitREADVAR("this", ClassType(self.className), 0, frame))
                    self.emit.printout(self.emit.emitPUSHICONST(int(get_dimen),frame))
                    self.emit.printout(self.emit.emitNEWARRAY(item.mtype.eleType,frame))
                    self.emit.printout(self.emit.emitPUTSTATIC(item.value.value+"/"+item.name,item.mtype,frame))
        
        # list(map(lambda x: self.visit(x, SubBody(frame, glenv)) if type(x) is not VarDecl else None, body.member))
        #moi them
        for item_func in body.member:
            if type(item_func) is BinaryOp:
                self.visitStatement(item_func,SubBody(frame,glenv))
            elif type(item_func) is not VarDecl:
                self.visit(item_func,SubBody(frame,glenv))
        
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if type(returnType) is VoidType:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        if isClinit:
            self.emit.printout(self.emit.emitRETURN(VoidType(),frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any
        
        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.genMETHOD(ast, subctxt.sym.copy(), frame)
        # return SubBody(None, [Symbol(ast.name, MType(list(), ast.returnType), CName(self.className))] + subctxt.sym)
        return None

    def visitVarDecl(self,ast,o):
        frame=o.frame
        nenv=o.sym
        getType=self.visit(ast.varType,o)
        if frame is None: #vardecl in global
            nenv.insert(0,Symbol(ast.variable,getType,CName(self.className)))
            self.emit.printout(self.emit.emitATTRIBUTE(ast.variable,getType,False,""))
        else: #vardecl in function or block
            index=frame.getNewIndex()
            nenv.insert(0,Symbol(ast.variable,getType,Index(index)))
            self.emit.printout(self.emit.emitVAR(index,ast.variable,getType,frame.getStartLabel(),frame.getEndLabel(),frame))
            #declare for arraytype variable
            if type(getType) is ArrayType:
                get_dimen=ast.varType.dimen
                self.emit.printout(self.emit.emitPUSHICONST(int(get_dimen),frame))
                self.emit.printout(self.emit.emitNEWARRAY(getType.eleType,frame))
                self.emit.printout(self.emit.emitWRITEVAR(ast.variable,getType,index,frame))
        

    def visitBlock(self,ast,o):
        subtxt=o
        frame=subtxt.frame
        sym=subtxt.sym.copy()
        frame.enterScope(False)
        list(map(lambda x: self.visit(x,SubBody(frame,sym)) if type(x) is VarDecl else None,ast.member))
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(),frame))
        # get_list=list(map(lambda x: self.visit(x,SubBody(frame,sym)) if type(x) is not VarDecl else None,ast.member))
        get_list=[]
        for item in ast.member:
            if type(item) is BinaryOp:
                get_list.append(self.visitStatement(item,SubBody(frame,sym)))
            elif type(item) is not VarDecl:
                get_list.append(self.visit(item,SubBody(frame,sym)))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(),frame))
        frame.exitScope()
        for x in get_list:
            if str(x)=="Return":
                return "Return"
        return None


    #--------------------------------------Statement---------------------------------#
    def visitStatement(self,ast,o):
        codeBin,typeBin=self.visit(ast,o)
        self.emit.printout(codeBin)
        

    def visitReturn(self,ast,o):
        if ast.expr is None:
            self.emit.printout(self.emit.emitRETURN(VoidType(),o.frame))
        else:
            rettype=o.frame.returnType
            ecode, etype=self.visit(ast.expr,Access(o.frame,o.sym,False,True))
            temp=""
            if type(ast.expr) is ArrayCell:
                ecode1,etype1=self.visit(ast.expr,Access(o.frame,o.sym,False,False))
                temp=ecode1
                etype=etype.eleType
            if type(rettype) is FloatType and type(etype) is IntType:
                self.emit.printout(ecode + temp + self.emit.emitI2F(o.frame) + self.emit.emitRETURN(rettype,o.frame))
            else:
                self.emit.printout(ecode+ temp + self.emit.emitRETURN(rettype,o.frame))
        return "Return"

    def visitIf(self,ast,o):
        ctxt=o
        frame=o.frame
        sym=o.sym
        expCode, expType= self.visit(ast.expr,Access(frame,ctxt.sym,False,True))
        labelELSE= frame.getNewLabel()
        labelEXIT= frame.getNewLabel() if ast.elseStmt else None
        self.emit.printout(expCode+self.emit.emitIFFALSE(labelELSE,frame))
        # thenStmt=self.visit(ast.thenStmt,ctxt) if type(ast.thenStmt) is not BinaryOp else self.visitStatement(ast.thenStmt,ctxt)
        thenStmt=""
        if type(ast.thenStmt) is BinaryOp:
            thenStmt=self.visitStatement(ast.thenStmt,Access(frame,sym,False,True))
        elif type(ast.thenStmt) is CallExpr:
            thenStmt=self.visit(ast.thenStmt,SubBody(frame,sym))
        else:
            thenStmt=self.visit(ast.thenStmt,Access(frame,sym,False,True))

        self.emit.printout(self.emit.emitGOTO(labelEXIT,frame)) if ast.elseStmt and str(thenStmt) != "Return" else None
        self.emit.printout(self.emit.emitLABEL(labelELSE,frame))
        elseStmt=""
        if ast.elseStmt:
            # elseStmt=self.visit(ast.elseStmt,ctxt) if type(ast.elseStmt) is not BinaryOp else self.visitStatement(ast.elseStmt,ctxt)
            if type(ast.elseStmt) is BinaryOp:
                elseStmt=self.visitStatement(ast.elseStmt,Access(frame,sym,False,True))
            elif type(ast.elseStmt) is CallExpr:
                elseStmt=self.visit(ast.elseStmt,SubBody(frame,sym))
            else:
                elseStmt=self.visit(ast.elseStmt,Access(frame,sym,False,True))
            
            self.emit.printout(self.emit.emitLABEL(labelEXIT,frame))

        if str(thenStmt) == "Return" and str(elseStmt) == "Return":
            return "Return"
        return None
            
    def visitFor(self,ast,o):
        ctxt=o
        frame=o.frame
        sym=o.sym

        frame.enterLoop()
        labelLoop=frame.getNewLabel()
        labelBreak=frame.getBreakLabel()
        labelContinue=frame.getContinueLabel()
        
        #Generate code for initial expr
        self.visit(ast.expr1, Access(frame,sym,False,True)) if type(ast.expr1) is not BinaryOp else self.visitStatement(ast.expr1,Access(frame,sym,False,True))

        #Generate code label to start loop
        self.emit.printout(self.emit.emitLABEL(labelLoop,frame))
        #Generate code for condition expr
        expr2Code, expr2Type=self.visit(ast.expr2,Access(frame,sym,False,True))
        self.emit.printout(expr2Code)
        self.emit.printout(self.emit.emitIFFALSE(labelBreak,frame))
        #Generate code for loop statement
        # self.visit(ast.loop,Access(frame,sym,False,True)) if type(ast.loop) is not BinaryOp else self.visitStatement(ast.loop,Access(frame,sym,False,True))
        # self.visit(ast.loop,ctxt) if type(ast.loop) is not BinaryOp else self.visitStatement(ast.loop,ctxt)
        
        if type(ast.loop) is BinaryOp:
            self.visitStatement(ast.loop,Access(frame,sym,False,True))
        elif type(ast.loop) is CallExpr:
            self.visit(ast.loop,SubBody(frame,sym))
        else:
            self.visit(ast.loop,Access(frame,sym,False,True))

        #Generate code for expression step or increase variable count
        self.emit.printout(self.emit.emitLABEL(labelContinue,frame))
        self.visit(ast.expr3, Access(frame,sym,False,True)) if type(ast.expr3) is not BinaryOp else self.visitStatement(ast.expr3,Access(frame,sym,False,True))
        #goto label loop if condition is still true
        self.emit.printout(self.emit.emitGOTO(labelLoop,frame))
        #generate label exit or label break to exit
        self.emit.printout(self.emit.emitLABEL(labelBreak,frame))

        frame.exitLoop()

        return None

    # def visitDowhile(self,ast,o):
    #     ctxt=o
    #     frame=o.frame
    #     sym=o.sym

    #     frame.enterLoop()
    #     labelLoop=frame.getNewLabel()
    #     breakLabel=frame.getBreakLabel()
    #     continueLabel=frame.getContinueLabel()
    #     #generate label continue or label to start loop
    #     self.emit.printout(self.emit.emitLABEL(labelLoop,frame))
    #     #generate code for body of dowhile statement
    #     temp=[self.visit(x,Access(frame,sym,False,True)) for x in ast.sl]
    #     #generate code for label continue
    #     self.emit.printout(self.emit.emitLABEL(continueLabel,frame))
    #     #generate code for condition in while
    #     expCode,expType= self.visit(ast.exp,Access(frame,sym,False,True))
    #     self.emit.printout(expCode)
    #     #check condition is true or false
    #     self.emit.printout(self.emit.emitIFFALSE(breakLabel,frame))
    #     #goto label continue if condition is still true
    #     self.emit.printout(self.emit.emitGOTO(labelLoop,frame))
    #     #generate label exit or label break to exit
    #     self.emit.printout(self.emit.emitLABEL(breakLabel,frame))
        
    #     frame.exitLoop()
        # for item in temp:
        #     if str(item) == "Return":
        #         return "Return"
        # return None           

    def visitDowhile(self,ast,o):
        ctxt=o
        frame=o.frame
        sym=o.sym

        frame.enterLoop()

        labelStart = frame.getNewLabel() #new
        breakLabel=frame.getBreakLabel()
        continueLabel=frame.getContinueLabel()
        #generate label continue or label to start loop
        # self.emit.printout(self.emit.emitLABEL(continueLabel,frame)) 
        self.emit.printout(self.emit.emitLABEL(labelStart,frame)) 
        #generate code for body of dowhile statement
        # temp=[self.visit(x,Access(frame,sym,False,True)) for x in ast.sl]
        temp=[]
        for item in ast.sl:
            if type(item) is BinaryOp:
                temp.append(self.visitStatement(item,Access(frame,sym,False,True)))
            elif type(item) is CallExpr:
                temp.append(self.visit(item,SubBody(frame,sym)))
            else:
                temp.append(self.visit(item,Access(frame,sym,False,True)))
        self.emit.printout(self.emit.emitLABEL(continueLabel,frame))        
        #generate code for condition in while
        expCode,expType= self.visit(ast.exp,Access(frame,sym,False,True))
        self.emit.printout(expCode)
        #check condition is true or false
        self.emit.printout(self.emit.emitIFTRUE(labelStart,frame))
        #goto label continue if condition is still true
        # self.emit.printout(self.emit.emitGOTO(continueLabel,frame))
        #generate label exit or label break to exit
        self.emit.printout(self.emit.emitLABEL(breakLabel,frame))        
        frame.exitLoop()
        if temp != []:
            for x in temp:
                if str(x)== "Return":
                    return "Return"
                else:
                    return None
        else:
            return None
    
    def visitBreak(self,ast,o):
        frame=o.frame
        self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(),frame))

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

    #--------------------------------------Expression---------------------------------#


    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))

        in_=""
        merge=list(zip(ctype.partype,ast.param))
        
        for x in merge:
            str1, typ1=self.visit(x[1],Access(frame,nenv,False,True))
            # if type(typ1) is ArrayType:
            if type(x[1]) is ArrayCell:
                str2,typ2= self.visit(x[1],Access(frame,nenv,False,False))
                str1+=str2
            if type(x[0]) is FloatType and type(typ1) is IntType:
                str1+=self.emit.emitI2F(frame)
            in_+=str1
            # if type(typ1) is ArrayPointerType:
            #     in_+=str2
        
        if type(ctxt) is SubBody:
            self.emit.printout(in_ + self.emit.emitINVOKESTATIC(cname+"/"+ast.method.name,ctype,frame)) 
            return "", ctype.rettype 
        if ctxt.isLeft==False and ctxt.isFirst==True:
            temp=in_ + self.emit.emitINVOKESTATIC(cname+"/"+ast.method.name,ctype,frame)
            return temp, ctype.rettype
        elif ctxt.isLeft==False and ctxt.isFirst==False:
            str_code, str_type=self.visit(ast.method,Access(frame,nenv,False,False))
            return str_code,str_type
        else:
            frame.push()
            str_code, str_type=self.visit(ast.method,Access(frame,nenv,True,False))
            return str_code,str_type
        
    def check_is_assign(self,type_to_check):
        if type(type_to_check) is BinaryOp:
            if type_to_check.op == '=':
                return True
        return False

    def visitBinaryOp(self,ast,o):
        ctxt=o
        frame=ctxt.frame
        nenv=ctxt.sym
        #visit assign
        if ast.op == "=":
            
            if self.check_is_assign(ast.right):
                rightCode, typeRight=self.visit(ast.right,Access(frame,nenv,False,False))
            else:
                rightCode, typeRight=self.visit(ast.right,Access(frame,nenv,False,True))
            leftCode, typeLeft=self.visit(ast.left,Access(frame,nenv,True,True))
            if type(typeRight) is not ArrayPointerType:
                if type(ast.right) is BinaryOp:
                    if ast.right.op != "=":
                        rightCode, typeRight=self.visit(ast.right,Access(frame,nenv,False,True))
                else:
                    rightCode, typeRight=self.visit(ast.right,Access(frame,nenv,False,True))

            if type(typeRight) in [ArrayType,ArrayPointerType]: #visit to load
                if type(ast.right) not in [CallExpr,Id]:
                    if not self.check_is_assign(ast.right):
                        rightCode1, typeRight1=self.visit(ast.right,Access(frame,nenv,False,False))
                        rightCode+=rightCode1
            #visit for many assign
            # if type(ast.right) is BinaryOp:
            #     if ast.right.op == "=":
            #         # temp=self.emit.emitDUP(frame)
            #         # rightCode+=temp
            #         self.visit(ast.right,Access(frame,nenv,False,False))
            #         # rightCode+=rightCode1

            temp_access=""
            if type(o) is Access:
                if o.isLeft==False and o.isFirst==False:
                    if type(ast.left) is not ArrayCell:
                        temp_access=self.emit.emitDUP(frame)
                    if type(ast.left) is ArrayCell:
                        temp_access=self.emit.emitDUPX2(frame)
                    # return temp,typeLeft
                    # rightCode+=temp_access

            if (type(typeLeft) is FloatType and type(typeRight) is IntType) :
                # self.emit.printout(rightCode+self.emit.emitI2F(frame)+leftCode)
                rightCode+=self.emit.emitI2F(frame)+temp_access+leftCode
            elif type(typeLeft) in [ArrayType,ArrayPointerType]:
                temp=""
                if type(typeLeft.eleType) is FloatType and type(typeRight) is IntType:
                    temp=self.emit.emitI2F(frame)
                if type(typeLeft.eleType) is FloatType and type(typeRight) in [ArrayType,ArrayPointerType]:
                    if type(typeRight.eleType) is IntType:
                        temp=self.emit.emitI2F(frame)
                
                if type(ast.left) is ArrayCell:
                    # if self.check_is_assign(ast.right):
                    #     self.emit.printout(leftCode)
                    # else:

                    # self.emit.printout(leftCode+rightCode+temp)
                    self.emit.printout(leftCode)

                    rightCode+=temp+temp_access
                    leftCode, typeLeft= self.visit(ast.left,Access(frame,nenv,True,False))
                    # self.emit.printout(leftCode)
                    rightCode+=leftCode
                else: #visit if lhs is array type
                    # self.emit.printout(rightCode+temp)
                    rightCode+=temp+temp_access
                    frame.push()
                    leftCode, typeLeft= self.visit(ast.left,Access(frame,nenv,True,True))
                    # self.emit.printout(leftCode)
                    rightCode+=leftCode
            else:
                # self.emit.printout(rightCode+leftCode)
                rightCode+=temp_access+ leftCode
            
            return rightCode,typeLeft
            # return None
        else:   # visit others
            leftCode, typeLeft=self.visit(ast.left,Access(frame,nenv,False,True))
            rightCode, typeRight=self.visit(ast.right,Access(frame,nenv,False,True))
            #visit second times for array cell
            if type(typeLeft) in [ArrayType,ArrayPointerType]:
                leftCode1, typeLeft1=self.visit(ast.left,Access(frame,nenv,False,False))
                leftCode+=leftCode1
                typeLeft=typeLeft.eleType
            if type(typeRight) in [ArrayType,ArrayPointerType]:
                rightCode1, typeRight1=self.visit(ast.right,Access(frame,nenv,False,False))
                rightCode+=rightCode1
                typeRight=typeRight.eleType
            #cast type
            if type(typeRight) is IntType and type(typeLeft) is FloatType:
                rightCode+=self.emit.emitI2F(frame)
                typeRight=FloatType()
            elif type(typeRight) is FloatType and type(typeLeft) is IntType:
                leftCode+=self.emit.emitI2F(frame)
                typeLeft=FloatType()
            
            if ast.op in ['+','-','*','/']:
                op_str=leftCode+rightCode
                op_str+=self.emit.emitADDOP(ast.op,typeLeft,frame) if ast.op in ['+','-'] else self.emit.emitMULOP(ast.op,typeLeft,frame)
                res_type=typeLeft
            elif ast.op == '%':
                op_str=leftCode+rightCode
                op_str += self.emit.emitMOD(frame)    
                res_type=IntType()
            elif ast.op in ['||','&&']:
                op_str=leftCode+rightCode
                op_str+= self.emit.emitANDOP(frame) if ast.op=='&&' else self.emit.emitOROP(frame)
                res_type=BoolType()
            elif ast.op in ['==','!=','>','<','>=','<=']:
                temp_new=self.emit.emitREOP(ast.op,typeLeft,frame)
                op_str=leftCode+rightCode+temp_new
                res_type=BoolType()

            return op_str,res_type

    def visitUnaryOp(self,ast,o):
        if type(o) is SubBody:
            expCode, expType=self.visit(ast.body, Access(o.frame,o.sym,False,True))
            if ast.op=='!':
                op_str=expCode+self.emit.emitNOT(expType,o.frame)
            elif ast.op=='-':
                op_str=expCode+self.emit.emitNEGOP(expType,o.frame)
            return op_str,expType
        #type o is Access and visit the first times
        if o.isLeft==False and o.isFirst==True:
            expCode, expType=self.visit(ast.body, Access(o.frame,o.sym,False,True))
            if type(expType) in [ArrayType,ArrayPointerType]: #array cell is return immediately, to the second visit, load data done, after visit op
                return expCode,expType
            else:
                if ast.op=='!':
                    op_str=expCode+self.emit.emitNOT(expType,o.frame)
                elif ast.op=='-':
                    op_str=expCode+self.emit.emitNEGOP(expType,o.frame)
                return op_str,expType
        else:   #visit the second times
            expCode, expType=self.visit(ast.body, Access(o.frame,o.sym,False,False))
            if ast.op=='!':
                op_str=expCode+self.emit.emitNOT(expType.eleType,o.frame)
            elif ast.op=='-':
                op_str=expCode+self.emit.emitNEGOP(expType.eleType,o.frame)
            return op_str,expType
            
    def visitId(self,ast,o):
        get_id=self.lookup(ast.name,o.sym,lambda x:x.name)
        if o.isFirst:
            if o.isLeft: #store
                if type(get_id.value) is CName:
                    return self.emit.emitPUTSTATIC(get_id.value.value+"/"+get_id.name,get_id.mtype,o.frame), get_id.mtype
                else:
                    return self.emit.emitWRITEVAR(get_id.name,get_id.mtype,get_id.value.value,o.frame) , get_id.mtype
            else:   #load
                if type(get_id.value) is CName:
                    return self.emit.emitGETSTATIC(get_id.value.value+"/"+get_id.name,get_id.mtype,o.frame), get_id.mtype
                else:
                    return self.emit.emitREADVAR(get_id.name,get_id.mtype,get_id.value.value,o.frame), get_id.mtype
        else:   #visit seconds times for array cell
            if o.isLeft: #store
                if type(get_id.mtype) is not MType:
                    get_type=get_id.mtype.eleType
                    return self.emit.emitWRITEVAR2(get_id.name,get_type,o.frame),get_id.mtype
                elif type(get_id.mtype) is MType:
                    get_type=get_id.mtype.rettype.eleType
                    return self.emit.emitWRITEVAR2(get_id.name,get_type,o.frame),get_id.mtype.rettype
            else: #load
                if type(get_id.mtype) is MType:
                    get_type=get_id.mtype.rettype.eleType
                    return self.emit.emitREADVAR2(get_id.name,get_type,o.frame),get_id.mtype.rettype
                else:
                    get_type=get_id.mtype.eleType
                    return self.emit.emitREADVAR2(get_id.name,get_type,o.frame),get_id.mtype

    def visitArrayCell(self,ast,o):
        frame=o.frame
        sym=o.sym
        
        if o.isFirst: #Lan 1 cho ca hai ben
            codeArr,typeArr=self.visit(ast.arr,Access(frame,sym,False,True))
            codeIdx,typeIdx=self.visit(ast.idx,Access(frame,sym,False,True))
            if type(ast.idx) is ArrayCell:
                codeArr1,typeArr1=self.visit(ast.idx,Access(frame,sym,False,False))
                codeIdx+=codeArr1
            
        elif o.isFirst==False and o.isLeft==True: #Ben trai va lan 2
            codeArr,typeArr=self.visit(ast.arr,Access(frame,sym,True,False))
            codeIdx=""
           
        elif o.isFirst==False and o.isLeft==False: #Ben phai va lan 2
            codeArr,typeArr=self.visit(ast.arr,Access(frame,sym,False,False))
            codeIdx=""
        
        return codeArr+codeIdx,typeArr
    
    #-----------------------------------Literals----------------------------------#
    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):
        ctxt=o
        frame=ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value),frame), FloatType()

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

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

    #---------------------------Type--------------------------------#
    def visitIntType(self, ast, o):
        return IntType()
    
    def visitFloatType(self, ast, o):
        return FloatType()
    
    def visitBoolType(self, ast, o):
        return BoolType()
    
    def visitStringType(self, ast, o):
        return StringType()
    
    def visitVoidType(self, ast, o):
        return VoidType()
    
    def visitArrayType(self, ast, o):
        return ArrayType(int(ast.dimen),self.visit(ast.eleType,o))

    def visitArrayPointerType(self,ast,o):
        return ArrayPointerType(self.visit(ast.eleType,o))
Example #14
0
    def visitClassDecl(self, ast, c):
        #ast:ClassDecl
        #c:Any
        emit = Emitter(self.path + "/" + ast.classname.name + ".j")
        parentname = ast.parentname.name if ast.parentname else "java.lang.Object"
        emit.printout(emit.emitPROLOG(ast.classname.name, parentname))
        e = MethodEnv(emit, ast.classname.name, parentname, [])

        #genAttribute
        for x in self.env:
            if ast.classname.name == x.cname:
                for y in reversed(x.mem):
                    if type(y.mtype) is not MType:
                        isFinal = False if y.value is None else True
                        if type(y.sikind) is Static:
                            emit.printout(
                                emit.emitATTRIBUTE(y.name, y.mtype, isFinal,
                                                   ""))
                        else:
                            emit.printout(
                                emit.emitATTRIBUTE(y.name, y.mtype, isFinal,
                                                   ""))

                break
                ### ------------

        lstMethod = list(filter(lambda x: type(x) is MethodDecl, ast.memlist))
        list(map(lambda x: self.visit(x, e), lstMethod))
        # generate default constructor
        self.genMETHOD(
            MethodDecl(Instance(), Id("<init>"), list(), None,
                       Block(list(), list())), e, Frame("<init>", VoidType()))
        emit.emitEPILOG()
        return c
Example #15
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 = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.curFunc = None

    #generate the static field for global variable
    def VarGlobal(self, ast, c):
        ctxt = c
        nameAt = ast.variable.name
        typeAt = ast.varType 
        self.emit.printout(self.emit.emitATTRIBUTE(nameAt, typeAt, False, ""))
        symbol = Symbol(ast.variable.name, typeAt, 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 printoutstmt(self, ast, env):
        #env : subbody
        frame = env.frame
        newEnv = env.sym
        if type(ast) is Assign:
            self.emit.printout(self.visit(ast, Access(frame, newEnv, True, True))[0])
        elif type(ast) is BinaryOp:
            self.emit.printout(self.visit(ast, Access(frame, newEnv, False, True))[0])
        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

        elif type(ast) is CallStmt:
            self.emit.printout(self.visit(ast, SubBody(frame, newEnv)))
        elif type(ast) is UnaryOp or type(ast) is Id 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))[0])
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            self.visit(ast, env)


    def visitProgram(self, ast, c):
        #ast: Program
        #c: Any
        self.emit.printout(self.emit.emitPROLOG(self.className, "java.lang.Object"))
        nenv = 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 [])
        
        lstFunc = list(filter(lambda x:type(x) is FuncDecl, ast.decl))
        reduce(lambda a,b: self.visit(b,a), lstFunc, SubBody(None, nenv))
        #e = SubBody(None, self.env)
        #for x in ast.decl:
        #    e = self.visit(x, e)
        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(),None), c, Frame("<init>", VoidType))
        self.emit.emitEPILOG()
        return c

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

    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)

        #generate method for a function . use emitMETHOD(methodname, type_descrip, true if static, frame)
        self.emit.printout(self.emit.emitMETHOD(methodName, mtype, not isInit, frame))

        #involked when parsing new scope
        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 a,b: self.visit(b,a), consdecl.param, SubBody(frame, glenv))

        temp = glSubBody
        glSubBody = reduce(lambda a,b: self.visit(b, a), consdecl.local, temp) 

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

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

        #list(map(lambda x: self.visit(x, SubBody(frame, glSubBody.sym)), body))
        list(map(lambda x: self.printoutstmt(x, glSubBody),body))
        
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))

        returnstmt = list(filter(lambda x: type(x)is Return, body))
        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 visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any ... subbody
        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.curFunc = self.lookup(ast.name.name.lower(), subctxt.sym, lambda x: x.name.lower())
        self.genMETHOD(ast, subctxt.sym, frame)

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

    def visitAssign(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        env = ctxt.sym

        assign_str = ""
        str_I2F = ""

        (resLeft, typeLeft) = self.visit(ast.lhs, Access(frame, env, True, True))
        (resRight, typeRight) = self.visit(ast.exp, Access(frame, env, False, True))

        if type(typeLeft) == FloatType and type(typeRight) == IntType:
            str_I2F = self.emit.emitI2F(frame)

        (resLeft1, typeLeft1) = self.visit(ast.lhs, Access(frame, env, True, False))
        assign_str = resLeft + resRight + str_I2F + resLeft1
        resType = typeLeft1

        return (assign_str, resType)
    
    def visitIf(self, ast, c):
        #c : SubBody
        frame = c.frame
        env = c.sym
        (resExpr, typeExpr) = self.visit(ast.expr, Access(frame, env, False, True))
        if not ast.elseStmt:
            falseLabel = frame.getNewLabel()
            self.emit.printout(resExpr + self.emit.emitIFFALSE(falseLabel, frame))
            list(map(lambda x: self.printoutstmt(x, c),ast.thenStmt))
            self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
        else:
            falseLabel = frame.getNewLabel()
            trueLabel = frame.getNewLabel()
            self.emit.printout(resExpr + self.emit.emitIFFALSE(falseLabel, frame))
            list(map(lambda x: self.printoutstmt(x, c),ast.thenStmt))
            self.emit.printout(self.emit.emitGOTO(str(trueLabel), frame) + self.emit.emitLABEL(str(falseLabel), frame))
            list(map(lambda x: self.printoutstmt(x, c),ast.elseStmt))
            self.emit.printout(self.emit.emitLABEL(str(trueLabel), frame))


    def visitWhile(self, ast, c):
        frame = c.frame
        env = c.sym

        frame.enterLoop()
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        resExpr, typeExpr = self.visit(ast.exp,Access(frame, env,False,False))
        self.emit.printout(resExpr)
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))
        list(map(lambda x:self.printoutstmt(x,c) ,ast.sl))
        self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitFor(self, ast, c):
        frame = c.frame
        env = c.sym
        beginLabel = frame.getNewLabel()
        frame.enterLoop()
        #sinh ma cho expr1
        self.emit.printout(self.visit(Assign(ast.id,ast.expr1),SubBody(frame, env))[0])
        self.emit.printout(self.emit.emitLABEL(beginLabel, frame))
        
        #sinh ma cho expr2
        op_ = ('<=','+') if ast.up is True else ('>=','-')
        self.emit.printout(self.visit(BinaryOp(op_[0],ast.id,ast.expr2),SubBody(frame, env))[0])
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))

        #sinh stmt
        list(map(lambda x:self.printoutstmt(x,c) ,ast.loop))

        #sinh ma continue
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        
        #sinh ma expr3
        self.emit.printout(self.visit(Assign(ast.id,BinaryOp(op_[1],ast.id,IntLiteral(1))),SubBody(frame, env))[0])
        
        #back
        self.emit.printout(self.emit.emitGOTO(beginLabel, frame))

        #sinh ma break
        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 visitWith(self, ast, c):
        #decl:list(VarDecl)
        #stmt:list(Stmt)
        frame = c.frame
        env = c.sym
            
        frame.enterScope(False)
        withSubBody = reduce(lambda a,b: self.visit(b, a), ast.decl, c)
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        list(map(lambda x: self.printoutstmt(x, withSubBody),ast.stmt))  
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) 
        frame.exitScope()
        
        return c

    def visitReturn(self, ast, c):
        #expr:Expr
        if ast.expr:
            (resExpr, resType) = self.visit(ast.expr, Access(c.frame, c.sym, False, 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 visitCallStmt(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name.lower(), nenv, lambda x: x.name.lower())

        method_name = sym.name
        cname = sym.value.value
        ctype = sym.mtype
        returnType = ctype.rettype

        listparamType = ctype.partype
        
        checkList = []
        for item in range(len(listparamType)):
            checkList.append((ast.param[item], listparamType[item]))
        
        in_ = ("", [])
        for x in checkList:
            #gan param
            (code, ty) = self.visit(x[0], Access(frame, nenv, False, True))
            if type(ty) is IntType and type(x[1]) is FloatType:
                in_ = (in_[0] + code + self.emit.emitI2F(frame), in_[1] + [ty])
            else:
                in_ = (in_[0] + code, in_[1] + [ty])
        
        return in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + method_name, ctype, frame)

    def visitCallExpr(self, ast, o):
        #ast: CallStmt
        #o: Any
        #method:Id
        #param:list(Expr)
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name.lower(), nenv, lambda x: x.name.lower())

        method_name = sym.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 : param
                #typ1 : type param
                (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] + [typ1])
                else:
                    in_ = (in_[0] + str1, in_[1] + [typ1])
        
        return (in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + method_name, ctype, frame), returnType)
        #return (in_[0], returnType)
          

    def visitBinaryOp(self, ast, c):
        #op:string
        #left:Expr
        #right:Expr
        ctxt = c
        frame = c.frame
        env = ctxt.sym
        op = ast.op
        resType = IntType()
        code = ""
        opstr = ""
        stri2f = ""

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

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


        elif op.lower() == "div":
            opstr = resLeft + resRight + self.emit.emitDIV(frame)
            resType = IntType()
        elif op.lower() == "mod":
            opstr = 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:
                opstr = resLeft + resRight + self.emit.emitI2F(frame) + self.emit.emitREOP(op, FloatType(), frame)
            elif type(typeLeft) is IntType and type(typeRight) is FloatType:
                opstr = resLeft + self.emit.emitI2F(frame) + resRight + self.emit.emitREOP(op, FloatType(), frame)
            else:
                opstr = resLeft + resRight + self.emit.emitREOP(op, typeLeft, frame)
            resType = BoolType()
        
        elif (op == "<>" or op == "="):
            if type(typeLeft) is FloatType and type(typeRight) is IntType:
                opstr = resLeft + resRight + self.emit.emitI2F(frame) + self.emit.emitREOP(op, FloatType(), frame)
            elif type(typeLeft) is IntType and type(typeRight) is FloatType:
                opstr = resLeft + self.emit.emitI2F(frame) + resRight + self.emit.emitREOP(op, FloatType(), frame)
            else:
                opstr = resLeft + resRight + self.emit.emitREOP(op, typeLeft, frame)
            
            resType = BoolType()
            
        elif (op.lower() == "and" or op.lower() == "or"):
            #opstr = resLeft + resRight + self.emit.emitANDOP(frame) if ast.op.lower() == "and" else self.emit.emitOROP(frame)
            if ast.op.lower() == "and":
                opstr = resLeft + resRight + self.emit.emitANDOP(frame)
            elif ast.op.lower() == "or":
                opstr = resLeft + resRight + self.emit.emitOROP(frame)
            resType = BoolType()
        elif ast.op.lower() == "andthen" or ast.op.lower() == "orelse":
            opstr = self.emit.emitAndThen_OrElse(ast.op.lower(), resLeft, resRight, frame)
            resType = BoolType()
        
        return(opstr, 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))
        if ast.op.lower() == "not":
            return (resExpr + self.emit.emitNOT(typeExpr, frame), typeExpr)

        elif ast.op == "-": 
            return (resExpr + self.emit.emitNEGOP(typeExpr, frame), typeExpr)
    

    
    def visitId(self, ast, o):
        #o : Access or SubBody
        
        if type(o) is not SubBody: 
            sym = self.lookup(ast.name.lower(), o.sym, lambda x: x.name.lower())

            name_id = sym.name
            code = ""
            if o.isLeft is True and o.isFirst is True:
                pass
            #putStatic or store var
            elif o.isLeft is True:
                if type(sym.value) is CName:
                    code = self.emit.emitPUTSTATIC(sym.value.value + "." + name_id, sym.mtype, o.frame)
                elif type(sym.value) is Index:
                    code = self.emit.emitWRITEVAR(name_id, sym.mtype, sym.value.value, o.frame)
            #if lhs -> getstatic or load var
            elif o.isLeft is False:
                if type(sym.value) is CName:
                    code = self.emit.emitGETSTATIC(sym.value.value + "." + name_id, sym.mtype, o.frame)
                elif type(sym.value) is Index:
                    code = self.emit.emitREADVAR(name_id, 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 visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(int(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 visitBooleanLiteral(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        return (self.emit.emitPUSHICONST(str(ast.value).lower(), frame), BoolType())

    def visitStringLiteral(self, ast, o):
        #ast: StringLiteral
        #o: Any
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHCONST(str(ast.value), StringType(), frame), StringType()
Example #16
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")
            # not in original version
        self.listGlobalArray = [] # list(VarDecl: array declare global)


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

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

        ###################################################################################
        staticDecl = self.env
        for x in ast.decl:
            if type(x) is FuncDecl:
                partype = [i.varType for i in x.param]
                staticDecl = [Symbol(x.name.name.lower(), MType(
                    partype, x.returnType), CName(self.className))] + staticDecl
            else:
                newSym = self.visit(x, SubBody(None, None, isGlobal=True))
                staticDecl = [newSym] + staticDecl

        e = SubBody(None, staticDecl)

        # visit ast tree
        for x in ast.decl:
            if type(x) is FuncDecl:
                e = self.visit(x, e)

        ###################################################################################

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

    def visitVarDecl(self, ast: VarDecl, o: SubBody):
        subctxt = o
        frame = o.frame
        isGlobal = o.isGlobal
        varName = ast.variable
        varType = ast.varType
        if isGlobal:
            self.emit.printout(self.emit.emitATTRIBUTE(varName, StupidUtils.retrieveType(varType), False, ""))
            if type(ast.varType) is ArrayType: 
                self.listGlobalArray.append(ast)
            return Symbol(varName, varType)
        # params
        idx = frame.getNewIndex()
        self.emit.printout(self.emit.emitVAR(idx, varName, StupidUtils.retrieveType(varType), frame.getStartLabel(), frame.getEndLabel(), frame))
        return SubBody(frame, [Symbol(varName, varType, Index(idx))] + subctxt.sym)

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

        glenv = o

        methodName = consdecl.name.name

        isInit = consdecl.returnType is None and methodName == "<init>"
        isClassInit = consdecl.returnType is None and methodName == "<clinit>"
        isMain = consdecl.name.name == "main" and len(consdecl.param) == 0 and type(consdecl.returnType) is VoidType
        returnType = VoidType() if isInit or isClassInit else consdecl.returnType
        methodName = "<init>" if isInit else consdecl.name.name
        intype = [ArrayPointerType(StringType())] if isMain else [StupidUtils.retrieveType(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))

        # listParamArray = [] # list(Symbol(name, mtype, value: Index(idx)))
        # listLocalArray = [] # list(Symbol(name, mtype, value: Index(idx)))
        paramList = SubBody(frame, glenv)

        for x in consdecl.param:
            paramList = self.visit(x, paramList)
            if type(x.varType) is ArrayType:
                listParamArray.append(paramList.sym[0])

        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))

        # # Init global array declare
        # if isClassInit:
        #     for x in self.listGlobalArray:
        #         size = x.varType.upper - x.varType.lower + 1
        #         self.emit.printout(self.emit.emitInitNewStaticArray(self.className + "/" + x.variable.name, size, x.varType.eleType, frame))

        # # Init local array declare
        # for sym in listLocalArray:
        #     index = sym.value.value
        #     varType = sym.mtype
        #     size = varType.upper - varType.lower + 1
        #     self.emit.printout(self.emit.emitInitNewLocalArray(index, size, varType.eleType, frame))

        # # Clone params array
        # for sym in listParamArray:
        #     index = sym.value.value
        #     eleType = sym.mtype.eleType
        #     self.emit.printout(self.emit.emitCloneArray(index, eleType, frame))

        # for x in o:
        #     print(x)

        # visit block member
        # list(map(lambda x: self.visit(x, SubBody(frame, paramList.sym)), consdecl.body.member))
        self.visit(consdecl.body, SubBody(frame, paramList.sym))

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

    def visitBlock(self, ast: Block, o: SubBody):
        ctxt = o
        frame = ctxt.frame
        symbols = ctxt.sym

        listLocalArray = [] # list(Symbol(name, mtype, value: Index(idx)))

        hasReturnStmt = False
        for x in ast.member:
            if type(x) is VarDecl:
                # var decl
                ctxt = self.visit(x, ctxt)
                symbols = ctxt.sym
                # handle array variable
                if type(x.varType) is ArrayType:
                    index = ctxt.sym[0].value.value
                    varType = ctxt.sym[0].mtype
                    size = varType.dimen
                    self.emit.printout(self.emit.emitInitNewLocalArray(index, size, varType.eleType, frame))
            else:
                # statement
                e = SubBody(frame, symbols)
                if self.visit(x, e) == True:
                    hasReturnStmt = True
        return hasReturnStmt

    def visitCallExpr(self, ast: CallExpr, o):
        # call statement
        if type(o) is SubBody:
            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
            paramType = ctype.partype

            paramsCode = ""
            idx = 0
            for x in ast.param:
                pCode, pType = self.visit(x, Access(frame, nenv, False, True))
                if type(paramType[idx]) is FloatType and type(pType) is IntType:
                    pCode = pCode + self.emit.emitI2F(frame)
                if type(paramType[idx]) is ArrayType:
                    pass
                paramsCode = paramsCode + pCode
                idx = idx + 1
        
            code = paramsCode + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame) 
            self.emit.printout(code)

            # idx = 0
            # in_ = ("", [])
            # for x in ast.param:
            #     pCode, pType = self.visit(x, Access(frame, nenv, False, True))
            #     if type(paramType[idx]) is FloatType and type(pType) is IntType:
            #         pCode = pCode + self.emit.emitI2F(frame)
            #     in_ = (in_[0] + pCode, in_[1].append(pType))
            #     idx = idx + 1

            # code = in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame)
            # self.emit.printout(code)
        else:
            # call expression
            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
            paramType = ctype.partype


            paramsCode = ""
            idx = 0
            for x in ast.param:
                pCode, pType = self.visit(x, Access(frame, nenv, False, True))
                if type(paramType[idx]) is FloatType and type(pType) is IntType:
                    pCode = pCode + self.emit.emitI2F(frame)
                if type(paramType[idx]) is ArrayType:
                    pass
                paramsCode = paramsCode + pCode
                idx = idx + 1
        
            code = paramsCode + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame) 
            return code, ctype.rettype

            # idx = 0
            # in_ = ("", [])
            # for x in ast.param:
            #     print(len(ast.param))
            #     pCode, pType = self.visit(x, Access(frame, nenv, False, True))
            #     if type(paramType[idx]) is FloatType and type(pType) is IntType:
            #         pCode = pCode + self.emit.emitI2F(frame)
            #     in_ = (in_[0] + pCode, in_[1].append(pType))
            #     idx = idx + 1

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

    def visitIf(self, ast: If, o: SubBody):
        # ctxt = o
        # frame = ctxt.frame
        # nenv = ctxt.sym
        # # [print(x) for x in nenv]
        # expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, True))
        # self.emit.printout(expCode)

        # labelT = frame.getNewLabel() # eval is true
        # labelE = frame.getNewLabel() # label end

        # self.emit.printout(self.emit.emitIFTRUE(labelT, frame)) # false
        # # False
        # self.visit(ast.elseStmt, ctxt)
        # self.emit.printout(self.emit.emitGOTO(labelE, frame)) # go to end
        # # True
        # self.emit.printout(self.emit.emitLABEL(labelT, frame))
        # self.visit(ast.thenStmt, ctxt)
        # # End
        # self.emit.printout(self.emit.emitLABEL(labelE, frame))
        # return False

        ######################################################################
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, True))
        self.emit.printout(expCode)
        if ast.elseStmt:
            labelT = frame.getNewLabel() # eval is true
            labelE = frame.getNewLabel() # label end

            self.emit.printout(self.emit.emitIFTRUE(labelT, frame)) # false
            # False
            hasReturnStmt = True in [self.visit(ast.elseStmt, ctxt)]
            if not hasReturnStmt:
                    self.emit.printout(self.emit.emitGOTO(labelE, frame)) # go to end
            # True
            self.emit.printout(self.emit.emitLABEL(labelT, frame))
            hasReturnStmt = True in [self.visit(ast.thenStmt, ctxt)] and hasReturnStmt
            # End
            self.emit.printout(self.emit.emitLABEL(labelE, frame))
            return hasReturnStmt
        else:
            labelT = frame.getNewLabel() # eval is true
            labelE = frame.getNewLabel() # label end

            self.emit.printout(self.emit.emitIFTRUE(labelT, frame)) # false
            self.emit.printout(self.emit.emitGOTO(labelE, frame)) # go to end
            # True
            self.emit.printout(self.emit.emitLABEL(labelT, frame))
            hasReturnStmt = True in [self.visit(ast.thenStmt, ctxt)] and hasReturnStmt
            # End
            self.emit.printout(self.emit.emitLABEL(labelE, frame))
            return hasReturnStmt

    def visitDowhile(self, ast: Dowhile, o: SubBody):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True))
        
        # do statement once before go in loop
        frame.enterLoop()
        [self.visit(x, o) for x in ast.sl]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

        labelS = frame.getNewLabel() # label start
        labelE = frame.getNewLabel() # label end
        # enter loop
        frame.enterLoop()
        self.emit.printout(self.emit.emitLABEL(labelS, frame))
        self.emit.printout(expCode)
        self.emit.printout(self.emit.emitIFFALSE(labelE, frame))
        hasReturnStmt = True in [self.visit(x, o) for x in ast.sl]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        if not hasReturnStmt:
            self.emit.printout(self.emit.emitGOTO(labelS, frame)) # loop
        self.emit.printout(self.emit.emitLABEL(labelE, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

        # def visitBreak(self, ast: Break, o: SubBody):
        # ctxt = o
        # frame = ctxt.frame
        # return self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))


    def visitFor(self, ast: For, o: SubBody):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym

        exp2Code, _ = self.visit(ast.expr2, Access(frame, nenv, False, True))
        
        labelS = frame.getNewLabel() # label start
        labelE = frame.getNewLabel() # label end

        # Init value
        self.visit(ast.expr1, SubBody(frame, nenv))
        frame.enterLoop()
        # Loop
        self.emit.printout(self.emit.emitLABEL(labelS, frame))
        # 1. Condition
        self.emit.printout(exp2Code)
        self.emit.printout(self.emit.emitIFFALSE(labelE, frame))
        # 2. Statements
        hasReturnStmt = True in [self.visit(ast.loop, ctxt)]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        # 3. Update index
        self.visit(ast.expr3, SubBody(frame, nenv))

        if not hasReturnStmt:
            self.emit.printout(self.emit.emitGOTO(labelS, frame)) # loop
        self.emit.printout(self.emit.emitLABEL(labelE, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitReturn(self, ast: Return, o: SubBody):

        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        retType = frame.returnType

        if not type(retType) is VoidType:
            expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, True))
            if type(retType) is FloatType and type(expType) is IntType:
                expCode = expCode + self.emit.emitI2F(frame)
            self.emit.printout(expCode)
        self.emit.printout(self.emit.emitRETURN(retType, frame))
        return True

    def visitBreak(self, ast: Break, o: SubBody):
        ctxt = o
        frame = ctxt.frame
        return self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))

    def visitContinue(self, ast: Continue, o: SubBody):
        ctxt = o
        frame = ctxt.frame
        return self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))

    #################### Expression ######################
    def visitId(self, ast: Id, o: Access):
        # Return (name, type, index)
        ctxt = o
        frame = ctxt.frame
        symbols = ctxt.sym
        isLeft = ctxt.isLeft
        isFirst = ctxt.isFirst


        if isLeft and ctxt.checkArrayType:
            return False, None

        sym = self.lookup(ast.name, symbols, lambda x: x.name)

        # recover status of stack in frame
        if not isFirst and isLeft: 
            frame.push()
        elif not isFirst and not isLeft: 
            frame.pop()

        isArrayType = type(sym.mtype) is ArrayType
        emitType = StupidUtils.retrieveType(sym.mtype)
        if sym.value is None: # not index -> global var - static field
            if isLeft and not isArrayType:
                retCode = self.emit.emitPUTSTATIC(self.className + "/" + sym.name, emitType, frame)
            else:
                retCode = self.emit.emitGETSTATIC(self.className + "/" + sym.name, emitType, frame)
        else:
            if isLeft and not isArrayType:
                retCode = self.emit.emitWRITEVAR(sym.name, emitType, sym.value.value, frame)
            else:
                retCode = self.emit.emitREADVAR(sym.name, emitType, sym.value.value, frame)

        return retCode, sym.mtype

    
    def visitArrayCell(self, ast: ArrayCell, o: Access):
        ctxt = o
        frame = ctxt.frame
        symbols = ctxt.sym
        isLeft = ctxt.isLeft
        isFirst = ctxt.isFirst

        if isLeft and ctxt.checkArrayType: return True, None

        arrCode, arrType = self.visit(ast.arr, Access(frame, symbols, True, True))
        idxCode, idxType = self.visit(ast.idx, Access(frame, symbols, False, True))
        # update index jvm, i.e [3..5] -> [0..2], access [4] -> [1]
        # idxCode = idxCode + self.emit.emitPUSHICONST(arrType.lower, frame) + self.emit.emitADDOP('-', IntType(), frame)
        # Steps: aload(address index) -> iconst(access index) -> iaload
        if isLeft:
            return [arrCode + idxCode, self.emit.emitASTORE(arrType.eleType, frame)], arrType.eleType
        return arrCode + idxCode + self.emit.emitALOAD(arrType.eleType, frame), arrType.eleType
        

    def visitBinaryOp(self, ast: BinaryOp, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        op = str(ast.op)
            
        if StupidUtils.isOpForNumber(op): # for number type
            lCode, lType = self.visit(ast.left, ctxt)
            rCode, rType = self.visit(ast.right, ctxt)
            mType = StupidUtils.mergeNumberType(lType, rType)
            # if op == '/': 
            #     mType = FloatType() # mergeType >= lType, rType
            if type(lType) is IntType and type(mType) != type(lType):
                lCode = lCode + self.emit.emitI2F(frame)
            if type(rType) is IntType and type(mType) != type(rType):
                rCode = rCode + self.emit.emitI2F(frame)
            if StupidUtils.isOpForNumberToNumber(op):
                if op in ['+', '-']:
                    return lCode + rCode + self.emit.emitADDOP(op, mType, frame), mType
                if op in ['*', '/']:
                    return lCode + rCode + self.emit.emitMULOP(op, mType, frame), mType
                if op == '%':
                    return lCode + rCode + self.emit.emitMOD(frame), mType
            else: # op to boolean: > <= == !=, ...
                return lCode + rCode + self.emit.emitREOP(op, mType, frame), BoolType()
        elif op == '=':
            if type(o) is Access:
                # print("access")
                isArray, _ = self.visit(ast.left, Access(frame, nenv, True, True, True))

                if not isArray:
                    expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True))
                    lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

                    if type(lhsType) is FloatType and type(expType) is IntType:
                        expCode = expCode + self.emit.emitI2F(frame)
                    self.emit.printout(expCode + self.emit.emitDUP(frame) + lhsCode)
                    return "",expType
                else:
                    for i in range(0, 2): frame.push()

                    # handle array
                    if o.getLeft == False:
                        # print("right")
                        expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True, False, False))
                        lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

                        if type(lhsType) is FloatType and type(expType) is IntType:
                            expCode = expCode + self.emit.emitI2F(frame)
                        self.emit.printout(lhsCode[0])
                        for i in range(0, 2): frame.push()
                        return expCode, expType
                    elif o.getLeft == True:
                        # print("left")
                        expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True, False, True))
                        lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

                        if type(lhsType) is FloatType and type(expType) is IntType:
                            expCode = expCode + self.emit.emitI2F(frame)
                        self.emit.printout(self.emit.emitDUPX2(frame) + lhsCode[1])
                        for i in range(0, 2): frame.push()
                        return None, None
            else:
                # print("subbody")
                isArray, _ = self.visit(ast.left, Access(frame, nenv, True, True, True))

                if isArray:
                    # handle array
                    for i in range(0, 2): frame.push()

                    lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))
                    expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True))
                    self.emit.printout(lhsCode[0] + expCode)
                    _, _ = self.visit(ast.right, Access(frame, nenv, False, True, False, True))
                    self.emit.printout(lhsCode[1])
                    
                    for i in range(0, 2): frame.pop()
                else:
                    # push 1 slot for duplicate value
                    frame.push()
                    expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True))
                    lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

                    if type(lhsType) is FloatType and type(expType) is IntType:
                        expCode = expCode + self.emit.emitI2F(frame)

                    self.emit.printout(expCode + lhsCode)
                    # recover status of stack
                    frame.pop()

                ###################################################
                # frame.push()
                # expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True))
                # lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

                # if type(lhsType) is FloatType and type(expType) is IntType:
                #     expCode = expCode + self.emit.emitI2F(frame)
                # if not isArray:
                #     self.emit.printout(expCode + lhsCode)
                #     frame.pop()
                # else:
                #     self.emit.printout(lhsCode[0] + expCode + lhsCode[1])
                #     [frame.pop() for i in range(0,2)]
            ############################################################################
            # isArray, _ = self.visit(ast.left, Access(frame, nenv, True, True, True))

            # if isArray:
            #     for i in range(0, 2):
            #         frame.push()

            # expCode, expType = self.visit(ast.right, Access(frame, nenv, False, True))
            # lhsCode, lhsType = self.visit(ast.left, Access(frame, nenv, True, True))

            # if type(lhsType) is FloatType and type(expType) is IntType:
            #     expCode = expCode + self.emit.emitI2F(frame)
            # if not isArray:
            #     self.emit.printout(expCode + lhsCode)
            # else:
            #     self.emit.printout(lhsCode[0] + expCode + lhsCode[1])
            #     # recover stack status
            #     [frame.pop() for i in range(0,2)]
            # return expCode + lhsCode, None

        else: # for boolean type
            lCode, lType = self.visit(ast.left, ctxt)
            rCode, rType = self.visit(ast.right, ctxt)
            mType = BoolType()
            if op == '||': return lCode + rCode + self.emit.emitOROP(frame), mType
            if op == '&&': return lCode + rCode + self.emit.emitANDOP(frame), mType


    def visitUnaryOp(self, ast: UnaryOp, o: Access):
        ctxt = o
        frame = ctxt.frame
        op = ast.op
        bodyCode, bodyType = self.visit(ast.body, ctxt)
        if op == '-':
            return bodyCode + self.emit.emitNEGOP(bodyType, frame), bodyType
        if op == '!':
            return bodyCode + self.emit.emitNOT(bodyType, frame), bodyType

    ###################### Literal ##########################
    def visitIntLiteral(self, ast: IntLiteral, o: Access):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()

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

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

    def visitStringLiteral(self, ast: StringLiteral, o: Access):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHCONST(ast.value, StringType(), frame), StringType()
Example #17
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

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

        # Get all decl init

        for decl in ast.decl:
            if isinstance(decl, VarDecl):
                self.emit.printout(self.emit.emitATTRIBUTE(
                    decl.variable, decl.varType))
                temp = Symbol(decl.variable, decl.varType)
                c.sym.append(temp)
            else:
                temp = Symbol(decl.name.name, MType(
                    [x.varType for x in decl.param], decl.returnType), CName(self.className))
                c.sym.append(temp)

        # Initial class method (object constructor)
        init_frame = Frame('<clinit>', VoidType())
        self.emit.printout(self.emit.emitMETHOD(
            '<clinit>', MType([], VoidType()), False, init_frame))

        # generate default constructor
        for x in ast.decl:
            if isinstance(x, VarDecl) and isinstance(x.varType, ArrayType):
                self.emit.printout(self.emit.emitPUSHICONST(
                    x.varType.dimen, init_frame))
                self.emit.printout(self.emit.emitNEWARRAY(x.varType.eleType))
                self.emit.printout(self.emit.emitPUTSTATIC(
                    self.className + '.' + x.variable, x.varType, init_frame))
        self.emit.printout(self.emit.emitLIMITSTACK(
            init_frame.getMaxOpStackSize()))
        self.emit.printout(self.emit.emitLIMITLOCAL(init_frame.getMaxIndex()))
        self.emit.printout(self.emit.emitRETURN(VoidType(), init_frame))
        

        self.emit.printout(self.emit.emitENDMETHOD(init_frame))

        #start visit others
        for decl in ast.decl:
            if isinstance(decl, FuncDecl):
                self.visit(decl, c)
        self.emit.emitEPILOG()
        return

    def visitFuncDecl(self, ast, c):
        method_header = ''
        frame = None
        if (ast.name.name == 'main'):
            frame = Frame('main', VoidType())
            method_header = self.emit.emitMETHOD('main', MType(
                [ArrayPointerType(StringType())], VoidType()), True, frame)
            c.is_main = True

        else:
            c.is_main = False
            frame = Frame(ast.name.name, ast.returnType)
            method_header = self.emit.emitMETHOD(ast.name.name, MType(
                [x.varType for x in ast.param], ast.returnType), True, frame)

        self.emit.printout(method_header)
        c.frame = frame
        c.func_param = ast.param
        c.is_body = True
        c.return_type = ast.returnType
        result = self.visit(ast.body, c)

        self.emit.printout(self.emit.emitLIMITSTACK(frame.getMaxOpStackSize()))
        self.emit.printout(self.emit.emitLIMITLOCAL(frame.getMaxIndex()))

        self.emit.printout(result)
        self.emit.printout(self.emit.emitENDMETHOD(frame))

    def visitBlock(self, ast, c):
        c = c.dup()
        frame = c.frame
        frame.enterScope(c.is_body)
        result = []
        block_header = []
        start_label = frame.getStartLabel()
        end_label = frame.getEndLabel()

        # Before enter scope, params insert/init
        if (c.is_body):
            if (c.is_main):
                t = self.emit.emitVAR(frame.getNewIndex(), 'args', ArrayPointerType(
                    StringType()), start_label, end_label, frame)
                block_header.append(t)
            else:
                for decl in c.func_param:
                    t1, t2 = self.visit(decl, c)
                    block_header.append(t1)
                    result += t2

        # Inside block
        result.append(self.emit.emitLABEL(start_label, frame))
        for stmt in ast.member:
            if isinstance(stmt, VarDecl):
                head, code = self.visit(stmt, c)
                block_header.append(head)
                result += code
            elif isinstance(stmt, Expr):
                code = self.visit(stmt, c)[0]
                result += code
                if frame.getStackSize() > 0:
                    result.append(self.emit.emitPOP(c.frame))
            else:
                c1 = c.dup()
                c1.is_body = False
                x = self.visit(stmt, c1)
                result += x
        if isinstance(c.return_type, VoidType) and (c.is_body):
            result.append(self.emit.emitRETURN(c.return_type, frame))
            
        elif isinstance(c.return_type, IntType) and (c.is_body):
            result.append(self.emit.emitPUSHICONST(1, frame))
            result.append(self.emit.emitRETURN(c.return_type, frame))
        elif isinstance(c.return_type, FloatType) and (c.is_body):
            result.append(self.emit.emitPUSHFCONST(1, frame))
            result.append(self.emit.emitRETURN(c.return_type, frame))
        elif isinstance(c.return_type, BoolType) and (c.is_body):
            result.append(self.emit.emitPUSHICONST(1, frame))
            result.append(self.emit.emitRETURN(c.return_type, frame))


        result.append(self.emit.emitLABEL(end_label, frame))

        frame.exitScope()
        return ''.join(block_header + result)

    def visitVarDecl(self, ast, c):
        frame = c.frame
        new_label = frame.getNewLabel()
        index = frame.getNewIndex()
        header = self.emit.emitVAR(
            index, ast.variable, ast.varType, new_label, frame.getEndLabel(), frame)

        result = [self.emit.emitLABEL(new_label, frame)]
        c.sym.append(Symbol(ast.variable, ast.varType, index))
        if isinstance(ast.varType, ArrayType):
            result.append(self.emit.emitPUSHICONST(str(ast.varType.dimen), frame))
            result.append(self.emit.emitNEWARRAY(ast.varType.eleType))
            result.append(self.emit.emitWRITEVAR(ast.variable, ast.varType, index, frame))
        return header, result

    def visitCallExpr(self, ast, c):
        #ast: CallExpr
        #c: Any
        frame = c.frame
        symbol = c.find(ast.method.name)
        cname = symbol.value.value
        result = []
        for p, st in zip(ast.param, symbol.mtype.partype):
            code, pt = self.visit(p, c)
            result += code
            if isinstance(pt, IntType) and isinstance(st, FloatType):
                result.append(self.emit.emitI2F(frame))
        result.append(self.emit.emitINVOKESTATIC(
            str(cname) + "/" + ast.method.name, symbol.mtype, frame))
        return result, symbol.mtype.rettype

    def visitId(self, ast, c):
        frame = c.frame
        symbol = c.find(ast.name)
        result = []
        if (symbol and symbol.value is not None):
            result.append(self.emit.emitREADVAR(
                symbol.name, symbol.mtype, symbol.value, frame))
        else:
            result.append(self.emit.emitGETSTATIC(
                self.className + '/' + ast.name, symbol.mtype, frame))
        return result, symbol.mtype

    def visitIntLiteral(self, ast, c):
        frame = c.frame
        return [self.emit.emitPUSHICONST(ast.value, frame)], IntType()

    def visitFloatLiteral(self, ast, c):
        frame = c.frame
        return [self.emit.emitPUSHFCONST(ast.value, frame)], FloatType()

    def visitBooleanLiteral(self, ast, c):
        frame = c.frame
        result = self.emit.emitPUSHCONST("true" if ast.value else "false", IntType(), c.frame)
        return [result], BoolType()

    def visitStringLiteral(self, ast, c):
        frame = c.frame
        return [self.emit.emitPUSHCONST(str(ast.value), StringType(), c.frame)], StringType()

    def visitBinaryOp(self, ast, c):
        frame = c.frame
        result = []
        retType = None
        if ast.op in ['&&', '||']:
            end_label = frame.getNewLabel()
            left, leftType = self.visit(ast.left, c)
            result += left
            result.append(self.emit.emitDUP(frame))

            if ast.op == '||':
                result.append(self.emit.emitIFTRUE(end_label, frame))
            else:
                result.append(self.emit.emitIFFALSE(end_label, frame))
 
            right, rightType = self.visit(ast.right, c)
            result += right

            if ast.op == '||':
                code = self.emit.emitOROP(frame)
            else:
                code = self.emit.emitANDOP(frame)
            result.append(code)

            result.append(self.emit.emitLABEL(end_label, frame))
            retType = BoolType()

        elif ast.op in ['==','!=']:
            left, leftType = self.visit(ast.left, c)
            right, rightType = self.visit(ast.right, c)
            result += left
            result += right
            result.append(self.emit.emitREOP(ast.op, leftType, frame))
            retType = leftType

        elif ast.op in ['>=', '<=', '>', '<']:
            left, leftType = self.visit(ast.left, c)
            right, rightType = self.visit(ast.right, c)
            if isinstance(leftType, FloatType) or isinstance(rightType, FloatType):
                if isinstance(leftType, IntType):
                    result += left
                    result.append(self.emit.emitI2F(frame))
                    result += right
                elif isinstance(rightType, IntType):
                    result += left
                    result += right
                    result.append(self.emit.emitI2F(frame))
                else:
                    result += left
                    result += right
                result.append(self.emit.emitREOPFlOAT(ast.op, FloatType(), frame))
                retType = FloatType()
            else:
                result += left
                result += right
                if isinstance(leftType, IntType):
                    result.append(self.emit.emitREOP(ast.op, leftType, frame))
                else:
                    result.append(self.emit.emitREOPFlOAT(ast.op, leftType, frame))

                retType = leftType

        elif ast.op in ['%']:
            left, leftType = self.visit(ast.left, c)
            right, rightType = self.visit(ast.right, c)
            result += left
            result += right
            result.append(self.emit.emitMOD(frame))
            retType = IntType()

        elif ast.op in ['+', '-']:
            left, leftType = self.visit(ast.left, c)
            right, rightType = self.visit(ast.right, c)
            if isinstance(leftType, FloatType) or isinstance(rightType, FloatType):
                if isinstance(leftType, IntType):
                    result += left
                    result.append(self.emit.emitI2F(frame))
                    result += right
                elif isinstance(rightType, IntType):
                    result += left
                    result += right
                    result.append(self.emit.emitI2F(frame))
                else:
                    result += left
                    result += right
                result.append(self.emit.emitADDOP(ast.op, FloatType(), frame))
                retType = FloatType()
            else:
                result += left
                result += right
                result.append(self.emit.emitADDOP(ast.op, leftType, frame))
                retType = leftType
        
        elif ast.op in ['*', '/']:
            left, leftType = self.visit(ast.left, c)
            right, rightType = self.visit(ast.right, c)

            if isinstance(leftType, FloatType) or isinstance(rightType, FloatType):
                if isinstance(leftType, IntType):
                    result += left
                    result.append(self.emit.emitI2F(frame))
                    result += right
                elif isinstance(rightType, IntType):
                    result += left
                    result += right
                    result.append(self.emit.emitI2F(frame))
                else:
                    result += left
                    result += right
                result.append(self.emit.emitMULOP(ast.op, FloatType(), frame))
                retType = FloatType()
            else:
                result += left
                result += right
                result.append(self.emit.emitMULOP(ast.op, leftType, frame))
                retType = leftType

        elif ast.op in ['=']:
            if isinstance(ast.left, Id):
                right, rightType = self.visit(ast.right, c)
                result += right
                symbol = c.find(ast.left.name)
                if isinstance(rightType, IntType) and isinstance(symbol.mtype, FloatType):
                    result.append(self.emit.emitI2F(c.frame))
                result.append(self.emit.emitDUP(c.frame))
                if symbol.value is not None:
                    result.append(self.emit.emitWRITEVAR(ast.left.name, symbol.mtype, symbol.value, c.frame))
                else:
                    result.append(self.emit.emitPUTSTATIC(self.className + '.' + symbol.name, symbol.mtype, c.frame))
                retType = symbol.mtype
            elif isinstance(ast.left, ArrayCell):
                left, left_type = self.visit(ast.left.arr, c)
                result += left
                itmp, iType = self.visit(ast.left.idx, c)   
                result += itmp
                right, right_type = self.visit(ast.right, c)
                result += right
                if isinstance(right_type, IntType) and isinstance(left_type.eleType, FloatType):
                    result.append(self.emit.emitI2F(c.frame)) 
                result.append(self.emit.emitDUPX2(c.frame))
                result.append(self.emit.emitASTORE(left_type.eleType, c.frame))

                retType = left_type.eleType

        return result, retType
        
    def visitUnaryOp(self, ast, c):
        frame = c.frame
        result, valType = self.visit(ast.body, c)
        if ast.op == '-':
            result.append(self.emit.emitNEGOP(valType, frame))
        elif ast.op == '!':
            result.append(self.emit.emitNOT(valType, frame))
            c.frame.pop()

        return result, valType

    def visitArrayCell(self, ast, c):
        result = []
        tmp, ctype = self.visit(ast.arr, c)
        result += tmp
        itmp, itype = self.visit(ast.idx, c)
        result += itmp
        result.append(self.emit.emitALOAD(ctype.eleType, c.frame))
        return result, ctype.eleType

    def visitFor(self, ast, c):
        frame = c.frame
        frame.enterLoop()
        result = []

        # Before for, do expr1 
        result += self.visit(ast.expr1, c)[0]
        if c.frame.getStackSize() > 0:
            result.append(self.emit.emitPOP(c.frame))
        # Label for next loop (condition expr)
        start_label = frame.getNewLabel()
        continue_label = str(frame.getContinueLabel())
        end_label = str(frame.getBreakLabel())

        result.append(self.emit.emitLABEL(start_label, frame))

        # Code gen for expr 2
        result += self.visit(ast.expr2,c)[0]
        result.append(self.emit.emitIFFALSE(str(end_label), frame))
        
        if isinstance(ast.loop, Expr): 
            result += self.visit(ast.loop, c)[0]
            if c.frame.getStackSize() > 0:
                result.append(self.emit.emitPOP(c.frame))
        else:
            result += self.visit(ast.loop, c)
        result.append(self.emit.emitLABEL(continue_label, frame))
        result += self.visit(ast.expr3, c)[0]
        if c.frame.getStackSize() > 0:
            result.append(self.emit.emitPOP(c.frame))
        result.append(self.emit.emitGOTO(str(start_label), frame))
        result.append(self.emit.emitLABEL(end_label, frame))
        frame.exitLoop()

        return result
    
    def visitIf(self, ast, c):
        frame = c.frame
        result = []
        result += self.visit(ast.expr, c)[0]
        end_label = frame.getNewLabel()

        if (ast.elseStmt):
            else_label = frame.getNewLabel()

            result.append(self.emit.emitIFFALSE(else_label, frame))
            if isinstance(ast.thenStmt, Expr):
                result += self.visit(ast.thenStmt, c)[0]
                if c.frame.getStackSize() > 0:
                    result.append(self.emit.emitPOP(c.frame))
            else:
                result += self.visit(ast.thenStmt, c)
            
            result.append(self.emit.emitGOTO(str(end_label), frame))
            result.append(self.emit.emitLABEL(else_label, frame))

            if (ast.elseStmt): 
                if isinstance(ast.elseStmt, Expr):
                    result += self.visit(ast.elseStmt, c)[0]
                    if c.frame.getStackSize() > 0:
                        result.append(self.emit.emitPOP(c.frame))
                else:
                    result += self.visit(ast.elseStmt, c)
        else:
            result.append(self.emit.emitIFFALSE(end_label, frame))
            if isinstance(ast.thenStmt, Expr):
                result += self.visit(ast.thenStmt, c)[0]
                if c.frame.getStackSize() > 0:
                    result.append(self.emit.emitPOP(c.frame))
            else:
                result += self.visit(ast.thenStmt, c)
        result.append(self.emit.emitLABEL(end_label, frame))
        return result
    
    def visitDowhile(self, ast, c):
        frame = c.frame
        frame.enterLoop()
        result = []
        start_label = str(frame.getContinueLabel())
        end_label = str(frame.getBreakLabel())
        c.break_label = end_label
        c.continue_label = start_label
        result.append(self.emit.emitLABEL(start_label, frame))

        for stmt in ast.sl:
            if isinstance(stmt, Expr):
                result += self.visit(stmt, c)[0]
                if c.frame.getStackSize() > 0:
                    result.append(self.emit.emitPOP(c.frame))
            else:
                result += self.visit(stmt, c)
            
        result += self.visit(ast.exp, c)[0]
        result.append(self.emit.emitIFFALSE(end_label, frame))
        result.append(self.emit.emitGOTO(str(start_label), frame))
        result.append(self.emit.emitLABEL(end_label, frame))
        frame.exitLoop()
        return result
    
    def visitBreak(self, ast, c):
        frame = c.frame
        result = []
        result.append(self.emit.emitGOTO(str(frame.getBreakLabel()), c.frame))
        return result
    
    def visitContinue(self, ast, c):
        frame = c.frame
        result = []
        result.append(self.emit.emitGOTO(str(frame.getContinueLabel()), c.frame))
        return result
    
    def visitReturn(self, ast, c):
        frame = c.frame
        return_type = c.return_type
        result = []
        if not isinstance(c.return_type, VoidType):
            code, rType = self.visit(ast.expr, c)
            result += code
            if isinstance(rType, IntType) and isinstance(return_type, FloatType):
                result.append(self.emit.emitI2F(frame))
        result.append(self.emit.emitRETURN(return_type, frame))
        return result
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 = "MPClass"
        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"))

        glenv = [self.visit(x, 0) for x in ast.decl]
        e = SubBody(None, self.env + glenv)
        for x in ast.decl:
            self.visit(x, e)

        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), c,
                       Frame("<init>", VoidType))
        self.genMETHOD(
            FuncDecl(Id("<clinit>"), list(), list(), list(), VoidType()),
            e.sym, Frame("<clinit>", VoidType))
        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
        ls_param = [self.visit(x, 1) for x in consdecl.param]
        intype = [ArrayPointerType(StringType())] if isMain else ls_param
        mtype = MType(intype, returnType)

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

        frame.enterScope(True)
        # 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))

        # glenv = o
        glenv = [] if o is None else o
        if consdecl.name.name == "<clinit>":
            for x in glenv:
                if type(x.mtype) is ArrayType:
                    self.emit.printout(
                        self.visit(
                            IntLiteral(
                                int(str(x.mtype.upper)) -
                                int(str(x.mtype.lower)) + 1),
                            SubBody(frame, glenv))[0])
                    self.emit.printout(
                        self.emit.emitArray(x.mtype, x.value, frame, x.name))
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
            self.emit.printout(self.emit.emitENDMETHOD(frame))
            frame.exitScope()
            return

        lcenv = []
        e = SubBody(frame, lcenv)
        penv = []
        p = SubBody(frame, penv)
        for x in consdecl.param:
            p = self.visit(x, p)
        for x in consdecl.local:
            e = self.visit(x, e)
        body = consdecl.body
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for x in e.sym:
            if type(x.mtype) is ArrayType:
                self.emit.printout(
                    self.visit(
                        IntLiteral(
                            int(str(x.mtype.upper)) - int(str(x.mtype.lower)) +
                            1), e)[0])
                self.emit.printout(
                    self.emit.emitArray(x.mtype, x.value, frame, x.name))

        e.sym = e.sym + p.sym + glenv
        # 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))
        list(map(lambda x: self.visit(x, e), body))

        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitVarDecl(self, ast, o):
        # def emitATTRIBUTE(self, lexeme, in_, isFinal, value):
        #lexeme: String
        #in_: Type
        #isFinal: Boolean
        #value: String
        if o == 0:
            self.emit.printout(
                self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False,
                                        None))
            return Symbol(ast.variable.name, ast.varType,
                          CName(self.className))
        if o == 1:
            return ast.varType
        subctxt = o
        frame = o.frame
        env = o.sym
        if frame is None:

            return SubBody(None, [
                Symbol(ast.variable.name, ast.varType, CName(self.className))
            ] + subctxt.sym)
        else:
            idx = frame.getNewIndex()
            self.emit.printout(
                self.emit.emitVAR(idx, ast.variable.name, ast.varType,
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
            return SubBody(
                frame,
                [Symbol(ast.variable.name, ast.varType, Index(idx))] + env)

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

        if o == 0:
            ls_param = [self.visit(x, 1) for x in ast.param]
            return Symbol(ast.name.name, MType(ls_param, ast.returnType),
                          CName(self.className))

        subctxt = o
        frame = Frame(ast.name, ast.returnType)

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

    def visitIf(self, ast, o):
        #expr:Expr
        #thenStmt:list(Stmt)
        #elseStmt:list(Stmt)
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        exp, exptype = self.visit(ast.expr, Access(frame, nenv, False, True))
        label1 = frame.getNewLabel()
        self.emit.printout(exp)
        self.emit.printout(self.emit.emitIFFALSE(label1, frame))
        list(map(lambda x: self.visit(x, o), ast.thenStmt))

        if ast.elseStmt != []:
            label2 = frame.getNewLabel()
            self.emit.printout(self.emit.emitGOTO(label2, frame))
        self.emit.printout(self.emit.emitLABEL(label1, frame))
        if ast.elseStmt != []:
            list(map(lambda x: self.visit(x, o), ast.elseStmt))
            self.emit.printout(self.emit.emitLABEL(label2, frame))

    def visitWhile(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        exp, exptype = self.visit(ast.exp, Access(frame, nenv, False, True))
        frame.enterLoop()
        label1 = frame.getContinueLabel()
        label2 = frame.getBreakLabel()
        self.emit.printout(self.emit.emitLABEL(label1, frame))
        self.emit.printout(exp)
        self.emit.printout(self.emit.emitIFFALSE(label2, frame))
        list(map(lambda x: self.visit(x, o), ast.sl))
        self.emit.printout(self.emit.emitGOTO(label1, frame))
        self.emit.printout(self.emit.emitLABEL(label2, frame))
        frame.exitLoop()

    def visitFor(self, ast, o):
        #id:Id
        #expr1,expr2:Expr
        #loop:list(Stmt)
        #up:Boolean #True => increase; False => decrease
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        op = '<=' if ast.up else '>='
        op2 = '+' if ast.up else '-'
        op3 = '-' if ast.up else '+'
        frame.enterLoop()
        label1 = frame.getContinueLabel()
        label2 = frame.getBreakLabel()
        self.visit(Assign(ast.id, ast.expr1), o)
        self.visit(Assign(ast.id, BinaryOp(op3, ast.id, IntLiteral(1))), o)
        self.emit.printout(self.emit.emitLABEL(label1, frame))
        self.visit(Assign(ast.id, BinaryOp(op2, ast.id, IntLiteral(1))), o)
        self.emit.printout(
            self.visit(BinaryOp(op, ast.id, ast.expr2),
                       Access(frame, nenv, False, True))[0])

        self.emit.printout(self.emit.emitIFFALSE(label2, frame))
        list(map(lambda x: self.visit(x, o), ast.loop))
        self.emit.printout(self.emit.emitGOTO(label1, frame))
        self.emit.printout(self.emit.emitLABEL(label2, frame))
        frame.exitLoop()

    def visitWith(self, ast, o):
        ctxt = o
        frame = o.frame
        #decl:list(VarDecl)
        #stmt:list(Stmt)
        env = o.sym
        frame.enterScope(False)
        e = SubBody(frame, [])
        for x in ast.decl:
            e = self.visit(x, e)
        env = e.sym + env
        for y in e.sym:
            if type(y.mtype) is ArrayType:
                self.emit.printout(
                    self.visit(
                        IntLiteral(
                            int(str(y.mtype.upper)) - int(str(y.mtype.lower)) +
                            1), SubBody(frame, env))[0])
                self.emit.printout(
                    self.emit.emitArray(y.mtype, y.value, frame, y.name))

        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        list(map(lambda x: self.visit(x, SubBody(frame, env)), ast.stmt))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()

    def visitCallStmt(self, ast, o):
        #ast: CallStmt
        #o: Any
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name.lower(), reversed(nenv),
                          lambda x: x.name.lower())
        cname = sym.value.value
        ctype = sym.mtype
        ctype2 = MType([], ClassType('java/lang/Object'))
        in_ = ("", list())
        ls = zip(ast.param, ctype.partype)
        for x, y in ls:
            str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
            if type(typ1) is ArrayType:
                bonus = self.emit.emitINVOKEVIRTUAL(
                    self.emit.getJVMType(typ1) + '/clone', ctype2, frame
                ) + '\t' + 'checkcast ' + self.emit.getJVMType(typ1) + '\n'
                str1 = str1 + bonus

            if type(typ1) is IntType and type(y) is FloatType:
                bonus2 = self.emit.emitI2F(frame)
                str1 = str1 + bonus2
            if type(typ1) is ArrayPointerType and type(
                    typ1.eleType) is IntType and type(y) is FloatType:
                bonus2 = self.emit.emitI2F(frame)
                str1 = str1 + bonus2
            in_ = (in_[0] + str1, in_[1] + [typ1])
        self.emit.printout(in_[0])
        self.emit.printout(
            self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame))

    def visitBinaryOp(self, ast, o):
        #frame: Frame
        #sym: List[Symbol]
        #isLeft: Boolean
        # #isFirst: Boolean
        #  emitREOP emitRELOP
        ctxt = o
        frame = ctxt.frame
        leftcode, lefttype = self.visit(ast.left, o)
        rightcode, righttype = self.visit(ast.right, o)
        leftcode2 = leftcode + self.emit.emitI2F(frame) if (
            type(lefttype) is IntType or
            (type(lefttype) is ArrayPointerType
             and type(lefttype.eleType) is IntType)) else leftcode
        rightcode2 = rightcode + self.emit.emitI2F(frame) if (
            type(righttype) is IntType or
            (type(righttype) is ArrayPointerType
             and type(righttype.eleType) is IntType)) else rightcode
        typ1 = lefttype.eleType if type(
            lefttype) is ArrayPointerType else lefttype
        typ2 = righttype.eleType if type(
            righttype) is ArrayPointerType else righttype
        if type(typ1) == type(typ2):
            if ast.op in ['+', '-']:
                return leftcode + rightcode + self.emit.emitADDOP(
                    ast.op, typ1, frame), lefttype
            elif ast.op is '*':
                return leftcode + rightcode + self.emit.emitMULOP(
                    ast.op, typ1, frame), lefttype
            elif ast.op is '/':
                return leftcode2 + rightcode2 + self.emit.emitMULOP(
                    ast.op, FloatType(), frame), FloatType()
            elif ast.op.lower() == 'div':
                return leftcode + rightcode + self.emit.emitDIV(frame), typ1
            elif ast.op.lower() == 'mod':
                return leftcode + rightcode + self.emit.emitMOD(frame), typ1
            elif ast.op == 'and':
                return leftcode + rightcode + self.emit.emitANDOP(
                    frame), BoolType()
            elif ast.op == 'or':
                return leftcode + rightcode + self.emit.emitOROP(
                    frame), BoolType()
            elif ast.op in ['<', '>', '<=', '>=', '=', '<>']:
                return leftcode + rightcode + self.emit.emitREOP(
                    ast.op, typ1, frame), BoolType()
            elif ast.op.lower() == 'andthen':
                label1 = frame.getNewLabel()
                code = leftcode + self.emit.emitDUP(frame)
                code = code + self.emit.emitIFFALSE(label1, frame)
                code = code + rightcode + self.emit.emitANDOP(frame)
                code = code + self.emit.emitLABEL(label1, frame)
                return code, BoolType()
            elif ast.op.lower() == 'orelse':
                label1 = frame.getNewLabel()
                code = leftcode + self.emit.emitDUP(frame)
                code = code + self.emit.emitIFTRUE(label1, frame)
                code = code + rightcode + self.emit.emitOROP(frame)
                code = code + self.emit.emitLABEL(label1, frame)
                return code, BoolType()
        else:
            if ast.op in ['+', '-']:
                return leftcode2 + rightcode2 + self.emit.emitADDOP(
                    ast.op, FloatType(), frame), FloatType()
            elif ast.op in ['*', '/']:
                return leftcode2 + rightcode2 + self.emit.emitMULOP(
                    ast.op, FloatType(), frame), FloatType()
            elif ast.op.lower() in ['<', '>', '<=', '>=', '=', '<>']:
                return leftcode2 + rightcode2 + self.emit.emitREOP(
                    ast.op, FloatType(), frame), BoolType()

    def visitCallExpr(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name.lower(), reversed(nenv),
                          lambda x: x.name.lower())
        cname = sym.value.value
        ctype = sym.mtype
        ctype2 = MType([], ClassType('java/lang/Object'))
        in_ = ("", list())
        ls = zip(ast.param, ctype.partype)
        for x, y in ls:
            str1, typ1 = self.visit(x, Access(frame, nenv, False, True))
            if type(typ1) is ArrayType:
                bonus = self.emit.emitINVOKEVIRTUAL(
                    self.emit.getJVMType(typ1) + '/clone', ctype2, frame
                ) + '\t' + 'checkcast ' + self.emit.getJVMType(typ1) + '\n'
                str1 = str1 + bonus
            if type(typ1) is IntType and type(y) is FloatType:
                bonus2 = self.emit.emitI2F(frame)
                str1 = str1 + bonus2
            if type(typ1) is ArrayPointerType and type(
                    typ1.eleType) is IntType and type(y) is FloatType:
                bonus2 = self.emit.emitI2F(frame)
                str1 = str1 + bonus2
            in_ = (in_[0] + str1, in_[1] + [typ1])
        return in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name,
                                                   ctype, frame), ctype.rettype

    def visitUnaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        bodyCode, bodyType = self.visit(ast.body, o)
        _type = bodyType.eleType if type(
            bodyType) is ArrayPointerType else bodyType
        if ast.op.lower() == 'not':
            return bodyCode + self.emit.emitNOT(StringType(),
                                                frame), BoolType()
        else:
            return bodyCode + self.emit.emitNEGOP(_type, frame), _type

    def visitAssign(self, ast, o):
        frame = o.frame
        frame.push()
        frame.push()
        expCode, expType = self.visit(ast.exp, Access(frame, o.sym, False,
                                                      True))
        lhsCode, lhsType = self.visit(ast.lhs, Access(frame, o.sym, True,
                                                      True))
        if isinstance(lhsType, FloatType) and isinstance(expType, IntType):
            expCode = expCode + self.emit.emitI2F(frame)
        if isinstance(ast.lhs, ArrayCell):
            self.emit.printout(
                lhsCode + expCode +
                self.visit(ast.lhs, Access(frame, o.sym, True, False)))
        else:
            self.emit.printout(expCode + lhsCode)
        frame.pop()
        frame.pop()

    def visitId(self, ast, o):
        frame = o.frame
        sym = self.lookup(ast.name.lower(), o.sym, lambda x: x.name.lower())
        _type = sym.mtype if not isinstance(
            sym.mtype, ArrayType) else ArrayPointerType(sym.mtype.eleType)
        if not isinstance(sym.value, Index):
            if isinstance(o, Access) and o.isLeft is True:
                return self.emit.emitPUTSTATIC(
                    sym.value.value + "." + sym.name, _type, frame), sym.mtype
            else:
                return self.emit.emitGETSTATIC(
                    sym.value.value + "." + sym.name, _type, frame), sym.mtype
        else:
            if isinstance(o, Access) and o.isLeft is True:
                return self.emit.emitWRITEVAR(sym.name, _type, sym.value.value,
                                              frame), sym.mtype
            else:
                return self.emit.emitREADVAR(sym.name, _type, sym.value.value,
                                             frame), sym.mtype

    def visitArrayCell(self, ast, o):
        #arr:Expr
        #idx:Expr

        frame = o.frame
        arr, arrtype = self.visit(ast.arr, Access(frame, o.sym, False, True))
        idx, idxtype = self.visit(ast.idx, Access(frame, o.sym, False, True))
        idx = idx + self.visit(IntLiteral(
            arrtype.lower), o)[0] + self.emit.emitADDOP("-", IntType(
            ), frame) if arrtype.lower >= 0 else idx + self.visit(
                IntLiteral(-arrtype.lower), o)[0] + self.emit.emitADDOP(
                    "+", IntType(), frame)
        if isinstance(o, Access) and o.isLeft is True and o.isFirst is True:
            return arr + idx, arrtype.eleType
        elif isinstance(o, Access) and o.isLeft is True and o.isFirst is False:
            return self.emit.emitASTORE(arrtype.eleType, frame)
        else:
            return arr + idx + self.emit.emitALOAD(arrtype.eleType,
                                                   frame), arrtype.eleType

    def visitBreak(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))

    def visitContinue(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))

    def visitReturn(self, ast, o):
        ctxt = o
        frame = o.frame
        if ast.expr is None:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        else:
            expcode, exptype = self.visit(ast.expr,
                                          Access(frame, o.sym, False, True))

            if type(frame.returnType) is FloatType and type(
                    exptype) is IntType:
                self.emit.printout(expcode + self.emit.emitI2F(frame) +
                                   self.emit.emitRETURN(FloatType(), frame))
            else:
                self.emit.printout(expcode +
                                   self.emit.emitRETURN(exptype, frame))

    def visitStringLiteral(self, ast, o):
        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).lower(),
                                        frame), BoolType()

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

    def visitFloatLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()
Example #19
0
class CodeGenVisitor(BaseVisitor):
    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.static = []
        self.initVar = []
        self.ret = []
        self.envFuncNum = 0
        self.staticFunction = []
        self.initStatic = []
        self.clinitStackSize = 0

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

        self.emit.printout(
            self.emit.emitPROLOG(self.className, "java.lang.Object"))
        e = MethodEnv(None, self.env)
        self.envFuncNum = len(self.env)
        # self.env = [self.visit(decl, e) for decl in ast.decl] + self.env
        for decl in ast.decl:
            s = self.visit(decl, e)
            e.symbol.append(s)
        # reduce(lambda e, decl: e.symbol + [self.visit(decl, e)], ast.decl, e)
        # self.genMain(e)
        # generate default constructor
        self.genInit()
        self.genClinit()
        # generate class init if necessary
        self.emit.emitEPILOG()
        return c

    # We do not need to save the signature of all the function due to
    # the assumption that there is no semantic error!
    # In the callee we only need to infer the type it self
    # def visitGlobal(self,ast,c):
    #     if isinstance(ast, FuncDecl):
    #         return Symbol(ast.name.name, MType([None]*len(ast.param), None))
    #     if isinstance(ast, VarDecl):
    #         return Symbol(ast.variable.name, None)

    def genInit(self):
        methodname, methodtype = "<init>", MType([], VoidType())
        frame = Frame(methodname, methodtype.rettype)
        self.emit.printout(
            self.emit.emitMETHOD(methodname, methodtype, False, frame))
        frame.enterScope(True)
        varname, vartype, varindex = "this", ClassType(
            self.className), frame.getNewIndex()
        startLabel, endLabel = frame.getStartLabel(), frame.getEndLabel()
        self.emit.printout(
            self.emit.emitVAR(varindex, varname, vartype, startLabel, endLabel,
                              frame))
        self.emit.printout(self.emit.emitLABEL(startLabel, frame))
        self.emit.printout(
            self.emit.emitREADVAR(varname, vartype, varindex, frame))
        self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        # printout the init_code of the static field
        a = Access(frame, self.env, isLeft=False)
        [static.init(a, self) for static in self.static]
        self.clinitStackSize = a.frame.getMaxOpStackSize()
        # _________
        self.emit.printout(self.emit.emitLABEL(endLabel, frame))
        self.emit.printout(self.emit.emitRETURN(methodtype.rettype, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))

    def genClinit(self):
        methodname, methodtype = "<clinit>", MType([], VoidType())
        frame = Frame(methodname, methodtype.rettype)
        self.emit.printout(
            self.emit.emitMETHOD(methodname, methodtype, True, frame))
        frame.enterScope(True)
        varname, vartype, varindex = "this", ClassType(
            self.className), frame.getNewIndex()
        startLabel, endLabel = frame.getStartLabel(), frame.getEndLabel()
        # self.emit.printout(self.emit.emitVAR(varindex, varname, vartype, startLabel, endLabel,frame ))
        self.emit.printout(self.emit.emitLABEL(startLabel, frame))
        # self.emit.printout(self.emit.emitREADVAR(varname, vartype, varindex, frame))
        # self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        # printout the init_code of the static field
        [self.emit.printout(p) for p in self.initStatic]
        self.initStatic = []
        frame.maxOpStackSize = self.clinitStackSize
        # _________
        self.emit.printout(self.emit.emitLABEL(endLabel, frame))
        self.emit.printout(self.emit.emitRETURN(methodtype.rettype, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))

    """
    * In var decl, this should add the symbol to frame for later work
    TODOs: 
    @param: self
    @param: 
    """

    def visitVarDecl(self, ctx: VarDecl, o):
        var_name = ctx.variable.name
        dimen = list(ctx.varDimen)
        if isinstance(dimen, tuple):
            dimen = dimen[0]
        a = Access(o.frame, o.symbol, isLeft=False)
        if ctx.varInit:
            # handle normal declarations with the assumption of the ass4
            if o.frame == None:
                self.static.append(
                    StaticAttribute(self.className, var_name, ctx))
                methodname, methodtype = "<init>", MType([], VoidType())
                a.frame = Frame(methodname, methodtype.rettype)
                init_code, typ = self.visit(ctx.varInit, a)
                init_code += self.emit.emitPUTSTATIC(
                    self.className + '.' + var_name, typ, a.frame)
                self.initStatic.append(init_code)
                return Symbol(var_name, typ, CName(self.className))
            else:
                init_code, typ = self.visit(ctx.varInit, o)
                # if len(dimen):
                #     typ = ArrayType(typ, dimen)
                idx = o.frame.getNewIndex()
                start_label = o.frame.getStartLabel()
                end_label = o.frame.getEndLabel()
                self.emit.printout(
                    self.emit.emitVAR(idx, var_name, typ, start_label,
                                      end_label, o.frame))
                init_code += self.emit.emitWRITEVAR(var_name, typ, idx,
                                                    o.frame)
                self.initVar.append(init_code)
                # print('Index of {} in decl is {}'.format(var_name, idx))
                return Symbol(var_name, typ, Index(idx))
        else:
            # for param in functions
            idx = o.frame.getNewIndex()
            # self.emit.printout(self.emit.emitVAR(idx, var_name, typ, start_label, end_label, o.frame))
            if len(dimen):
                typ = ArrayType(None, dimen)
            else:
                typ = None
            return Symbol(var_name, typ, Index(idx))

    def visitFuncDecl(self, ctx: FuncDecl, o):
        frame = Frame(ctx.name.name, VoidType())
        subBody = SubBody(frame, o.symbol)
        frame.enterScope(True)
        begin_pos = self.emit.getBuffLen()
        partype = rettype = None
        for method in self.staticFunction:
            if method.name == ctx.name.name:
                # have invoked before its decl
                partype = method.mtype.partype
                rettype = method.mtype.rettype
        params = [self.visit(p, subBody) for p in ctx.param]
        if partype != None:
            params = list(
                map(lambda x, y: Symbol(x.name, y, x.value), params, partype))
        subBody.symbol = params + subBody.symbol
        # reduce(lambda e, decl: e.symbol + [self.visit(decl, e)], ctx.param, subBody)
        subBody.symbol = [self.visit(p, subBody)
                          for p in ctx.body[0]] + subBody.symbol
        # reduce(lambda e, decl: e.symbol + [self.visit(decl, e)], ctx.body[0], subBody)
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        [self.emit.printout(p) for p in self.initVar]
        self.initVar = []
        [self.visit(p, subBody) for p in ctx.body[1]]
        # after visit all stmt inside the body
        # there a trick to printout the method decl
        intype = []
        for name in [decl.variable.name for decl in ctx.param]:
            for sym in subBody.symbol:
                if sym.name == name:
                    start_label = subBody.frame.getStartLabel()
                    end_label = subBody.frame.getEndLabel()
                    if type(sym.mtype) is ArrayType:
                        if isinstance(sym.mtype.dimen, tuple):
                            sym.mtype.dimen = sym.mtype.dimen[0]
                    self.emit.printAt(
                        self.emit.emitVAR(sym.value.value, name, sym.mtype,
                                          start_label, end_label, o.frame),
                        self.emit.getBuffLen() - begin_pos)
                    intype.append(sym.mtype)
                    break
        typ = MType(intype, subBody.getRet())
        # for the Main function: it should be public static void main(String[] args)
        if ctx.name.name == 'main':
            start_label = subBody.frame.getStartLabel()
            end_label = subBody.frame.getEndLabel()
            self.emit.printAt(
                self.emit.emitVAR(frame.getNewIndex(), 'args',
                                  ArrayType(StringType(), [1]), start_label,
                                  end_label, o.frame),
                self.emit.getBuffLen() - begin_pos)
            typ = MType([ArrayType(StringType(), [1])], VoidType())
            print('come here')
        self.emit.printAt(
            self.emit.emitMETHOD(ctx.name.name, typ, True, o.frame),
            self.emit.getBuffLen() - begin_pos)
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        # [self.emit.printout(code) for code in self.ret]
        # self.emit.printout(self.emit.emitRETURN(typ.rettype, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()
        o.symbol += [Symbol(ctx.name.name, typ, CName(self.className))]

    def visitAssign(self, ctx: Assign, o):
        access = Access(o.frame, o.symbol, isLeft=False)
        rhs_code, r_type = self.visit(ctx.rhs, access)
        access.isLeft = True
        lhs_code, l_type = self.visit(ctx.lhs, access)
        # Infer the type of unknown
        if rhs_code == None:
            self.infer(ctx.rhs, l_type, access)
            access.isLeft = False
            rhs_code, r_type = self.visit(ctx.rhs, access)
            # print(rhs_code)
        if lhs_code == None:
            self.infer(ctx.lhs, r_type, access)
            access.isLeft = True
            lhs_code, l_type = self.visit(ctx.lhs, access)
        # We must have the correct type after infered (instead of None)
        lines = lhs_code.split('\n')
        lines.insert(-2, rhs_code)
        self.emit.printout('\n'.join(lines))

    def visitIf(self, ctx: If, o):
        labels = list(
            map(lambda x: o.frame.getNewLabel(),
                range(len(ctx.ifthenStmt) + 1)))
        for idx in range(len(ctx.ifthenStmt)):
            access = Access(o.frame, o.symbol, False)
            expr_code, typ = self.visit(ctx.ifthenStmt[idx][0], access)
            if typ == None:
                self.inferId(ctx.ifthenStmt[idx][0], BoolType(), access)
                expr_code, typ = self.visit(ctx.ifthenStmt[idx][0], access)
            l1 = labels[idx]
            l2 = labels[-1]
            self.emit.printout(expr_code)
            self.emit.printout(self.emit.emitIFFALSE(l1, access.frame))
            access.symbol = [
                self.visit(decl, access) for decl in ctx.ifthenStmt[idx][1]
            ] + access.symbol
            [self.emit.printout(p) for p in self.initVar]
            self.initVar = []
            [self.visit(stmt, access) for stmt in ctx.ifthenStmt[idx][2]]
            self.emit.printout(self.emit.emitGOTO(l2, access.frame))
            self.emit.printout(self.emit.emitLABEL(l1, access.frame))
        if ctx.elseStmt:
            access.symbol = [
                self.visit(decl, access) for decl in ctx.elseStmt[0]
            ] + access.symbol
            [self.emit.printout(p) for p in self.initVar]
            self.initVar = []
            [self.visit(stmt, access) for stmt in ctx.elseStmt[1]]
        self.emit.printout(self.emit.emitLABEL(labels[-1], access.frame))

    def visitWhile(self, ctx: While, o):
        access = Access(o.frame, o.symbol, False)
        o.frame.enterLoop()
        inL, outL = o.frame.getContinueLabel(), o.frame.getBreakLabel()
        self.emit.printout(self.emit.emitLABEL(inL, o.frame))
        # condition
        expr_code, typ = self.visit(ctx.exp, access)
        if expr_code == None:
            self.infer(ctx.exp, BoolType(), access)
            expr_code, typ = self.visit(ctx.exp, access)
        self.emit.printout(expr_code)
        self.emit.printout(self.emit.emitIFFALSE(outL, access.frame))
        # declaration
        access.symbol = [self.visit(decl, access)
                         for decl in ctx.sl[0]] + access.symbol
        [self.emit.printout(p) for p in self.initVar]
        self.initVar = []
        # enter loop
        [self.visit(stmt, access) for stmt in ctx.sl[1]]
        self.emit.printout(self.emit.emitGOTO(inL, access.frame))
        self.emit.printout(self.emit.emitLABEL(outL, access.frame))
        o.frame.exitLoop()

    def visitFor(self, ctx: For, o):
        o.frame.enterLoop()
        inL, outL = o.frame.getContinueLabel(), o.frame.getBreakLabel()
        o_ = Access(o.frame, o.symbol, False)
        # init
        expr1_code, _ = self.visit(ctx.expr1, o_)
        if expr1_code == None:
            self.infer(ctx.expr1, IntType(), o_)
            expr1_code, _ = self.visit(ctx.expr1, o_)
        o_.isLeft = True
        idx1_code, _ = self.visit(ctx.idx1, o_)
        o_.isLeft = False
        expr2_code, _ = self.visit(ctx.expr2, o_)
        if expr2_code == None:
            self.infer(ctx.expr2, IntType(), o_)
            expr1_code, _ = self.visit(ctx.expr2, o_)
        expr3_code, _ = self.visit(ctx.expr3, o_)
        if expr3_code == None:
            self.infer(ctx.expr3, IntType(), o_)
            expr1_code, _ = self.visit(ctx.expr3, o_)
        # decl
        [self.visit(decl, o_) for decl in ctx.loop[0]]
        [self.emit.printout(p) for p in self.initVar]
        self.initVar = []
        self.emit.printout(self.emit.emitLABEL(inL, o.frame))
        # condition
        self.emit.printout(expr2_code)
        self.emit.printout(self.emit.emitIFFALSE(outL, o.frame))
        # loop stmt
        [self.visit(stmt, o_) for stmt in ctx.loop[1]]
        # update
        o_.isLeft = False
        idx1_code_load, _ = self.visit(ctx.idx1, o_)
        self.emit.printout(idx1_code_load)
        self.emit.printout(expr3_code)
        self.emit.printout(self.emit.emitADDOP('+', IntType(), o_.frame))
        self.emit.printout(idx1_code)
        self.emit.printout(self.emit.emitGOTO(inL, o.frame))
        self.emit.printout(self.emit.emitLABEL(outL, o.frame))
        o.frame.exitLoop()

    def visitBreak(self, ctx: Break, o):
        outL = o.frame.getBreakLabel()
        self.emit.printout(self.emit.emitGOTO(outL, o.frame))

    def visitContinue(self, ctx: Continue, o):
        inL = o.frame.getContinueLabel()
        self.emit.printout(self.emit.emitGOTO(inL, o.frame))

    def visitReturn(self, ctx: Return, o):
        a = Access(o.frame, o.symbol, isLeft=False)
        typ = VoidType()
        if ctx.expr:
            expr_code, typ = self.visit(ctx.expr, a)
            self.ret.append(expr_code)
            self.emit.printout(expr_code)
        self.emit.printout(self.emit.emitRETURN(typ, a.frame))
        o.setRet(typ)

    def visitDowhile(self, ctx: Dowhile, o):
        access = Access(o.frame, o.symbol, False)
        expr_code, _ = self.visit(ctx.exp, access)
        if expr_code == None:
            self.infer(ctx.expr, BoolType(), access)
            expr_code, _ = self.visit(ctx.exp, access)
        o.frame.enterLoop()
        inL, outL = o.frame.getContinueLabel(), o.frame.getBreakLabel()
        # declaration
        access.symbol = [self.visit(decl, access)
                         for decl in ctx.sl[0]] + access.symbol
        [self.emit.printout(p) for p in self.initVar]
        self.initVar = []
        # enter loop
        self.emit.printout(self.emit.emitLABEL(inL, o.frame))
        [self.visit(stmt, access) for stmt in ctx.sl[1]]
        # condition
        self.emit.printout(expr_code)
        self.emit.printout(self.emit.emitIFFALSE(outL, o.frame))
        self.emit.printout(self.emit.emitGOTO(inL, o.frame))
        self.emit.printout(self.emit.emitLABEL(outL, o.frame))
        o.frame.exitLoop()

    def visitCallStmt(self, ctx: CallStmt, o):
        method_sym = None
        for sym in o.symbol:
            if sym.name == ctx.method.name:
                method_sym = sym
                break
        access = Access(o.frame, o.symbol, isLeft=False)
        expr_codes = []
        if method_sym != None:
            # infer the args in case the function has been inferred
            # print(list(map(lambda x,y: (x,y), ctx.param, method_sym.mtype.partype)))
            for (expr, expect) in list(
                    map(lambda x, y: (x, y), ctx.param,
                        method_sym.mtype.partype)):
                expr_code, typ = self.visit(expr, access)
                if expr_code == None:
                    self.infer(expr, expect, access)
                    expr_code, typ = self.visit(expr, access)
                expr_codes.append([expr_code, typ])
        else:
            name = ctx.method.name
            partype = [None] * len(ctx.param)
            rettype = VoidType()
            typ = MType(partype, rettype)
            self.staticFunction.append(Symbol(name, typ,
                                              CName(self.className)))
            method_sym = self.staticFunction[-1]
            expr_codes = [self.visit(expr, access) for expr in ctx.param]
        [self.emit.printout(code) for code in [ret[0] for ret in expr_codes]]
        typ = None
        className = self.className
        if method_sym == None:
            typ = MType([ret[1] for ret in expr_codes], VoidType())
            self.staticFunction.append(
                Symbol(ctx.method.name, typ, CName(self.className)))
        else:
            typ = method_sym.mtype
            className = method_sym.value.value
        self.emit.printout(
            self.emit.emitINVOKESTATIC(className + "." + ctx.method.name, typ,
                                       o.frame))

    def visitCallExpr(self, ctx: CallExpr, o):
        method_sym = None
        for sym in o.symbol:
            if sym.name == ctx.method.name:
                method_sym = sym
                break
        # Not yet go through
        if method_sym == None:
            for method in self.staticFunction:
                if method.name == ctx.method.name:
                    method_sym = method
                    break
        if method_sym == None:
            o.frame.push()
            return None, None
        access = Access(o.frame, o.symbol, isLeft=False)
        expr_codes = []
        if method_sym != None:
            if any([p == None for p in method_sym.mtype.partype]):
                # print('come here: ', method_sym.mtype.rettype)
                return None, None
            partype = method_sym.mtype.partype
            # infer the args in case the function has been inferred
            # print(list(map(lambda x,y: (x,y), ctx.param, method_sym.mtype.partype)))
            for (idx, p) in enumerate(ctx.param):
                code, typ = self.visit(p, access)
                if code == None:
                    if partype[idx] == None:
                        partype[idx] = IntType()
                    self.infer(p, partype[idx], access)
                    code, typ = self.visit(p, access)
                partype[idx] = typ
                expr_codes.append((code, typ))
        else:
            expr_codes = [self.visit(expr, access) for expr in ctx.param]
        code = ""
        if len(expr_codes) > 1:
            code = reduce(lambda x, y: x + y, [ret[0] for ret in expr_codes],
                          "")
        elif len(expr_codes) == 1:
            code = expr_codes[0][0]
        print('the code: ', code)
        typ = method_sym.mtype
        className = method_sym.value.value
        # print('name of sym: {} and name of method: {}'.format(3method_sym.name, ctx.method.name))
        code += self.emit.emitINVOKESTATIC(className + "." + ctx.method.name,
                                           typ, o.frame)
        return code, method_sym.mtype.rettype

    """
    ! I dont know if we can use emitREADVAR for this
    TODOs: try some experiences
    """

    def visitArrayCell(self, ctx, o):
        access = Access(o.frame, o.symbol, isLeft=False)
        code, typ = self.visit(ctx.arr, access)
        if typ.eleType == None:
            return None, typ.eleType
        idxs_code = [self.visit(expr, access)[0] for expr in ctx.idx]
        for idx_code in idxs_code[:-1]:
            code += idx_code + self.emit.emitALOAD(ArrayType(typ, [1]),
                                                   o.frame)
        if o.isLeft:
            code += idxs_code[-1] + self.emit.emitASTORE(typ.eleType, o.frame)
        else:
            code += idxs_code[-1] + self.emit.emitALOAD(typ.eleType, o.frame)
        return code, typ.eleType

    def visitUnaryOp(self, ctx, o):
        expr, typ = self.visit(ctx.body, o)
        if expr == None:
            self.infer(ctx.body, BoolType(), o)
            expr, typ = self.visit(ctx.body, o)
        if ctx.op in ['!']:
            code = expr + self.emit.emitNOT(BoolType(), o.frame)
            return code, BoolType()
        elif ctx.op in ['-', '-.']:
            code = expr + self.emit.emitNEGOP(typ, o.frame)
            return code, typ

    def visitBinaryOp(self, ctx, o):
        l, ltyp = self.visit(ctx.left, o)
        r, rtyp = self.visit(ctx.right, o)
        if ltyp == None:
            if ctx.op in [
                    '+', '-', '*', '\\', '%', '==', '!=', '<', '>', '<=', '>='
            ]:
                self.infer(ctx.left, IntType(), o)
            elif ctx.op in ['||', '&&']:
                self.infer(ctx.left, BoolType(), o)
            else:
                self.infer(ctx.left, FloatType(), o)
            l, ltyp = self.visit(ctx.left, o)
        elif rtyp == None:
            if ctx.op in [
                    '+', '-', '*', '\\', '%', '==', '!=', '<', '>', '<=', '>='
            ]:
                self.infer(ctx.right, IntType(), o)
            elif ctx.op in ['||', '&&']:
                self.infer(ctx.right, BoolType(), o)
            else:
                self.infer(ctx.right, FloatType(), o)
            r, rtyp = self.visit(ctx.right, o)
        typ = ltyp
        code, rettyp = None, None

        if ctx.op in ['+', '-', '+.', '-.']:
            if ctx.op in ['+', '+.']:
                code = l + r + self.emit.emitADDOP('+', typ, o.frame)
                rettyp = typ
            else:
                code = l + r + self.emit.emitADDOP('-', typ, o.frame)
                rettyp = typ
        elif ctx.op in ['*', '*.', '\\', '\\.', '%']:
            if ctx.op in ['*', '*.']:
                code = l + r + self.emit.emitMULOP('*', typ, o.frame)
                rettyp = typ
            elif ctx.op in ['\\', '\\.']:
                code = l + r + self.emit.emitMULOP('\\', typ, o.frame)
                rettyp = typ
            else:
                code = l + r + self.emit.emitMOD(o.frame)
                rettyp = typ
        elif ctx.op in ['&&', '||']:
            if ctx.op in ['&&']:
                code = l + r + self.emit.emitANDOP(o.frame)
                rettyp = BoolType()
            else:
                code = l + r + self.emit.emitOROP(o.frame)
                rettyp = BoolType()
        elif ctx.op in [
                '==', '!=', '<', '>', '<=', '>=', '=/=', '<.', '>.', '<=.',
                '>=.'
        ]:
            if ctx.op in ['==']:
                code = l + r + self.emit.emitREOP('==', typ, o.frame)
            elif ctx.op in ['!=', '=/=']:
                code = l + r + self.emit.emitREOP('!=', typ, o.frame)
            elif ctx.op in ['<', '<.']:
                code = l + r + self.emit.emitREOP('<', typ, o.frame)
            elif ctx.op in ['>', '>.']:
                code = l + r + self.emit.emitREOP('>', typ, o.frame)
            elif ctx.op in ['<=', '<=.']:
                code = l + r + self.emit.emitREOP('<=', typ, o.frame)
            elif ctx.op in ['>=', '>=.']:
                code = l + r + self.emit.emitREOP('>=', typ, o.frame)
            rettyp = BoolType()
        return code, rettyp

    def visitIntLiteral(self, ctx, o):
        code = self.emit.emitPUSHICONST(ctx.value, o.frame)
        return code, IntType()

    def visitFloatLiteral(self, ctx, o):
        code = self.emit.emitPUSHFCONST(str(ctx.value), o.frame)
        return code, FloatType()

    def visitStringLiteral(self, ctx, o):
        code = self.emit.emitPUSHCONST('"' + ctx.value + '"', StringType(),
                                       o.frame)
        return code, StringType()

    def visitBooleanLiteral(self, ctx, o):
        code = self.emit.emitPUSHICONST(str(ctx.value).lower(), o.frame)
        return code, BoolType()

    def visitArrayLiteral(self, ctx, o):
        access = o
        # lit_code = list(map(lambda x: self.visit(x, access), ctx.value))
        # lit_code = [ret[0] for ret in lit_code]
        # lit_code = list(map(lambda code, idx: self.emit.emitDUP(access.frame) + \
        #         self.emit.emitPUSHICONST(idx, access.frame) + code + \
        #         self.emit.emitASTORE(ele_type, access.frame), lit_code, range(len(lit_code))))
        init_code = ""
        ele_type = None
        for (idx, lit) in enumerate(ctx.value):
            init_code += self.emit.emitDUP(access.frame)
            init_code += self.emit.emitPUSHICONST(idx, access.frame)
            code, ele_type = self.visit(lit, access)
            init_code += code
            init_code += self.emit.emitASTORE(ele_type, access.frame)
        access.frame.maxOpStackSize += 1
        code = self.emit.emitANEWARRAY(ele_type, len(ctx.value), access.frame)
        code = code + init_code
        if isinstance(ele_type, ArrayType):
            # print(ele_type.dimen)
            if isinstance(ele_type.dimen, tuple):
                ele_type.dimen = ele_type.dimen[0]
            ele_type.dimen = [len(ctx.value)] + ele_type.dimen
        else:
            ele_type = ArrayType(ele_type, [len(ctx.value)])
        return code, ele_type

    def visitId(self, ctx, o):
        id_sym = None
        for _sym in o.symbol:
            if _sym.name == ctx.name:
                id_sym = _sym
                break
        if id_sym.mtype == None:
            return None, id_sym.mtype
        elif isinstance(id_sym.mtype,
                        ArrayType) and id_sym.mtype.eleType == None:
            return None, id_sym.mtype
        # print('name: {}, mtype: {}, index: {}'.format(id_sym.name, id_sym.mtype, id_sym.value.value))
        if o.isLeft:
            if isinstance(id_sym.value, Index):
                # print('name: {}, mtype: {}, index: {}'.format(id_sym.name, id_sym.mtype, id_sym.value.value))
                code = self.emit.emitWRITEVAR(id_sym.name, id_sym.mtype,
                                              id_sym.value.value, o.frame)
                return code, id_sym.mtype
            else:
                code = self.emit.emitPUTSTATIC(
                    id_sym.value.value + '.' + ctx.name, id_sym.mtype, o.frame)
                return code, id_sym.mtype
        else:
            if isinstance(id_sym.value, Index):
                code = self.emit.emitREADVAR(id_sym.name, id_sym.mtype,
                                             id_sym.value.value, o.frame)
                return code, id_sym.mtype
            else:
                code = self.emit.emitGETSTATIC(
                    id_sym.value.value + '.' + ctx.name, id_sym.mtype, o.frame)
                return code, id_sym.mtype

    def inferId(self, id, expect_type, o):
        for sym in o.symbol:
            if id.name == sym.name:
                if sym.mtype == None:
                    sym.mtype = expect_type
                if isinstance(sym.mtype, ArrayType):
                    if sym.mtype.eleType == None:
                        return None, sym.mtype
                break

    def inferArray(self, arr, expect_type, o):
        access = Access(o.frame, o.symbol, isLeft=o.isLeft)
        code, typ = self.visit(arr.arr, access)
        if typ.eleType == None:
            typ.eleType = expect_type
            ele_type = typ.eleType
            code, typ = self.visit(arr.arr, access)
            lit = None
            dimen = typ.dimen[0]
            if isinstance(typ.eleType, IntType):
                lit = ArrayLiteral([IntLiteral(0)] * dimen[-1])
            elif isinstance(typ.eleType, BoolType):
                lit = ArrayLiteral([BooleanLiteral(False)] * dimen[-1])
            elif isinstance(typ.eleType, StringType):
                lit = ArrayLiteral([StringLiteral("")] * dimen[-1])
            elif isinstance(typ.eleType, FloatType):
                lit = ArrayLiteral([FloatType(0.0)] * dimen[-1])
            for d in dimen[::-1][1:]:
                lit = ArrayLiteral([lit] * d)
            lit_code, _ = self.visitArrayLiteral(lit, access)
            code = lit_code + code
        self.emit.printout(code)

    def inferCallExpr(self, callee, expect_type, o):
        # args_and_types = [self.visit(p,o) for p in callee.param]
        name = callee.method.name
        method_sym = None
        for method in self.staticFunction:
            if method.name == name:
                method_sym = method
                break
        if method_sym == None:
            partype = [None] * len(callee.param)
            rettype = expect_type
            typ = MType(partype, rettype)
            self.staticFunction.append(Symbol(name, typ,
                                              CName(self.className)))
            method_sym = self.staticFunction[-1]
        partype = method_sym.mtype.partype
        """
        TODOs: infer the function  that be invokeed before declared
        e.g.: foo(foo(x))
        """
        args_and_types = []
        access = o
        for (idx, p) in enumerate(callee.param):
            code, typ = self.visit(p, access)
            if code == None:
                if partype[idx] == None:
                    partype[idx] = IntType()
                self.infer(p, partype[idx], access)
                code, typ = self.visit(p, access)
            partype[idx] = typ
        # access = o
        # for p in callee.param:
        #     code, typ = self.visit(p, access)
        #     if code == None:
        #         code, typ = self.infer(p, access)
        # for (expr, expect) in list(map(lambda x,y: (x,y), callee.param, method_sym.mtype.partype)):
        #         expr_code, typ = self.visit(expr, access)
        #         if expr_code == None:
        #             self.infer(expr, expect, access)
        #             expr_code, typ = self.visit(expr, access)
        #         expr_codes.append([expr_code, typ])

    def infer(self, x, expect_type, o):
        if isinstance(x, Id):
            self.inferId(x, expect_type, o)
            return None
        elif isinstance(x, ArrayCell):
            self.inferArray(x, expect_type, o)
            return None
        elif isinstance(x, CallExpr):
            return self.inferCallExpr(x, expect_type, o)
Example #20
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 = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.curFunc = Symbol("null", MType([], VoidType()),
                              CName(self.className))

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

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

        lsFunc = list(filter(lambda x: type(x) is FuncDecl, ast.decl))

        for x in ast.decl:
            if type(x) is VarDecl:
                self.emit.printout(
                    self.emit.emitATTRIBUTE(x.variable.name, x.varType, False,
                                            ""))
                symbol = Symbol(x.variable.name, x.varType,
                                CName(self.className))
                self.env.append(symbol)
            else:
                typeFunc = MType([y.varType for y in x.param], x.returnType)
                symbol = Symbol(x.name.name, typeFunc, CName(self.className))
                self.env.append(symbol)

        e = SubBody(None, self.env)
        for x in lsFunc:
            self.visit(x, e)

        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), c,
                       Frame("<init>", VoidType))
        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)

        lsVarLocal = []
        # 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))
        else:
            for x in consdecl.param:
                self.visit(x, SubBody(frame, lsVarLocal))
                #self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), x.variable.name, x.varType, frame.getStartLabel(), frame.getEndLabel(), frame))
                #lsVarLocal.append(Symbol(x.variable.name, x.varType,Index(frame.currIndex-1)))
        for y in consdecl.local:
            self.visit(y, SubBody(frame, lsVarLocal))
            #self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), y.variable.name, y.varType, frame.getStartLabel(), frame.getEndLabel(), frame))
            #lsVarLocal.append(Symbol(y.variable.name, y.varType,Index(frame.currIndex-1)))

        glenv = lsVarLocal + (o if o != None else [])

        body = consdecl.body
        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))

        list(map(lambda x: self.visit(x, SubBody(frame, glenv)), body))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if type(returnType) is VoidType:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        else:

            self.emit.printout(self.emit.emitRETURN(returnType, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitVarDecl(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        glenv = ctxt.sym
        name = ast.variable.name
        mtype = ast.varType

        if frame is not None:
            idx = frame.getNewIndex()
            self.emit.printout(
                self.emit.emitVAR(idx, name, mtype, frame.getStartLabel(),
                                  frame.getEndLabel(), frame))
        return SubBody(frame, glenv.append(Symbol(name, mtype, Index(idx))))

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any
        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.curFunc = self.lookup(ast.name.name, subctxt.sym,
                                   lambda x: x.name)
        self.genMETHOD(ast, subctxt.sym, frame)
        return SubBody(None, [
            Symbol(ast.name, MType(list(), ast.returnType),
                   CName(self.className))
        ] + subctxt.sym)

    def visitAssign(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        env = ctxt.sym
        str_I2f = ''
        (resExpr, typeExpr) = self.visit(ast.exp,
                                         Access(c.frame, c.sym, False, True))
        (reslhs, typelhs) = self.visit(ast.lhs,
                                       Access(c.frame, c.sym, True, False))
        #print(typeExpr)
        #print(reslhs)
        if type(typelhs) == FloatType and type(typeExpr) == IntType:
            str_I2f = self.emit.emitI2F(frame)
        self.emit.printout(resExpr + str_I2f + reslhs)

    def visitIf(self, ast, c):  #
        ctxt = c
        frame = ctxt.frame
        nenv = ctxt.sym
        #Code for expr
        expr, typeD = self.visit(ast.expr, Access(frame, nenv, False, False))

        #Get 2 new lables
        falseLabel = frame.getNewLabel()
        trueLabel = frame.getNewLabel()
        #Code "ifeq" + falseLabel
        self.emit.printout(expr + self.emit.emitIFFALSE(falseLabel, frame))
        #Code for "then" stmt
        for i in ast.thenStmt:
            self.visit(i, SubBody(frame, nenv))

        #visitStmt(ast.thenStmt, frame, nenv)

        #code "goto" + trueLabel
        self.emit.printout(
            self.emit.emitGOTO(str(trueLabel), frame) +
            self.emit.emitLABEL(falseLabel, frame))

        #code for "else" stmt
        if (ast.elseStmt != None):
            for x in ast.elseStmt:
                self.visit(x, SubBody(frame, nenv))
        # visitStmt(ast.elseStmt.get, frame, nenv)

        #Code "trueLabel"
        self.emit.printout(self.emit.emitLABEL(trueLabel, frame))

    # def visitFor(self, ast, c):

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

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

    def visitReturn(self, ast, c):
        if ast.expr:
            (resExp, resType) = self.visit(ast.expr,
                                           Access(c.frame, c.sym, False, True))
            typeFun = self.curFunc.mtype.rettype
            if type(typeFun) is FloatType and type(resType) is IntType:
                self.emit.printout(resExp + self.emit.emitI2F(c.frame))
            else:
                self.emit.printout(resExp)
        self.emit.printout(self.emit.emitGOTO(c.frame.getEndLabel(), c.frame))

    def visitFor(self, ast, c):
        frame = c.frame
        frame.enterLoop()
        inB = frame.getNewLabel()
        contiLabel = frame.getContinueLabel()
        bkLabel = frame.getBreakLabel()

        self.visit(Assign(ast.id, ast.expr1), c)
        self.emit.printout(self.emit.emitLABEL(inB, frame))
        op = '<=' if ast.up else '>='
        (resExC, resT) = self.visit(BinaryOp(op, ast.id, ast.expr2),
                                    Access(frame, c.sym, False, True))
        self.emit.printout(resExC + self.emit.emitIFFALSE(bkLabel, frame))
        for i in ast.loop:
            self.visit(i, SubBody(frame, c.sym))
        self.emit.printout(self.emit.emitLABEL(contiLabel, frame))
        op = '+' if ast.up else '-'
        self.visit(Assign(ast.id, BinaryOp(op, ast.id, IntLiteral(1))), c)
        self.emit.printout(self.emit.emitGOTO(inB, frame))
        self.emit.printout(self.emit.emitLABEL(bkLabel, frame))
        frame.exitLoop()

    def visitWith(self, ast, c):
        frame = c.frame

        frame.enterScope(False)
        lsVarLocal = []
        # Generate code for parameter declarations

        for y in ast.decl:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), y.variable.name,
                                  y.varType, frame.getStartLabel(),
                                  frame.getEndLabel(), frame))
            lsVarLocal.append(
                Symbol(y.variable.name, y.varType, Index(frame.currIndex - 1)))

        glenv = lsVarLocal + c.sym
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for x in ast.stmt:
            self.visit(x, SubBody(frame, glenv))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()

    def visitWhile(self, ast, c):  #
        frame = c.frame
        nenv = c.sym
        # enter loop
        frame.enterLoop()
        breakLabel = frame.getBreakLabel()
        continueLabel = frame.getContinueLabel()
        # code for continueLabel
        self.emit.printout(self.emit.emitLABEL(continueLabel, frame))
        expr, typeD = self.visit(ast.exp, Access(frame, nenv, False, True))
        #print(expr)
        #print(typeD)
        self.emit.printout(expr + self.emit.emitIFFALSE(breakLabel, frame))

        for x in ast.sl:
            self.visit(x, SubBody(frame, nenv))

        self.emit.printout(self.emit.emitGOTO(continueLabel, frame))
        self.emit.printout(self.emit.emitLABEL(breakLabel, frame))
        frame.exitLoop()

    def visitCallStmt(self, ast, o):
        self.callStmtAndExp(ast, o)
        #print(self.callStmtAndExp(ast, o))
    def visitCallExpr(self, ast, o):
        return (self.callStmtAndExp(ast, o)[0], self.callStmtAndExp(ast, o)[1])

    def callStmtAndExp(self, ast, o):
        #ast: CallStmt
        #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
        partype = sym.mtype.partype
        #print(ctype)
        #print(cname)
        #print((sym.name))
        # print(frame)
        code = ""
        typeList = list()
        for x in range(len(ast.param)):
            #  print(ast.param[x])
            str1, typ1 = self.visit(ast.param[x],
                                    Access(frame, nenv, False, True))
            # print(str1)
            # print(typ1)
            code += str1
            typeList.append(typ1)

            if type(partype[x]) is FloatType and type(typ1) is IntType:
                code += self.emit.emitI2F(frame)
        if type(ast) is CallStmt:
            self.emit.printout(code)
            self.emit.printout(
                self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name,
                                           ctype, frame))
        else:
            return (code + self.emit.emitINVOKESTATIC(
                cname + "/" + ast.method.name, ctype, frame), returnType)

    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):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()

    def visitBooleanLiteral(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(ast.value, StringType(),
                                       frame), StringType()

    def visitId(self, ast, c):
        sym = self.lookup(ast.name, c.sym, lambda x: x.name)
        if c.isLeft:
            if type(sym.value) is CName:
                return self.emit.emitPUTSTATIC(self.className + '.' + sym.name,
                                               sym.mtype, c.frame), sym.mtype
            else:
                return self.emit.emitWRITEVAR(sym.name, sym.mtype,
                                              sym.value.value,
                                              c.frame), sym.mtype
        else:
            if type(sym.value) is CName:
                return self.emit.emitGETSTATIC(self.className + '.' + sym.name,
                                               sym.mtype, c.frame), sym.mtype
            else:
                return self.emit.emitREADVAR(sym.name, sym.mtype,
                                             sym.value.value,
                                             c.frame), sym.mtype

    def checkEqual(self, lt, rt):
        if type(lt) == type(rt):
            return True
        else:
            return False

    def visitUnaryOp(self, ast, o):
        lc, lt = self.visit(ast.body, Access(o.frame, o.sym, False, True))
        if ast.op == '-':
            return lc + self.emit.emitNEGOP(lt, o.frame), lt
        elif ast.op == 'not':
            return lc + self.emit.emitNOT(lt, o.frame), lt

    def visitBinaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame

        if ast.op == 'andthen':
            codeEndthen = ""
            Label1 = frame.getNewLabel()
            Label2 = frame.getNewLabel()
            lc, lt = self.visit(ast.left, Access(frame, o.sym, False, True))
            codeEndthen += lc + self.emit.emitIFFALSE(
                Label1, frame) + self.emit.emitPUSHICONST('true', frame)
            rc, rt = self.visit(ast.right, Access(frame, o.sym, False, True))
            codeEndthen += rc + self.emit.emitANDOP(
                frame) + self.emit.emitGOTO(
                    Label2, frame) + self.emit.emitLABEL(
                        Label1, frame) + self.emit.emitPUSHICONST(
                            'false', frame) + self.emit.emitLABEL(
                                Label2, frame)
            #print(codeEndthen)
            return codeEndthen, BoolType()
        elif ast.op == 'orelse':
            codeOrelse = ""
            Label1 = frame.getNewLabel()
            Label2 = frame.getNewLabel()
            lc, lt = self.visit(ast.left, Access(frame, o.sym, False, True))
            codeOrelse += lc + self.emit.emitIFFALSE(
                Label1, frame) + self.emit.emitPUSHICONST('false', frame)
            rc, rt = self.visit(ast.right, Access(frame, o.sym, False, True))
            codeOrelse += rc + self.emit.emitOROP(frame) + self.emit.emitGOTO(
                Label2, frame) + self.emit.emitLABEL(
                    Label1, frame) + self.emit.emitPUSHICONST(
                        'true', frame) + self.emit.emitLABEL(Label2, frame)
            #print(codeEndthen)
            return codeOrelse, BoolType()

        lc, lt = self.visit(ast.left, Access(frame, o.sym, False, True))
        rc, rt = self.visit(ast.right, Access(frame, o.sym, False, True))
        # print(lc)
        #print(rc) a(ifl)+b(int)
        if ast.op in ['+', '-']:
            if self.checkEqual(lt, rt):
                return lc + rc + self.emit.emitADDOP(ast.op, lt, frame), lt
            else:
                if type(lt) is FloatType and type(rt) is IntType:
                    return lc + rc + self.emit.emitI2F(
                        frame) + self.emit.emitADDOP(ast.op, lt, frame), lt
                else:
                    return lc + self.emit.emitI2F(
                        frame) + rc + self.emit.emitADDOP(ast.op, rt,
                                                          frame), rt
        elif ast.op == '*':
            if self.checkEqual(lt, rt):
                return lc + rc + self.emit.emitMULOP(ast.op, lt, frame), lt
            else:
                if type(lt) is FloatType and type(rt) is IntType:
                    return lc + rc + self.emit.emitI2F(
                        frame) + self.emit.emitMULOP(ast.op, lt, frame), lt
                else:
                    return lc + self.emit.emitI2F(
                        frame) + rc + self.emit.emitMULOP(ast.op, rt,
                                                          frame), rt
        elif ast.op == '/':
            if self.checkEqual(lt, rt):
                if type(lt) is IntType:
                    return lc + self.emit.emitI2F(
                        frame) + rc + self.emit.emitI2F(
                            frame) + self.emit.emitMULOP(
                                ast.op, FloatType, frame), FloatType()
                return lc + rc + self.emit.emitMULOP(ast.op, lt, frame), lt
            else:
                if type(lt) is FloatType and type(rt) is IntType:
                    return lc + rc + self.emit.emitI2F(
                        frame) + self.emit.emitMULOP(ast.op, lt, frame), lt
                else:
                    return lc + self.emit.emitI2F(
                        frame) + rc + self.emit.emitMULOP(ast.op, rt,
                                                          frame), rt
        elif ast.op == 'div':
            return lc + rc + self.emit.emitDIV(frame), lt
        elif ast.op == 'mod':
            return lc + rc + self.emit.emitMOD(frame), lt
        elif ast.op == 'and':
            return lc + rc + self.emit.emitANDOP(frame), BoolType()
        elif ast.op == 'or':
            return lc + rc + self.emit.emitOROP(frame), BoolType()
        elif ast.op in ['<', '<=', '>', '>=', '<>', '=']:
            if type(lt) is FloatType and type(rt) is IntType:
                return lc + rc + self.emit.emitI2F(frame) + self.emit.emitREOP(
                    ast.op, FloatType(), frame), BoolType()
            elif type(lt) is IntType and type(rt) is FloatType:
                return lc + self.emit.emitI2F(frame) + rc + self.emit.emitREOP(
                    ast.op, FloatType(), frame), BoolType()
            else:
                return lc + rc + self.emit.emitREOP(ast.op, lt,
                                                    frame), BoolType()
Example #21
0
class CodeGenVisitor(BaseVisitor, Utils):
    def __init__(self, astTree, env, dir_):
        self.astTree = astTree
        self.env = env
        self.className = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.arrayGlobals = list()

    def visitProgram(self, ast, c):
        self.emit.printout(self.emit.emitPROLOG(self.className, "java/lang/Object"))
        funcDecls = []
        for d in ast.decl:
            if isinstance(d, VarDecl):
                self.env = self.visit(d, self.env)
                if type(d.varType) is ArrayType:
                    self.arrayGlobals.append(d)
            else:
                funcDecls.append(d)
                self.env = self.visit(d, (self.env, True))
        for d in funcDecls:
            self.visit(d, (self.env, False))
        self.genCONSTRUCTOR(Frame("<init>", VoidType()))
        if len(self.arrayGlobals) > 0:
            self.genSTATICCONSTRUCTOR(Frame("<clinit>", VoidType()))
        self.emit.emitEPILOG()

    def genSTATICCONSTRUCTOR(self, frame):
        self.emit.printout(self.emit.emitMETHOD("<clinit>", MType(list(), VoidType()), True, frame))
        frame.enterScope(True)
        for arr in self.arrayGlobals:
            self.emit.printout(self.emit.emitNEWARRAY(arr.varType, frame))
            self.emit.printout(self.emit.emitPUTSTATIC(self.className + '.' + arr.variable.name, arr.varType, frame))
        self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def genCONSTRUCTOR(self, frame):
        self.emit.printout(self.emit.emitMETHOD("<init>", MType(list(), VoidType()), False, frame))
        frame.enterScope(True)
        self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "this", ClassType(self.className), frame.getStartLabel(), frame.getEndLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        self.emit.printout(self.emit.emitREADVAR("this", ClassType(self.className), 0, frame))
        self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def genMETHOD(self, consdecl, env, frame):
        returnType = consdecl.returnType
        isMain = consdecl.name.name.lower() == "main" and len(consdecl.param) == 0 and type(returnType) is VoidType
        methodName = "main" if isMain else consdecl.name.name
        intype = [ArrayType(None, None, StringType())] if isMain else [p.varType for p in consdecl.param]
        mtype = MType(intype, returnType)
        self.emit.printout(self.emit.emitMETHOD(methodName, mtype, True, frame))
        frame.enterScope(True)
        nenv = env[:]
        if isMain:
            self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "args", ArrayType(None, None, StringType()), frame.getStartLabel(), frame.getEndLabel(), frame))
        else:
            for p in consdecl.param:
                index = frame.getNewIndex()
                nenv = [Symbol(p.variable.name, p.varType, Index(index))] + nenv
                self.emit.printout(self.emit.emitVAR(index, p.variable.name, p.varType, frame.getStartLabel(), frame.getEndLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for v in consdecl.local:
            index = frame.getNewIndex()
            nenv = [Symbol(v.variable.name, v.varType, Index(index))] + nenv
            if type(v.varType) is ArrayType:
                self.emit.printout(self.emit.emitNEWARRAY(v.varType, frame))
                self.emit.printout(self.emit.emitWRITEVAR(v.variable.name, v.varType, index, frame))
        list(map(lambda x: self.visit(x, SubBody(frame, nenv)), consdecl.body))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if type(returnType) is VoidType:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitFuncDecl(self, ast, o):
        glenv, isFirstTime = o
        if isFirstTime:
            inType = [x.varType for x in ast.param]
            return [Symbol(ast.name.name, MType(inType, ast.returnType), CName(self.className))] + glenv
        frame = Frame(ast.name.name, ast.returnType)
        self.genMETHOD(ast, glenv, frame)

    def visitVarDecl(self, ast, o):
        glenv = o
        self.emit.printout(self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False, None))
        return [Symbol(ast.variable.name, ast.varType, CName(self.className))] + glenv

    def visitAssign(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        if isinstance(ast.lhs, Id):
            expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True))
            self.emit.printout(expCode)
            sym = self.lookup(ast.lhs.name.lower(), nenv, lambda x: x.name.lower())
            if isinstance(expType, IntType) and isinstance(sym.mtype, FloatType):
                self.emit.printout(self.emit.emitI2F(frame))
        else:
            arrayCellCode, arrayCellType = self.visit(ast.lhs, Access(frame, nenv, True, True))
            self.emit.printout(arrayCellCode)
            expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True))
            self.emit.printout(expCode)
            if isinstance(expType, IntType) and isinstance(arrayCellType, FloatType):
                self.emit.printout(self.emit.emitI2F(frame))
        self.visit(ast.lhs, Access(frame, nenv, True, False))
        return False
    
    def visitWith(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        arrays = list()
        frame.enterScope(False)
        for d in ast.decl:
            index = frame.getNewIndex()
            nenv = [Symbol(d.variable.name, d.varType, Index(index))] + nenv
            if type(d.varType) is ArrayType:
                arrays.append((d, index))
            self.emit.printout(self.emit.emitVAR(index, d.variable.name, d.varType, frame.getStartLabel(), frame.getEndLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for arr, index in arrays:
            self.emit.printout(self.emit.emitNEWARRAY(arr.varType, frame))
            self.emit.printout(self.emit.emitWRITEVAR(arr.variable.name, arr.varType, index, frame))
        unReachable = False
        for stmt in ast.stmt:
            unReachable = self.visit(stmt, SubBody(frame, nenv))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()
        return unReachable

    def visitIf(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        self.emit.printout(self.visit(ast.expr, Access(frame, nenv, False, True))[0])
        if len(ast.elseStmt) == 0:
            label = frame.getNewLabel()
            self.emit.printout(self.emit.emitIFFALSE(label, frame))
            list(map(lambda x: self.visit(x, SubBody(frame, nenv)), ast.thenStmt))
            self.emit.printout(self.emit.emitLABEL(label, frame))
            return False
        else:
            label1 = frame.getNewLabel()
            label2 = None
            unReachableThen, unReachableElse = False, False
            self.emit.printout(self.emit.emitIFFALSE(label1, frame))
            for stmt in ast.thenStmt:
                unReachableThen = self.visit(stmt, SubBody(frame, nenv))
            if not unReachableThen:
                label2 = frame.getNewLabel()
                self.emit.printout(self.emit.emitGOTO(label2, frame))
            self.emit.printout(self.emit.emitLABEL(label1, frame))
            for stmt in ast.elseStmt:
                unReachableElse = self.visit(stmt, SubBody(frame, nenv))
            if not unReachableThen:
                self.emit.printout(self.emit.emitLABEL(label2, frame))
            return unReachableThen and unReachableElse
    
    def visitFor(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        frame.enterLoop()
        continueLabel, breakLabel = frame.getContinueLabel(), frame.getBreakLabel()
        labelS = frame.getNewLabel()
        ini_ = Assign(ast.id, ast.expr1)
        self.visit(ini_, SubBody(frame, nenv))
        self.emit.printout(self.emit.emitLABEL(labelS, frame))
        sym = self.lookup(ast.id.name.lower(), nenv, lambda x: x.name.lower())
        isLocal = type(sym.value) is Index
        if isLocal:
            self.emit.printout(self.emit.emitREADVAR(sym.name, sym.mtype, sym.value.value, frame))
        else:
            self.emit.printout(self.emit.emitGETSTATIC(sym.value.value + '.' + sym.name, sym.mtype, frame))
        expr2Code, expr2Type = self.visit(ast.expr2, Access(frame, nenv, False, True))
        self.emit.printout(expr2Code)
        if ast.up:
            self.emit.printout(self.emit.emitIFICMPGT(breakLabel, frame))
        else:
            self.emit.printout(self.emit.emitIFICMPLT(breakLabel, frame))
        list(map(lambda x: self.visit(x, SubBody(frame, nenv)), ast.loop))
        self.emit.printout(self.emit.emitLABEL(continueLabel, frame))
        step_ = Assign(ast.id, BinaryOp('+', ast.id, IntLiteral(1))) if ast.up else Assign(ast.id, BinaryOp('-', ast.id, IntLiteral(1)))
        self.visit(step_, SubBody(frame, nenv))
        self.emit.printout(self.emit.emitGOTO(labelS, frame))
        self.emit.printout(self.emit.emitLABEL(breakLabel, frame))
        frame.exitLoop()
        return False

    def visitContinue(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))
        return True
    
    def visitBreak(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))
        return True
    
    def visitReturn(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        if ast.expr is None:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        else:
            expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, True))
            self.emit.printout(expCode)
            retType = expType
            if isinstance(expType, IntType) and isinstance(frame.returnType, FloatType):
                self.emit.printout(self.emit.emitI2F(frame))
                retType = FloatType()
            self.emit.printout(self.emit.emitRETURN(retType, frame))
        return True
    
    def visitWhile(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        frame.enterLoop()
        continueLabel, breakLabel = frame.getContinueLabel(), frame.getBreakLabel()
        self.emit.printout(self.emit.emitLABEL(continueLabel, frame))
        self.emit.printout(self.visit(ast.exp, Access(frame, nenv, False, True))[0])
        self.emit.printout(self.emit.emitIFFALSE(breakLabel, frame))
        list(map(lambda x: self.visit(x, SubBody(frame, nenv)), ast.sl))
        self.emit.printout(self.emit.emitGOTO(continueLabel, frame))
        self.emit.printout(self.emit.emitLABEL(breakLabel, frame))
        frame.exitLoop()
        return False

    def visitCallStmt(self, ast, o):
        ctxt = o
        frame, nenv = ctxt.frame, ctxt.sym
        sym = self.lookup(ast.method.name.lower(), nenv, lambda x: x.name.lower())
        cName = sym.value.value
        ctype = sym.mtype
        inType = ctype.partype
        for i in range(len(inType)):
            expCode, expType = self.visit(ast.param[i], Access(frame, nenv, False, True))
            self.emit.printout(expCode)
            if isinstance(expType, IntType) and isinstance(inType[i], FloatType):
                self.emit.printout(self.emit.emitI2F(frame))
            if isinstance(expType, ArrayType):
                if type(expType.eleType) is not StringType:
                    self.emit.printout(self.emit.emitCLONE(expType, frame))
        self.emit.printout(self.emit.emitINVOKESTATIC(cName + "/" + sym.name, ctype, frame))
        return False

    def visitBinaryOp(self, ast, o):
        access = o
        frame, nenv = access.frame, access.sym
        leftCode, leftType = self.visit(ast.left, Access(frame, nenv, False, True))
        op = ast.op.lower()
        expCode = ""
        if op in ['+', '-', '*', '/', 'div', 'mod', 'and', 'or']:
            rightCode, rightType = self.visit(ast.right, Access(frame, nenv, False, True))
            expType = FloatType() if type(leftType) != type(rightType) else leftType
            expType = FloatType() if op == '/' else expType
            expCode += leftCode
            if type(leftType) != type(expType):
                expCode += self.emit.emitI2F(frame)
            expCode += rightCode
            if type(rightType) != type(expType):
                expCode += self.emit.emitI2F(frame)
            if op in ['+', '-']:
                expCode += self.emit.emitADDOP(op, expType, frame)
            elif op in ['*', '/']:
                expCode += self.emit.emitMULOP(op, expType, frame)
            elif op == 'div':
                expCode += self.emit.emitDIV(frame)
            elif op == 'mod':
                expCode += self.emit.emitMOD(frame)
            elif op == 'and':
                expCode += self.emit.emitANDOP(frame)
            elif op == 'or':
                expCode += self.emit.emitOROP(frame)
        elif op in ['>', '<', '>=', '<=', '<>', '=']:
            rightCode, rightType = self.visit(ast.right, Access(frame, nenv, False, True))
            expType = BoolType()
            relType = FloatType() if type(leftType) is not type(rightType) else leftType
            expCode += leftCode
            if type(leftType) != type(relType):
                expCode += self.emit.emitI2F(frame)
            expCode += rightCode
            if type(rightType) != type(relType):
                expCode += self.emit.emitI2F(frame)
            expCode += self.emit.emitREOP(op, relType, frame)
        else:
            expType = BoolType()
            expCode += leftCode
            label1 = frame.getNewLabel()
            label2 = frame.getNewLabel()
            expCode += self.emit.emitIFFALSE(label1, frame) if op == 'andthen' else self.emit.emitIFTRUE(label1, frame)
            rightCode, rightType = self.visit(ast.right, Access(frame, nenv, False, True))
            expCode += rightCode
            expCode += self.emit.emitIFFALSE(label1, frame) if op == 'andthen' else self.emit.emitIFTRUE(label1, frame)
            expCode += self.emit.emitPUSHCONST(str(op == 'andthen'), BoolType(), frame)
            expCode += self.emit.emitGOTO(label2, frame)
            expCode += self.emit.emitLABEL(label1, frame)
            expCode += self.emit.emitPUSHCONST(str(op == 'orelse'), BoolType(), frame)
            expCode += self.emit.emitLABEL(label2, frame)
            frame.pop()
        return expCode, expType

    def visitUnaryOp(self, ast, o):
        access = o
        frame, nenv = access.frame, access.sym
        bodyCode, bodyType = self.visit(ast.body, Access(frame, nenv, False, True))
        expCode, expType = bodyCode, bodyType
        if ast.op == '-':
            expCode += self.emit.emitNEGOP(expType, frame)
        else:
            expCode += self.emit.emitNOT(expType, frame)
        return expCode, expType
    
    def visitCallExpr(self, ast, o):
        access = o
        frame, nenv = access.frame, access.sym
        sym = self.lookup(ast.method.name.lower(), nenv, lambda x: x.name.lower())
        cName = sym.value.value
        ctype = sym.mtype
        inType = ctype.partype
        expCode, expType = '', ctype.rettype
        for i in range(len(inType)):
            paramCode, paramType = self.visit(ast.param[i], Access(frame, nenv, False, True))
            expCode += paramCode
            if isinstance(paramType, IntType) and isinstance(inType[i], FloatType):
                expCode += self.emit.emitI2F(frame)
            if isinstance(paramType, ArrayType):
                if type(paramType.eleType) is not StringType:
                    expCode += self.emit.emitCLONE(paramType, frame)
        expCode += self.emit.emitINVOKESTATIC(cName + "/" + sym.name, ctype, frame)
        return expCode, expType
    
    def visitId(self, ast, o):
        access = o
        frame, nenv, isLeft, isFirst = access.frame, access.sym, access.isLeft, access.isFirst
        sym = self.lookup(ast.name.lower(), nenv, lambda x: x.name.lower())
        idType, isLocal = sym.mtype, type(sym.value) is Index
        if isLeft:
            if isLocal:
                self.emit.printout(self.emit.emitWRITEVAR(sym.name, idType, sym.value.value, frame))
            else:
                self.emit.printout(self.emit.emitPUTSTATIC(sym.value.value + '.' + sym.name, idType, frame))
        else:
            if isLocal:
                idCode = self.emit.emitREADVAR(sym.name, idType, sym.value.value, frame)
            else:
                idCode = self.emit.emitGETSTATIC(sym.value.value + '.' + sym.name, idType, frame)
            return idCode, idType

    def visitArrayCell(self, ast, o):
        access = o
        frame, nenv, isLeft, isFirst = access.frame, access.sym, access.isLeft, access.isFirst
        if isLeft and not isFirst:
            isId = type(ast.arr) is Id
            name = ast.arr.name if isId else ast.arr.method.name
            sym = self.lookup(name.lower(), nenv, lambda x: x.name.lower())
            arrType = sym.mtype if isId else sym.mtype.rettype
            frame.push()
            self.emit.printout(self.emit.emitASTORE(arrType.eleType, frame))
        else:
            arrCode, arrType = self.visit(ast.arr, Access(frame, nenv, False, True))
            idxCode, idxType = self.visit(ast.idx, Access(frame, nenv, False, True))
            arrayCellCode = arrCode + idxCode
            arrayCellCode += self.emit.emitPUSHICONST(arrType.lower, frame)
            arrayCellCode += self.emit.emitADDOP('-', IntType(), frame)
            if not isLeft:
                arrayCellCode += self.emit.emitALOAD(arrType.eleType, frame)
            return arrayCellCode, arrType.eleType
    
    def visitIntLiteral(self, ast, o):
        access = o
        frame = access.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()
    
    def visitFloatLiteral(self, ast, o):
        access = o
        frame = access.frame
        return self.emit.emitPUSHFCONST(ast.value, frame), FloatType()

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

    def visitStringLiteral(self, ast, o):
        access = o
        frame = access.frame
        return self.emit.emitPUSHCONST(ast.value, StringType(), frame), StringType()
Example #22
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 #23
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")
        # global variable
        self.listGlobalArray = [] 

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

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

        staticDecl = self.env
        for x in ast.decl:
            if type(x) is FuncDecl:
                paramType = [y.varType for y in x.param]
                staticDecl = [Symbol(x.name.name.lower(), MType(paramType, x.returnType), CName(self.className))] + staticDecl
            else:
                newSymbol = self.visit(x, SubBody(None, None, isGlobal=True))
                staticDecl = [newSymbol] + staticDecl

        e = SubBody(None, staticDecl)

        for x in ast.decl:
            if type(x) is FuncDecl:
                e = self.visit(x, e)

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

        self.emit.emitEPILOG()

        return c

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

        global_env = o

        funcName = consdecl.name.name

        isInit = consdecl.returnType is None and funcName == "<init>"

        isClassInit = consdecl.returnType is None and funcName == "<clinit>"

        isMain = consdecl.name.name == "main" and len(consdecl.param) == 0 and type(consdecl.returnType) is VoidType

        returnType = VoidType() if isInit or isClassInit else consdecl.returnType

        methodName = "<init>" if isInit else consdecl.name.name

        intype = [ArrayPointerType(StringType())] if isMain else [Ctils.retrieveType(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)

        # 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))

        listParamArray = [] 
        paramList = SubBody(frame, global_env)


        for x in consdecl.param:
            paramList = self.visit(x, paramList)
            if type(x.varType) is ArrayType:
                listParamArray.append(paramList.sym[0])

        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))

        # Init global array declare
        if isClassInit:
            for x in self.listGlobalArray:
                size = x.varType.dimen
                self.emit.printout(self.emit.emitInitNewStaticArray(self.className + "/" + x.variable, size, x.varType.eleType, frame))

        # Clone params array
        for sym in listParamArray:
            index = sym.value.value
            eleType = sym.mtype.eleType
            self.emit.printout(self.emit.emitCloneArray(index, eleType, frame))
            
        
        self.visit(consdecl.body, SubBody(frame, paramList.sym))

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

        if type(returnType) is VoidType:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))

        self.emit.printout(self.emit.emitENDMETHOD(frame))

        frame.exitScope()

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

        subcontext = o
        frame = Frame(ast.name, ast.returnType)

        self.genMETHOD(ast, subcontext.sym, frame)

        return SubBody(None, [Symbol(ast.name, MType([], ast.returnType), CName(self.className))] + subcontext.sym)

    def visitVarDecl(self, ast: VarDecl, subbody: SubBody):
        subcontext = subbody
        frame = subbody.frame
        isGlobal = subbody.isGlobal
        varName = ast.variable
        varType = ast.varType

        if isGlobal:
            self.emit.printout(self.emit.emitATTRIBUTE(varName, Ctils.retrieveType(varType), False, ""))
            if type(ast.varType) is ArrayType:
                self.listGlobalArray.append(ast)
            return Symbol(varName, varType)

        idx = frame.getNewIndex()

        self.emit.printout(self.emit.emitVAR(idx, varName, Ctils.retrieveType(varType), frame.getStartLabel(), frame.getEndLabel(), frame))

        return SubBody(frame, [Symbol(varName, varType, Index(idx))] + subcontext.sym)

    def visitBlock(self, ast: Block, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        symbols = subcontext.sym

        listLocalArray = []
        
        for x in ast.member:
            if type(x) is VarDecl:
                subcontext = self.visit(x, subcontext)
                symbols = subcontext.sym
                if type(x.varType) is ArrayType:
                    index = subcontext.sym[0].value.value
                    varType = subcontext.sym[0].mtype
                    size = varType.dimen
                    self.emit.printout(self.emit.emitInitNewLocalArray(index, size, varType.eleType, frame))
            else: 
                e = SubBody(frame, symbols)
                if self.visit(x, e) == True:
                    return True
        return False

    def visitIf(self, ast: If, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        newEnv = subcontext.sym
        expCode, expType = self.visit(ast.expr, Access(frame, newEnv, False, True))
        self.emit.printout(expCode)

        labelT = frame.getNewLabel() # if expr is true
        labelE = frame.getNewLabel() # label end
        
        self.emit.printout(self.emit.emitIFTRUE(labelT, frame))
        # handle else stmt
        if ast.elseStmt:
            # False
            isReturn = True in [self.visit(ast.elseStmt, subcontext)]
            if not isReturn:
                self.emit.printout(self.emit.emitGOTO(labelE, frame))
            # True
            self.emit.printout(self.emit.emitLABEL(labelT, frame))
            isReturn = True in [self.visit(ast.thenStmt, subcontext)] and isReturn
            # End
            self.emit.printout(self.emit.emitLABEL(labelE, frame))
            return isReturn
        else:
            # self.emit.printout(self.emit.emitIFTRUE(labelT, frame))
            self.emit.printout(self.emit.emitGOTO(labelE, frame))
            # True
            self.emit.printout(self.emit.emitLABEL(labelT, frame))
            isReturn = True in [self.visit(ast.thenStmt, subcontext)] 
            # End
            self.emit.printout(self.emit.emitLABEL(labelE, frame))
            return isReturn

    def visitFor(self, ast: For, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        newEnv = subcontext.sym

        expr2, _ = self.visit(ast.expr2, Access(frame, newEnv, False, True))

        labelS = frame.getNewLabel()
        labelE = frame.getNewLabel()

        # init value
        self.visit(ast.expr1, SubBody(frame, newEnv))
        frame.enterLoop()

        # loop
        self.emit.printout(self.emit.emitLABEL(labelS, frame))

        # condition
        self.emit.printout(expr2)
        self.emit.printout(self.emit.emitIFFALSE(labelE, frame))

        # stmt
        isReturn = True in [self.visit(ast.loop, subcontext)]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))

        # update index
        self.visit(ast.expr3, SubBody(frame, newEnv))

        if not isReturn:
            self.emit.printout(self.emit.emitGOTO(labelS, frame))
        self.emit.printout(self.emit.emitLABEL(labelE, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitDowhile(self, ast: Dowhile, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        newEnv = subcontext.sym
        expr, exprType = self.visit(ast.exp, Access(frame, newEnv, False, True))

        labelS = frame.getNewLabel()
        labelE = frame.getNewLabel()

        # enter loop
        frame.enterLoop()
        [self.visit(x, o) for x in ast.sl]
        self.emit.printout(self.emit.emitLABEL(labelS, frame))
        self.emit.printout(expr)
        self.emit.printout(self.emit.emitIFFALSE(labelE, frame))
        isReturn = True in [self.visit(x, o) for x in ast.sl]
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame))
        if not isReturn:
            self.emit.printout(self.emit.emitGOTO(labelS, frame))
        self.emit.printout(self.emit.emitLABEL(labelE, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitBreak(self, ast: Break, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        return self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))

    def visitContinue(self, ast: Continue, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        return self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))

    def visitReturn(self, ast: Return, o: SubBody):
        subcontext = o
        frame = subcontext.frame1
        newEnv = subcontext.sym
        retType = frame.returnType

        if type(retType) is not VoidType:   
            expr, exprType = self.visit(ast.expr, Access(frame, newEnv, False, True))
            if type(retType) is FloatType and type(exprType) is IntType:
                expr += self.emit.emitI2F(frame)
            self.emit.printout(expr)
        self.emit.printout(self.emit.emitRETURN(retType, frame))
        return True

    def visitBinaryOp(self, ast: BinaryOp, o: SubBody):
        subcontext = o
        frame = subcontext.frame
        newEnv = subcontext.sym
        op = str(ast.op)

        if Ctils.isOpForNum(op):
            left, lType = self.visit(ast.left, subcontext)
            right, rType = self.visit(ast.right, subcontext)
            mtype = Ctils.mergeNumberType(lType, rType)
            if type(lType) is IntType and type(mtype) != type(lType):
                left += self.emit.emitI2F(frame)
            if type(rType) is IntType and type(mtype) != type(rType):
                right += self.emit.emitI2F(frame)
            if Ctils.isOpForNumToNum(op):
                if op in ['+', '-']:
                    return left + right + self.emit.emitADDOP(op, mtype, frame), mtype
                if op in ['*', '/']:
                    return left + right + self.emit.emitMULOP(op, mtype, frame), mtype
                if op == '%':
                    return left + right + self.emit.emitMOD(frame), mtype
            else:
                return left + right + self.emit.emitREOP(op, mtype, frame), BoolType()
        elif op == '=':
            if type(o) is Access:
                isArray, _ = self.visit(ast.left, Access(frame, newEnv, True, True, True))

                if not isArray: 
                    expr, expType = self.visit(ast.right, Access(frame, newEnv, False, True))
                    lhs, lhsType = self.visit(ast.left, Access(frame, newEnv, True, True))
                    if type(lhsType) is FloatType and type(expType) is IntType:
                        expr += self.emit.emitI2F(frame)
                    self.emit.printout(expr + self.emit.emitDUP(frame) + lhs)
                    return "", expType
                # else:
                #     for i in range(0, 2):
                #         frame.push()
                #     if o.getLeft == False:
                #         expr, expType = self.visit(ast.right, Access(frame, newEnv, False, True, False, False))
                #         lhs, lhsType = self.visit(ast.left, Access(frame, newEnv, True, True))
                #         if type(lhsType) is FloatType and type(expType) is IntType:
                #             expr += self.emit.emitI2F(frame)
                #         self.emit.printout(lhs[0])
                #         for i in range(0, 2):
                #             frame.push()
                #         return expr, expType
                #     elif o.getLeft == True:
                #         expr, expType = self.visit(ast.right, Access(frame, newEnv, False, True, False, True))
                #         lhs, lhsType = self.visit(ast.left, Access(frame, newEnv, True, True))
                #         if type(lhsType) is FloatType and type(expType) is IntType:
                #             expr += self.emit.emitI2F(frame)
                #         self.emit.printout(self.emit.emitDUPX2(frame) + lhs[1])
                #         for i in range(0, 2):
                #             frame.push()
                #         return None, None
                
            else:
                isArray, _ = self.visit(ast.left, Access(frame, newEnv, True, True, True))

                # if isArray: 
                #     for i in range(0, 2):
                #         frame.push()
                #     expr, expType = self.visit(ast.right, Access(frame, newEnv, False, True))
                #     lhs, lhsType = self.visit(ast.left, Access(frame, newEnv, True, True))
                #     self.emit.printout(lhs[0] + expr)
                #     _, _ = self.visit(ast.right, Access(frame, newEnv, False, True, False, True))
                #     self.emit.printout(lhs[1])
                #     for i in range(0, 2):
                #         frame.pop()
                else:
                    frame.push()
                    expr, expType = self.visit(ast.right, Access(frame, newEnv, False, True))
                    lhs, lhsType = self.visit(ast.left, Access(frame, newEnv, True, True))
                    if type(lhsType) is FloatType and type(expType) is IntType:
                        expr += self.emit.emitI2F(frame)
                    self.emit.printout(expr + lhs)
                    frame.pop()
Example #24
0
class CodeGenVisitor(BaseVisitor, Utils):

    var_status = ["Global", "Parameter", "Local"]

    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"))
        declList = self.env
        # e = SubBody(None, self.env)
        # for x in ast.decl:
        #     e = self.visit(x, e)
        for x in ast.decl:
            if type(x) is FuncDecl:
                declList = [
                    Symbol(x.name.name,
                           MType([y.varType for y in x.param], x.returnType),
                           CName(self.className))
                ] + declList
            else:
                symbol = self.visit(x, (SubBody(None, None), "Global"))
                declList = [symbol] + declList

        e = SubBody(None, declList)
        [self.visit(x, e) for x in ast.decl if type(x) is FuncDecl]
        # generate default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), None, Block(list())), c,
                       Frame("<init>", VoidType))
        self.emit.emitEPILOG()
        return c

    def genMETHOD(self, consdecl, o, frame):
        #consdecl: FuncDecl
        #o: Any
        #frame: Frame
        glenv = o
        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
        isProc = type(returnType) is VoidType
        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(isProc)

        # 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))

        var_List = SubBody(frame, glenv)
        for x in consdecl.param:
            var_List = self.visit(x, (var_List, "Parameter"))

        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))
        # list(map(lambda x: self.visit(x, SubBody(frame, glenv)), body.member))

        for x in consdecl.body.member:
            if type(x) is not VarDecl:
                self.visit(x, var_List)
            else:
                var_List = self.visit(x, (var_List, "Local"))

        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        if isProc:
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    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 visitVarDecl(self, ast, o):
        ctxt, location = o
        frame = ctxt.frame
        varName = ast.variable
        varType = ast.varType
        if location == "Global":
            self.emit.printout(
                self.emit.emitATTRIBUTE(varName, varType, False, ""))
            return Symbol(ast.variable, ast.varType)
        elif location == "Local":
            idx = frame.getNewIndex()
            labelStart = frame.getNewLabel()
            self.emit.printout(
                self.emit.emitVAR(idx, varName, varType, labelStart,
                                  frame.getEndLabel(), frame))
            self.emit.printout(self.emit.emitLABEL(labelStart, frame))
            return SubBody(frame,
                           [Symbol(varName, varType, Index(idx))] + ctxt.sym)
        else:
            idx = frame.getNewIndex()
            self.emit.printout(
                self.emit.emitVAR(idx, varName, varType, frame.getStartLabel(),
                                  frame.getEndLabel(), frame))
            return SubBody(frame,
                           [Symbol(varName, varType, Index(idx))] + ctxt.sym)

    # Visit statements:
    def visitBlock(self, ast, o):
        ctxt = o
        frame = o.frame
        nenv = o.sym
        var_List = SubBody(frame, nenv)
        frame.enterScope(False)
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for x in ast.member:
            if type(x) is not VarDecl:
                self.visit(x, var_List)
            else:
                var_List = self.visit(x, (var_List, False))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()

    def visitIf(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        expCode, expType = self.visit(ast.expr, Access(frame, nenv, False,
                                                       True))
        self.emit.printout(expCode)
        labelThen = frame.getNewLabel()  # eval is true
        labelExit = frame.getNewLabel()  # label end
        if ast.elseStmt is None:
            self.emit.printout(self.emit.emitIFTRUE(labelThen, frame))
            self.emit.printout(self.emit.emitGOTO(labelExit, frame))
            self.emit.printout(self.emit.emitLABEL(labelThen, frame))
            self.visit(ast.thenStmt, o)
        else:  # has else stmt
            self.emit.printout(self.emit.emitIFTRUE(labelThen, frame))
            if type(ast.thenStmt) is Block:
                [self.visit(x, o) for x in ast.elseStmt.member]
            else:
                self.visit(ast.elseStmt, o)
            self.emit.printout(self.emit.emitGOTO(labelExit, frame))
            self.emit.printout(self.emit.emitLABEL(labelThen, frame))
            # if type(ast.thenStmt) is Block:
            #     [self.visit(x, o) for x in ast.thenStmt.member]
            # else:
            self.visit(ast.thenStmt, o)
        self.emit.printout(self.emit.emitLABEL(labelExit, frame))

    def visitDowhile(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        labelLoop = frame.getNewLabel()
        labelExit = frame.getNewLabel()
        frame.enterLoop()
        self.emit.printout(self.emit.emitLABEL(labelLoop, frame))
        list(
            map(
                lambda x: self.visit(x, o)
                if type(x) is not VarDecl else self.visit(x, (o, "Local")),
                ast.sl))

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        expCode, expType = self.visit(ast.exp, Access(frame, nenv, False,
                                                      True))
        self.emit.printout(expCode)
        self.emit.printout(self.emit.emitIFTRUE(labelLoop, frame))
        self.emit.printout(self.emit.emitGOTO(labelExit, frame))
        self.emit.printout(self.emit.emitLABEL(labelExit, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitFor(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        labelLoop = frame.getNewLabel()
        labelExit = frame.getNewLabel()
        # exp1Code, exp1Type = self.visit(ast.expr1,  o)
        exp2Code, _ = self.visit(ast.expr2, Access(frame, nenv, False, True))
        # exp3Code, _ = self.visit(ast.expr3, o)
        frame.enterLoop()
        # self.emit.printout(exp1Code)
        self.visit(ast.expr1, o)
        self.emit.printout(self.emit.emitLABEL(labelLoop, frame))
        self.emit.printout(exp2Code)
        self.emit.printout(self.emit.emitIFFALSE(labelExit, frame))
        self.visit(ast.loop, o)
        # self.emit.printout(exp3Code)
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        self.visit(ast.expr3, o)
        self.emit.printout(self.emit.emitGOTO(labelLoop, frame))
        self.emit.printout(self.emit.emitLABEL(labelExit, frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))
        frame.exitLoop()

    def visitBreak(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame))

    def visitContinue(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame))

    def visitReturn(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        retType = frame.returnType
        if not type(retType) is VoidType:
            expCode, expType = self.visit(ast.expr,
                                          Access(frame, nenv, False, True))
            if type(retType) is FloatType and type(expType) is IntType:
                expCode = expCode + self.emit.emitI2F(frame)
            self.emit.printout(expCode)
        self.emit.printout(self.emit.emitRETURN(retType, frame))

    # Visit expression
    def visitBinaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        op = ast.op
        nenv = ctxt.sym
        if op == "=":
            expCode, expType = self.visit(ast.right,
                                          Access(frame, nenv, False, True))
            lhsCode, lhsType = self.visit(ast.left,
                                          Access(frame, nenv, True, True))
            if type(lhsType) is FloatType and type(expType) is IntType:
                expCode = expCode + self.emit.emitI2F(frame)
            # self.emit.printout(expCode + lhsCode)
            returnCode = expCode + lhsCode
            frame.push()
            if type(o) is SubBody:
                # return "", lhsType
                self.emit.printout(returnCode)
            else:
                returnCode = expCode + self.emit.emitDUP(frame) + lhsCode
                return returnCode, lhsType
        else:
            is_statement = type(o) is SubBody
            leftCode, leftType = self.visit(ast.left,
                                            Access(frame, nenv, False, True))
            rightCode, rightType = self.visit(ast.right,
                                              Access(frame, nenv, False, True))
            expr_type = FloatType() if type(leftType) is not type(
                rightType) else leftType
            if type(expr_type) is FloatType:
                if type(leftType) is IntType:
                    leftCode = leftCode + self.emit.emitI2F(frame)
                if type(rightType) is IntType:
                    rightCode = rightCode + self.emit.emitI2F(frame)
            if op in ["+", "-"]:
                code = leftCode + rightCode + self.emit.emitADDOP(
                    op, expr_type, frame)
            elif op in ["*", "/"]:
                code = leftCode + rightCode + self.emit.emitMULOP(
                    op, expr_type, frame)
            elif op == "%":
                code = leftCode + rightCode + self.emit.emitMOD(frame)
            elif op == "||":
                labelTrue = frame.getNewLabel()
                labelEnd = frame.getNewLabel()
                code = leftCode + self.emit.emitIFTRUE(labelTrue, frame)
                code += rightCode + self.emit.emitIFTRUE(labelTrue, frame)
                code += self.emit.emitPUSHICONST(0, frame)
                code += self.emit.emitGOTO(labelEnd, frame)
                code += self.emit.emitLABEL(labelTrue, frame)
                code += self.emit.emitPUSHICONST(1, frame)
                code += self.emit.emitLABEL(labelEnd, frame)
                # code = leftCode + rightCode + self.emit.emitOROP(frame)
            elif op == "&&":
                labelEnd = frame.getNewLabel()
                labelFalse = frame.getNewLabel()
                code = leftCode + self.emit.emitIFFALSE(labelFalse, frame)
                code += rightCode + self.emit.emitIFFALSE(labelFalse, frame)
                code += self.emit.emitPUSHICONST(1, frame)
                code += self.emit.emitGOTO(labelEnd, frame)
                code += self.emit.emitLABEL(labelFalse, frame)
                code += self.emit.emitPUSHICONST(0, frame)
                code += self.emit.emitLABEL(labelEnd, frame)
                # code = leftCode + rightCode + self.emit.emitANDOP(frame)
            else:
                code = leftCode + rightCode + self.emit.emitREOP(
                    op, expr_type, frame)
                expr_type = BoolType()

            if is_statement:
                self.emit.printout(code)
                self.emit.printout(self.emit.emitPOP(frame))
            else:
                return code, expr_type

    def visitUnaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        op = ast.op
        nenv = ctxt.sym
        expCode, expType = self.visit(ast.body, Access(frame, nenv, False,
                                                       True))
        if op == "!":
            expCode = expCode + self.emit.emitNOT(BoolType(), frame)
        else:
            expCode = expCode + self.emit.emitNEGOP(expType, frame)
        if type(o) is SubBody:
            self.emit.printout(expCode)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            return expCode, expType

    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
        paramTypes = ctype.partype

        code = ""
        idx = 0
        for x in ast.param:
            paraCode, paraType = self.visit(x, Access(frame, nenv, False,
                                                      True))
            if type(paramTypes[idx]) is FloatType and type(
                    paraType) is IntType:
                paraCode = paraCode + self.emit.emitI2F(frame)
            code = code + paraCode
            idx += 1

        code = code + self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name,
                                                 ctype, frame)
        # self.emit.printout(self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame))
        if type(o) is SubBody:
            self.emit.printout(code)
        else:
            return code, ctype.rettype

    def visitId(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        symbols = ctxt.sym
        if type(o) is SubBody:
            sym = self.lookup(ast.name, symbols, lambda x: x.name)
            emitType = sym.mtype
            if sym.value is None:  # not index -> global var - static field
                retCode = self.emit.emitGETSTATIC(
                    self.className + "/" + sym.name, emitType, frame)
            else:
                retCode = self.emit.emitREADVAR(sym.name, emitType,
                                                sym.value.value, frame)
            self.emit.printout(retCode)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            isLeft = ctxt.isLeft
            isFirst = ctxt.isFirst
            sym = self.lookup(ast.name, symbols, lambda x: x.name)
            # recover status of stack in frame
            if not isFirst and isLeft:
                frame.push()
            elif not isFirst and not isLeft:
                frame.pop()
            emitType = sym.mtype
            if sym.value is None:  # not index -> global var - static field
                if isLeft:
                    retCode = self.emit.emitPUTSTATIC(
                        self.className + "/" + sym.name, emitType, frame)
                else:
                    retCode = self.emit.emitGETSTATIC(
                        self.className + "/" + sym.name, emitType, frame)
            else:
                if isLeft:
                    retCode = self.emit.emitWRITEVAR(sym.name, emitType,
                                                     sym.value.value, frame)
                else:
                    retCode = self.emit.emitREADVAR(sym.name, emitType,
                                                    sym.value.value, frame)
            return retCode, sym.mtype

    def visitIntLiteral(self, ast, o):
        #ast: IntLiteral
        #o: Any
        ctxt = o
        frame = ctxt.frame
        code = self.emit.emitPUSHICONST(ast.value, frame)
        if type(o) is SubBody:
            self.emit.printout(code)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            return code, IntType()

    def visitFloatLiteral(self, ast, o):
        #ast: FloatLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        code = self.emit.emitPUSHFCONST(str(ast.value), frame)
        if type(o) is SubBody:
            self.emit.printout(code)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            return code, FloatType()

    def visitStringLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        code = self.emit.emitPUSHCONST('''"''' + str(ast.value) + '''"''',
                                       StringType(), frame)
        if type(o) is SubBody:
            self.emit.printout(code)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            return code, StringType()

    def visitBooleanLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        code = self.emit.emitPUSHICONST(str(ast.value).lower(), frame)
        if type(o) is SubBody:
            self.emit.printout(code)
            self.emit.printout(self.emit.emitPOP(frame))
        else:
            return code, BoolType()
Example #25
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 = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")

    def visitProgram(self, ast, ctxt):
        self.emit.printout(
            self.emit.emitPROLOG(self.className, "java.lang.Object"))
        global_env = SubBody(None, self.env)
        functions = list(filter(lambda y: not type(y) is VarDecl, ast.decl))
        if len(functions) < len(ast.decl): self.emit.printout("\n")
        # static fields
        for x in ast.decl:
            global_env = self.visit(x, global_env)
        # default constructor
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None),
                       ctxt, Frame("<init>", VoidType))
        # generate code for functions
        for x in functions:
            self.visit(x, SubBody("", global_env.sym))
        self.emit.emitEPILOG()
        return ctxt

    def visitVarDecl(self, ast, ctxt):
        frame = ctxt.frame
        if frame is None:
            self.emit.printout(
                self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False,
                                        ""))
            return SubBody(frame, [
                Symbol(ast.variable.name, ast.varType, CName(self.className))
            ] + ctxt.sym)
        else:
            value = frame.getNewIndex()
            self.emit.printout(
                self.emit.emitVAR(value, ast.variable.name, ast.varType,
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
            return SubBody(frame,
                           [Symbol(ast.variable.name, ast.varType, value)] +
                           ctxt.sym)

    def visitFuncDecl(self, ast, ctxt):
        if ctxt.frame is None:
            return SubBody(None, [
                Symbol(ast.name.name,
                       MType([x.varType for x in ast.param], ast.returnType),
                       CName(self.className))
            ] + ctxt.sym)
        else:
            self.genMETHOD(ast, ctxt.sym, Frame(ast.name, ast.returnType))

    def genMETHOD(self, ast, global_env, frame):
        #ast: FuncDecl
        isInit = ast.returnType is None
        isMain = ast.name.name.lower() == "main" and len(
            ast.param) == 0 and type(ast.returnType) is VoidType
        returnType = VoidType() if isInit else ast.returnType
        methodName = "<init>" if isInit else ast.name.name
        # main function uses java syntax
        intype = [ArrayPointerType(StringType())
                  ] if isMain else [x.varType for x in ast.param]
        mtype = MType(intype, returnType)
        self.emit.printout(
            self.emit.emitMETHOD("main" if isMain else methodName, mtype,
                                 not isInit, frame))
        frame.enterScope(True)

        # special methods
        if isInit:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "this",
                                  ClassType(self.className),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))
            self.emit.printout(
                self.emit.emitREADVAR("this", ClassType(self.className), 0,
                                      frame))
            self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        if isMain:
            self.emit.printout(
                self.emit.emitVAR(frame.getNewIndex(), "args",
                                  ArrayPointerType(StringType()),
                                  frame.getStartLabel(), frame.getEndLabel(),
                                  frame))

        # Generate code for parameter declarations
        curr_env = SubBody(frame, global_env)
        for x in ast.param + ast.local:
            curr_env = self.visit(x, curr_env)
        # Visit body and generate code for statements
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for x in ast.body:
            self.visit(x, SubBody(frame, curr_env.sym))
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        # handle the last areturn/ireturn/freturn
        if not type(returnType) is VoidType:
            frame.push()
            retcode = self.emit.emitRETURN(returnType, frame)
            self.emit.reversedremove(retcode)
        else:
            retcode = self.emit.emitRETURN(returnType, frame)
        self.emit.printout(retcode)
        # .end method
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope()

    def visitId(self, ast, ctxt):
        r = self.getSymbol(ast.name, ctxt.sym)
        frame = ctxt.frame
        if type(r.value) is CName:  # static (global)
            if ctxt.isLeft:
                return self.emit.emitPUTSTATIC(r.value.value + '/' + r.name,
                                               r.mtype, frame), r.mtype
            else:
                return self.emit.emitGETSTATIC(r.value.value + '/' + r.name,
                                               r.mtype, frame), r.mtype
        else:  # local
            if ctxt.isLeft:
                return self.emit.emitWRITEVAR(r.name, r.mtype, r.value,
                                              frame), r.mtype
            else:
                return self.emit.emitREADVAR(r.name, r.mtype, r.value,
                                             frame), r.mtype

    ################################################################
    ## Statements
    ################################################################

    def visitAssign(self, ast, ctxt):
        exp_code, exp_type = self.visit(
            ast.exp, Access(ctxt.frame, ctxt.sym, False, True))
        lhs_code, lhs_type = self.visit(
            ast.lhs, Access(ctxt.frame, ctxt.sym, True, True))
        if type(exp_type) is IntType and type(lhs_type) is FloatType:
            exp_code += self.emit.emitI2F(ctxt.frame)
            exp_type = FloatType()
        self.emit.printout(exp_code + lhs_code)

    def visitCall(self, ast, ctxt):
        frame = ctxt.frame
        r = self.getSymbol(ast.method.name, ctxt.sym)
        out_ = ""
        for x in zip(ast.param, r.mtype.partype):
            xstr, xtype = self.visit(x[0], Access(frame, ctxt.sym, False,
                                                  True))
            if type(xtype) is IntType and type(x[1]) is FloatType:
                xstr += self.emit.emitI2F(frame)
                xtype = FloatType()
            out_ += xstr
        out_ += self.emit.emitINVOKESTATIC(r.value.value + "/" + r.name,
                                           r.mtype, frame)
        return out_, r.mtype.rettype

    def visitCallStmt(self, ast, ctxt):
        self.emit.printout(self.visitCall(ast, ctxt)[0])

    def visitReturn(self, ast, ctxt):
        frame = ctxt.frame
        if not ast.expr is None:
            code, typ = self.visit(ast.expr,
                                   Access(frame, ctxt.sym, False, True))
            if type(typ) is IntType and type(frame.returnType) is FloatType:
                code += self.emit.emitI2F(frame)
                typ = FloatType()
            self.emit.printout(code)
        else:
            typ = VoidType()
        self.emit.printout(self.emit.emitRETURN(typ, frame))

    def visitWith(self, ast, ctxt):
        frame = ctxt.frame
        frame.enterScope(False)
        # with scope declarations
        curr_env = SubBody(ctxt.frame, ctxt.sym)
        for x in ast.decl:
            curr_env = self.visit(x, curr_env)
        # statements
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame))
        for x in ast.stmt:
            self.visit(x, curr_env)
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        frame.exitScope()

    def visitIf(self, ast, ctxt):
        frame = ctxt.frame
        if len(ast.elseStmt) > 0:
            labelFalse = frame.getNewLabel()
            labelOut = frame.getNewLabel()
            # visit if expression
            exp_code = self.visit(ast.expr, Access(frame, ctxt.sym, False,
                                                   True))[0]
            self.emit.printout(exp_code +
                               self.emit.emitIFFALSE(labelFalse, frame))
            # visit true statements
            for x in ast.thenStmt:
                self.visit(x, ctxt)
            self.emit.printout(self.emit.emitGOTO(labelOut, frame))
            # visit false statements
            self.emit.printout(self.emit.emitLABEL(labelFalse, frame))
            for x in ast.elseStmt:
                self.visit(x, ctxt)
        else:
            labelOut = frame.getNewLabel()
            # visit if expression
            exp_code = self.visit(ast.expr, Access(frame, ctxt.sym, False,
                                                   True))[0]
            self.emit.printout(exp_code +
                               self.emit.emitIFFALSE(labelOut, frame))
            # visit true statements
            for x in ast.thenStmt:
                self.visit(x, ctxt)
        # labelOut
        self.emit.printout(self.emit.emitLABEL(labelOut, frame))

    def visitFor(self, ast, ctxt):
        frame = ctxt.frame
        frame.enterLoop()
        labelIn = frame.getNewLabel()
        labelContinue = frame.getContinueLabel()
        labelBreak = frame.getBreakLabel()
        # store first to i
        self.visit(Assign(ast.id, ast.expr1), ctxt)
        self.emit.printout(self.emit.emitLABEL(labelIn, frame))
        # compare i with expr2 to gen jump code
        rcode = self.visit(ast.id, Access(ctxt.frame, ctxt.sym, False,
                                          True))[0]
        expr2 = self.visit(ast.expr2, Access(ctxt.frame, ctxt.sym, False,
                                             True))[0]
        jumpcode = self.emit.emitIFICMPGT(
            labelBreak, frame) if ast.up else self.emit.emitIFICMPLT(
                labelBreak, frame)
        self.emit.printout(rcode + expr2 + jumpcode)
        # loop body
        for x in ast.loop:
            self.visit(x, ctxt)
        # continue label (i:=i+1)
        self.emit.printout(self.emit.emitLABEL(labelContinue, frame))
        self.visit(
            Assign(ast.id,
                   BinaryOp('+' if ast.up else '-', ast.id, IntLiteral(1))),
            ctxt)
        # goto loop and break label
        self.emit.printout(
            self.emit.emitGOTO(labelIn, frame) +
            self.emit.emitLABEL(labelBreak, frame))
        frame.exitLoop()

    def visitWhile(self, ast, ctxt):
        frame = ctxt.frame
        frame.enterLoop()
        labelContinue = frame.getContinueLabel()
        labelBreak = frame.getBreakLabel()
        # labelContinue and expression
        self.emit.printout(self.emit.emitLABEL(labelContinue, frame))
        exp_code = self.visit(ast.exp, Access(frame, ctxt.sym, False, True))[0]
        self.emit.printout(exp_code + self.emit.emitIFFALSE(labelBreak, frame))
        # statements
        for x in ast.sl:
            self.visit(x, ctxt)
        self.emit.printout(self.emit.emitGOTO(labelContinue, frame))
        # labelBreak
        self.emit.printout(self.emit.emitLABEL(labelBreak, frame))
        frame.exitLoop()

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

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

    ################################################################
    ## Expressions
    ################################################################

    def visitCallExpr(self, ast, ctxt):
        return self.visitCall(ast, ctxt)

    def visitIntLiteral(self, ast, ctxt):
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(ast.value, frame), IntType()

    def visitFloatLiteral(self, ast, ctxt):
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(float(ast.value)),
                                        frame), FloatType()

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

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

    def visitBinaryOp(self, ast, ctxt):
        frame = ctxt.frame
        lcode, ltype = self.visit(ast.left, ctxt)
        rcode, rtype = self.visit(ast.right, ctxt)
        if FloatType in (type(ltype), type(rtype)) or ast.op == '/':
            if type(ltype) is IntType:
                lcode += self.emit.emitI2F(frame)
                ltype = FloatType()
            if type(rtype) is IntType:
                rcode += self.emit.emitI2F(frame)
                rtype = FloatType()

        if ast.op in ('+', '-'):
            return lcode + rcode + self.emit.emitADDOP(ast.op, ltype,
                                                       frame), ltype
        elif ast.op in ('*', '/'):
            return lcode + rcode + self.emit.emitMULOP(ast.op, ltype,
                                                       frame), ltype
        elif ast.op.lower() == 'div':
            return lcode + rcode + self.emit.emitDIV(frame), IntType()
        elif ast.op.lower() == 'mod':
            return lcode + rcode + self.emit.emitMOD(frame), IntType()
        elif ast.op.lower() == 'and':
            return lcode + rcode + self.emit.emitANDOP(frame), BoolType()
        elif ast.op.lower() == 'or':
            return lcode + rcode + self.emit.emitOROP(frame), BoolType()
        elif ast.op.lower() in ('>', '>=', '<', '<=', '<>', '='):
            return lcode + rcode + self.emit.emitREOP(ast.op, ltype,
                                                      frame), BoolType()
        elif ast.op in ('andthen', 'orelse'):
            return self.genShortCircuit(ast.op, lcode, rcode, frame)
        else:
            return

    def genShortCircuit(self, op, left, right, frame):
        res = ""
        labelBrk = frame.getNewLabel()
        labelOut = frame.getNewLabel()
        if op == 'andthen':
            res += left + self.emit.emitIFFALSE(labelBrk, frame)\
             + right + self.emit.emitIFFALSE(labelBrk, frame)\
             + self.emit.emitPUSHCONST("1", IntType(), frame)\
             + self.emit.emitGOTO(labelOut, frame)\
             + self.emit.emitLABEL(labelBrk, frame)\
             + self.emit.emitPUSHCONST("0", IntType(), frame)\
             + self.emit.emitLABEL(labelOut, frame)
        else:
            res += left + self.emit.emitIFTRUE(labelBrk, frame)\
             + right + self.emit.emitIFTRUE(labelBrk, frame)\
             + self.emit.emitPUSHCONST("0", IntType(), frame)\
             + self.emit.emitGOTO(labelOut, frame)\
             + self.emit.emitLABEL(labelBrk, frame)\
             + self.emit.emitPUSHCONST("1", IntType(), frame)\
             + self.emit.emitLABEL(labelOut, frame)
        return res, BoolType()

    def visitUnaryOp(self, ast, ctxt):
        code, typ = self.visit(ast.body, ctxt)
        if ast.op.lower() == 'not':
            return code + self.emit.emitNOT(ctxt.frame), BoolType()
        else:
            return code + self.emit.emitNEGOP(typ, ctxt.frame), typ

    def getSymbol(self, name, env):
        return self.lookup(name.lower(), env, lambda x: x.name.lower())
Example #26
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 = "MPClass"
        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"))
        for x in ast.decl:
            if type(x) is VarDecl:
                self.env += [Symbol(x.variable.name,x.varType, CName(self.className))]
                self.emit.printout(self.emit.emitATTRIBUTE(x.variable.name, x.varType,False,""))
            else:
                self.env += [Symbol(x.name.name,MType([i.varType for i in x.param ] if len(x.param)>0 else [],x.returnType), CName(self.className))]
        #e = SubBody(None, self.env)
        for x in ast.decl:
            self.visit(x, SubBody(None,self.env[:]))
        # generate default constructor
        a = self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(),None), c, Frame("<init>", VoidType))
        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)

        a =  self.emit.emitMETHOD(methodName, mtype, not isInit, frame)
        self.emit.printout(a)
        frame.enterScope(True)

        # Generate code for parameter declarations
        if isInit:
            self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "this", ClassType(self.className), frame.getStartLabel(), frame.getEndLabel(), frame))
        else:
            glenv = o.sym
            if isMain: self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "args", ArrayPointerType(StringType()), frame.getStartLabel(), frame.getEndLabel(), frame))
            else:
                for x in consdecl.param:
                    idx = frame.getNewIndex()
                    glenv += [Symbol(x.variable.name, x.varType, Index(idx))]
                    c = self.emit.emitVAR(idx,x.variable.name,x.varType,frame.getStartLabel(), frame.getEndLabel(),frame)
                    self.emit.printout(c)
                    #idx += 1
            for x in consdecl.local:
                idx = frame.getNewIndex()
                glenv += [Symbol(x.variable.name, x.varType, Index(idx))]
                d = self.emit.emitVAR(idx,x.variable.name,x.varType,frame.getStartLabel(), frame.getEndLabel(),frame)
                self.emit.printout(d)
                #idx += 1

        body = consdecl.body
        b = self.emit.emitLABEL(frame.getStartLabel(), frame)
        self.emit.printout(b)

        # 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))
        for x in body:
            self.visit(x, SubBody(frame, glenv))

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

    def visitFuncDecl(self, ast, o):
        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.genMETHOD(ast, subctxt, frame)
        return o
        #return SubBody(None, [Symbol(ast.name.name, MType([i for i in ast.param], ast.returnType), CName(self.className))]+ o.sym[1])

    def visitVarDecl(self,ast,o):
        vtype = ast.varType
        if type(vtype) is ArrayType: raise Exception("No Array Pls")
        #self.emit.printout(self.emit.emitATTRIBUTE(ast.variable.name,vtype,False,""))
        #return None 
        return SubBody(None,[Symbol(ast.variable.name,vtype,CName(self.className))]+o.sym)

    def visitAssign(self,ast,o):
        rc, rt = self.visit(ast.exp,Access(o.frame,o.sym,False,True))
        lc,lt = self.visit(ast.lhs,Access(o.frame,o.sym,True,False))
        if type(lt) is FloatType and type(rt) is IntType:
            self.emit.printout(rc + self.emit.emitI2F(None) +lc)
            #self.emit.emitI2F(None)
        else:
            self.emit.printout(rc+lc)
        pass

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

        in_ = ("", list())
        for idx, val in enumerate(ast.param):
            str1, typ1 = self.visit(val, Access(frame, nenv, False, True))
            in_ = (in_[0] + str1, in_[1] + [typ1])
            if type(sym.mtype.partype[idx]) is FloatType and type(in_[1][idx]) is IntType:
                in_ = (in_[0] + self.emit.emitI2F(frame), in_[1])
            
        #self.emit.printout(in_[0])
        #checkPrintIntWithPutFloat = (cname + "/" + sym.name)
        #if checkPrintIntWithPutFloat in ['io/putFloat','io/putFloatLn'] and type(in_[1][0]) is IntType:
        #    buonNgu = self.emit.emitI2F(frame)
        #else:
        #    buonNgu = ""
        self.emit.printout(in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame))
        
    def visitIf(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym

        checkReturnAtTheEndThen = False
        
        expc, expt = self.visit(ast.expr,Access(frame,nenv,False,True))
        self.emit.printout(expc)
        falseLabel = frame.getNewLabel()
        endLabel = frame.getNewLabel()
        self.emit.printout(self.emit.emitIFFALSE(falseLabel,frame))
        if ast.thenStmt == []: 
            self.emit.printout(self.emit.emitGOTO(endLabel,frame))
        for x in ast.thenStmt: self.visit(x,SubBody(frame,nenv))
        if len(ast.thenStmt) > 0 and not type(ast.thenStmt[-1]) is Return:
            self.emit.printout(self.emit.emitGOTO(endLabel,frame))
        self.emit.printout(self.emit.emitLABEL(falseLabel,frame))
        for x in ast.elseStmt:
            self.visit(x,SubBody(frame,nenv))
        self.emit.printout(self.emit.emitLABEL(endLabel,frame))
        pass

    def visitWhile(self,ast,o):
        ctxt =o
        frame = ctxt.frame
        nenv = o.sym

        startLabel = frame.getNewLabel()
        endLabel = frame.getNewLabel()
        frame.brkLabel.append(endLabel)
        frame.conLabel.append(startLabel)

        self.emit.printout(self.emit.emitLABEL(startLabel,frame))
        expc, expt = self.visit(ast.exp,Access(frame,nenv,False,True))
        self.emit.printout(expc)
        self.emit.printout(self.emit.emitIFFALSE(endLabel,frame))
        for x in ast.sl:
            self.visit(x,SubBody(frame,nenv))
        self.emit.printout(self.emit.emitGOTO(startLabel,frame))
        self.emit.printout(self.emit.emitLABEL(endLabel,frame))
        
        frame.brkLabel = frame.brkLabel[:-1]
        frame.conLabel = frame.conLabel[:-1]
        pass

    def visitFor(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        nenv = o.sym

        loopLable = frame.getNewLabel()
        endLabel = frame.getNewLabel()
        increaseLabel = frame.getNewLabel()
        frame.brkLabel.append(endLabel)
        frame.conLabel.append(increaseLabel)

        exp1c, exp1t = self.visit(ast.expr1,Access(frame,nenv,False,True))
        self.emit.printout(exp1c)
        idc, idt = self.visit(ast.id,Access(frame,nenv,True,False))
        self.emit.printout(idc)
        self.emit.printout(self.emit.emitLABEL(loopLable,frame))
        idc1, idt1 = self.visit(ast.id,Access(frame,nenv,False,True))
        self.emit.printout(idc1)
        exp2c, exp2t = self.visit(ast.expr2,Access(frame,nenv,False,True))
        self.emit.printout(exp2c)
        if ast.up: 
            incrcode = "\tiadd\n"
            self.emit.printout(self.emit.emitIFICMPGT(endLabel,frame))
        else:
            incrcode = "\tisub\n"
            self.emit.printout(self.emit.emitIFICMPLT(endLabel,frame))
        for x in ast.loop:
            self.visit(x,SubBody(frame,nenv))
        #self.emit.printout(self.emit.emitLABEL(loopLable,frame))
        idc2, idt2 = self.visit(ast.id,Access(frame,nenv,False,True))
        self.emit.printout(self.emit.emitLABEL(increaseLabel,frame))
        self.emit.printout(idc2 + "\ticonst_1\n" + incrcode)
        idc3, idt3 = self.visit(ast.id,Access(frame,nenv,True,False))
        self.emit.printout(idc3)
        self.emit.printout(self.emit.emitGOTO(loopLable,frame))
        self.emit.printout(self.emit.emitLABEL(endLabel,frame))

        frame.brkLabel = frame.brkLabel[:-1]
        frame.conLabel = frame.conLabel[:-1]
        pass

    def visitWith(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        nenv = o.sym[:]

        frame.enterScope(False)
        startLabel = frame.getNewLabel()
        endLabel = frame.getNewLabel()
        for x in ast.decl:
            idx = frame.getNewIndex()
            self.emit.printout(self.emit.emitVAR(idx,x.variable.name,x.varType,startLabel,endLabel,frame))
            nenv += [Symbol(x.variable.name, x.varType, Index(idx))]
        self.emit.printout(self.emit.emitLABEL(startLabel,frame))
        for x in ast.stmt:
            self.visit(x,SubBody(frame,nenv))
        self.emit.printout(self.emit.emitLABEL(endLabel,frame))
        frame.exitScope()
        pass    

    def visitReturn(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        if ast.expr:
            exp_c, exp_t = self.visit(ast.expr,Access(frame,nenv,False,True))
            self.emit.printout(exp_c)
            if type(frame.returnType) is FloatType and type(exp_t) is IntType:
                self.emit.printout(self.emit.emitI2F(frame))
                exp_t = frame.returnType
            self.emit.printout(self.emit.emitRETURN(exp_t,frame))
        else:
            self.emit.printout(self.emit.emitRETURN(VoidType(),frame))
        pass

    def visitBreak(self,ast,o):
        frame = o.frame
        #self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(),frame))
        self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(),frame))
        pass

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

    def visitBinaryOp(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        op = ast.op

        if op in ['andthen','orelse']:
            outLabel = frame.getNewLabel()
            falseLabel = frame.getNewLabel()
            trueLabel = frame.getNewLabel()

            lcode, ltype = self.visit(ast.left,Access(frame,o.sym,False,True))
            self.emit.printout(lcode)
            if op == 'andthen':
                self.emit.printout(self.emit.emitIFFALSE(falseLabel,frame))
                rcode, rtype = self.visit(ast.right,Access(frame,o.sym,False,True))
                self.emit.printout(rcode)
                self.emit.printout(self.emit.emitGOTO(outLabel,frame))
                self.emit.printout(self.emit.emitLABEL(falseLabel,frame))
                self.emit.printout("\ticonst_0\n")
                self.emit.printout(self.emit.emitLABEL(outLabel,frame))
            else:
                self.emit.printout(self.emit.emitIFTRUE(trueLabel,frame))
                rcode, rtype = self.visit(ast.right,Access(frame,o.sym,False,True))
                self.emit.printout(rcode)
                self.emit.printout(self.emit.emitGOTO(outLabel,frame))
                self.emit.printout(self.emit.emitLABEL(trueLabel,frame))
                self.emit.printout("\ticonst_1\n")
                self.emit.printout(self.emit.emitLABEL(outLabel,frame))
            return "",BoolType()
        else:
            lcode, ltype = self.visit(ast.left,Access(frame,o.sym,False,True))
            rcode, rtype = self.visit(ast.right,Access(frame,o.sym,False,True))
            if type(ltype) != type(rtype):
                if type(ltype) is IntType:
                    lcode += self.emit.emitI2F(frame)
                    ltype = FloatType()
                else:
                    rcode += self.emit.emitI2F(frame)
                    rtype = FloatType()
            if op in ['+','-']:
                opcode = self.emit.emitADDOP(op,ltype,frame)
            elif op in ['*','/']:
                if op == '/' and type(ltype) is IntType and type(rtype) is IntType:
                    lcode += self.emit.emitI2F(frame)
                    rcode += self.emit.emitI2F(frame)
                    ltype = FloatType()
                    rtype = FloatType()
                opcode = self.emit.emitMULOP(op,ltype,frame)
            elif op.lower() == 'and':
                opcode = self.emit.emitANDOP(frame)
            elif op.lower() == 'or':
                opcode = self.emit.emitOROP(frame)
            elif op.lower() == 'div':
                opcode = self.emit.emitDIV(frame)
            elif op.lower() == 'mod':
                opcode = self.emit.emitMOD(frame)
            else:
                if type(ltype) is FloatType:
                    falseLabel = frame.getNewLabel()
                    outLabel = frame.getNewLabel()
                    if op == '=': code = "\tifne Label" 
                    elif op == '<>': code = "\tifeq Label" 
                    elif op == '>': code = "\tifle Label" 
                    elif op == '<': code = "\tifge Label" 
                    elif op == '>=': code = "\tiflt Label" 
                    elif op == '<=': code = "\tifgt Label" 
                    opcode = "\tfcmpl\n" + code + str(falseLabel) + "\n" + "\ticonst_1\n" + self.emit.emitGOTO(outLabel,frame) + self.emit.emitLABEL(falseLabel,frame) + "\ticonst_0\n" + self.emit.emitLABEL(outLabel,frame)
                    ltype = BoolType()
                else:
                    opcode = self.emit.emitREOP(op,ltype,frame)
                    ltype = BoolType()
            #sef.emit.printout(lcode + rcode + opcode)
            return lcode + rcode + opcode,ltype

    def visitUnaryOp(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        op = ast.op

        expc, expt = self.visit(ast.body,Access(frame,o.sym,False,True))
        if op == '-':
            opcode = self.emit.emitNEGOP(expt,frame)
        elif op == "not":
            opcode = self.emit.emitNOT(expt,frame)
        return expc + opcode, expt

    def visitId(self,ast,o):
        sym = self.lookup(ast.name.lower(),o.sym[::-1],lambda x:x.name.lower())
        if o.isLeft:
            if type(sym.value) is CName:
                res = self.emit.emitPUTSTATIC(sym.value.value + "/" + sym.name, sym.mtype, o.frame)
                #self.emit.printout(res)
                return res,sym.mtype
            elif type(sym.value) is Index:
                res = self.emit.emitWRITEVAR(sym.name,sym.mtype,sym.value.value,o.frame)
                #self.emit.printout(res)
                return res,sym.mtype
            else:
                return "",VoidType()
        else:
            if type(sym.value) is CName:
                res = self.emit.emitGETSTATIC(sym.value.value + "/" + sym.name, sym.mtype, o.frame)
                #self.emit.printout(res)
                return res,sym.mtype
            elif type(sym.value) is Index:
                res = self.emit.emitREADVAR(sym.name,sym.mtype,sym.value.value,o.frame)
                #self.emit.printout(res)
                return res,sym.mtype
            else:
                return "",VoidType()

    def visitCallExpr(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        sym = self.lookup(ast.method.name.lower(), nenv, lambda x: x.name.lower())
        cname = sym.value.value
        ctype = sym.mtype
        in_ = ("", [])
        for idx, val in enumerate(ast.param):
            str1, typ1 = self.visit(val, Access(frame, nenv, False, True))
            in_ = (in_[0] + str1, in_[1] + [typ1])
            if type(sym.mtype.partype[idx]) is FloatType and type(in_[1][idx]) is IntType:
                in_ = (in_[0] + self.emit.emitI2F(frame), in_[1])
        res = in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame)
        #self.emit.printout(res)
        return res,ctype.rettype 

    def visitArrayCell(self,ast,o):
        raise Exception("Array Cant visit that shit")

    def visitIntLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        res = self.emit.emitPUSHICONST(ast.value, frame)
        #self.emit.printout(res)
        return res,IntType()

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

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

    def visitStringLiteral(self,ast,o):
        ctxt = o
        frame = ctxt.frame
        res = self.emit.emitPUSHCONST(str(ast.value),StringType(),frame)
        #self.emit.printout(res)
        return res,StringType()
Example #27
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") #accept input that file MCClass.j

#==================================Declaration===================================
    '''
    this section is to visit Declaration for generating drectives:

        .source MCClass.java
        .class public MCClass
        .super java.lang.Object
        .method public static foo(I)I

    '''
    def visitProgram(self, ast, gloenvi):
        '''
        *print lines of directives 
        1. visit all vardecls in global and set static field
        2. visit funcdecls
        '''
        gloenvi=self.env
        
        self.emit.printout(self.emit.emitPROLOG(self.className, "java.lang.Object"))

        #in global: frame = None
        subBody = SubBody(None,gloenvi )

       
        #visit Declarations:
        '''
        1. visit all var declarations in global
        2. add func declarations in global to env (for calling inter functions)
        3. visit all all func declarations
        '''
        for x in filter(lambda x: isinstance(x,VarDecl), ast.decl):
            subBody = self.visit(x, subBody)
        for x in filter(lambda x: isinstance(x,FuncDecl), ast.decl):
            subBody.sym = [Symbol(x.name.name, MType([y.varType for y in x.param],x.returnType),CName(self.className))]+subBody.sym
        for x in filter(lambda x: isinstance(x,FuncDecl), ast.decl):
            subBody = self.visit(x, subBody)

        # generate default constructor
        initConstructor = FuncDecl(Id("<init>"), list(), None, Block(list()))
        initClass = FuncDecl(Id("<clinit>"), list(), None, Block(list()))
        self.genMETHOD(initConstructor, subBody.sym, Frame("<init>", VoidType))
        self.genMETHOD(initClass, subBody.sym, Frame("<clinit>", VoidType))

        self.emit.emitEPILOG()
        return gloenvi

    def visitFuncDecl(self, ast, subBody):
        
        frame = Frame(ast.name.name, ast.returnType) #Frame('main', void)
        subBody.sym=[Symbol(ast.name.name, MType([x.varType for x in ast.param] if ast.name.name not in ['main','<init>'] else list(), ast.returnType), CName(self.className))] + subBody.sym
        self.genMETHOD(ast, subBody.sym, frame)
        return subBody
    
    def genMETHOD(self, ast,envi, frame):
     
        #ast: FuncDecl
        #envi: list Symbols
        #frame: Frame

        isInit = ast.name.name == "<init>"
        isClinit = ast.name.name == "<clinit>"
        isMain = ast.name.name == "main" 
       
        returnType = VoidType() if isInit or isClinit else ast.returnType
        methodName = ast.name.name
        #main: String[] args
        intype = [ArrayPointerType(StringType())] if isMain else [x.varType for x in ast.param]
    
        mtype = MType(intype, VoidType()) if isMain else MType(intype,returnType) 

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

        frame.enterScope(True)

        localEnvi = envi
        # Generate code for parameter declarations
        if isInit:
            #.var 0 is this LMCClass; from Label0 to Label1
            self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "this", ClassType(self.className), frame.getStartLabel(), frame.getEndLabel(), frame))
        elif isClinit:
            #in isClinit, there is not declaration, just initialize
            pass
        if isMain:
            #.var 0 is args [Ljava/lang/String; from Label0 to Label1
            self.emit.printout(self.emit.emitVAR(frame.getNewIndex(), "args", ArrayPointerType(StringType()), frame.getStartLabel(), frame.getEndLabel(), frame))
        
        s= SubBody(frame,localEnvi)
        
        for x in ast.param:
            s= self.visit(x,s)
         
        body = ast.body

        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))
        
        if isClinit:
            '''
            bipush 10
            newarray int
            putstatic MCClass.a [I
	
            '''
            globalArrVar = filter(lambda x:(isinstance(x.value, CName) and isinstance(x.mtype, ArrayType)),envi )
            for ast_i in globalArrVar:
                self.emit.printout(self.emit.emitClinitForArrayGlobal(ast_i.value.value+"."+ ast_i.name, ast_i.mtype,frame ))
        for x in body.member:
            if isinstance(x,VarDecl):
                s= self.visit(x,s)
            else:
                self.visit(x,s)

          
        # [self.visit(x, s) for x in body.member]
        # [print(x.name) for x in s]
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))
        # Generate Return for only VoidType or Return in Main function must be convert into VoidType:
  
        if (type(returnType) is VoidType) or (frame.name == "main"):
            self.emit.printout(self.emit.emitRETURN(VoidType(), frame))

        self.emit.printout(self.emit.emitENDMETHOD(frame))
        frame.exitScope();

    def visitVarDecl(self, ast, sBody):
        #in global declaration
        if sBody.frame is None: 
            #============================drafts
            #neu la global thi dung clinit de new array
            tem=self.emit.emitATTRIBUTE(ast.variable, ast.varType, False, "")
            self.emit.printout(tem)
            return SubBody(None, [Symbol(ast.variable, ast.varType, CName(self.className))] + sBody.sym)
        else: #in local of function
            index = sBody.frame.getNewIndex()
            self.emit.printout(self.emit.emitVAR(index, ast.variable, ast.varType, sBody.frame.getStartLabel(), sBody.frame.getEndLabel(), sBody.frame))
            return SubBody(sBody.frame, [Symbol(ast.variable, ast.varType, Index(index))] + sBody.sym)

#==================================Statement=====================================
    '''
    this section is to visit Statement:
        - Return nothing
        - printout rigth when visit
    '''

    def visitReturn(self, ast: Return, o: SubBody):
        '''generate Return for methods different VoidType and not in main function'''

        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        retType = frame.returnType

        if (not isinstance(retType, VoidType)) and (frame.name != "main"):
            expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, False))
            if type(retType) is FloatType and type(expType) is IntType:
                expCode = expCode + self.emit.emitI2F(frame)
            self.emit.printout(expCode)
            self.emit.printout(self.emit.emitRETURN(retType, frame))
        return True #isReturn , for check isReturn later
    def visitIf(self, ast: If, o: SubBody):
        '''
            1. visit expr
            2. if true go to label 1
            3. do elseStmt
            4. go to label 2
            5.Label 1
            6. do thenStmt
            7.Label 2
            8.label end

        '''
        exprCode, exprType = self.visit(ast.expr, Access(o.frame, o.sym, False, False))
        self.emit.printout(exprCode)
        
        labelTrue = o.frame.getNewLabel()
        labelEnd = o.frame.getNewLabel()
        #labelFalse = o.frame.getNewLabel()
        self.emit.printout(self.emit.emitIFTRUE(labelTrue, o.frame))

        # self.emit.printout(self.emit.emitGOTO(labelFalse, o.frame))
        isReturnElse=False
        if ast.elseStmt is not None:
            if self.visit(ast.elseStmt,o) is True: isReturnElse = True

        if not isReturnElse:
            self.emit.printout(self.emit.emitGOTO(labelEnd, o.frame))

        self.emit.printout(self.emit.emitLABEL(labelTrue, o.frame))
        
        isReturnThen=False
        if self.visit(ast.thenStmt,o) is True:
            isReturnThen=True
        
        self.emit.printout(self.emit.emitLABEL(labelEnd, o.frame))
        return isReturnThen and isReturnElse
    def visitDowhile(self, ast:Dowhile, o: SubBody):
        '''
        1. Label Start
        2. visit list stmt
        3. Label Continue
        4. visit Expr
        5. if True go to Label Start
        6. Label Break
        
        '''
        labelStart = o.frame.getNewLabel()
        
        o.frame.enterLoop()

        self.emit.printout(self.emit.emitLABEL(labelStart, o.frame))

        [self.visit(x, o) for x in ast.sl]

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

        expCode, expType = self.visit(ast.exp, Access(o.frame, o.sym, False, False))

        self.emit.printout(expCode)
        
        self.emit.printout(self.emit.emitIFTRUE(labelStart, o.frame))
        
        self.emit.printout(self.emit.emitLABEL(o.frame.getBreakLabel(), o.frame))
        
        o.frame.exitLoop()
        
    def visitFor(self, ast: For, o: SubBody):
        '''
        1.visit expr 1 (like visit a stmt: visit(ast, SubBody) because this is assign op)
        2.Label condition
        3.visit expr 2 (like visit a expr: visit(ast, Access)) 
        4.if True goto Label True
        5.go to Label Break (the same purpose with Label End)
        6.Label True
        7.visit Stmt
        8.Label Continue
        9.visit expr3 (like visit a stmt: visit(ast, SubBody))
        10. go to Label condition
        11. Label Break

        '''
        labelTrue  = o.frame.getNewLabel()
        labelCondition = o.frame.getNewLabel()
        o.frame.enterLoop()
        labelBreak = o.frame.getBreakLabel()
        labelContinue = o.frame.getContinueLabel()
        isReturn=False
        self.visit(ast.expr1,o)
        self.emit.printout(self.emit.emitLABEL(labelCondition, o.frame))
        expr2Code, expr2Type = self.visit(ast.expr2, Access(o.frame, o.sym, False, False))
        self.emit.printout(expr2Code)
        self.emit.printout(self.emit.emitIFTRUE(labelTrue, o.frame))
        self.emit.printout(self.emit.emitGOTO(labelBreak, o.frame))
        self.emit.printout(self.emit.emitLABEL(labelTrue, o.frame))
        if self.visit(ast.loop, o) is True:
            isReturn = True
        self.emit.printout(self.emit.emitLABEL(labelContinue, o.frame))
        if not isReturn:
            self.visit(ast.expr3, o)
            self.emit.printout(self.emit.emitGOTO(labelCondition, o.frame))
        self.emit.printout(self.emit.emitLABEL(labelBreak, o.frame))

        o.frame.exitLoop()
        return isReturn

    def visitBreak(self, ast: Break, o: SubBody):
        '''
        when enter the loop, we call frame.enterLoop to create BreakLabel
        and then we placed it in some place
        '''
        self.emit.printout(self.emit.emitGOTO(o.frame.getBreakLabel(), o.frame))
    
    def visitContinue(self, ast: Continue, o:SubBody):
        '''
        when enter the loop, we call frame.enterLoop to create ContinueLabel
        and then we placed it in some place
        '''
        self.emit.printout(self.emit.emitGOTO(o.frame.getContinueLabel(),o.frame))

    def visitBlock(self, ast: Block, o: SubBody):
        '''
        remember to pop variable declared in scope
        '''
        frame=o.frame
        frame.enterScope(False)
        self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(),frame))
        #count the number of vardecl to pop it out of sym after exit scope
        count=0
        isReturn=False
        for x in ast.member:
            if isinstance(x,VarDecl):
                o= self.visit(x,o)
                count+=1
            else:
                if self.visit(x,o) is True:
                    isReturn=True
        o.sym = o.sym[count:]
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(),frame))
        frame.exitScope()
        return isReturn

#==================================Expression====================================
    '''
    *Param:     ast, Access(frame, sym, isLeft, isFirst)
    *Return:    code, type
    *Note:      the first command in each method  "isinstance(acc,SubBody): return" say that 
                if expr which called as a statement should do nothing (except assign expression, and call)
    '''

    def visitId(self, ast: Id, acc):
        '''
        *every varible is visited two times
        *array, field of class in left : first: load reference,  second: store value
        *simple variable  and array, field of class in right :  first: do nothing,     second: store value
        '''

        if isinstance(acc,SubBody): return
        resultCode=""
        sym = self.lookup(ast.name, acc.sym, lambda x: x.name)
        isGlobal =isinstance(sym.value,CName)
        if acc.isLeft: #left
            if acc.isFirst:#first
                if isinstance(sym.mtype,(ArrayPointerType,ArrayType)):
                    if isGlobal :
                        resultCode+= self.emit.emitGETSTATIC(sym.value.value+"." + ast.name, sym.mtype,acc.frame)
                    else:
                        resultCode+= self.emit.emitREADVAR(ast.name, sym.mtype, sym.value.value, acc.frame)
            
            else: #second
                if isGlobal:
                    #name = Class name + "." +field name 
                    resultCode+= self.emit.emitPUTSTATIC(sym.value.value+"." + ast.name, sym.mtype, acc.frame)
                else:
                    resultCode+= self.emit.emitWRITEVAR(ast.name, sym.mtype, sym.value.value, acc.frame)

        else: #right
            if acc.isFirst: #left
                pass
            else:#second
                if  isGlobal:
                    resultCode+= self.emit.emitGETSTATIC(sym.value.value+"." + ast.name, sym.mtype, acc.frame)
                else:
                    resultCode+= self.emit.emitREADVAR(ast.name, sym.mtype, sym.value.value, acc.frame)
        return resultCode, sym.mtype
    
    def visitArrayCell(self, ast: ArrayCell, acc):
        '''
        *in LSH and in second time access: store (aload)
        *in RHS: load value (<type>astore)
        '''
        if isinstance(acc,SubBody): return
        
        if acc.isLeft: #LHS
            '''
            *if a[10] is LHS example: a[10]=3000;
                1. aload , iconst (first time)
                2. iconst 3000 (don't care)
                3. iastore      (second time)
            '''
            
            if acc.isFirst:
                # aload , iconst
                arrcode1, arrtype1 = self.visit(ast.arr, acc)
                indexcode,indextype = self.visit(ast.idx, Access(acc.frame, acc.sym,False, False ))
                result = arrcode1+ indexcode 
            else:
                arrcode1, arrtype1 = self.visit(ast.arr, Access(acc.frame, acc.sym,True, True ))
                 # iastore
                result = self.emit.emitASTORE(arrtype1.eleType, acc.frame)


        else :#RHS
            '''
            *if a[10] is RHS example: i = a[10];
                1. aload <index of a> (second time)
                2. iconst 10            (second time)
                3. iaload               (second time)
                4. istore <dont care>
            '''
            
            if acc.isFirst:
                result=""
            else:
                arrcode1, arrtype1 = self.visit(ast.arr, acc)
                indexcode, indextype = self.visit(ast.idx, acc)
                result= arrcode1 + indexcode + self.emit.emitALOAD(arrtype1.eleType, acc.frame)

        #print(" left ",acc.isLeft , ";     first ", acc.isFirst," :\n ",result)
        return result, arrtype1.eleType

    def visitCallExpr(self, ast: CallExpr, o):
        '''
        *input o: subBody or Access
        *subBody when Call is a statement => print code JVM
        *Access when Call is a expression => return code JVM for caller
        '''

        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 i, arg in enumerate(ast.param):
            #arg:expr
            #in RHS just visit in 2nd time
            paramcode, paramtype = self.visit(arg, Access(frame, nenv, False, False))

            #convert float to int
            if isinstance(paramtype,IntType) and isinstance(sym.mtype.partype[i],FloatType): 
                paramcode+= self.emit.emitI2F(frame)
 
            in_ = (in_[0] + paramcode, in_[1]+[paramtype])

        
        temp= self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame)
        if isinstance(o,SubBody):
            self.emit.printout(in_[0])
            self.emit.printout(temp)
        else:
            return in_[0] + temp, sym.mtype.rettype

    def visitBinaryOp(self, ast:BinaryOp, acc):
        '''
        divide into two type of Operation
        1. Assign: can be statement or expression
        2. Others: just be expression
        '''
        # Not assign Op
        if ast.op != '=':
            lcode, ltype = self.visit(ast.left, acc)
            #print("binOp left: "+ str(acc.frame.currOpStackSize))
            rcode, rtype = self.visit(ast.right, acc)
            #print("binOp right: "+ str(acc.frame.currOpStackSize))

            result=lcode
            #coercions type
            if isinstance(ltype,IntType) and isinstance(rtype,FloatType):
                ltype=rtype=FloatType()
                result+=self.emit.emitI2F(acc.frame)
                result+=rcode
            elif isinstance(ltype,FloatType) and isinstance(rtype,IntType):
                ltype=rtype=FloatType()
                result+=rcode
                result+=self.emit.emitI2F(acc.frame)
            else:
                result+=rcode
            
            #generate code for Op
            if ast.op in [ '<', '<=', '>', '>=', '==', '!=' ]: 
                result+= self.emit.emitREOP(ast.op,ltype,acc.frame)
            elif ast.op == '||': 
                result+= self.emit.emitOROP(acc.frame)
            elif ast.op == '&&': 
                result += self.emit.emitANDOP(acc.frame)
            elif ast.op in ['+','-']:
                result+= self.emit.emitADDOP(ast.op,ltype,acc.frame)
            elif ast.op in ['*','/']:
                result+= self.emit.emitMULOP(ast.op,ltype,acc.frame)
            elif ast.op == '%':
                result+= self.emit.emitMOD(acc.frame)
            #print(ast,result)
            return result, ltype
            
        else: #ast.op is assign op
            lcode, ltype = self.visit(ast.left, Access(acc.frame,acc.sym,True,True))

            rcode, rtype = self.visit(ast.right, Access(acc.frame,acc.sym,False,False))
         
            lcode2, ltype2 = self.visit(ast.left, Access(acc.frame,acc.sym,True,False))

            if isinstance(ltype,FloatType) and isinstance(rtype,IntType):
                result= lcode+rcode+self.emit.emitI2F(acc.frame)+lcode2
            else:
                result= lcode+rcode+lcode2

            #just print if this is assign Op:
            if isinstance(acc,SubBody): #statement
                self.emit.printout(result)
            else: #expression => a=4 return 5 => need load a to Op stack
                rcode2, rtype2 = self.visit(ast.left, Access(acc.frame,acc.sym,False,False))
                return result + rcode2, ltype

    def visitUnaryOp(self, ast: UnaryOp, acc):
        '''
        too easy to describe
        '''
        if isinstance(acc,SubBody): return

        bodycode, bodytype = self.visit(ast.body,acc)
        if ast.op == '-':
            return bodycode + self.emit.emitNEGOP(bodytype, acc.frame), bodytype
        if ast.op =='!':
            return bodycode + self.emit.emitNOT(bodytype, acc.frame), bodytype
        
    def visitIntLiteral(self, ast, acc):
        if isinstance(acc,SubBody): return
        return self.emit.emitPUSHICONST(ast.value, acc.frame), IntType()

       
    def visitFloatLiteral(self, ast, acc):
        if isinstance(acc,SubBody): return
        return self.emit.emitPUSHFCONST(str(ast.value), acc.frame), FloatType()

    def visitBooleanLiteral(self, ast, acc):
        if isinstance(acc,SubBody): return
        return self.emit.emitPUSHICONST(str(ast.value), acc.frame), BoolType()
   
    
    def visitStringLiteral(self, ast, acc):
        if isinstance(acc,SubBody): return
        return self.emit.emitPUSHCONST(ast.value,StringType(), acc.frame), StringType()
Example #28
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 = "MPClass"
        self.path = dir_
        self.emit = Emitter(self.path + "/" + self.className + ".j")
        self.current_function = None  #Symbol("",MType([],VoidType()),CName(self.className))

    def VarGlobal(self, ast, c):
        ctxt = c
        nameAtt = ast.variable.name
        typeAtt = ast.varType
        self.emit.printout(self.emit.emitATTRIBUTE(nameAtt, typeAtt, False,
                                                   ""))
        symbol = Symbol(nameAtt, 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"))
        #get global env
        nenv = 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 [])

        e = SubBody(None, nenv)
        # visit all funtion in program
        lsFun = list(filter(lambda x: type(x) is FuncDecl, ast.decl))
        for x in lsFun:
            e = self.visit(x, e)
        # generate default constructor for MPClass
        self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), c,
                       Frame("<init>", VoidType))
        self.emit.emitEPILOG()
        return c

    def genMETHOD(self, consdecl, c, frame):
        #consdecl: FuncDecl
        #c: 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 = c

        # 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, glSubBody)

        body = consdecl.body

        current_env = functools.reduce(lambda a, b: self.visit(b, a),
                                       consdecl.local, 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))

        #visit body of function
        list(map(lambda x: self.visit(x, current_env), body))

        # get and print Endlabel
        self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame))

        returnstmt = list(filter(lambda x: type(x) is Return, body))
        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, c):
        # this function visit local variable(not global)
        #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.name, ast.varType,
                              c.frame.getStartLabel(), c.frame.getEndLabel(),
                              c.frame))
        return SubBody(c.frame,
                       [Symbol(ast.variable.name, ast.varType, Index(indx))] +
                       env)

    def visitFuncDecl(self, ast, o):
        #ast: FuncDecl
        #o: Any
        subctxt = o
        frame = Frame(ast.name, ast.returnType)
        self.current_function = self.lookup(ast.name.name.lower(), subctxt.sym,
                                            lambda x: x.name.lower())
        self.genMETHOD(ast, subctxt.sym, frame)
        return o

    def Call(self, ast, c):
        ctxt = c
        frame = ctxt.frame
        nenv = ctxt.sym

        sym = self.lookup(ast.method.name.lower(), nenv,
                          lambda x: x.name.lower())

        cname = sym.value.value
        ctype = sym.mtype
        method_name = sym.name

        param_type = list(zip(ast.param, ctype.partype))
        ret = ""
        for x in param_type:
            str1, typ1 = self.visit(x[0], Access(frame, nenv, False, True))
            ret += str1 + self.emit.emitI2F(frame) if (type(typ1), type(
                x[1])) == (IntType, FloatType) else str1
        return (ret + self.emit.emitINVOKESTATIC(cname + "/" + method_name,
                                                 ctype, frame), ctype.rettype)

    def visitCallStmt(self, ast, c):
        self.emit.printout(self.Call(ast, c)[0])

    def visitCallExpr(self, ast, c):
        return self.Call(ast, c)

    def visitAssign(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        env = ctxt.sym

        resRight, typeRight = self.visit(ast.exp,
                                         Access(frame, env, False, False))
        resLeft, typeLeft = self.visit(ast.lhs, Access(frame, env, True,
                                                       False))
        str_I2f = self.emit.emitI2F(frame) if (
            type(typeLeft), type(typeRight)) == (FloatType, IntType) else ""

        self.emit.printout(resRight + str_I2f + resLeft)

    def visitIf(self, ast, c):
        frame = c.frame
        env = c.sym

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

        if len(ast.elseStmt) == 0:
            falseLabel = frame.getNewLabel()
            self.emit.printout(resExpr +
                               self.emit.emitIFFALSE(falseLabel, frame))
            list(map(lambda x: self.visit(x, c), ast.thenStmt))
            self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
        else:
            falseLabel = frame.getNewLabel()
            trueLabel = frame.getNewLabel()
            # if false go to falselabel
            self.emit.printout(resExpr +
                               self.emit.emitIFFALSE(falseLabel, frame))
            # if true then do stmt
            list(map(lambda x: self.visit(x, c), ast.thenStmt))
            # then go to Truelable
            self.emit.printout(self.emit.emitGOTO(trueLabel, frame))

            self.emit.printout(self.emit.emitLABEL(falseLabel, frame))
            list(map(lambda x: self.visit(x, c), ast.elseStmt))
            self.emit.printout(self.emit.emitLABEL(trueLabel, frame))

    def visitWhile(self, ast, c):
        frame = c.frame
        env = c.sym

        frame.enterLoop()

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

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

        self.emit.printout(resExpr)

        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))

        list(map(lambda x: self.visit(x, c), ast.sl))

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

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

        frame.exitLoop()

    def visitFor(self, ast, c):

        frame = c.frame
        env = c.sym
        beginLabel = frame.getNewLabel()
        frame.enterLoop()

        self.visit(Assign(ast.id, ast.expr1), SubBody(frame, env))

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

        op_ = ('<=', '+') if ast.up is True else ('>=', '-')

        self.emit.printout(
            self.visit(BinaryOp(op_[0], ast.id, ast.expr2),
                       SubBody(frame, env))[0])

        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))

        list(map(lambda x: self.visit(x, SubBody(frame, env)), ast.loop))

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

        self.visit(Assign(ast.id, BinaryOp(op_[1], ast.id, IntLiteral(1))),
                   SubBody(frame, env))

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

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

        frame.exitLoop()

    def visitReturn(self, ast, c):
        if ast.expr:
            resExpr, resType = self.visit(ast.expr,
                                          Access(c.frame, c.sym, False, True))
            typeFunc = self.current_function.mtype.rettype
            if (type(typeFunc), type(resType)) == (FloatType, 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))

            # try:
            #     lable = c.frame.getBreakLabel()
            # except:
            #     lable = -1
            # if lable !=-1 :self.emit.printout(self.emit.emitGOTO(c.frame.getBreakLabel(), c.frame))

        else:
            self.emit.printout(self.emit.emitRETURN(VoidType(), c.frame))

    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 visitWith(self, ast, c):

        ctxt = c
        frame = ctxt.frame
        newEnv = ctxt.sym

        frame.enterScope(False)

        varEnv = functools.reduce(lambda a, b: self.visit(b, a), ast.decl,
                                  SubBody(frame, newEnv))

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

        list(map(lambda x: self.visit(x, varEnv), ast.stmt))

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

        frame.exitScope()

        return c

    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 visitBinaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        nenv = ctxt.sym
        op = ast.op.lower()

        # str1, type1 = self.visit(ast.left,o)

        # str2, type2 = self.visit(ast.right,o)
        str1, type1 = self.visit(ast.left, Access(frame, nenv, False, False))

        str2, type2 = self.visit(ast.right, Access(frame, nenv, False, False))

        retType = type1
        # convert type of factor and return type of expression
        if (type(type1), type(type2)) == (FloatType, IntType):
            str2 += self.emit.emitI2F(frame)
            retType = FloatType()
        elif (type(type1), type(type2)) == (IntType, FloatType):
            str1 += self.emit.emitI2F(frame)
            retType = FloatType()
        elif (type(type1), type(type2)) == (IntType, IntType):
            if ast.op is '/':
                str2 += self.emit.emitI2F(frame)
                str1 += self.emit.emitI2F(frame)
                retType = FloatType()
            else:
                retType = IntType()

        if op in ['+', '-']:
            return str1 + str2 + self.emit.emitADDOP(op, retType,
                                                     frame), retType
        elif op in ['*', '/']:
            return str1 + str2 + self.emit.emitMULOP(op, retType,
                                                     frame), retType
        elif op == 'mod':  # error ,let fix as soon as posible
            return str1 + str2 + self.emit.emitMOD(frame), IntType()
        elif op == 'div':
            return str1 + str2 + self.emit.emitDIV(frame), IntType()
        elif op in ['<', '>', '<=', '>=', '=', '<>']:
            return str1 + str2 + self.emit.emitREOP(op, retType,
                                                    frame), BoolType()

        elif op in ['and', 'or']:
            str_op = self.emit.emitANDOP(
                frame) if op == 'and' else self.emit.emitOROP(frame)
            return str1 + str2 + str_op, BoolType()
        elif op in ['andthen', 'orelse']:
            return self.emit.emit_ANDTHEN_ORELSE(op, str1, str2,
                                                 frame), BoolType()

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

    def visitId(self, ast, o):

        if type(o) is Access:
            sym = self.lookup(ast.name.lower(), o.sym,
                              lambda x: x.name.lower())
            code = ""
            nameId = sym.name
            if o.isLeft:
                if type(sym.value) is CName:
                    code = self.emit.emitPUTSTATIC(
                        sym.value.value + "." + nameId, sym.mtype, o.frame)
                elif type(sym.value) is Index:
                    code = self.emit.emitWRITEVAR(nameId, sym.mtype,
                                                  sym.value.value, o.frame)
            else:
                if type(sym.value) is CName:
                    code = self.emit.emitGETSTATIC(
                        sym.value.value + "." + nameId, sym.mtype, o.frame)
                elif type(sym.value) is Index:
                    code = self.emit.emitREADVAR(nameId.lower(), sym.mtype,
                                                 sym.value.value, o.frame)

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

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

    def visitBooleanLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHICONST(str(ast.value).lower(),
                                        frame), BoolType()
Example #29
0
class CodeGenVisitor(BaseVisitor):
    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 = MethodEnv(None, self.env)
        self.genMain(e)
        # generate default constructor
        self.genInit()
        # generate class init if necessary
        self.emit.emitEPILOG()
        return c

    def genInit(self):
        methodname, methodtype = "<init>", MType([], VoidType())
        frame = Frame(methodname, methodtype.rettype)
        self.emit.printout(self.emit.emitMETHOD(
            methodname, methodtype, False, frame))
        frame.enterScope(True)
        varname, vartype, varindex = "this", ClassType(
            self.className), frame.getNewIndex()
        startLabel, endLabel = frame.getStartLabel(), frame.getEndLabel()
        self.emit.printout(self.emit.emitVAR(
            varindex, varname, vartype, startLabel, endLabel, frame))
        self.emit.printout(self.emit.emitLABEL(startLabel, frame))
        self.emit.printout(self.emit.emitREADVAR(
            varname, vartype, varindex, frame))
        self.emit.printout(self.emit.emitINVOKESPECIAL(frame))
        self.emit.printout(self.emit.emitLABEL(endLabel, frame))
        self.emit.printout(self.emit.emitRETURN(methodtype.rettype, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))

    # The following code is just for initial, students should remove it and write your visitor from here
    def genMain(self, o):
        methodname, methodtype = "main", MType(
            [ArrayType(StringType())], VoidType())
        frame = Frame(methodname, methodtype.rettype)
        self.emit.printout(self.emit.emitMETHOD(
            methodname, methodtype, True, frame))
        frame.enterScope(True)
        varname, vartype, varindex = "args", methodtype.partype[0], frame.getNewIndex(
        )
        startLabel, endLabel = frame.getStartLabel(), frame.getEndLabel()
        self.emit.printout(self.emit.emitVAR(
            varindex, varname, vartype, startLabel, endLabel, frame))
        self.emit.printout(self.emit.emitLABEL(startLabel, frame))
        self.emit.printout(self.emit.emitPUSHICONST(120, frame))
        sym = next(filter(lambda x: x.name == "string_of_int", o.sym))
        self.emit.printout(self.emit.emitINVOKESTATIC(
            sym.value.value+"/string_of_int", sym.mtype, frame))
        sym = next(filter(lambda x: x.name == "print", o.sym))
        self.emit.printout(self.emit.emitINVOKESTATIC(
            sym.value.value+"/print", sym.mtype, frame))
        self.emit.printout(self.emit.emitLABEL(endLabel, frame))
        self.emit.printout(self.emit.emitRETURN(methodtype.rettype, frame))
        self.emit.printout(self.emit.emitENDMETHOD(frame))
        pass
Example #30
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 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 list()
        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))

        body = consdecl.body
        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))

        #list(map(lambda x: self.visit(x, SubBody(frame, glenv)), body.member))
        for x in body.member:  # TODO: change to visitBody
            if type(x) is VarDecl:
                glenv = self.visit(x, SubBody(frame, glenv.sym))
            else:
                self.visit(x, SubBody(frame, glenv.sym))

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

    def visitReturn(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        retType = frame.returnType

        if ast.expr:
            exprStr, exprType = self.visit(
                ast.expr, Access(frame, ctxt.sym, False, True))
            self.emit.printout(exprStr)

            if type(exprType) is IntType and type(retType) is FloatType:
                self.emit.printout(self.emit.emitI2F(frame))

        self.emit.printout(self.emit.emitRETURN(retType, frame))

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

        subctxt = o
        frame = Frame(ast.name.name, ast.returnType)
        self.genMETHOD(ast, subctxt, frame)
        paramTypes = list(map(lambda x: x.varType, ast.param))
        return SubBody(None, [
            Symbol(ast.name.name, MType(paramTypes, ast.returnType),
                   CName(self.className))
        ] + subctxt.sym)

    def visitVarDecl(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        varName = ast.variable
        varType = ast.varType
        if frame is None:  #global
            self.emit.printout(
                self.emit.emitATTRIBUTE(varName, varType, False, None))
            return SubBody(None,
                           [Symbol(varName, varType, CName(self.className))] +
                           ctxt.sym)

        else:  #local var
            index = frame.getNewIndex()
            var = self.emit.emitVAR(index, varName, varType,
                                    frame.getStartLabel(), frame.getEndLabel(),
                                    frame)
            self.emit.printout(
                var)  # TODO: Can you move .getLabel() into Emitter?
            return SubBody(frame, [Symbol(varName, varType, index)] + ctxt.sym)

    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))
        return in_[0], ctype

    def visitDowhile(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        frame.enterLoop()
        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        for st in ast.sl:  # TODO: Add updating sym
            self.visit(st, SubBody(frame, ctxt.sym))
        exp, exptyp = self.visit(ast.exp, Access(frame, ctxt.sym, False,
                                                 False))
        self.emit.printout(exp)
        self.emit.printout(
            self.emit.emitIFTRUE(frame.getContinueLabel(), frame))
        self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame))

        frame.exitLoop()

    def visitIf(self, ast, o):
        ctxt = o
        frame = ctxt.frame

        elseLabel = frame.getNewLabel()
        endLabel = frame.getNewLabel()

        expStr, expType = self.visit(ast.expr,
                                     Access(frame, o.sym, False, False))
        self.emit.printout(expStr)
        self.emit.printout(self.emit.emitIFFALSE(elseLabel, frame))

        self.visit(ast.thenStmt, o)
        self.emit.printout(self.emit.emitGOTO(endLabel, frame))

        self.emit.printout(self.emit.emitLABEL(elseLabel, frame))
        if ast.elseStmt:
            self.visit(ast.elseStmt, o)  # TODO: printout somewhere??

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

    def visitFor(self, ast, o):
        # expr1:Expr
        # expr2:Expr
        # expr3:Expr
        # loop:Stmt
        ctxt = o
        frame = ctxt.frame
        frame.enterLoop()
        exp1, exp1typ = self.visit(ast.expr1,
                                   Access(frame, ctxt.sym, False, False))

        self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(),
                                               frame))
        exp2, exp2typ = self.visit(ast.expr2,
                                   Access(frame, ctxt.sym, False, False))
        self.emit.printout(exp2)
        self.emit.printout(self.emit.emitIFFALSE(frame.getBreakLabel(), frame))

        # loop
        self.visit(ast.loop, ctxt)  #TODO: ctxt Correct?
        #list(map(lambda x: self.visit(x, SubBody(frame, ctxt.sym)), ast.loop)) # from Jim
        #exp3
        exp3, exp3typ = self.visit(ast.expr3, o)

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

        frame.exitLoop()

    # evaluate expr1
    # label1
    # evaluate expr2
    # if false, jump to label 2
    # evaluate loop
    # evaluate expr 3
    # goto label1
    # label 2

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

    def visitContinue(self, ast, o):
        frame = o.frame
        self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), 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: FloatLiteral
        #o: Any

        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType()

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

    def visitStringLiteral(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        return self.emit.emitPUSHCONST('"' + ast.value + '"', StringType(),
                                       frame), BoolType()

    def visitUnaryOp(self, ast, o):
        # TODO: [] needed?
        ctxt = o
        frame = ctxt.frame
        operator = ast.op
        expStr, expType = self.visit(ast.body, o)

        if operator == '-':
            return expStr + self.emit.emitNEGOP(expType, frame), expType
        if operator == '!':
            return expStr + self.emit.emitNOT(BoolType(), frame), expType

    def visitBinaryOp(self, ast, o):
        ctxt = o
        frame = ctxt.frame
        if ast.op == "=":
            return self.visitAssignment(ast, o)

        if ast.op in ["+", "-", "*", "/"]:
            operandStr, type_ = self.getOperands(ast.left, ast.right, o)
            if ast.op == "+" or ast.op == "-":
                operandStr += self.emit.emitADDOP(ast.op, type_, frame)
            else:
                operandStr += self.emit.emitMULOP(ast.op, type_, frame)

            return operandStr, type_
        if ast.op in [">", "<", ">=", "<=", "==", "!="]:
            leftStr, leftType = self.visit(ast.left,
                                           Access(frame, o.sym, False, False))
            rightStr, rightType = self.visit(
                ast.right, Access(frame, o.sym, False, False))

            operandStr = leftStr + rightStr
            if type(leftType) is FloatType and type(rightType) is IntType:
                operandStr += self.emit.emitI2F(frame)

            operandStr += self.emit.emitREOP(ast.op, leftType, frame)
            return operandStr, BoolType()  # TODO: with or without brackets?!

    def visitAssignment(self, ast, o):
        # a = b (index1 = index2)
        # iload_2
        # dup # always leave value on stack after assignment/expression
        # istore_1

        ctxt = o
        frame = ctxt.frame
        #this visit just for type checking
        _, l_ = self.visit(ast.left, Access(frame, o.sym, True, True))

        rightStr, r_ = self.visit(ast.right, Access(frame, o.sym, False,
                                                    False))
        operandStr = rightStr

        leftType = type(l_)
        rightType = type(r_)

        if leftType is not rightType:
            if leftType is IntType and rightType is FloatType:
                raise Exception(
                    "Cannot assign float to int.. But didn't we do that in StaticCheck?!"
                )
            elif leftType is FloatType and rightType is IntType:
                operandStr += self.emit.emitI2F(frame)
            # else:
            #     raise NotImplementedError("Supporting only Int and Float atm") # cannot use this because it breaks genMETHOD. lol.

            # duplicate result of assignment so it stays after storing
            # get store cell
        leftStr, leftType = self.visit(ast.left,
                                       Access(frame, o.sym, True, False))
        operandStr += leftStr  # TODO: CHECK: deleted "self.emit.emitDUP(frame) + " before leftStr so Code works.. Does it get dup'd elsewhere?

        self.emit.printout(operandStr)
        return operandStr, leftType

    def visitId(self, ast, o):
        frame = o.frame
        symbols = o.sym
        isFirst = o.isFirst
        isLeft = o.isLeft

        id_ = self.lookup(ast.name, symbols, lambda x: x.name)

        type_ = id_.mtype

        if type(id_.value) is CName:
            name = self.className + "/" + id_.name
            if isLeft:
                if isFirst:  #just for type checking, NO emit here
                    x = "", type_
                    return x  # find id in symbols
                else:
                    return self.emit.emitPUTSTATIC(
                        name, type_, frame), type_  # find id, store
            else:
                return self.emit.emitGETSTATIC(
                    name, type_, frame), type_  #find id in symbols, load index
        else:  #local
            name = id_.name
            index = id_.value
            if isLeft:
                if isFirst:  #just for type checking, NO emit here
                    x = "", type_
                    return x  # find id in symbols
                else:
                    return self.emit.emit(
                        name, type_, index, frame
                    ), type_  # find id, store # TODO: Jim has writeVAR func
            else:
                return self.emit.emitREADVAR(
                    name, type_, index,
                    frame), type_  #find id in symbols, load index

    def getOperands(self, lOp, rOp, o):
        frame = o.frame
        lStr, l_ = self.visit(lOp, Access(frame, o.sym, False, False))
        rStr, r_ = self.visit(rOp, Access(frame, o.sym, False, False))

        lType = type(l_)
        rType = type(r_)

        if lType is rType:
            return lStr + rStr, lType
        elif lType is FloatType and rType is IntType:
            return lStr + rStr + self.emit.emitI2F(
                frame), FloatType  #TODO: delete () again (move to Emitter)
        elif lType is IntType and rType is FloatType:
            return lStr + self.emit.emitI2F(frame) + rStr, FloatType
        else:
            raise Exception("Should never come here")