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 __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 __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 = []
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)
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 = []
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 __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()
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()
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()
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))
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
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()
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()
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()
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)
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()
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()
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()
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()
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()
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())
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()
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()
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()
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
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")