class CodeGenVisitor(BaseVisitor, Utils): def lst(self,l): a = [] for x in l: a += [[i.name for i in x ]] print(a) def lst2(self,l): print([x.name for x in l]) 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 callBody(self, ast, o): ctxt = o frame = ctxt.frame nenv = ctxt.sym symLst = [] for x in o.sym: symLst+= x sym = self.lookup(ast.method.name.lower(), symLst, lambda x: x.name.lower()) cname = sym.value.value # print(cname) ctype = sym.mtype 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(x[0]) is FloatType and type(typ1) is IntType: str1 += self.emit.emitI2F(frame) in_ += str1 return in_ + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame), ctype.rettype 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: temp = self.visit(x, SubBody(None, self.env)) self.env = temp+ self.env else: isMain = x.name.name == "main" and len(x.param) == 0 and type(x.returnType) is VoidType intype = [ArrayPointerType(StringType())] if isMain else [self.visit(x.varType,c) for x in x.param] self.env.insert(0,Symbol(x.name.name, MType(intype, x.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)) 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 isFunc = (not isMain) and (not isInit) returnType = VoidType() if isInit else consdecl.returnType methodName = "<init>" if isInit else consdecl.name.name if isMain : intype = [ArrayPointerType(StringType())] else: intype = [self.visit(x.varType,o) 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[-1] if o != None else None # 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)) #list(map(lambda x: self.visit(x, SubBody(frame, glenv)), consdecl.local)) if isFunc: list(map(lambda x: self.visit(x, SubBody(frame, glenv)), consdecl.param )) # Generate code for statements body = consdecl.body.member 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)) if o!=None: d = o.copy() for x in body: temp = self.visit(x, SubBody(frame, d)) if type(x) is VarDecl: d[0] = temp + d[0] #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() #----------------------------------------------------------------------------# #----------------------------Declaration-------------------------------------# def visitFuncDecl(self, ast, o): #frame: Frame #sym: List[Symbol] frame = Frame(ast.name, ast.returnType) sym = [] for x in ast.param: index = frame.getNewIndex() sym+= [Symbol(x.variable, self.visit(x.varType,o), Index(index))] #[Symbol(x.variable, self.visit(x.varType,o), CName(self.className))] d = [sym, o.sym] subctxt = o self.genMETHOD(ast, d, frame) return None def visitVarDecl(self, ast, o): frame = o.frame nenv = o.sym if frame is None:# var declaration in golbal #nenv.insert(0,Symbol(ast.variable, self.visit(ast.varType,o), CName(self.className))) #print([x.name.lower() for x in nenv] ) self.emit.printout(self.emit.emitATTRIBUTE(ast.variable, self.visit(ast.varType, o), False, "")) return [Symbol(ast.variable, self.visit(ast.varType,o), CName(self.className))] else:# var declaration in function or with statement index = frame.getNewIndex() #nenv.insert(0, Symbol(ast.variable, self.visit(ast.varType,o), Index(index))) #chu y varType self.emit.printout(self.emit.emitVAR(index, ast.variable, self.visit(ast.varType, o), frame.getStartLabel(), frame.getEndLabel(),frame)) return [Symbol(ast.variable, self.visit(ast.varType,o), Index(index))] #----------------------------------------------------------------------------# #-----------------------------Statements-------------------------------------# 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)) if type(rettype) is FloatType and type(etype) is IntType: self.emit.printout(ecode + self.emit.emitI2F(o.frame) + self.emit.emitRETURN(rettype, o.frame)) else: self.emit.printout(ecode + self.emit.emitRETURN(rettype, o.frame)) return "Return" def visitCallExpr(self, ast, o): symLst = [] for x in o.sym: symLst+= x sym = self.lookup(ast.method.name.lower(), symLst, lambda x: x.name.lower()) cname = sym.value.value if cname == 'io': self.emit.printout(self.callBody(ast, o)[0]) return None else: return self.callBody(ast, o) def visitIf(self, ast, o): #exp:Expr , thenStmt:Stmt, elseStmt: Stmt = None ctxt = o frame = o.frame expCode, expType = self.visit(ast.expr, Access(o.frame, o.sym, False, True)) self.emit.printout(expCode) labelF = frame.getNewLabel() labelT = frame.getNewLabel() if ast.elseStmt else None self.emit.printout(self.emit.emitIFFALSE(labelF, frame)) thenStmt = list(map(lambda x: self.visit(x, ctxt), [ast.thenStmt])) self.emit.printout(self.emit.emitGOTO(labelT,frame)) if ast.elseStmt and (len(thenStmt)==0 or str(thenStmt[-1]) != "Return") else None self.emit.printout(self.emit.emitLABEL(labelF, frame)) elseStmt = [] if ast.elseStmt: elseStmt = list(map(lambda x: self.visit(x, ctxt), [ast.elseStmt])) self.emit.printout(self.emit.emitLABEL(labelT, frame)) if thenStmt != [] and elseStmt != [] and str(thenStmt[-1]) == "Return" and str(elseStmt[-1]) == "Return": return "Return" else: return None def visitFor(self, ast, o): ctxt = o frame = o.frame sym = o.sym frame.enterLoop() labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() labelStart = frame.getNewLabel() #expCode, expType = self.visit(ast.exp, Access(frame, sym, False, True)) exp1, e1 = self.visit(ast.expr1, Access(frame, sym, False, True)) if exp1!=None: self.emit.printout(exp1) self.emit.printout(self.emit.emitLABEL(labelStart, frame)) exp2, e2 = self.visit(ast.expr2, Access(frame, sym, False, True)) if exp2!=None: self.emit.printout(exp2) self.emit.printout(self.emit.emitIFFALSE(labelBreak, frame)) self.visit(ast.loop, ctxt) self.emit.printout(self.emit.emitLABEL(labelContinue, frame)) exp3, e3 = self.visit(ast.expr3, Access(frame, sym, False, True)) if exp3!=None: self.emit.printout(exp3) self.emit.printout(self.emit.emitGOTO(labelStart, frame)+ self.emit.emitLABEL(labelBreak,frame)) frame.exitLoop() return None def visitDowhile(self, ast, o): ctxt = o frame = o.frame sym = o.sym frame.enterLoop() labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() labelStart = frame.getNewLabel() self.emit.printout(self.emit.emitLABEL(labelStart,frame)) list(map(lambda x: self.visit(x, ctxt), ast.sl)) self.emit.printout(self.emit.emitLABEL(labelContinue,frame)) expCode, expType = self.visit(ast.exp, Access(frame, sym, False, True)) self.emit.printout(expCode + self.emit.emitIFTRUE(labelStart, frame) + self.emit.emitLABEL(labelBreak,frame)) frame.exitLoop() return None def visitBlock(self, ast,o): ctxt = o frame = o.frame sym = o.sym frame.enterScope(False) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) sym4Scope = [[]] + sym for x in ast.member: temp = self.visit(x, SubBody(frame, sym4Scope)) if type(x) is VarDecl: sym4Scope[0] = temp + sym4Scope[0] # stmt = list(map(lambda x: self.visit(x, SubBody(frame, sym)), ast.member)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() #return stmt[-1] if stmt != [] else None return None def visitContinue(self, ast, o): self.emit.printout(self.emit.emitGOTO(o.frame.getContinueLabel(), o.frame)) return None def visitBreak(self, ast, o): self.emit.printout(self.emit.emitGOTO(o.frame.getBreakLabel(), o.frame)) return None #----------------------------------------------------------------------------# #-----------------------------Expression-------------------------------------# def visitBinaryOp(self, ast, o): #################### ASSIGN #################### if (ast.op == '='): rightCode, typeRight = self.visit(ast.right, Access(o.frame, o.sym, False, True)) leftCode, typeLeft = self.visit(ast.left, Access(o.frame, o.sym, True, False)) if type(typeLeft) is FloatType and type(typeRight) is IntType: self.emit.printout(rightCode + self.emit.emitI2F(o.frame) + leftCode) else: self.emit.printout(rightCode + leftCode) return None,typeRight ################################################ ctxt = o frame = ctxt.frame nenv = ctxt.sym leftCode, typeLeft = self.visit(ast.left, Access(frame, nenv, False, True)) rightCode, typeRight = self.visit(ast.right, Access(frame, nenv, False, True)) if type(typeLeft) != type(typeRight): if type(typeLeft) is IntType: leftCode += self.emit.emitI2F(frame) typeLeft = FloatType() elif type(typeRight) is IntType: rightCode += self.emit.emitI2F(frame) typeRight = FloatType() if ast.op in ['+', '-']: op_str = leftCode + rightCode op_str += self.emit.emitADDOP(ast.op, typeLeft, frame) resType = typeLeft elif ast.op is '*': op_str = leftCode + rightCode op_str += self.emit.emitMULOP(ast.op, typeLeft, frame) resType = typeLeft elif ast.op in ['/', '%']: op_str = leftCode + rightCode op_str += self.emit.emitDIV(frame) if ast.op =='/' else self.emit.emitMOD(frame) resType = IntType() elif ast.op in ['&&','||']: op_str = leftCode + rightCode op_str += self.emit.emitANDOP(frame) if ast.op.lower() =='and' else self.emit.emitOROP(frame) resType = BoolType() elif ast.op in ['==', '!=', '<', '<=', '>', '>='] : op_str = leftCode + rightCode + self.emit.emitREOP(ast.op, typeLeft, frame) resType = BoolType() return op_str, resType def visitUnaryOp(self, ast, o): 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) else: op_str = expCode + self.emit.emitNEGOP(expType, o.frame) return op_str ,expType def visitId(self, ast, o): symLst = [] for x in o.sym: symLst+= x sym = self.lookup(ast.name.lower(), symLst, lambda x: x.name.lower()) if o.isLeft: if type(sym.value) is CName: return self.emit.emitPUTSTATIC(sym.value.value + "/" + sym.name,sym.mtype,o.frame), sym.mtype #store else: return self.emit.emitWRITEVAR(sym.name, sym.mtype, sym.value.value, o.frame), sym.mtype else: if type(sym.value) is CName: return self.emit.emitGETSTATIC(sym.value.value + "/" + sym.name,sym.mtype,o.frame), sym.mtype #load else: return self.emit.emitREADVAR(sym.name, sym.mtype, sym.value.value, o.frame), sym.mtype #----------------------------------------------------------------------------# #-----------------------------Literal----------------------------------------# def visitIntLiteral(self, ast, o): return self.emit.emitPUSHCONST(ast.value, IntType(), o.frame), IntType() def visitFloatLiteral(self, ast, o): return self.emit.emitPUSHCONST(ast.value, FloatType(), o.frame), FloatType() def visitBooleanLiteral(self, ast, o): return self.emit.emitPUSHCONST(ast.value, BoolType(), o.frame), BoolType() def visitStringLiteral(self, ast, o): return self.emit.emitPUSHCONST(ast.value, StringType(), o.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 ArrayPointerType(self.visit(ast.eleType,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 = "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): 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") 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") 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))
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 = "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 = "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")) #First visit e = SubBody(None, self.env, True) for x in ast.decl: e = self.visit(x, e) #Second visit e.firstVisit = False 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.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 env = SubBody(frame, glenv) #print(env.sym[0].name) # 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: env = self.visit(x, env) for x in consdecl.local: env = self.visit(x, env) body = consdecl.body 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)) list(map(lambda x: self.visit(x, env), 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): #ast: FuncDecl #o: Any subctxt = o frame = Frame(ast.name, ast.returnType) #First visit if subctxt.firstVisit: return SubBody(None, [ Symbol(ast.name.name, MType(list(), ast.returnType), CName(self.className)) ] + subctxt.sym, True) #second visit self.genMETHOD(ast, subctxt.sym, frame) #print(ast.name.name) #return SubBody(None, [Symbol(ast.name.name, MType(list(), ast.returnType), CName(self.className))] + subctxt.sym) 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_ = ("", list()) L = zip(ast.param, ctype.partype) #print(ctype.partype) for x in L: str1, typ1 = self.visit(x[0], Access(frame, nenv, False, True)) in_ = (in_[0] + str1 + (self.emit.emitI2F(frame) if type(typ1) is IntType and type(x[1]) is FloatType else ""), 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 #print(sym.name) ctype = sym.mtype in_ = ("", list()) L = zip(ast.param, ctype.partype) #print(ctype.partype) for x in L: str1, typ1 = self.visit(x[0], Access(frame, nenv, False, True)) #print(str1) in_ = (in_[0] + str1 + (self.emit.emitI2F(frame) if type(typ1) is IntType and type(x[1]) is FloatType else ""), in_[1] + [typ1]) # self.emit.printout(in_[0]) # self.emit.printout(self.emit.emitINVOKESTATIC(cname + "/" + ast.method.name, ctype, frame)) return in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame), ctype.rettype def visitId(self, ast, o): ctxt = o frame = ctxt.frame # print(ctxt.sym[0].name) sym = self.lookup(ast.name.lower(), ctxt.sym, lambda x: x.name.lower()) if (ctxt.isLeft): if type(sym.value) is Index: return self.emit.emitWRITEVAR(sym.name, sym.mtype, sym.value.value, frame), sym.mtype else: return self.emit.emitPUTSTATIC( sym.value.value + '/' + sym.name, sym.mtype, frame), sym.mtype else: if type(sym.value) is Index: return self.emit.emitREADVAR(sym.name, sym.mtype, sym.value.value, frame), sym.mtype else: return self.emit.emitGETSTATIC( sym.value.value + '/' + sym.name, sym.mtype, frame), sym.mtype def visitAssign(self, ast, o): #lhs:Expr #exp:Expr ctxt = o frame = ctxt.frame rhs = self.visit(ast.exp, Access(frame, ctxt.sym, False, ""))[0] lhs = self.visit(ast.lhs, Access(frame, ctxt.sym, True, ""))[0] self.emit.printout(rhs + lhs) return def visitIf(self, ast, o): ctxt = o frame = ctxt.frame env = ctxt.sym hasElse = len(ast.elseStmt) != 0 exp, expType = self.visit(ast.expr, Access(frame, env, False, "")) elseLabel = frame.getNewLabel() nextLabel = frame.getNewLabel() if hasElse else elseLabel self.emit.printout(exp + self.emit.emitIFFALSE(elseLabel, frame)) for stmt in ast.thenStmt: self.visit(stmt, SubBody(frame, env)) self.emit.printout(self.emit.emitGOTO(nextLabel, frame)) self.emit.printout(self.emit.emitLABEL(elseLabel, frame)) for stmt in ast.elseStmt: self.visit(stmt, SubBody(frame, env)) if hasElse: self.emit.printout(self.emit.emitLABEL(nextLabel, frame)) 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 visitReturn(self, ast, o): ctxt = o frame = ctxt.frame env = ctxt.sym if ast.expr is None: self.emit.printout(self.emit.emitRETURN(VoidType(), frame)) else: str1, typ1 = self.visit(ast.expr, Access(frame, env, False, "")) self.emit.printout(str1) if (type(frame.returnType) == FloatType and type(typ1) == IntType): self.emit.printout(self.emit.emitI2F(frame)) self.emit.printout(self.emit.emitRETURN(frame.returnType, frame)) def visitWhile(self, ast, o): frame = o.frame frame.enterLoop() label1 = frame.getContinueLabel() label2 = frame.getBreakLabel() code = self.emit.emitLABEL(label1, frame) code += self.visit(ast.exp, Access(frame, o.sym, False, True))[0] code += self.emit.emitIFFALSE(label2, frame) self.emit.printout(code) list(map(lambda x: self.visit(x, o), ast.sl)) code = self.emit.emitGOTO(str(label1), frame) code += self.emit.emitLABEL(label2, frame) self.emit.printout(code) frame.exitLoop() def visitFor(self, ast, o): ctxt = o frame = ctxt.frame nenv = ctxt.sym frame.enterLoop() conLabel = frame.getContinueLabel() breLabel = frame.getBreakLabel() labelXXX = frame.getNewLabel() expr1, typ1 = self.visit(ast.expr1, Access(frame, nenv, False, False)) _id1, tid_1 = self.visit(ast.id, Access(frame, nenv, True, False)) self.emit.printout(expr1) self.emit.printout(_id1) self.emit.printout(self.emit.emitLABEL(labelXXX, frame)) if ast.up is True: _id2, tid_2 = self.visit(ast.id, Access(frame, nenv, False, False)) self.emit.printout(_id2) expr2, typ2 = self.visit(ast.expr2, Access(frame, nenv, False, False)) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFICMPGT(breLabel, frame)) else: _id2, tid_2 = self.visit(ast.id, Access(frame, nenv, False, False)) self.emit.printout(_id2) expr2, typ2 = self.visit(ast.expr2, Access(frame, nenv, False, False)) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFICMPLT(breLabel, frame)) for x in ast.loop: self.visit(x, SubBody(frame, nenv)) self.emit.printout(self.emit.emitLABEL(conLabel, frame)) if ast.up is True: exp_2, ty_2 = self.visit(BinaryOp('+', ast.id, IntLiteral(1)), Access(frame, nenv, False, False)) id_1, t_1 = self.visit(ast.id, Access(frame, nenv, True, False)) self.emit.printout(exp_2) self.emit.printout(id_1) else: exp_2, ty_2 = self.visit(BinaryOp('-', ast.id, IntLiteral(1)), Access(frame, nenv, False, False)) id_1, t_1 = self.visit(ast.id, Access(frame, nenv, True, False)) self.emit.printout(exp_2) self.emit.printout(id_1) self.emit.printout(self.emit.emitGOTO(labelXXX, frame)) self.emit.printout(self.emit.emitLABEL(breLabel, frame)) frame.exitLoop() def visitWith(self, ast, o): frame = o.frame frame.enterScope(False) e = SubBody(frame, []) for x in ast.decl: e = self.visit(x, e) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) arraySym = list(filter(lambda x: isinstance(x.mtype, ArrayType), e.sym)) codelist = list( map( lambda x: self.visit( IntLiteral(x.mtype.upper - x.mtype.lower + 1), e)[0] + self .emit.emitNEW(x.mtype.eleType, frame) + self.emit.emitWRITEVAR( x.name, ArrayPointerType(x.mtype.eleType), x.value.value, e .frame), arraySym)) #if codelist !=[]: code = reduce(lambda x, y: x + y, codelist, "") self.emit.printout(code) o = SubBody(frame, e.sym + o.sym) list(map(lambda x: self.visit(x, o), ast.stmt)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() def visitFloatLiteral(self, ast, o): #ast: FloatLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType() def visitIntLiteral(self, ast, o): #ast: IntLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHICONST(ast.value, frame), IntType() def visitStringLiteral(self, ast, o): ctxt = o frame = ctxt.frame return self.emit.emitPUSHCONST(str(ast.value), StringType(), frame), StringType() def visitBooleanLiteral(self, ast, o): #ast: FloatLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHICONST(str(ast.value), frame), BoolType() def visitVarDecl(self, ast, o): ctxt = o frame = ctxt.frame #first visit if ctxt.firstVisit: return SubBody(None, [ Symbol(ast.variable.name, ast.varType, CName(self.className)) ] + ctxt.sym, True) #Second visit if frame is None: self.emit.printout( self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False, "")) #return SubBody(None, [Symbol(ast.variable.name, ast.varType, CName(self.className))] + ctxt.sym) else: #parameter or local variable self.emit.printout( self.emit.emitVAR(frame.getNewIndex(), ast.variable.name, ast.varType, frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody(frame, [ Symbol(ast.variable.name, ast.varType, Index(frame.getCurrIndex() - 1)) ] + ctxt.sym) def visitUnaryOp(self, ast, o): ctxt = o frame = ctxt.frame exp, expType = self.visit(ast.body, o) if ast.op == '-': return exp + self.emit.emitNEGOP(expType, frame), expType elif ast.op == 'not': return exp + self.emit.emitNOT(expType, frame), expType def visitBinaryOp(self, ast, o): #op:string: AND THEN => andthen; OR ELSE => orelse; other => keep it #left:Expr #right:Expr ctxt = o frame = ctxt.frame leftExp, leftType = self.visit(ast.left, o) rightExp, rightType = self.visit(ast.right, o) if type(leftType) != type(rightType): if type(leftType) == IntType: leftExp += self.emit.emitI2F(frame) if type(rightType) == IntType: rightExp += self.emit.emitI2F(frame) if ast.op in ['+', '-']: return leftExp + rightExp + self.emit.emitADDOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['*', '/']: return leftExp + rightExp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['<', '>', '>=', '<=', '=', '<>']: return leftExp + rightExp + self.emit.emitREOP( ast.op, leftType, frame), BoolType() else: if ast.op in ['+', '-']: return leftExp + rightExp + self.emit.emitADDOP( ast.op, leftType, frame), leftType elif ast.op == '*': return leftExp + rightExp + self.emit.emitMULOP( ast.op, leftType, frame), leftType elif ast.op == '/': if type(leftType) == IntType: return leftExp + self.emit.emitI2F( frame) + rightExp + self.emit.emitI2F( frame) + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() else: return leftExp + rightExp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op.lower() == 'or': return leftExp + rightExp + self.emit.emitOROP( frame), BoolType() elif ast.op.lower() == 'and': return leftExp + rightExp + self.emit.emitANDOP( frame), BoolType() elif ast.op.lower() == 'mod': return leftExp + rightExp + self.emit.emitMOD(frame), IntType() elif ast.op.lower() == 'div': return leftExp + rightExp + self.emit.emitDIV(frame), IntType() elif ast.op in ['<', '>', '>=', '<=', '=', '<>']: if type(leftType) == IntType: leftExp += self.emit.emitI2F(frame) if type(rightType) == IntType: rightExp += self.emit.emitI2F(frame) return leftExp + rightExp + self.emit.emitREOP( ast.op, leftType, 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 = "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 listParamArray = [] # list(Symbol(name, mtype, value: Index(idx))) listLocalArray = [] # list(Symbol(name, mtype, value: Index(idx))) if isInit: self.emit.printout( self.emit.emitVAR(frame.getNewIndex(), "this", ClassType(self.className), frame.getStartLabel(), frame.getEndLabel(), frame)) elif isMain: self.emit.printout( self.emit.emitVAR(frame.getNewIndex(), "args", ArrayPointerType(StringType()), frame.getStartLabel(), frame.getEndLabel(), frame)) else: e = SubBody(frame, glenv) for x in consdecl.param: e = self.visit(x, e) glenv = e.sym if type(x.varType) is ArrayType: idx = glenv[0].value.value self.emit.printout( self.emit.emitINITARRAY(idx, x.varType, frame)) listParamArray.append(glenv[0]) for x in listParamArray: self.emit.printout( self.emit.emitCOPYARRAY(x.value.value, x.mtype, 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: if type(x) is VarDecl: e = SubBody(frame, glenv) e = self.visit(x, e) glenv = e.sym if type(x.varType) is ArrayType: idx = glenv[0].value.value self.emit.printout( self.emit.emitINITARRAY(idx, x.varType, frame)) # self.emit.printout(self.visit(x, SubBody(frame, glenv))[0]) else: 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): #ast: FuncDecl #o: Any 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 visitBlock(self, ast, o): #ast: Block ctxt = o frame = ctxt.frame nenv = ctxt.sym for x in ast.member: self.visit(x, o) def visitVarDecl(self, ast, o): #ast: VarDecl #o: SubBody #ast.variable: Id #ast.varType: Type subctxt = o frame = subctxt.frame mtype = ast.varType name = ast.variable if frame is None: # Decl mot bien global self.emit.printout(self.emit.emitATTRIBUTE(name, mtype, False, "")) return SubBody(None, [Symbol(name, mtype, CName(self.className))] + subctxt.sym) else: # Decl mot bien local hoac param idx = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(idx, name, mtype, frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody(frame, [Symbol(name, mtype, Index(idx))] + subctxt.sym) def visitIf(self, ast, o): #ast: If #o: Any #expr:Expr #thenStmt:Stmt #elseStmt:Stmt ctxt = o frame = ctxt.frame nenv = ctxt.sym expr, _ = self.visit(ast.expr, Access(frame, nenv, False, True)) self.emit.printout(expr) label1 = frame.getNewLabel() label2 = None if ast.elseStmt is not None: label2 = frame.getNewLabel() self.emit.printout(self.emit.emitIFFALSE(label1, frame)) self.visit(ast.thenStmt, o) if ast.elseStmt is not None: self.emit.printout(self.emit.emitGOTO(str(label2), frame)) self.emit.printout(self.emit.emitLABEL(label1, frame)) if ast.elseStmt is not None: self.visit(ast.elseStmt, o) self.emit.printout(self.emit.emitLABEL(label2, frame)) def visitDowhile(self, ast, o): #o: Any #ast.sl: List[Stmt] #ast.exp: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym frame.enterLoop() labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() list(map(lambda x: self.visit(x, o), ast.sl)) self.emit.printout(self.emit.emitLABEL(labelContinue, frame)) expr, _ = self.visit(ast.exp, Access(frame, nenv, False, True)) self.emit.printout(expr) self.emit.printout(self.emit.emitIFFALSE(labelBreak, frame)) list(map(lambda x: self.visit(x, o), ast.sl)) self.emit.printout(self.emit.emitGOTO(str(labelContinue), frame)) self.emit.printout(self.emit.emitLABEL(labelBreak, frame)) def visitFor(self, ast, o): #o: Any #expr1:Expr #expr2:Expr #expr3:Expr #loop:Stmt ctxt = o frame = ctxt.frame nenv = ctxt.sym expr1, _ = self.visit(ast.expr1, Access(frame, nenv, False, True)) self.emit.printout(expr1) frame.enterLoop() labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() expr2, _ = self.visit(ast.expr2, Access(frame, nenv, False, True)) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFFALSE(labelBreak, frame)) self.visit(ast.loop, o) self.emit.printout(self.emit.emitLABEL(labelContinue, frame)) if type(ast.expr3) is BinaryOp and ast.expr3.op == '=': self.visit(ast.expr3, Access(frame, nenv, False, True)) else: expr3, _ = self.visit(ast.expr3, Access(frame, nenv, False, True)) self.emit.printout(expr3) expr2, _ = self.visit(ast.expr2, Access(frame, nenv, False, True)) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFFALSE(labelBreak, frame)) self.visit(ast.loop, o) self.emit.printout(self.emit.emitGOTO(str(labelContinue), frame)) self.emit.printout(self.emit.emitLABEL(labelBreak, frame)) def visitBreak(self, ast, o): #o:any ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame)) def visitContinue(self, ast, o): #o:any ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame)) def visitReturn(self, ast, o): #o:any #ast.expr: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym if ast.expr is not None: str1, typ1 = self.visit(ast.expr, Access(frame, nenv, False, True)) if type(typ1) is IntType and type(frame.returnType) is FloatType: str1 += self.emit.emitI2F(frame) self.emit.printout(str1) #self.emit.printout(self.emit.emitGOTO(frame.getEndLabel(), frame)) self.emit.printout(self.emit.emitRETURN(frame.returnType, frame)) def visitArrayCell(self, ast, o): #o:any #ast.arr:Expr #ast.idx:Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym lst = [] arr, typeArr = self.visit(ast.arr, Access(frame, nenv, False, True)) idx, typeIdx = self.visit(ast.idx, Access(frame, nenv, False, True)) typ = typeArr.eleType lst.append(arr) lst.append(self.emit.emitPUSHICONST(typeArr.dimen - 1, frame)) lst.append(idx) lst.append(self.emit.emitADDOP('-', IntType(), frame)) if not o.isLeft: lst.append(self.emit.emitALOAD(typ, frame)) return ''.join(lst), typ def visitBinaryOp(self, ast, o): #ast:BinaryOp #ast.op:str #ast.left:Expr #ast.right:Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym leftOp, typeLHS = self.visit(ast.left, Access(frame, nenv, False, True)) if type(ast.right) == CallExpr: self.visit(ast.right, Access(frame, nenv, False, True)) else: rightOp, typeRHS = self.visit(ast.right, Access(frame, nenv, False, True)) if ast.op == '=': if type(ast.left) is ArrayCell: leftOp, typeLHS = self.visit(ast.left, Access(frame, nenv, True, True)) self.emit.printout(leftOp) if type(ast.right) == CallExpr: self.visit(ast.right, Access(frame, nenv, False, True)) else: rightOp, typeRHS = self.visit( ast.right, Access(frame, nenv, False, True)) self.emit.printout(rightOp) if type(typeLHS) != type(typeRHS): self.emit.printout(self.emit.emitI2F(frame)) self.emit.printout(self.emit.emitASTORE(typeLHS, frame)) else: leftOp, typeLHS = self.visit(ast.left, Access(frame, nenv, True, True)) if type(ast.right) == CallExpr: self.visit(ast.right, Access(frame, nenv, False, True)) else: rightOp, typeRHS = self.visit( ast.right, Access(frame, nenv, False, True)) if type(typeRHS) is IntType and type(typeLHS) is FloatType: rightOp += self.emit.emitI2F(frame) self.emit.printout(rightOp + leftOp) elif type(typeLHS) == type(typeRHS): if type(typeLHS) is BoolType: if ast.op.lower() == '&&': return leftOp + rightOp + self.emit.emitANDOP( frame), BoolType() elif ast.op.lower() == '||': return leftOp + rightOp + self.emit.emitOROP( frame), BoolType() elif ast.op in ['==', '!=']: return leftOp + rightOp + self.emit.emitREOP( ast.op, BoolType(), frame), BoolType() elif type(typeLHS) is IntType: if ast.op in ['+', '-']: return leftOp + rightOp + self.emit.emitADDOP( ast.op, IntType(), frame), IntType() elif ast.op == '*': return leftOp + rightOp + self.emit.emitMULOP( ast.op, IntType(), frame), IntType() elif ast.op == '/': return leftOp + rightOp + self.emit.emitDIV( frame), IntType() elif ast.op == '%': return leftOp + rightOp + self.emit.emitMOD( frame), IntType() elif ast.op in ['<', '<=', '>', '>=', '!=', '==']: return leftOp + rightOp + self.emit.emitREOP( ast.op, IntType(), frame), BoolType() elif type(typeLHS) is FloatType: if ast.op in ['+', '-']: return leftOp + rightOp + self.emit.emitADDOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '*': return leftOp + rightOp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '/': return leftOp + rightOp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['<', '<=', '>', '>=', '!=', '==']: return self.emit.emitFREOP(ast.op, leftOp, rightOp, frame), BoolType() else: if ast.op in ['+', '-']: if type(typeLHS) is FloatType and type(typeRHS) is IntType: return leftOp + rightOp + self.emit.emitI2F( frame) + self.emit.emitADDOP(ast.op, FloatType(), frame), FloatType() elif type(typeLHS) is IntType and type(typeRHS) is FloatType: return leftOp + self.emit.emitI2F( frame) + rightOp + self.emit.emitADDOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '*': if type(typeLHS) is FloatType and type(typeRHS) is IntType: return leftOp + rightOp + self.emit.emitI2F( frame) + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() elif type(typeLHS) is IntType and type(typeRHS) is FloatType: return leftOp + self.emit.emitI2F( frame) + rightOp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() else: if type(typeLHS) is IntType: leftOp += self.emit.emitI2F(frame) if type(typeRHS) is IntType: rightOp += self.emit.emitI2F(frame) if ast.op == '/': return leftOp + rightOp + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['<', '<=', '>', '>=', '!=', '==']: return self.emit.emitFREOP(ast.op, leftOp, rightOp, frame), BoolType() def visitUnaryOp(self, ast, o): #o: Any #ast.op: string #ast.body: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym body, typ = self.visit(ast.body, Access(frame, nenv, False, True)) if ast.op == '!' and type(typ) is BoolType: return body + self.emit.emitNOT(IntType(), frame), BoolType() elif ast.op == '-' and type(typ) is IntType: return body + self.emit.emitNEGOP(IntType(), frame), IntType() elif ast.op == '-' and type(typ) is FloatType: return body + self.emit.emitNEGOP(FloatType(), frame), FloatType() 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_ = ("", []) for x in ast.param: if type(x) is CallExpr: self.visit(x, Access(frame, nenv, False, True)) else: 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 + "/" + ast.method.name, ctype, frame)) def visitId(self, ast, o): #o: Any #ast.name: string sym = self.lookup(ast.name, o.sym, lambda x: x.name) typ = sym.mtype if o.isLeft: if type(sym.value) is CName: return self.emit.emitPUTSTATIC( sym.value.value + "/" + sym.name, typ, o.frame), typ else: return self.emit.emitWRITEVAR(sym.name, typ, sym.value.value, o.frame), typ else: if type(sym.value) is CName: return self.emit.emitGETSTATIC( sym.value.value + "/" + sym.name, typ, o.frame), typ else: return self.emit.emitREADVAR(sym.name, typ, sym.value.value, o.frame), typ 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 visitBooleanLiteral(self, ast, o): #ast: BooleanLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHCONST( str(ast.value).lower(), IntType(), frame), BoolType() def visitStringLiteral(self, ast, o): #ast: StringLiteral #o: Any 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 = "MPClass" self.path = dir_ self.emit = Emitter(self.path + "/" + self.className + ".j") self.listGlobalArray = [] # list(VarDecl: array declare global) def visitProgram(self, ast: Program, c): # 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) [self.visit(x, e) for x in ast.decl if type(x) is FuncDecl] # generate default constructor self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), c, Frame("<init>", VoidType)) # class init - static field self.genMETHOD(FuncDecl(Id("<clinit>"), list(), list(), list(), None), c, Frame("<clinit>", VoidType)) self.emit.emitEPILOG() return c def visitFuncDecl(self, ast: FuncDecl, o: SubBody): subctxt = o frame = Frame(ast.name.name, ast.returnType) self.genMETHOD(ast, subctxt.sym, frame) def visitVarDecl(self, ast: VarDecl, o: SubBody): subctxt = o frame = o.frame isGlobal = o.isGlobal varName = ast.variable.name 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, decl: FuncDecl, o, frame: Frame): # o: Any glenv = o methodName = decl.name.name.lower() isInit = decl.returnType is None and methodName == "<init>" isClassInit = decl.returnType is None and methodName == "<clinit>" isMain = methodName == "main" and len( decl.param) == 0 and type(decl.returnType) is VoidType returnType = VoidType() if isInit or isClassInit else decl.returnType isProc = type(returnType) is VoidType intype = [ArrayPointerType(StringType())] if isMain else [ StupidUtils.retrieveType(x.varType) for x in decl.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)) listParamArray = [] # list(Symbol(name, mtype, value: Index(idx))) listLocalArray = [] # list(Symbol(name, mtype, value: Index(idx))) varList = SubBody(frame, glenv) for x in decl.param: varList = self.visit(x, varList) if type(x.varType) is ArrayType: listParamArray.append(varList.sym[0]) for x in decl.local: varList = self.visit(x, varList) if type(x.varType) is ArrayType: listLocalArray.append(varList.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)) list(map(lambda x: self.visit(x, varList), decl.body)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) if isProc: 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() # ================ Visit Statements ================= # Param: o: SubBody(frame, sym) def visitCallStmt(self, ast: CallStmt, o: SubBody): ctxt = o frame = ctxt.frame symbols = ctxt.sym self.handleCall(ast, frame, symbols, isStmt=True) def handleCall(self, ast, frame, symbols, isStmt=False): # ast: CallStmt | CallExpr sym = self.lookup(ast.method.name.lower(), symbols, lambda x: x.name.lower()) cname = sym.value.value ctype = sym.mtype paramTypes = ctype.partype paramsCode = "" idx = 0 for x in ast.param: pCode, pType = self.visit(x, Access(frame, symbols, False, True)) if type(paramTypes[idx]) is FloatType and type(pType) is IntType: pCode = pCode + self.emit.emitI2F(frame) if type(paramTypes[idx]) is ArrayType: pass paramsCode = paramsCode + pCode idx = idx + 1 # if sym.name.lower() == "main": ctype = MType([ArrayPointerType(StringType())], VoidType()) code = paramsCode + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame) if isStmt: self.emit.printout(code) else: return code, ctype.rettype 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.emitGOTO(frame.getEndLabel(), frame)) self.emit.printout(self.emit.emitRETURN(retType, frame)) return True def visitIf(self, ast: If, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym 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 hasReturnStmt = True in [self.visit(x, o) for x in ast.elseStmt] 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(x, o) for x in ast.thenStmt] and hasReturnStmt # End self.emit.printout(self.emit.emitLABEL(labelE, frame)) return hasReturnStmt def visitWhile(self, ast: While, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True)) labelS = frame.getNewLabel() # label start labelE = frame.getNewLabel() # label end 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 visitFor(self, ast: For, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym exp1Code, _ = self.visit(ast.expr1, Access(frame, nenv, False, True)) exp2Code, _ = self.visit(ast.expr2, Access(frame, nenv, False, True)) lhsWCode, _ = self.visit(ast.id, Access(frame, nenv, True, True)) # Write code lhsRCode, _ = self.visit(ast.id, Access(frame, nenv, False, False)) # Read code labelS = frame.getNewLabel() # label start labelE = frame.getNewLabel() # label end # Init value self.emit.printout(exp1Code) self.emit.printout(lhsWCode) frame.enterLoop() # Loop self.emit.printout(self.emit.emitLABEL(labelS, frame)) # 1. Condition self.emit.printout(lhsRCode) self.emit.printout(exp2Code) if ast.up: self.emit.printout(self.emit.emitIFICMPGT(labelE, frame)) else: self.emit.printout(self.emit.emitIFICMPLT(labelE, frame)) # 2. Statements hasReturnStmt = True in [self.visit(x, o) for x in ast.loop] self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) # 3. Update index self.emit.printout(lhsRCode) self.emit.printout(self.emit.emitPUSHICONST(1, frame)) self.emit.printout( self.emit.emitADDOP('+' if ast.up else '-', IntType(), frame)) self.emit.printout(lhsWCode) 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 visitWith(self, ast: With, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym frame.enterScope(False) listLocalArray = [] # list(Symbol(name, mtype, value: Index(idx))) varList = SubBody(frame, nenv) for x in ast.decl: varList = self.visit(x, varList) if type(x.varType) is ArrayType: listLocalArray.append(varList.sym[0]) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), 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)) list(map(lambda x: self.visit(x, varList), ast.stmt)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() def visitBreak(self, ast: Break, o: SubBody): ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame)) def visitContinue(self, ast: Continue, o: SubBody): ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame)) def visitAssign(self, ast: Assign, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym # Pre-prepare for assign to array cell # stack: ..., arrayref, index, value -> ... # push 2 slot for arrayref and index, visit exp first isArray, _ = self.visit( ast.lhs, Access(frame, nenv, True, True, checkArrayType=True)) if isArray: [frame.push() for i in range(0, 2)] # Visit LHS: Id || ArrayCell expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True)) lhsCode, lhsType = self.visit(ast.lhs, 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)] # ================ Visit Expression ================= # Param: o: Access(frame, sym, isLeft, isFirst) # Return: (code, type) 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.lower(), symbols, lambda x: x.name.lower()) # 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 visitCallExpr(self, ast: CallExpr, o: Access): ctxt = o frame = ctxt.frame symbols = ctxt.sym return self.handleCall(ast, frame, symbols, isStmt=False) def visitBinaryOp(self, ast: BinaryOp, o: Access): ctxt = o frame = ctxt.frame op = str(ast.op).lower() if op in ['orelse', 'andthen']: result = [] lCode, lType = self.visit(ast.left, ctxt) result.append(lCode) labelF = frame.getNewLabel() # eval is false labelT = frame.getNewLabel() # eval is true if op == 'andthen': result.append(self.emit.emitIFFALSE(labelF, frame)) # false else: result.append(self.emit.emitIFTRUE(labelT, frame)) # true rCode, rType = self.visit(ast.right, ctxt) result.append(rCode) if op == 'andthen': result.append(self.emit.emitIFFALSE(labelF, frame)) # false result.append(self.emit.emitPUSHICONST("true", frame)) # push true result.append(self.emit.emitGOTO(labelT, frame)) # go to true result.append(self.emit.emitLABEL(labelF, frame)) # push false result.append(self.emit.emitPUSHICONST("false", frame)) result.append(self.emit.emitLABEL(labelT, frame)) else: result.append(self.emit.emitIFTRUE(labelT, frame)) # true result.append(self.emit.emitPUSHICONST("false", frame)) # push false result.append(self.emit.emitGOTO(labelF, frame)) # go to false result.append(self.emit.emitLABEL(labelT, frame)) # push true result.append(self.emit.emitPUSHICONST("true", frame)) result.append(self.emit.emitLABEL(labelF, frame)) return ''.join(result), BoolType() lCode, lType = self.visit(ast.left, ctxt) rCode, rType = self.visit(ast.right, ctxt) if StupidUtils.isOpForNumber(op): # for number type 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 == 'div': return lCode + rCode + self.emit.emitDIV(frame), mType if op == 'mod': return lCode + rCode + self.emit.emitMOD(frame), mType else: # op to boolean: > <= = <>, ... return lCode + rCode + self.emit.emitREOP(op, mType, frame), BoolType() else: # for boolean type mType = BoolType() if op == 'or': return lCode + rCode + self.emit.emitOROP(frame), mType if op == 'and': return lCode + rCode + self.emit.emitANDOP(frame), mType def visitUnaryOp(self, ast: UnaryOp, o: Access): ctxt = o frame = ctxt.frame op = str(ast.op).lower() bCode, bType = self.visit(ast.body, ctxt) if op == '-': return bCode + self.emit.emitNEGOP(bType, frame), bType if op == 'not': return bCode + self.emit.emitNOT(bType, frame), bType 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 = "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) # 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 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)) 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 visitCallStmt(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 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() 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 lcode, ltype = self.visit(ast.left, ctxt) rcode, rtype = self.visit(ast.right, ctxt) if FloatType in (type(ltype), type(rtype)): 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 == '*': return lcode + rcode + self.emit.emitMULOP(ast.op, ltype, frame), ltype else: if type(ltype) is IntType: lcode += self.emit.emitI2F(frame) rcode += self.emit.emitI2F(frame) return lcode + rcode + self.emit.emitMULOP("/", FloatType(), frame), FloatType()
class CodeGenVisitor(BaseVisitor, Utils): 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 getDeclType(self, varType): return ArrayPointerType(varType.eleType) if type(varType) is ArrayType else varType def visitProgram(self, ast, c): #ast: Program #c: Any # print(ast) self.emit.printout(self.emit.emitPROLOG(self.className, "java.lang.Object")) staticDeclList = self.env for decl in ast.decl: if type(decl) is FuncDecl: paramType = [paramTemp.varType for paramTemp in decl.param] staticDeclList = [Symbol(decl.name.name, MType(paramType, decl.returnType), CName(self.className))] + staticDeclList else: varSym = self.visit(decl, (SubBody(None, self.env), "global")) staticDeclList = [varSym] + staticDeclList env = SubBody(None, staticDeclList) self.genMETHOD(FuncDecl(Id("<init>"), list(), None, Block(list())), c, Frame("<init>", VoidType)) if self.globalArrayVarList: self.genMETHOD(FuncDecl(Id("<clinit>"), list(), None, Block(list())), c, Frame("<clinit>", VoidType)) list(map(lambda func: self.visit(func, env), filter(lambda decl: type(decl) is FuncDecl, ast.decl))) self.emit.emitEPILOG() return c # declaration def genMETHOD(self, consdecl, globalEnv, frame): #consdecl: FuncDecl #globalEnv: Any #frame: Frame 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 inType = [ArrayPointerType(StringType())] if isMain else [self.getDeclType(decl.varType) for decl 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)) varList = SubBody(frame, globalEnv) for param in consdecl.param: varList = self.visit(param, (varList, "parameter")) if type(param.varType) is ArrayType: name = varList.sym[0].name idx = varList.sym[0].value.value varType = varList.sym[0].mtype self.emit.printout(self.emit.emitVAR(idx, name, varType, frame.getStartLabel(), frame.getEndLabel(), frame)) 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)) if isClassInit: for arrayVar in self.globalArrayVarList: # emitINITNEWARRAY(self, name, frame, varType, varSize) self.emit.printout(self.emit.emitINITNEWARRAY(self.className + "." + arrayVar.variable, frame, arrayVar.varType.eleType, arrayVar.varType.dimen)) for member in body.member: if type(member) is VarDecl: varList = self.visit(member, (varList, "local")) if type(member.varType) is ArrayType: idx = varList.sym[0].value.value varType = varList.sym[0].mtype.eleType self.emit.printout(self.emit.emitINITNEWARRAY(idx, frame, varType, member.varType.dimen, "local")) else: self.visit(member, varList) if frame.getStackSize() and type(member) is Expr: self.emit.printout(self.emit.emitPOP(frame)) 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, subGlobal): subGlobalTemp = subGlobal frame = Frame(ast.name.name, ast.returnType) self.genMETHOD(ast, subGlobalTemp.sym, frame) def visitVarDecl(self, ast, trackSubBody): subctxt = trackSubBody[0] frame = subctxt.frame varName = ast.variable varType = ast.varType if trackSubBody[1] == "global": self.emit.printout(self.emit.emitATTRIBUTE(varName, self.getDeclType(varType), False, "")) if type(ast.varType) is ArrayType: self.globalArrayVarList.append(ast) return Symbol(varName, varType) elif trackSubBody[1] == "parameter": # param idx = frame.getNewIndex() self.emit.printout(self.emit.emitVAR(idx, varName, self.getDeclType(varType), frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody(frame, [Symbol(varName, varType, Index(idx))] + subctxt.sym) else: # local idx = frame.getNewIndex() localVarLabel = frame.getNewLabel() self.emit.printout(self.emit.emitVAR(idx, varName, self.getDeclType(varType), localVarLabel, frame.getEndLabel(), frame)) self.emit.printout(self.emit.emitLABEL(localVarLabel, frame)) return SubBody(frame, [Symbol(varName, varType, Index(idx))] + subctxt.sym) # statement def visitCallExpr(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym sym = self.lookup(ast.method.name, symLst, lambda x: x.name) cname = sym.value.value ctype = sym.mtype paramsCode = "" for i in range(len(ast.param)): paramCode, paramType = self.visit(ast.param[i], Access(frame, symLst, False, True)) if type(sym.mtype.partype[i]) is FloatType and type(paramType) is IntType: paramCode = paramCode + self.emit.emitI2F(frame) paramsCode += paramCode result = paramsCode + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame) if type(ctxt) is SubBody: self.emit.printout(result) else: return result, ctype.rettype def visitBlock(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym frame.enterScope(False) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) varList = SubBody(frame, symLst) # Generate code for statements for member in ast.member: if type(member) is VarDecl: varList = self.visit(member, (varList, "local")) if type(member.varType) is ArrayType: idx = varList.sym[0].value.value varType = varList.sym[0].mtype.eleType self.emit.printout(self.emit.emitINITNEWARRAY(idx, frame, varType, member.varType.dimen, "local")) else: self.visit(member, varList) if frame.getStackSize() and type(member) is Expr: self.emit.printout(self.emit.emitPOP(frame)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() def visitIf(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym labelTrue = frame.getNewLabel() labelEnd = frame.getNewLabel() exprCode, exprType = self.visit(ast.expr, Access(frame, symLst, False, True)) self.emit.printout(exprCode) self.emit.printout(self.emit.emitIFTRUE(labelTrue, frame)) if ast.elseStmt is not None: self.visit(ast.elseStmt, ctxt) self.emit.printout(self.emit.emitGOTO(labelEnd, frame)) self.emit.printout(self.emit.emitLABEL(labelTrue, frame)) self.visit(ast.thenStmt, ctxt) self.emit.printout(self.emit.emitLABEL(labelEnd, frame)) def visitDowhile(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym labelStart = frame.getNewLabel() labelEnd = frame.getNewLabel() expCode, expType = self.visit(ast.exp, Access(frame, symLst, False, True)) frame.enterLoop() self.emit.printout(self.emit.emitLABEL(labelStart, frame)) list(map(lambda x: self.visit(x, ctxt), ast.sl)) self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) self.emit.printout(expCode) self.emit.printout(self.emit.emitIFFALSE(labelEnd, frame)) self.emit.printout(self.emit.emitGOTO(labelStart, frame)) self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame)) self.emit.printout(self.emit.emitLABEL(labelEnd, frame)) frame.exitLoop() def visitFor(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym labelStart = frame.getNewLabel() labelEnd = frame.getNewLabel() expr1Code, expr1Type = self.visit(ast.expr1, Access(frame, symLst, False, True)) expr2Code, expr2Type = self.visit(ast.expr2, Access(frame, symLst, False, True)) expr3Code, expr3Type = self.visit(ast.expr3, Access(frame, symLst, False, True)) self.emit.printout(expr1Code) self.emit.printout(self.emit.emitPOP(frame)) frame.enterLoop() self.emit.printout(self.emit.emitLABEL(labelStart, frame)) self.emit.printout(expr2Code) self.emit.printout(self.emit.emitIFFALSE(labelEnd, frame)) self.visit(ast.loop, ctxt) self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) self.emit.printout(expr3Code) self.emit.printout(self.emit.emitPOP(frame)) self.emit.printout(self.emit.emitGOTO(labelStart, frame)) self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame)) self.emit.printout(self.emit.emitLABEL(labelEnd, frame)) frame.exitLoop() def visitBreak(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame)) def visitContinue(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame)) def visitReturn(self, ast, trackSubBody): ctxt = trackSubBody frame = ctxt.frame symLst = ctxt.sym returnType = frame.returnType if not type(returnType) is VoidType: exprCode, exprType = self.visit(ast.expr, Access(frame, symLst, False, True)) if type(returnType) is FloatType and type(exprType) is IntType: exprCode = exprCode + self.emit.emitI2F(frame) self.emit.printout(exprCode) self.emit.printout(self.emit.emitRETURN(returnType, frame)) # expression def visitBinaryOp(self, ast, o): ctxt = o frame = ctxt.frame op = ast.op symLst = ctxt.sym if op in ['+', '-', '*', '/', '%', '<', '<=', '>', '>=', '==', '!=']: leftCode, leftType = self.visit(ast.left, Access(frame, symLst, False, False)) rightCode, rightType = self.visit(ast.right, Access(frame, symLst, False, False)) returnType = FloatType() if FloatType in [type(leftType), type(rightType)] else IntType() if type(leftType) is IntType and type(returnType) != type(leftType): leftCode = leftCode + self.emit.emitI2F(frame) if type(rightType) is IntType and type(returnType) != type(rightType): rightCode = rightCode + self.emit.emitI2F(frame) if op in ['+', '-', '*', '/', '%']: if op in ['+', '-']: return leftCode + rightCode + self.emit.emitADDOP(op, returnType, frame), returnType elif op in ['*', '/']: return leftCode + rightCode + self.emit.emitMULOP(op, returnType, frame), returnType elif op == '%': return leftCode + rightCode + self.emit.emitMOD(frame), IntType() else: return leftCode + rightCode + self.emit.emitREOP(op, returnType, frame), BoolType() elif op in ['||', '&&']: # short-circuit preOp = ctxt.labelShortCircuit[0] if type(o) is Access else None labelShortCircuit = ctxt.labelShortCircuit[1] if type(o) is Access else None if op != preOp: labelShortCircuit = frame.getNewLabel() leftCode, leftType = self.visit(ast.left, Access(frame, symLst, False, False, (op, labelShortCircuit))) rightCode, rightType = self.visit(ast.right, Access(frame, symLst, False, False, (op, labelShortCircuit))) if op != preOp: if op == '||': return leftCode + self.emit.emitDUP(frame) + self.emit.emitIFTRUE(labelShortCircuit, frame) + self.emit.emitPOP(frame) + rightCode + self.emit.emitLABEL(labelShortCircuit, frame), BoolType() else: return leftCode + self.emit.emitDUP(frame) + self.emit.emitIFFALSE(labelShortCircuit, frame) + self.emit.emitPOP(frame) + rightCode + self.emit.emitLABEL(labelShortCircuit, frame), BoolType() else: if op == '||': return leftCode + self.emit.emitDUP(frame) + self.emit.emitIFTRUE(labelShortCircuit, frame) + self.emit.emitPOP(frame) + rightCode, BoolType() else: return leftCode + self.emit.emitDUP(frame) + self.emit.emitIFFALSE(labelShortCircuit, frame) + self.emit.emitPOP(frame) + rightCode, BoolType() else: rightCode, rightType = self.visit(ast.right, Access(frame, symLst, False, False)) leftCode, leftType = self.visit(ast.left, Access(frame, symLst, True, False)) isArrayType = type(leftType) in [ArrayType, ArrayPointerType] if isArrayType: leftType = leftType.eleType if type(leftType) is FloatType and type(rightType) is IntType: rightCode = rightCode + self.emit.emitI2F(frame) if type(ctxt) is SubBody: if isArrayType: returnOp = leftCode[0] + rightCode + leftCode[1] [frame.push() for i in range(2)] else: returnOp = rightCode + leftCode self.emit.printout(returnOp) if isArrayType: [frame.pop() for i in range(2)] else: if isArrayType: returnOp = rightCode returnOp += leftCode[0] + rightCode + leftCode[1] [frame.push() for i in range(2)] # keep arr for right to assign else: returnOp = rightCode + self.emit.emitDUP(frame) + leftCode returnType = leftType return returnOp, returnType def visitUnaryOp(self, ast, o): ctxt = o frame = ctxt.frame symLst = ctxt.sym op = ast.op binaryCode, binaryType = self.visit(ast.body, Access(frame, symLst, False, True)) if op == '-': return binaryCode + self.emit.emitNEGOP(binaryType, frame), binaryType if op == '!': return binaryCode + self.emit.emitNOT(binaryType, frame), binaryType def visitId(self, ast, ctxtId): ctxt = ctxtId frame = ctxt.frame symLst = ctxt.sym sym = self.lookup(ast.name, symLst, lambda x: x.name) varType = self.getDeclType(sym.mtype) if type(ctxt) is not SubBody: isLeft = ctxt.isLeft isFirst = ctxt.isFirst if isLeft: frame.push() if sym.value is None: if isLeft and type(sym.mtype) not in [ArrayType, ArrayPointerType]: returnCode = self.emit.emitPUTSTATIC(self.className + "." + sym.name, varType, frame) else: returnCode = self.emit.emitGETSTATIC(self.className + "." + sym.name, varType, frame) else: if isLeft and type(sym.mtype) not in [ArrayType, ArrayPointerType]: returnCode = self.emit.emitWRITEVAR(sym.name, varType, sym.value.value, frame) else: returnCode = self.emit.emitREADVAR(sym.name, varType, sym.value.value, frame) else: if sym.value is None: returnCode = self.emit.emitGETSTATIC(self.className + "." + sym.name, varType, frame) else: returnCode = self.emit.emitREADVAR(sym.name, varType, sym.value.value, frame) return returnCode, sym.mtype def visitArrayCell(self, ast, o): ctxt = o frame = ctxt.frame symLst = ctxt.sym isLeft = ctxt.isLeft isFirst = ctxt.isFirst arrCode, arrType = self.visit(ast.arr, Access(frame, symLst, True, True)) idxCode, idxType = self.visit(ast.idx, Access(frame, symLst, False, True)) if isLeft: return [arrCode + idxCode, self.emit.emitASTORE(arrType.eleType, frame)], arrType # stack to keep right code if assign in another op [frame.push() for i in range(2)] return arrCode + idxCode + self.emit.emitALOAD(arrType.eleType, frame), arrType.eleType 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() 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()
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(Frame(None, None), self.env) list_fun = [] #visit de tao sym for x in ast.decl: if type(x) is FuncDecl: list_fun = list_fun + [x] else: e = self.visit(x, e) # print(','.join(str(x) for x in e.sym)) # visit doi voi fun_decl de tao constructor # print(','.join(str(x) for x in list_fun)) for x in list_fun: e = self.visit(x, e) # print(','.join(str(x) for x in e.sym)) en_sym = e.sym for func in list_fun: # print(func) e.frame.name = func.name e.frame.returnType = func.returnType self.genMETHOD(func, en_sym, e.frame) # 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: sym #frame: Frame # print(','.join(str(x) for x in o)) isInit = consdecl.name.name.lower( ) == "<init>" #or (consdecl.returnType is None) isMain = consdecl.name.name.lower() == "main" and len( consdecl.param) == 0 and type(consdecl.returnType) is VoidType # print(isMain) returnType = VoidType() if isInit else consdecl.returnType methodName = "<init>" if isInit else consdecl.name.name intype = None if isInit: #constructor intype = list() elif isMain: #main intype = [ArrayPointerType(StringType()) ] #Note......................................... else: #function and proceduce intype = [x.varType for x in consdecl.param] # print(','.join(str(x) for x in intype)) mtype = MType(intype, returnType) if isMain or isInit: self.emit.printout( self.emit.emitMETHOD(methodName.lower(), mtype, not isInit, frame)) else: self.emit.printout( self.emit.emitMETHOD(methodName, mtype, not isInit, frame)) frame.enterScope(True) glenv = o # sym # 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", ArrayType(None,None,StringType()), frame.getStartLabel(), frame.getEndLabel(), frame)) self.emit.printout( self.emit.emitVAR(frame.getNewIndex(), "args", ArrayPointerType(StringType()), frame.getStartLabel(), frame.getEndLabel(), frame) ) # Note.............................................. e = SubBody(frame, glenv) body = consdecl.body if not isInit: for x in consdecl.param: e = self.visit(x, e) for y in consdecl.local: e = self.visit(y, e) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) #Note............................................... #phan xu li array cho ki su tai nang bo qua!!!! #Note............................................... # 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, e.sym)), body)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) self.emit.printout(self.emit.emitRETURN(returnType, frame)) self.emit.printout(self.emit.emitENDMETHOD(frame)) frame.exitScope() #####################################################Decl################################################################# def visitVarDecl(self, ast, o): subctxt = o frame_ = o.frame sym_ = o.sym check_local = (len(frame_.indexLocal) != 0) if check_local: #bien local idex = frame_.getNewIndex() var_dec1 = self.emit.emitVAR(idex, ast.variable.name, ast.varType, frame_.getStartLabel(), frame_.getEndLabel(), frame_) sym_ = sym_ + [Symbol(ast.variable.name, ast.varType, idex)] self.emit.printout(var_dec1) else: #bien global var_dec2 = self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False, None) sym_ = sym_ + [Symbol(ast.variable.name, ast.varType, None)] self.emit.printout(var_dec2) return SubBody(frame_, sym_) def visitFuncDecl(self, ast, o): #ast: FuncDecl #o: Any subctxt = o sym_ = o.sym frame_ = o.frame if frame_ is None: frame_ = Frame(ast.name, ast.returnType) else: frame_.name = ast.name frame_.returnType = ast.returnType return SubBody( frame_, sym_ + [ Symbol(ast.name.name, MType([x.varType for x in ast.param], ast.returnType), CName(self.className)) ]) #############################################Statement################################################ def visitAssign(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame # print(ast) #visit left : 1 la code , 2 la type # left_1 ,left_2 = self.visit(ast.lhs, Access(frame_,sym_,True,True)) danh cho arraycell ma array khong dung den #Note........................... #visit right: right_1, right_2 = self.visit(ast.exp, Access(frame_, sym_, False, False)) #visit left: left_1, left_2 = self.visit(ast.lhs, Access(frame_, sym_, True, False)) #ep kieu if (type(left_2) is FloatType) and ( type(right_2) is IntType): #note.................................. right_1 = right_1 + self.emit.emitI2F(frame_) self.emit.printout(right_1 + left_1) def visitIf(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame #exp_1 la code , exp_2 la kieu exp_1, exp_2 = self.visit(ast.expr, Access(frame_, sym_, False, False)) self.emit.printout(exp_1) thenLabel = frame_.getNewLabel() elseLabel = frame_.getNewLabel() self.emit.printout(self.emit.emitIFTRUE(thenLabel, frame_)) if ast.elseStmt != []: e_2 = SubBody(frame_, sym_) list(map(lambda x: self.visit(x, e_2), ast.elseStmt)) self.emit.printout(self.emit.emitGOTO(elseLabel, frame_)) self.emit.printout(self.emit.emitLABEL(thenLabel, frame_)) e_1 = SubBody(frame_, sym_) list(map(lambda x: self.visit(x, e_1), ast.thenStmt)) self.emit.printout(self.emit.emitLABEL(elseLabel, frame_)) # def visitFor(self, ast, o): # subctxt = o # sym_ = subctxt.sym # frame_ = subctxt.frame # var = self.lookup(ast.id.name.lower(),sym_[::-1],lambda x: x.name.lower()) # # print(var) # # print(";".join(str(x) for x in sym_)) # expr_ = None # if ast.up == True: # expr_ = Assign(ast.id,BinaryOp('-' ,ast.expr1 ,IntLiteral(1))) # else: # expr_ = Assign(ast.id,BinaryOp('+' ,ast.expr1 ,IntLiteral(1))) # # print(expr_) # esub = SubBody(frame_,sym_) # self.visit(expr_, esub) # # print(temp[0]) # esub.frame.enterLoop() # continue_ = esub.frame.getContinueLabel() # break_ = esub.frame.getBreakLabel() # self.emit.printout(self.emit.emitLABEL(continue_,esub.frame)) # if var.value is not None: # self.emit.printout(self.emit.emitREADVAR(var.name ,var.mtype ,var.value ,esub.frame)) # else: # self.emit.printout(self.emit.emitGETSTATIC("io" + "." + var.name, var.mtype ,esub.frame)) # self.emit.printout(self.emit.emitPUSHICONST(1 ,esub.frame)) # if ast.up == True: #up # self.emit.printout(self.emit.emitADDOP('+' ,IntType() ,esub.frame)) # else: # self.emit.printout(self.emit.emitADDOP('-' ,IntType() ,esub.frame)) # if var.value is not None: # self.emit.printout(self.emit.emitWRITEVAR(var.name ,var.mtype ,var.value ,esub.frame)) # else: # self.emit.printout(self.emit.emitPUTSTATIC("io" + "." + var.name ,var.mtype , esub.frame)) # if var.value is not None: # self.emit.printout(self.emit.emitREADVAR(var.name ,var.mtype ,var.value , esub.frame)) # else: # self.emit.printout(self.emit.emitGETSTATIC("io" + "." + var.name ,var.mtype, esub.frame)) # exp_2,texp_2 = self.visit(ast.expr2,Access(esub.frame , esub.sym ,False,False)) # self.emit.printout(exp_2) # if ast.up == True: #up # self.emit.printout(self.emit.emitREOP('<=',IntType(), esub.frame)) # else: # self.emit.printout(self.emit.emitREOP('>=',IntType(), esub.frame)) # self.emit.printout(self.emit.emitIFFALSE(break_, esub.frame)) # e = SubBody(esub.frame, esub.sym) # list(map(lambda x: self.visit(x, e), ast.loop)) # self.emit.printout(self.emit.emitGOTO(continue_ ,esub.frame)) # self.emit.printout(self.emit.emitLABEL(break_ ,esub.frame)) # esub.frame.exitLoop() def visitFor(self, ast, o): subctxt = o frame_ = subctxt.frame sym_ = subctxt.sym labelfor = frame_.getNewLabel() frame_.enterLoop() accessT = Access(frame_, sym_, True, False) accessF = Access(frame_, sym_, False, False) expr1_, texpr1_ = self.visit(ast.expr1, Access(frame_, sym_, False, False)) id_, tid_ = self.visit(ast.id, Access(frame_, sym_, True, False)) self.emit.printout(expr1_) self.emit.printout(id_) self.emit.printout(self.emit.emitLABEL(labelfor, frame_)) continue_ = frame_.getContinueLabel() break_ = frame_.getBreakLabel() if ast.up is True: id_, tid_ = self.visit(ast.id, Access(frame_, sym_, False, False)) self.emit.printout(id_) expr2_, texpr2_ = self.visit(ast.expr2, Access(frame_, sym_, False, False)) self.emit.printout(expr2_) self.emit.printout(self.emit.emitIFICMPGT(break_, frame_)) else: id_, tid_ = self.visit(ast.id, Access(frame_, sym_, False, False)) self.emit.printout(id_) expr2_, texpr2_ = self.visit(ast.expr2, Access(frame_, sym_, False, False)) self.emit.printout(expr2_) self.emit.printout(self.emit.emitIFICMPLT(break_, frame_)) list(map(lambda x: self.visit(x, o), ast.loop)) self.emit.printout(self.emit.emitLABEL(continue_, frame_)) if ast.up is True: expr_, texpr_ = self.visit(BinaryOp('+', ast.id, IntLiteral(1)), Access(frame_, sym_, False, False)) id__, tid__ = self.visit(ast.id, Access(frame_, sym_, True, False)) self.emit.printout(expr_) self.emit.printout(id__) else: expr_, texpr_ = self.visit(BinaryOp('-', ast.id, IntLiteral(1)), Access(frame_, sym_, False, False)) id__, tid__ = self.visit(ast.id, Access(frame_, sym_, True, False)) self.emit.printout(expr_) self.emit.printout(id__) self.emit.printout(self.emit.emitGOTO(labelfor, frame_)) self.emit.printout(self.emit.emitLABEL(break_, frame_)) frame_.exitLoop() def visitWhile(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame frame_.enterLoop() continue_ = frame_.getContinueLabel() break_ = frame_.getBreakLabel() self.emit.printout(self.emit.emitLABEL(continue_, frame_)) exp_, texp_ = self.visit(ast.exp, Access(frame_, sym_, False, False)) self.emit.printout(exp_) self.emit.printout(self.emit.emitIFFALSE(break_, frame_)) e_ = SubBody(frame_, sym_) list(map(lambda x: self.visit(x, e_), ast.sl)) self.emit.printout(self.emit.emitGOTO(continue_, frame_)) self.emit.printout(self.emit.emitLABEL(break_, frame_)) frame_.exitLoop() def visitBreak(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame break_ = frame_.getBreakLabel() self.emit.printout(self.emit.emitGOTO(break_, frame_)) def visitContinue(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame continue_ = frame_.getContinueLabel() self.emit.printout(self.emit.emitGOTO(continue_, frame_)) def visitReturn(self, ast, o): subctxt = o sym_ = subctxt.sym frame_ = subctxt.frame if ast.expr is not None: exp_, texp_ = self.visit(ast.expr, Access(frame_, sym_, False, False)) self.emit.printout(exp_) if (type(texp_) is IntType) and (type(frame_.returnType) is FloatType): self.emit.printout(self.emit.emitI2F(frame_)) self.emit.printout(self.emit.emitGOTO(frame_.getEndLabel(), frame_)) def visitCallStmt(self, ast, o): #ast: CallStmt #o: Any ctxt = o frame = ctxt.frame nenv = ctxt.sym # print(ast) #tim ham tuong ung de goi sym = self.lookup(ast.method.name.lower(), nenv[::-1], lambda x: x.name.lower()) # print(sym) # print(sym) cname = sym.value.value ctype = sym.mtype in_ = ("", []) idx_ = 0 for x in ast.param: str1, typ1 = self.visit(x, Access(frame, nenv, False, False)) in_ = (in_[0] + str1, in_[1] + [typ1]) if (type(sym.mtype.partype[idx_]) is FloatType) and (type(typ1) is IntType): in_ = (in_[0] + self.emit.emitI2F(frame), in_[1]) idx_ = idx_ + 1 # print(str1,typ1) # print(in_[0]) self.emit.printout(in_[0]) self.emit.printout( self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame)) def visitWith(self, ast, o): ctxt = o frame_ = ctxt.frame sym_ = [] [sym_.append(x) for x in ctxt.sym] frame_.enterScope(False) self.emit.printout(self.emit.emitLABEL(frame_.getStartLabel(), frame_)) e = SubBody(frame_, sym_) for x in ast.decl: e = self.visit(x, e) list(map(lambda x: self.visit(x, e), ast.stmt)) #xoa bien cuc bo trong With e.sym = e.sym[:len(e.sym) - len(ast.decl)] self.emit.printout(self.emit.emitLABEL(frame_.getEndLabel(), frame_)) frame_.exitScope() ##########################################Exp############################################# def visitArrayCell(self, ast, o): #bo qua vi khong lam phan array!!! pass def visitId(self, ast, o): subctxt = o frame_ = subctxt.frame sym_ = subctxt.sym # print(','.join(str(x) for x in sym_)) # print(ast) isLeft_ = subctxt.isLeft isFirst_ = subctxt.isFirst sym_id = self.lookup(ast.name.lower(), sym_[::-1], lambda x: x.name.lower()) # print(sym_id) #khong lam kieu array nen khong quan tam isFirst if not isLeft_ and not isFirst_: #danh cho ve phai # print(1) if sym_id.value is None: return self.emit.emitGETSTATIC( self.className + "." + sym_id.name, sym_id.mtype, frame_), sym_id.mtype else: return self.emit.emitREADVAR(sym_id.name, sym_id.mtype, sym_id.value, frame_), sym_id.mtype if isLeft_ and not isFirst_: #danh cho ve trai # print(2) if type(sym_id.mtype) is not ArrayType: if sym_id.value is None: return self.emit.emitPUTSTATIC( self.className + "." + sym_id.name, sym_id.mtype, frame_), sym_id.mtype else: return self.emit.emitWRITEVAR(sym_id.name, sym_id.mtype, sym_id.value, frame_), sym_id.mtype # else: # return self.emit.emitASTORE(id_info.mtype.eleType,frame),id_info.mtype.eleType # load array khong dung den def visitCallExpr(self, ast, o): subctxt = o frame_ = subctxt.frame sym_ = subctxt.sym isLeft = subctxt.isLeft isFirst = subctxt.isFirst sym_id = self.lookup(ast.method.name.lower(), sym_[::-1], lambda x: x.name.lower()) cname = sym_id.value.value ctype = sym_id.mtype # print(sym_id) in_ = ("", []) idx_ = 0 for x in ast.param: str1, typ1 = self.visit(x, Access(frame_, sym_, False, False)) in_ = (in_[0] + str1, in_[1] + [typ1]) if (type(sym_id.mtype.partype[idx_]) is FloatType) and (type(typ1) is IntType): in_ = (in_[0] + self.emit.emitI2F(frame_), in_[1]) idx_ = idx_ + 1 # print(str1, typ1) # print(in_[0]) return in_[0] + self.emit.emitINVOKESTATIC( cname + "/" + sym_id.name, ctype, frame_), sym_id.mtype.rettype def visitUnaryOp(self, ast, o): subctxt = o frame_ = subctxt.frame sym_ = subctxt.sym unexp_, tunexp_ = self.visit(ast.body, Access(frame_, sym_, False, False)) if (type(tunexp_) is IntType) and (ast.op == '-'): return unexp_ + self.emit.emitNEGOP(IntType(), frame_), IntType() if (type(tunexp_) is FloatType) and (ast.op == '-'): return unexp_ + self.emit.emitNEGOP(FloatType(), frame_), FloatType() if ast.op.lower() == 'not': return unexp_ + self.emit.emitNOT(BoolType(), frame_), BoolType() def visitBinaryOp(self, ast, o): subctxt = o frame_ = subctxt.frame sym_ = subctxt.sym # print(ast) lexp_, tlexp_ = self.visit(ast.left, Access(frame_, sym_, False, False)) # print(lexp_, tlexp_) rexp_, trexp_ = self.visit(ast.right, Access(frame_, sym_, False, False)) # print(rexp_, trexp_) if (type(tlexp_) is BoolType) or (type(trexp_) is BoolType): if ast.op.lower() == 'and': return lexp_ + rexp_ + self.emit.emitANDOP(frame_), BoolType() elif ast.op.lower() == 'or': return lexp_ + rexp_ + self.emit.emitOROP(frame_), BoolType() elif ast.op.lower() == 'andthen': label1 = frame_.getNewLabel() label2 = frame_.getNewLabel() code_j = lexp_ code_j += self.emit.emitPUSHICONST(1, frame_) code_j += self.emit.emitANDOP(frame_) code_j += self.emit.emitIFFALSE(label2, frame_) code_j += rexp_ code_j += self.emit.emitPUSHICONST(1, frame_) code_j += self.emit.emitANDOP(frame_) code_j += self.emit.emitIFFALSE(label2, frame_) code_j += self.emit.emitPUSHICONST(1, frame_) code_j += self.emit.emitGOTO(label1, frame_) code_j += self.emit.emitLABEL(label2, frame_) code_j += self.emit.emitPUSHICONST(0, frame_) code_j += self.emit.emitLABEL(label1, frame_) return code_j, BoolType() elif ast.op.lower() == 'orelse': label1 = frame_.getNewLabel() label2 = frame_.getNewLabel() code_j = rexp_ code_j += self.emit.emitPUSHICONST(0, frame_) code_j += self.emit.emitOROP(frame_) code_j += self.emit.emitIFTRUE(label1, frame_) code_j += rexp_ code_j += self.emit.emitPUSHICONST(0, frame_) code_j += self.emit.emitOROP(frame_) code_j += self.emit.emitIFTRUE(label1, frame_) code_j += self.emit.emitPUSHICONST(0, frame_) code_j += self.emit.emitGOTO(str(label2), frame_) code_j += self.emit.emitLABEL(label1, frame_) code_j += self.emit.emitPUSHICONST(1, frame_) code_j += self.emit.emitLABEL(label2, frame_) return code_j, BoolType() elif ast.op in ['=', '<>']: return lexp_ + rexp_ + self.emit.emitREOP( ast.op, BoolType(), frame_), BoolType() if (type(tlexp_) is IntType) and (type(trexp_) is IntType): # print(1) if ast.op in ['+', '-']: return lexp_ + rexp_ + self.emit.emitADDOP( ast.op, IntType(), frame_), IntType() elif ast.op == '*': return lexp_ + rexp_ + self.emit.emitMULOP( ast.op, IntType(), frame_), IntType() elif ast.op.lower() == 'div': return lexp_ + rexp_ + self.emit.emitDIV(frame_), IntType() elif ast.op.lower() == 'mod': # print(1) return lexp_ + rexp_ + self.emit.emitMOD(frame_), IntType() elif ast.op == '/': lexp_ = lexp_ + self.emit.emitI2F(frame_) rexp_ = rexp_ + self.emit.emitI2F(frame_) return lexp_ + rexp_ + self.emit.emitMULOP( ast.op, FloatType(), frame_), FloatType() elif ast.op in ['<', '<=', '>', '>=', '<>', '=']: # print(1) return lexp_ + rexp_ + self.emit.emitREOP( ast.op, IntType(), frame_), BoolType() #either left or right is FLoat if type(tlexp_) is IntType: lexp_ = lexp_ + self.emit.emitI2F(frame_) if type(trexp_) is IntType: rexp_ = rexp_ + self.emit.emitI2F(frame_) if ast.op in ['+', '-']: return lexp_ + rexp_ + self.emit.emitADDOP(ast.op, FloatType(), frame_), FloatType() elif ast.op in ['*', '/']: return lexp_ + rexp_ + self.emit.emitMULOP(ast.op, FloatType(), frame_), FloatType() elif ast.op in ['<', '<=', '>', '>=', '<>', '=']: return lexp_ + rexp_ + self.emit.emitFREOP(ast.op, FloatType(), frame_), FloatType() # def visitBinaryOp(self, ast, o): # #o: any # #ast.op:string: AND THEN => andthen; OR ELSE => orelse; other => keep it # #ast.left:Expr # #ast.right:Expr # ctxt = o # frame = ctxt.frame # nenv = ctxt.sym # leftOprandstr, typL = self.visit(ast.left, Access(frame, nenv, False, False)) # rightOperandstr, typR = self.visit(ast.right, Access(frame, nenv, False, False)) # if type(typL) == type(typR): # if type(typL) is BoolType: # if ast.op.lower() == 'and': # return leftOprandstr + rightOperandstr + self.emit.emitANDOP(frame), BoolType() # elif ast.op.lower() == 'or': # return leftOprandstr + rightOperandstr + self.emit.emitOROP(frame), BoolType() # elif ast.op.lower() == 'andthen': # # right, typR1 = self.visit(BooleanLiteral(False), o) # # lst = leftOprandstr + right + self.emit.emitREOP('==', IntType(), frame) # lst = list() # label1 = frame.getNewLabel() # label2 = frame.getNewLabel() # lst.append(leftOprandstr) # lst.append(self.emit.emitIFFALSE(label1, frame)) # lst.append(rightOperandstr) # lst.append(self.emit.emitIFFALSE(label1, frame)) # lst.append(self.emit.emitPUSHICONST("true", frame)) # lst.append(self.emit.emitGOTO(label2,frame)) # lst.append(self.emit.emitLABEL(label1,frame)) # lst.append(self.emit.emitPUSHICONST("false", frame)) # lst.append(self.emit.emitLABEL(label2,frame)) # frame.pop() # return ''.join(lst), BoolType() # elif ast.op.lower() == 'orelse': # # right, typR1 = self.visit(BooleanLiteral(True), o) # # lst = leftOprandstr + right + self.emit.emitREOP('==', IntType(), frame) # lst = list() # label1 = frame.getNewLabel() # label2 = frame.getNewLabel() # lst.append(leftOprandstr) # lst.append(self.emit.emitIFTRUE(label1, frame)) # lst.append(rightOperandstr) # lst.append(self.emit.emitIFTRUE(label1, frame)) # lst.append(self.emit.emitPUSHICONST("false", frame)) # lst.append(self.emit.emitGOTO(label2,frame)) # lst.append(self.emit.emitLABEL(label1,frame)) # lst.append(self.emit.emitPUSHICONST("true", frame)) # lst.append(self.emit.emitLABEL(label2,frame)) # frame.pop() # return ''.join(lst), BoolType() # elif type(typL) is IntType: # if ast.op in ['+', '-']: # return leftOprandstr + rightOperandstr + self.emit.emitADDOP(ast.op, IntType(), frame), IntType() # elif ast.op == '*': # return leftOprandstr + rightOperandstr + self.emit.emitMULOP(ast.op, IntType(), frame), IntType() # elif ast.op.lower() == 'div': # return leftOprandstr + rightOperandstr + self.emit.emitDIV(frame), IntType() # elif ast.op.lower() == 'mod': # return leftOprandstr + rightOperandstr + self.emit.emitMOD(frame), IntType() # elif ast.op in ['<', '<=', '>', '>=']: # return leftOprandstr + rightOperandstr + self.emit.emitREOP(ast.op, IntType(), frame), BoolType() # elif ast.op == '<>': # return leftOprandstr + rightOperandstr + self.emit.emitREOP('!=', IntType(), frame), BoolType() # elif ast.op == '=': # return leftOprandstr + rightOperandstr + self.emit.emitREOP('==', IntType(), frame), BoolType() # elif ast.op == '/': # leftOprandstr += self.emit.emitI2F(frame) # rightOperandstr += self.emit.emitI2F(frame) # return leftOprandstr + rightOperandstr + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # elif type(typL) is FloatType: # if ast.op in ['+', '-']: # return leftOprandstr + rightOperandstr + self.emit.emitADDOP(ast.op, FloatType(), frame), FloatType() # elif ast.op == '*': # return leftOprandstr + rightOperandstr + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # elif ast.op == '/': # return leftOprandstr + rightOperandstr + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # elif ast.op in ['<', '<=', '>', '>=']: # return self.emit.emitFREOP(ast.op, leftOprandstr, rightOperandstr, frame), BoolType() # elif ast.op == '<>': # return self.emit.emitFREOP('!=', leftOprandstr, rightOperandstr, frame), BoolType() # elif ast.op == '=': # return self.emit.emitFREOP('==', leftOprandstr, rightOperandstr, frame), BoolType() # else: # if ast.op in ['+', '-']: # if type(typL) is FloatType and type(typR) is IntType: # return leftOprandstr + rightOperandstr + self.emit.emitI2F(frame) + self.emit.emitADDOP(ast.op, FloatType(), frame), FloatType() # elif type(typL) is IntType and type(typR) is FloatType: # return leftOprandstr + self.emit.emitI2F(frame) + rightOperandstr + self.emit.emitADDOP(ast.op, FloatType(), frame), FloatType() # elif ast.op == '*': # if type(typL) is FloatType and type(typR) is IntType: # return leftOprandstr + rightOperandstr + self.emit.emitI2F(frame) + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # elif type(typL) is IntType and type(typR) is FloatType: # return leftOprandstr + self.emit.emitI2F(frame) + rightOperandstr + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # else: # if type(typL) is IntType: # leftOprandstr += self.emit.emitI2F(frame) # if type(typR) is IntType: # rightOperandstr += self.emit.emitI2F(frame) # if ast.op == '/': # return leftOprandstr + rightOperandstr + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() # elif ast.op in ['<', '<=', '>', '>=']: # return self.emit.emitFREOP(ast.op, leftOprandstr, rightOperandstr, frame), BoolType() # elif ast.op == '<>': # return self.emit.emitFREOP('!=', leftOprandstr, rightOperandstr, frame), BoolType() # elif ast.op == '=': # return self.emit.emitFREOP('==', leftOprandstr, rightOperandstr, frame), BoolType() 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( '"' + ast.value + '"', StringType(), frame), StringType() #Note......................................
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 genMETHOD(self, consdecl, o: MyClass, frame): #consdecl: FuncDecl #o: Any #frame: Frame isGlobalArray = o.isGlobalArray lstDeclArray = o.lstDeclArray if isGlobalArray: # Constructor cho khai bao bien global la array returnType = VoidType() methodName = "<clinit>" intype = list() mtype = MType(intype, returnType) self.emit.printout( self.emit.emitMETHOD(methodName, mtype, True, frame)) frame.enterScope(True) for x in lstDeclArray: lexeme = self.className + "." + x.variable.name self.emit.printout( self.emit.emitINITARRAY(lexeme, x.varType, frame)) self.emit.printout(self.emit.emitRETURN(returnType, frame)) self.emit.printout(self.emit.emitENDMETHOD(frame)) # if frame.getStackSize() != 0: # print(methodName) frame.exitScope() else: 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( map(lambda x: x.varType, consdecl.param)) mtype = MType(intype, returnType) self.emit.printout( self.emit.emitMETHOD(methodName, mtype, not isInit, frame)) frame.enterScope(True) glenv = o.sym # Generate code for parameter declarations # danh sach cac array trong parameter declarations lstArrayParam = list() if isInit: idx = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(idx, "this", ClassType(self.className), frame.getStartLabel(), frame.getEndLabel(), frame)) elif isMain: idx = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(idx, "args", ArrayPointerType(StringType()), frame.getStartLabel(), frame.getEndLabel(), frame)) glenv.insert( 0, Symbol("args", ArrayPointerType(StringType()), Index(idx))) else: # Sinh ma cho parameter declarations e = SubBody(frame, glenv) for x in consdecl.param: e = self.visit(x, e) glenv = e.sym if type(x.varType) is ArrayType: lstArrayParam.append(glenv[0]) if not isInit: # Sinh ma cho local declarations e = SubBody(frame, glenv) for x in consdecl.local: e = self.visit(x, e) glenv = e.sym if type(x.varType) is ArrayType: idx = glenv[0].value.value self.emit.printout( self.emit.emitINITARRAY(idx, x.varType, frame)) self.emit.printout( self.emit.emitLABEL(frame.getStartLabel(), frame)) # Sao chep array tu param vao mot array moi for x in lstArrayParam: self.emit.printout( self.emit.emitCOPPYARRAY(x.value.value, x.mtype, frame)) if isInit: self.emit.printout( self.emit.emitREADVAR("this", ClassType(self.className), 0, frame)) self.emit.printout(self.emit.emitINVOKESPECIAL(frame)) # visit than ham list( map(lambda x: self.visit(x, SubBody(frame, glenv)), consdecl.body)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) self.emit.printout(self.emit.emitRETURN(returnType, frame)) self.emit.printout(self.emit.emitENDMETHOD(frame)) # if frame.getStackSize() != 0: # print(methodName) frame.exitScope() 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 cac bien array trong global lstArray = list() ## Them global declarations vao self.env for x in ast.decl: if type(x) is VarDecl: e = self.visit(x, e) self.env = e.sym if type(x.varType) is ArrayType: lstArray.append(x) else: self.env.insert( 0, Symbol( x.name.name, MType(list(map(lambda y: y.varType, x.param)), x.returnType), CName(self.className))) ## visit toi funcdecl for x in ast.decl: if type(x) is FuncDecl: e = self.visit(x, e) # generate default constructor self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), MyClass(c, False, list()), Frame("<init>", VoidType)) # Constructor cho array if len(lstArray) > 0: self.genMETHOD( FuncDecl(Id("<clinit>"), list(), list(), list(), None), MyClass(c, True, lstArray), Frame("<clinit>", VoidType)) self.emit.emitEPILOG() return c # Declaration def visitFuncDecl(self, ast, o): #o: SubBody #ast.name: Id #ast.param: list(VarDecl) #ast.returnType: Type => VoidType for Procedure #ast.local: list(VarDecl) #ast.body: list(Stmt) subctxt = o frame = Frame(ast.name.name, ast.returnType) self.genMETHOD(ast, MyClass(subctxt.sym, False, list()), frame) # return SubBody(None, [Symbol(ast.name, MType(list(), ast.returnType), CName(self.className))] + subctxt.sym) return SubBody(None, subctxt.sym) def visitVarDecl(self, ast, o): #ast: VarDecl #o: SubBody #ast.variable: Id #ast.varType: Type subctxt = o frame = subctxt.frame mtype = ast.varType name = ast.variable.name if frame is None: # Decl mot bien global self.emit.printout(self.emit.emitATTRIBUTE(name, mtype, False, "")) return SubBody(None, [Symbol(name, mtype, CName(self.className))] + subctxt.sym) else: # Decl mot bien local hoac param idx = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(idx, name, mtype, frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody(frame, [Symbol(name, mtype, Index(idx))] + subctxt.sym) # Statement # o.frame: Frame # o.sym: List[Symbol] def visitAssign(self, ast, o): #o: Any #ast.lhs: Expr #ast.exp: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym if type(ast.lhs) is ArrayCell: # gan mot gia tri cho mot index expression. lc, lt = self.visit(ast.lhs, Access(frame, nenv, True, True)) self.emit.printout(lc) rc, rt = self.visit(ast.exp, Access(frame, nenv, False, True)) self.emit.printout(rc) if type(lt) != type(rt): self.emit.printout(self.emit.emitI2F(frame)) self.emit.printout(self.emit.emitASTORE(lt, frame)) else: # gan mot gia tri cho mot bien rc, rt = self.visit(ast.exp, Access(frame, nenv, False, True)) lc, lt = self.visit(ast.lhs, Access(frame, nenv, True, True)) if type(rt) is IntType and type(lt) is FloatType: rc += self.emit.emitI2F(frame) self.emit.printout(rc + lc) def visitIf(self, ast, o): #o:any #ast.expr:Expr #ast.thenStmt:list(Stmt) #ast.elseStmt:list(Stmt) ctxt = o frame = ctxt.frame nenv = ctxt.sym # Kiem tra dieu kien expr, _ = self.visit(ast.expr, Access(frame, nenv, False, True)) self.emit.printout(expr) # label sai label1 = frame.getNewLabel() # label dung label2 = None if len(ast.elseStmt) != 0: label2 = frame.getNewLabel() # Neu dieu kien sai thi nhay toi label1 self.emit.printout(self.emit.emitIFFALSE(label1, frame)) list(map(lambda x: self.visit(x, o), ast.thenStmt)) if len(ast.elseStmt) != 0: self.emit.printout(self.emit.emitGOTO(label2, frame)) self.emit.printout(self.emit.emitLABEL(label1, frame)) if len(ast.elseStmt) != 0: list(map(lambda x: self.visit(x, o), ast.elseStmt)) self.emit.printout(self.emit.emitLABEL(label2, frame)) def visitWhile(self, ast, o): #o: any #ast.sl: list(Stmt) #ast.exp: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym frame.enterLoop() labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() self.emit.printout(self.emit.emitLABEL(labelContinue, frame)) expr, _ = self.visit(ast.exp, Access(frame, nenv, False, True)) self.emit.printout(expr) self.emit.printout(self.emit.emitIFFALSE(labelBreak, frame)) list(map(lambda x: self.visit(x, o), ast.sl)) self.emit.printout(self.emit.emitGOTO(labelContinue, frame)) self.emit.printout(self.emit.emitLABEL(labelBreak, frame)) frame.exitLoop() def visitFor(self, ast, o): #o:any #ast.id: Id #ast.expr1,expr2: Expr #ast.loop: list(Stmt) #ast.up: Boolean #True => increase; False => decrease ctxt = o frame = ctxt.frame nenv = ctxt.sym label1 = frame.getNewLabel() frame.enterLoop() accessT = Access(frame, nenv, True, True) accessF = Access(frame, nenv, False, True) # Gan gia tri expr1 cho id expr1, _ = self.visit(ast.expr1, accessF) id1, _ = self.visit(ast.id, accessT) self.emit.printout(expr1) self.emit.printout(id1) # In ra label 1 self.emit.printout(self.emit.emitLABEL(label1, frame)) labelContinue = frame.getContinueLabel() labelBreak = frame.getBreakLabel() if ast.up is True: id1, _ = self.visit(ast.id, accessF) self.emit.printout(id1) expr2, _ = self.visit(ast.expr2, accessF) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFICMPGT(labelBreak, frame)) else: id1, _ = self.visit(ast.id, accessF) self.emit.printout(id1) expr2, _ = self.visit(ast.expr2, accessF) self.emit.printout(expr2) self.emit.printout(self.emit.emitIFICMPLT(labelBreak, frame)) list(map(lambda x: self.visit(x, o), ast.loop)) self.emit.printout(self.emit.emitLABEL(labelContinue, frame)) if ast.up is True: # i + 1 dat len stack expr, _ = self.visit(BinaryOp('+', ast.id, IntLiteral(1)), accessF) # Gan gia tri tren stack vao Id id2, _ = self.visit(ast.id, accessT) self.emit.printout(expr) self.emit.printout(id2) else: # i - 1 dat len stack expr, _ = self.visit(BinaryOp('-', ast.id, IntLiteral(1)), accessF) # Gan gia tri tren stack vao id id2, _ = self.visit(ast.id, accessT) self.emit.printout(expr) self.emit.printout(id2) # quay lai label1 self.emit.printout(self.emit.emitGOTO(label1, frame)) self.emit.printout(self.emit.emitLABEL(labelBreak, frame)) frame.exitLoop() def visitBreak(self, ast, o): #o:any ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getBreakLabel(), frame)) def visitContinue(self, ast, o): #o:any ctxt = o frame = ctxt.frame self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame)) def visitReturn(self, ast, o): #o:any #ast.expr: Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym if ast.expr is not None: str1, typ1 = self.visit(ast.expr, Access(frame, nenv, False, True)) if type(typ1) is IntType and type(frame.returnType) is FloatType: str1 += self.emit.emitI2F(frame) self.emit.printout(str1) self.emit.printout(self.emit.emitGOTO(frame.getEndLabel(), frame)) def visitWith(self, ast, o): #o:any #ast.decl: list(VarDecl) #ast.stmt: list(Stmt) ctxt = o frame = ctxt.frame glenv = ctxt.sym frame.enterScope(False) e = SubBody(frame, glenv) for x in ast.decl: e = self.visit(x, e) glenv = e.sym if type(x.varType) is ArrayType: idx = glenv[0].value.value self.emit.printout( self.emit.emitINITARRAY(idx, x.varType, frame)) e = SubBody(frame, glenv) body = ast.stmt self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) list(map(lambda x: self.visit(x, e), body)) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() def visitCallStmt(self, ast, o): #o: Any #ast.method: Id #ast.param: list(Expr) 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 access = Access(frame, nenv, False, True) for i in range(len(ast.param)): str1, typ1 = self.visit(ast.param[i], access) if type(typ1) is IntType and type( sym.mtype.partype[i]) is FloatType: str1 += self.emit.emitI2F(frame) self.emit.printout(str1) self.emit.printout( self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame)) # Expression #o.frame: Frame #o.sym: List[Symbol] #o.isLeft: Boolean #o.isFirst: Boolean def visitBinaryOp(self, ast, o): #o: any #ast.op:string: AND THEN => andthen; OR ELSE => orelse; other => keep it #ast.left:Expr #ast.right:Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym leftOprandstr, typL = self.visit(ast.left, Access(frame, nenv, False, True)) rightOperandstr, typR = self.visit(ast.right, Access(frame, nenv, False, True)) if type(typL) == type(typR): if type(typL) is BoolType: if ast.op.lower() == 'and': return leftOprandstr + rightOperandstr + self.emit.emitANDOP( frame), BoolType() elif ast.op.lower() == 'or': return leftOprandstr + rightOperandstr + self.emit.emitOROP( frame), BoolType() elif ast.op.lower() == 'andthen': lst = list() label1 = frame.getNewLabel() label2 = frame.getNewLabel() lst.append(leftOprandstr) lst.append(self.emit.emitIFFALSE(label1, frame)) lst.append(rightOperandstr) lst.append(self.emit.emitIFFALSE(label1, frame)) lst.append(self.emit.emitPUSHICONST("true", frame)) lst.append(self.emit.emitGOTO(label2, frame)) lst.append(self.emit.emitLABEL(label1, frame)) lst.append(self.emit.emitPUSHICONST("false", frame)) lst.append(self.emit.emitLABEL(label2, frame)) frame.pop() return ''.join(lst), BoolType() elif ast.op.lower() == 'orelse': lst = list() label1 = frame.getNewLabel() label2 = frame.getNewLabel() label3 = frame.getNewLabel() lst.append(leftOprandstr) lst.append(self.emit.emitIFNE(label1, frame)) lst.append(rightOperandstr) lst.append(self.emit.emitIFEQ(label2, frame)) lst.append(self.emit.emitLABEL(label1, frame)) lst.append(self.emit.emitPUSHICONST("true", frame)) lst.append(self.emit.emitGOTO(label3, frame)) lst.append(self.emit.emitLABEL(label2, frame)) lst.append(self.emit.emitPUSHICONST("false", frame)) lst.append(self.emit.emitLABEL(label3, frame)) frame.pop() return ''.join(lst), BoolType() elif type(typL) is IntType: if ast.op in ['+', '-']: return leftOprandstr + rightOperandstr + self.emit.emitADDOP( ast.op, IntType(), frame), IntType() elif ast.op == '*': return leftOprandstr + rightOperandstr + self.emit.emitMULOP( ast.op, IntType(), frame), IntType() elif ast.op.lower() == 'div': return leftOprandstr + rightOperandstr + self.emit.emitDIV( frame), IntType() elif ast.op.lower() == 'mod': return leftOprandstr + rightOperandstr + self.emit.emitMOD( frame), IntType() elif ast.op in ['<', '<=', '>', '>=']: return leftOprandstr + rightOperandstr + self.emit.emitREOP( ast.op, IntType(), frame), BoolType() elif ast.op == '<>': return leftOprandstr + rightOperandstr + self.emit.emitREOP( '!=', IntType(), frame), BoolType() elif ast.op == '=': return leftOprandstr + rightOperandstr + self.emit.emitREOP( '==', IntType(), frame), BoolType() elif ast.op == '/': leftOprandstr += self.emit.emitI2F(frame) rightOperandstr += self.emit.emitI2F(frame) return leftOprandstr + rightOperandstr + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif type(typL) is FloatType: if ast.op in ['+', '-']: return leftOprandstr + rightOperandstr + self.emit.emitADDOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '*': return leftOprandstr + rightOperandstr + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '/': return leftOprandstr + rightOperandstr + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['<', '<=', '>', '>=']: return self.emit.emitFREOP(ast.op, leftOprandstr, rightOperandstr, frame), BoolType() elif ast.op == '<>': return self.emit.emitFREOP('!=', leftOprandstr, rightOperandstr, frame), BoolType() elif ast.op == '=': return self.emit.emitFREOP('==', leftOprandstr, rightOperandstr, frame), BoolType() else: if ast.op in ['+', '-']: if type(typL) is FloatType and type(typR) is IntType: return leftOprandstr + rightOperandstr + self.emit.emitI2F( frame) + self.emit.emitADDOP(ast.op, FloatType(), frame), FloatType() elif type(typL) is IntType and type(typR) is FloatType: return leftOprandstr + self.emit.emitI2F( frame) + rightOperandstr + self.emit.emitADDOP( ast.op, FloatType(), frame), FloatType() elif ast.op == '*': if type(typL) is FloatType and type(typR) is IntType: return leftOprandstr + rightOperandstr + self.emit.emitI2F( frame) + self.emit.emitMULOP(ast.op, FloatType(), frame), FloatType() elif type(typL) is IntType and type(typR) is FloatType: return leftOprandstr + self.emit.emitI2F( frame) + rightOperandstr + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() else: if type(typL) is IntType: leftOprandstr += self.emit.emitI2F(frame) if type(typR) is IntType: rightOperandstr += self.emit.emitI2F(frame) if ast.op == '/': return leftOprandstr + rightOperandstr + self.emit.emitMULOP( ast.op, FloatType(), frame), FloatType() elif ast.op in ['<', '<=', '>', '>=']: return self.emit.emitFREOP(ast.op, leftOprandstr, rightOperandstr, frame), BoolType() elif ast.op == '<>': return self.emit.emitFREOP('!=', leftOprandstr, rightOperandstr, frame), BoolType() elif ast.op == '=': return self.emit.emitFREOP('==', leftOprandstr, rightOperandstr, frame), BoolType() def visitUnaryOp(self, ast, o): #o:any #ast.op: string #ast.body: Exprs ctxt = o frame = ctxt.frame nenv = ctxt.sym body, typ = self.visit(ast.body, Access(frame, nenv, False, True)) if ast.op.lower() == 'not' and type(typ) is BoolType: return body + self.emit.emitNOT(IntType(), frame), BoolType() elif ast.op == '-' and type(typ) is IntType: return body + self.emit.emitNEGOP(IntType(), frame), IntType() elif ast.op == '-' and type(typ) is FloatType: return body + self.emit.emitNEGOP(FloatType(), frame), FloatType() def visitCallExpr(self, ast, o): #o:any #ast.method: Id #ast.param: list(Expr) 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 lst = list() access = Access(frame, nenv, False, True) for i in range(len(ast.param)): str1, typ1 = self.visit(ast.param[i], access) if type(typ1) is IntType and type( sym.mtype.partype[i]) is FloatType: str1 += self.emit.emitI2F(frame) lst.append(str1) lst.append( self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame)) return ''.join(lst), sym.mtype.rettype # LHS def visitId(self, ast, o): #o:any #ast.name: string sym = self.lookup(ast.name.lower(), o.sym, lambda x: x.name.lower()) typ = sym.mtype if o.isLeft: if type(sym.value) is CName: return self.emit.emitPUTSTATIC( sym.value.value + "/" + sym.name, typ, o.frame), typ else: return self.emit.emitWRITEVAR(sym.name, typ, sym.value.value, o.frame), typ else: if type(sym.value) is CName: return self.emit.emitGETSTATIC( sym.value.value + "/" + sym.name, typ, o.frame), typ else: return self.emit.emitREADVAR(sym.name, typ, sym.value.value, o.frame), typ def visitArrayCell(self, ast, o): #o:any #ast.arr:Expr #ast.idx:Expr ctxt = o frame = ctxt.frame nenv = ctxt.sym lst = list() arr, typeArr = self.visit(ast.arr, Access(frame, nenv, False, True)) idx, typeIdx = self.visit(ast.idx, Access(frame, nenv, False, True)) typ = typeArr.eleType lst.append(arr) lst.append(idx) lst.append(self.emit.emitPUSHICONST(typeArr.lower, frame)) lst.append(self.emit.emitADDOP('-', IntType(), frame)) if not o.isLeft: lst.append(self.emit.emitALOAD(typ, frame)) return ''.join(lst), typ # Literal def visitIntLiteral(self, ast, o): #o: Any #ast.value:int ctxt = o frame = ctxt.frame return self.emit.emitPUSHCONST(ast.value, IntType(), frame), IntType() def visitFloatLiteral(self, ast, o): #o:any #ast.value:float ctxt = o frame = ctxt.frame return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType() def visitBooleanLiteral(self, ast, o): #o:any #ast.value:boolean ctxt = o frame = ctxt.frame return self.emit.emitPUSHCONST( str(ast.value).lower(), IntType(), frame), BoolType() def visitStringLiteral(self, ast, o): #o:any #ast.value:string 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 # 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 = "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) fun_ref = list(filter(lambda x: isinstance(x, FuncDecl), ast.decl)) e.frame = Frame(None, None) for fun in fun_ref: self.visit(fun, 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 if isMain: intype = [ArrayPointerType(StringType())] else: intype = [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)) if glenv is None: glenv = [] s = SubBody(frame, glenv) for x in consdecl.param: s = self.visit(x, s) for x in consdecl.local: s = self.visit(x, s) 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)) # visit stmt => dont return list(map(lambda x: self.visit(x, s), body)) self.emit.printout(self.emit.jvm.INDENT + 'nop' + self.emit.jvm.END) 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.jvm.INDENT + 'nop' + self.emit.jvm.END) pass self.emit.printout(self.emit.emitENDMETHOD(frame)) frame.exitScope() def visitFuncDecl(self, ast, o): #ast: FuncDecl #o: Any subctxt = o frame = subctxt.frame if frame is not None: frame = Frame(ast.name.name, ast.returnType) self.genMETHOD(ast, subctxt.sym, frame) else: return SubBody(None, [ Symbol(ast.name.name, MType([x.varType for x in ast.param], ast.returnType), CName(self.className)) ] + subctxt.sym) def visitVarDecl(self, ast, o): subctxt = o frame = subctxt.frame if frame is None: self.emit.printout( self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False, "")) return SubBody(None, [ Symbol(ast.variable.name, ast.varType, CName(self.className)) ] + subctxt.sym) else: index = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(index, ast.variable.name, ast.varType, frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody( frame, [Symbol(ast.variable.name, ast.varType, Index(index))] + subctxt.sym) 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 # model params = ctype.partype in_ = ("", list()) for i, arg in enumerate(ast.param): ''' arg: Expr ''' str1, typ1 = self.visit(arg, Access(frame, nenv, False, True)) if isinstance(typ1, MType): if not isinstance(typ1.rettype, type(params[i])): str1 = str1 + self.emit.emitI2F(frame) elif not isinstance(typ1, type(params[i])): str1 = str1 + self.emit.emitI2F(frame) in_ = (in_[0] + str1, in_[1] + [typ1]) return in_[0] + (self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame)), ctype 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 # model params = ctype.partype params = ctype.partype in_ = ("", list()) for i, arg in enumerate(ast.param): ''' arg: Expr ''' str1, typ1 = self.visit(arg, Access(frame, nenv, False, True)) if isinstance(typ1, MType): if not isinstance(typ1.rettype, type(params[i])): str1 = str1 + self.emit.emitI2F(frame) elif not isinstance(typ1, type(params[i])): str1 = str1 + self.emit.emitI2F(frame) in_ = (in_[0] + str1, in_[1] + [typ1]) self.emit.printout(in_[0]) self.emit.printout( self.emit.emitINVOKESTATIC(cname + "/" + sym.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: FloatLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHFCONST(str(ast.value), frame), FloatType() def visitStringLiteral(self, ast, o): #ast: FloatLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHCONST('"' + ast.value + '"', StringType(), frame), StringType() def visitBooleanLiteral(self, ast, o): #ast: FloatLiteral #o: Any ctxt = o frame = ctxt.frame return self.emit.emitPUSHICONST(str(ast.value).lower(), frame), BoolType() def visitAssign(self, ast, o): #lhs:Expr #exp:Expr #frame: Frame #sym: List[Symbol] subctxt = o frame = subctxt.frame sym = subctxt.sym # input(ast.exp) # input(ast.lhs) exp, type_exp = self.visit(ast.exp, Access(frame, sym, False, True)) lhs, type_lhs = self.visit(ast.lhs, Access(frame, sym, True, True)) if isinstance(type_exp, MType): type_exp = type_exp.rettype if not isinstance(type_exp, type(type_lhs)): exp = exp + self.emit.emitI2F(frame) self.emit.printout(exp + lhs) def visitId(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym isLeft = subctxt.isLeft res = self.lookup(ast.name.lower(), sym, lambda env: env.name.lower()) # res = symbol(,,Cname) if res is None: return None, None if isLeft is True: if isinstance(res.value, CName): varname = res.value.value + '/' + res.name code = self.emit.emitPUTSTATIC(varname, res.mtype, frame) else: code = self.emit.emitWRITEVAR(res.name, res.mtype, res.value.value, frame) else: if isinstance(res.value, CName): varname = res.value.value + '/' + res.name code = self.emit.emitGETSTATIC(varname, res.mtype, frame) else: code = self.emit.emitREADVAR(res.name, res.mtype, res.value.value, frame) return code, res.mtype def visitBinaryOp(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym left, type_left = self.visit(ast.left, Access(frame, sym, False, True)) right, type_right = self.visit(ast.right, Access(frame, sym, False, True)) #input(ast.right) op = ast.op.lower() if isinstance(type_left, MType): type_left = type_left.rettype if isinstance(type_right, MType): type_right = type_right.rettype if not isinstance(type_left, type(type_right)): if isinstance(type_left, FloatType): right = right + self.emit.emitI2F(frame) type_right = FloatType() else: left = left + self.emit.emitI2F(frame) type_left = FloatType() if op in ["+", "-"]: code = left + right + self.emit.emitADDOP(op, type_left, frame) elif op in ["*"]: code = left + right + self.emit.emitMULOP(op, type_left, frame) elif op in ["/"]: if isinstance(type_left, IntType): left = left + self.emit.emitI2F(frame) right = right + self.emit.emitI2F(frame) type_left = FloatType() type_right = FloatType() code = left + right + self.emit.emitMULOP(op, type_left, frame) elif op in ["<=", ">=", "=", ">", "<", "<>"]: code = left + right + self.emit.emitREOP(op, type_left, frame) return code, BoolType() elif op == "or": code = left + right + self.emit.emitOROP(frame) elif op == "and": code = left + right + self.emit.emitANDOP(frame) elif op == "div": code = left + right + self.emit.emitDIV(frame) elif op == "mod": code = left + right + self.emit.emitMOD(frame) # and then, or else elif op == "andthen": falseLabel = frame.getNewLabel() endLabel = frame.getNewLabel() code = '' code = code + left # if left = 0 False code = code + self.emit.emitIFEQ(falseLabel, frame) code = code + right code = code + self.emit.emitIFEQ(falseLabel, frame) code = code + self.emit.emitPUSHICONST(1, frame) code = code + self.emit.emitGOTO(endLabel, frame) code = code + self.emit.emitLABEL(falseLabel, frame) code = code + self.emit.emitPUSHICONST(0, frame) code = code + self.emit.emitLABEL(endLabel, frame) type_left = BoolType() elif op == "orelse": trueLabel = frame.getNewLabel() endLabel = frame.getNewLabel() code = '' code = code + left code = code + self.emit.emitIFNE(trueLabel, frame) code = code + right code = code + self.emit.emitIFNE(trueLabel, frame) code = code + self.emit.emitPUSHICONST(0, frame) code = code + self.emit.emitGOTO(endLabel, frame) code = code + self.emit.emitLABEL(trueLabel, frame) code = code + self.emit.emitPUSHICONST(1, frame) code = code + self.emit.emitLABEL(endLabel, frame) type_left = BoolType() return code, type_left def visitUnaryOp(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym body, type_body = self.visit(ast.body, Access(frame, sym, False, True)) op = ast.op.lower() if op == "not": code = body + self.emit.emitNOT(type_body, frame) else: code = body + self.emit.emitNEGOP(type_body, frame) return code, type_body def visitIf(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym exp, type_exp = self.visit(ast.expr, Access(frame, sym, False, True)) self.emit.printout(exp) label1 = frame.getNewLabel() label2 = frame.getNewLabel() self.emit.printout(self.emit.emitIFEQ(label1, frame)) for x in ast.thenStmt: self.visit(x, SubBody(frame, sym)) self.emit.printout(self.emit.emitGOTO(label2, frame)) self.emit.printout(self.emit.emitLABEL(label1, frame)) for x in ast.elseStmt: self.visit(x, SubBody(frame, sym)) self.emit.printout(self.emit.emitLABEL(label2, frame)) def visitWhile(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym frame.enterLoop() breakLabel = frame.getBreakLabel() continueLabel = frame.getContinueLabel() self.emit.printout(self.emit.emitLABEL(continueLabel, frame)) exp, type_exp = self.visit(ast.exp, Access(frame, sym, False, True)) self.emit.printout(exp) self.emit.printout(self.emit.emitIFEQ(breakLabel, frame)) for x in ast.sl: self.visit(x, SubBody(frame, sym)) self.emit.printout(self.emit.emitGOTO(continueLabel, frame)) self.emit.printout(self.emit.emitLABEL(breakLabel, frame)) frame.exitLoop() def visitFor(self, ast, o): # if ast.up is False: # condition = BinaryOp(">=", ast.id, ast.expr2) # else: # condition = BinaryOp("<=", ast.id, ast.expr2) # self.visit(Assign(ast.id, ast.expr1), o) # increment = BinaryOp(inrop, ast.id, IntLiteral(1)) # loop = ast.loop[:] + [increment] # self.visit(While(condition, loop), o) subctxt = o frame = subctxt.frame sym = subctxt.sym frame.enterLoop() breakLabel = frame.getBreakLabel() startLabel = frame.getNewLabel() continueLabel = frame.getContinueLabel() expr1 = ast.expr1 self.visit(Assign(ast.id, expr1), o) self.emit.printout(self.emit.emitLABEL(startLabel, frame)) if ast.up is False: exp, type_exp = self.visit(BinaryOp(">=", ast.id, ast.expr2), o) else: exp, type_exp = self.visit(BinaryOp("<=", ast.id, ast.expr2), o) self.emit.printout(exp) self.emit.printout(self.emit.emitIFEQ(breakLabel, frame)) for x in ast.loop: self.visit(x, SubBody(frame, sym)) self.emit.printout(self.emit.emitGOTO(continueLabel, frame)) #tang giam 1 self.emit.printout(self.emit.emitLABEL(continueLabel, frame)) if ast.up is False: expr1 = BinaryOp("-", ast.id, IntLiteral(1)) else: expr1 = BinaryOp("+", ast.id, IntLiteral(1)) # input(expr1) #self.emit.printout(expr1) self.visit(Assign(ast.id, expr1), o) self.emit.printout(self.emit.emitGOTO(startLabel, frame)) self.emit.printout(self.emit.emitLABEL(breakLabel, frame)) frame.exitLoop() def visitWith(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym frame.enterScope(False) s = SubBody(frame, sym[:]) for x in ast.decl: s = self.visit(x, s) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) for x in ast.stmt: self.visit(x, s) self.emit.printout(self.emit.emitLABEL(frame.getEndLabel(), frame)) frame.exitScope() def visitReturn(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym code = '' if ast.expr: exp, type_exp = self.visit(ast.expr, Access(frame, sym, False, True)) code += exp if not isinstance(type_exp, type(frame.returnType)): # func returns Float, while "return Int" # other cases, checker code += self.emit.emitI2F(frame) code += self.emit.emitRETURN(frame.returnType, frame) self.emit.printout(code) def visitBreak(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym breakLabel = frame.getBreakLabel() self.emit.printout(self.emit.emitGOTO(breakLabel, frame)) def visitContinue(self, ast, o): subctxt = o frame = subctxt.frame sym = subctxt.sym continueLabel = frame.getContinueLabel() self.emit.printout(self.emit.emitGOTO(continueLabel, frame))
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): 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 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 and x.name.name == 'main': self.paramMain = x.param staticDecl = [ Symbol(x.name.name, MType([], VoidType()), CName(self.className)) ] + staticDecl elif type(x) is VarDecl: newSym = self.visit(x, SubBody(None, None, isGlobal=True)) staticDecl = [newSym] + staticDecl else: self.function.append(x) self.inferType = staticDecl.copy() e = SubBody(None, staticDecl) [ self.visit(x, e) for x in ast.decl if type(x) is FuncDecl and x.name.name == 'main' ] for x in self.visitFunc: staticDecl = [ Symbol(x.name.name, x.param[1], CName(self.className)) ] + staticDecl self.visit(x, SubBody(None, staticDecl)) self.emit.emitEPILOG() return c def inferReturn(self, func, scope): param = [ Symbol(func.param[0][i], func.param[1].partype[i]) for i in range(len(func.param[0])) ] scope += param for x in func.body[0]: scope.append(Symbol(x.variable.name, self.getTypeVar(x.varInit))) for x in func.body[1]: if type(x) is Return: typ = Utils.getSymbol(scope[::-1], x.expr) if typ is not None: return typ.mtype else: return Utils.getArrayType(x.expr) if type(x) is If: for i in x.ifthenStmt: for j in i[1]: scope.append( Symbol(j.variable.name, self.getTypeVar(j.varInit))) if len(i[2]) > 0 and type(i[2][-1]) is Return: typ = Utils.getSymbol(scope[::-1], i[2][-1].expr) if typ is not None: return typ.mtype else: return Utils.getArrayType(i[2][-1].expr) def visitVarDecl(self, ast, o): frame = o.frame isGlobal = o.isGlobal varName = ast.variable.name varType = self.getTypeVar(ast.varInit) if isGlobal: self.emit.printout( self.emit.emitATTRIBUTE(varName, Utils.retrieveType(varType), False, "")) if type(varType) is ArrayType: self.listGlobalArray.append(ast) return Symbol(varName, varType, val=ast.varInit, isGlobal=True) idx = frame.getNewIndex() self.emit.printout( self.emit.emitVAR(idx, varName, Utils.retrieveType(varType), frame.getStartLabel(), frame.getEndLabel(), frame)) return SubBody( frame, [Symbol(varName, varType, Index(idx), val=ast.varInit)] + o.sym) def getTypeVar(self, x): if type(x) is IntLiteral: return IntType() elif type(x) is FloatLiteral: return FloatType() elif type(x) is BooleanLiteral: return BoolType() elif type(x) is StringLiteral: return StringType() elif type(x) is ArrayLiteral: return Utils.getArrayType(x) def visitFuncDecl(self, ast, o): ret = Utils.getSymbol(o.sym, ast.name.name) frame = Frame(ast.name.name, ret) self.genMETHOD(ast, o.sym, frame) def genMETHOD(self, decl, o, frame): glenv = o methodName = decl.name.name returnType = Utils.getSymbol(o, decl.name.name).mtype.rettype if methodName == "main": returnType = VoidType() isMain = methodName == "main" isProc = type(returnType) is VoidType intype = [ArrayType(StringType(), []) ] if isMain else decl.param[1].partype mtype = MType(intype, returnType) self.emit.printout(self.emit.emitMETHOD(methodName, mtype, True, frame)) frame.enterScope(isProc) if isMain: self.emit.printout( self.emit.emitVAR(frame.getNewIndex(), "args", StringType(), frame.getStartLabel(), frame.getEndLabel(), frame)) listLocalArray = [] varList = SubBody(frame, glenv) if not isMain: for i in range(len(decl.param[0])): idx = varList.frame.getNewIndex() self.emit.printout( self.emit.emitVAR( idx, decl.param[0][i], Utils.retrieveType(decl.param[1].partype[i]), varList.frame.getStartLabel(), varList.frame.getEndLabel(), varList.frame)) varList = SubBody(varList.frame, [ Symbol(decl.param[0][i], decl.param[1].partype[i], Index(idx)) ] + varList.sym) for x in decl.body[0]: varList = self.visit(x, varList) if type(self.getTypeVar(x.varInit)) is ArrayType: listLocalArray.append(varList.sym[0]) self.emit.printout(self.emit.emitLABEL(frame.getStartLabel(), frame)) if isMain: for x in self.listGlobalArray: arr = Utils.getArrayType(x.varInit) size = 1 for i in arr.dimen: size *= i self.emit.printout( self.emit.emitInitNewStaticArray( self.className + "/" + x.variable.name, size, arr.eleType, frame)) for sym in listLocalArray: arr = sym.mtype size = 1 for i in arr.dimen: size *= i self.emit.printout( self.emit.emitInitNewLocalArray(sym.value.value, size, arr.eleType, frame)) visitSym = [] for x in varList.sym: if x.val and x.name not in visitSym: if not isMain and x.isGlobal: continue visitSym.append(x.name) self.visit(Assign(Id(x.name), x.val), varList) list(map(lambda x: self.visit(x, varList), decl.body[1])) 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 visitCallStmt(self, ast, o): self.handleCall(ast, o.frame, o.sym, isStmt=True) def handleCall(self, ast, frame, symbols, isStmt=False, typ=VoidType()): sym = Utils.lookup(ast.method.name, symbols, lambda x: x.name) paramsCode = "" idx = 0 parType = [] for i in range(len(ast.param)): if sym: pCode, pType = self.visit( ast.param[i], Access(frame, symbols, False, True, typ=sym.mtype.partype[i])) else: pCode, pType = self.visit( ast.param[i], Access(frame, symbols, False, True, typ=typ)) paramsCode = paramsCode + pCode parType.append(pType) idx = idx + 1 ctype = MType(parType, IntType()) if type(typ) is BoolType else MType( parType, typ) code = "" if sym is None: for i in self.function: if i.name.name == ast.method.name and not Utils.lookup( i.name.name, self.visitFunc, lambda x: x.name.name): varD = [j.variable.name for j in i.param] if type(ctype.rettype) is ArrayType: typFunc = self.inferReturn( FuncDecl(i.name, (varD, ctype), i.body), symbols) ctype = MType(parType, typFunc) self.visitFunc.append( FuncDecl(i.name, (varD, ctype), i.body)) code = paramsCode + self.emit.emitINVOKESTATIC( self.className + "/" + ast.method.name, ctype, frame) else: ctype = sym.mtype code = paramsCode + self.emit.emitINVOKESTATIC( sym.value.value + "/" + sym.name, ctype, frame) if isStmt: self.emit.printout(code) else: return code, ctype.rettype def visitReturn(self, ast, o): frame = o.frame nenv = o.sym retType = frame.returnType.mtype.rettype if not type(retType) is VoidType: expCode, expType = self.visit( ast.expr, Access(frame, nenv, False, True, typ=retType)) self.emit.printout(expCode) self.emit.printout(self.emit.emitRETURN(retType, frame)) return True def visitIf(self, ast, o): frame = o.frame nenv = o.sym labelE = frame.getNewLabel() hasReturnStmt = False for ele in ast.ifthenStmt: expCode, expType = self.visit( ele[0], Access(frame, nenv, False, True, typ=BoolType())) labelF = frame.getNewLabel() self.emit.printout(expCode) self.emit.printout(self.emit.emitIFFALSE(labelF, frame)) newScope = o for x in ele[1]: newScope = self.visit(x, newScope) for x in ele[1]: self.visit(Assign(Id(x.variable.name), x.varInit), newScope) hasReturnStmt = True in [self.visit(x, newScope) for x in ele[2]] if len(ele[2]) == 0 or type(ele[2][-1]) is not Return: self.emit.printout(self.emit.emitGOTO(labelE, frame)) self.emit.printout(self.emit.emitLABEL(labelF, frame)) newScope = o for x in ast.elseStmt[0]: newScope = self.visit(x, newScope) for x in ast.elseStmt[0]: self.visit(Assign(Id(x.variable.name), x.varInit), newScope) hasReturnStmt = True in [ self.visit(x, newScope) for x in ast.elseStmt[1] ] self.emit.printout(self.emit.emitLABEL(labelE, frame)) return hasReturnStmt def visitWhile(self, ast, o): frame = o.frame nenv = o.sym expCode, expType = self.visit( ast.exp, Access(frame, nenv, False, True, typ=BoolType())) labelS = frame.getNewLabel() labelE = frame.getNewLabel() frame.enterLoop() self.emit.printout(self.emit.emitLABEL(labelS, frame)) self.emit.printout(expCode) self.emit.printout(self.emit.emitIFFALSE(labelE, frame)) newScope = o for x in ast.sl[0]: newScope = self.visit(x, newScope) for x in ast.sl[0]: self.visit(Assign(Id(x.variable.name), x.varInit), newScope) hasReturnStmt = True in [self.visit(x, newScope) for x in ast.sl[1]] self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) if not hasReturnStmt: 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, o): frame = o.frame nenv = o.sym expCode, _ = self.visit( ast.exp, Access(frame, nenv, False, True, typ=BoolType())) labelS = frame.getNewLabel() labelE = frame.getNewLabel() frame.enterLoop() self.emit.printout(self.emit.emitLABEL(labelS, frame)) newScope = o for x in ast.sl[0]: newScope = self.visit(x, newScope) for x in ast.sl[0]: self.visit(Assign(Id(x.variable.name), x.varInit), newScope) hasReturnStmt = True in [self.visit(x, newScope) for x in ast.sl[1]] self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) if hasReturnStmt: self.emit.printout(self.emit.emitGOTO(labelE, frame)) self.emit.printout(expCode) self.emit.printout(self.emit.emitIFTRUE(labelS, frame)) self.emit.printout(self.emit.emitLABEL(labelE, frame)) self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame)) frame.exitLoop() def visitFor(self, ast, o): frame = o.frame nenv = o.sym exp1Code, _ = self.visit( ast.expr1, Access(frame, nenv, False, True, typ=IntType())) exp2Code, _ = self.visit( ast.expr2, Access(frame, nenv, False, True, typ=BoolType())) exp3Code, _ = self.visit( ast.expr3, Access(frame, nenv, False, True, typ=IntType())) lhsWCode, _ = self.visit( ast.idx1, Access(frame, nenv, True, True, typ=IntType())) lhsRCode, _ = self.visit( ast.idx1, Access(frame, nenv, False, False, typ=IntType())) labelS = frame.getNewLabel() labelE = frame.getNewLabel() self.emit.printout(exp1Code) self.emit.printout(lhsWCode) frame.enterLoop() self.emit.printout(self.emit.emitLABEL(labelS, frame)) self.emit.printout(exp2Code) self.emit.printout(self.emit.emitIFFALSE(labelE, frame)) newScope = o for x in ast.loop[0]: newScope = self.visit(x, newScope) for x in ast.loop[0]: self.visit(Assign(Id(x.variable.name), x.varInit), newScope) hasReturnStmt = True in [self.visit(x, newScope) for x in ast.loop[1]] self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) self.emit.printout(lhsRCode) self.emit.printout(exp3Code) self.emit.printout(self.emit.emitADDOP('+', IntType(), frame)) self.emit.printout(lhsWCode) if not hasReturnStmt: 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, 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 visitAssign(self, ast, o): frame = o.frame nenv = o.sym if type(ast.rhs) is ArrayLiteral: listEle = Utils.listElements(ast.rhs) for i in range(len(listEle)): temp = ArrayCell(ast.lhs, [IntLiteral(i)]) isArray, _ = self.visit( temp, Access(frame, nenv, True, True, checkArrayType=True)) if isArray: [frame.push() for i in range(0, 2)] rhsCode, rhsType = self.visit( listEle[i], Access(frame, nenv, False, True, typ=self.getTypeVar(listEle[i]))) lhsCode, lhsType = self.visit( temp, Access(frame, nenv, True, True, typ=self.getTypeVar(listEle[i]))) self.emit.printout(lhsCode[0] + rhsCode + lhsCode[1]) [frame.pop() for i in range(0, 2)] else: isArray, _ = self.visit( ast.lhs, Access(frame, nenv, True, True, checkArrayType=True)) if isArray: [frame.push() for i in range(0, 2)] left = Utils.getSymbol(nenv, ast.lhs) leftType = left.mtype if left else IntType() rhsCode, rhsType = self.visit( ast.rhs, Access(frame, nenv, False, True, typ=leftType)) lhsCode, lhsType = self.visit( ast.lhs, Access(frame, nenv, True, True, typ=rhsType)) if not isArray: self.emit.printout(rhsCode + lhsCode) else: self.emit.printout(lhsCode[0] + rhsCode + lhsCode[1]) [frame.pop() for i in range(0, 2)] def visitId(self, ast, o): frame = o.frame symbols = o.sym isLeft = o.isLeft isFirst = o.isFirst if isLeft and o.checkArrayType: return False, None sym = Utils.lookup(ast.name, symbols, lambda x: x.name) if sym is None: sym = Utils.lookup(ast.name, self.visitedPara, lambda x: x.name) if sym is None: for x in self.paramMain: if x.variable.name == ast.name: idx = frame.getNewIndex() if len(x.varDimen) > 0: self.emit.printout( self.emit.emitVAR( idx, ast.name, Utils.retrieveType( ArrayType(o.typ, x.varDimen)), frame.getStartLabel(), frame.getEndLabel(), frame)) size = 1 for i in x.varDimen: size *= i self.emit.printout( self.emit.emitInitNewLocalArray( idx, size, o.typ, frame)) self.visitedPara.append( Symbol(ast.name, ArrayType(o.typ, x.varDimen), Index(idx))) else: self.emit.printout( self.emit.emitVAR(idx, ast.name, Utils.retrieveType(o.typ), frame.getStartLabel(), frame.getEndLabel(), frame)) self.visitedPara.append( Symbol(ast.name, o.typ, Index(idx))) symbols = [ Symbol(ast.name, Utils.retrieveType(o.typ), Index(idx)) ] + o.sym sym = Utils.lookup(ast.name, self.visitedPara, lambda x: x.name) self.paramMain.remove(x) if not isFirst and isLeft: frame.push() elif not isFirst and not isLeft: frame.pop() isArrayType = type(sym.mtype) is ArrayType emitType = Utils.retrieveType(sym.mtype) if sym.value is None: if isLeft and not isArrayType: retCode = self.emit.emitPUTSTATIC( self.className + "/" + sym.name, emitType, frame) else: if isLeft and type(o.typ) is ArrayType: 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: if isLeft and type(o.typ) is ArrayType: 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, o): frame = o.frame symbols = o.sym isLeft = o.isLeft isFirst = o.isFirst if isLeft and o.checkArrayType: return True, None idxCode = "" if type(ast.arr) is CallExpr: arrCode, arrType = self.visit( ast.arr, Access(frame, symbols, isLeft, True, typ=ArrayType(o.typ, []))) asym = arrType.dimen if len(ast.idx) > 1: for i in range(len(ast.idx)): temp, _ = self.visit( ast.idx[i], Access(frame, symbols, False, True, typ=IntType())) for j in range(i + 1, len(asym)): temp = temp + self.emit.emitPUSHICONST( asym[j], frame) + self.emit.emitMULOP( '*', IntType(), frame) if i == 0: idxCode = temp else: idxCode = idxCode + temp + self.emit.emitADDOP( '+', IntType(), frame) else: idxCode, idxType = self.visit( ast.idx[0], Access(frame, symbols, False, True, typ=IntType())) if isLeft: return [arrCode + idxCode, self.emit.emitASTORE(o.typ, frame)], o.typ return arrCode + idxCode + self.emit.emitALOAD(o.typ, frame), o.typ else: arrCode, arrType = self.visit( ast.arr, Access(frame, symbols, isLeft, True, typ=o.typ)) asym = Utils.getSymbol(symbols, ast.arr) if asym: asym = asym.mtype.dimen else: asym = Utils.lookup(ast.arr.name, self.visitedPara, lambda x: x.name).mtype.dimen if len(ast.idx) > 1: for i in range(len(ast.idx)): temp, _ = self.visit( ast.idx[i], Access(frame, symbols, False, True, typ=IntType())) for j in range(i + 1, len(asym)): temp = temp + self.emit.emitPUSHICONST( asym[j], frame) + self.emit.emitMULOP( '*', IntType(), frame) if i == 0: idxCode = temp else: idxCode = idxCode + temp + self.emit.emitADDOP( '+', IntType(), frame) else: idxCode, idxType = self.visit( ast.idx[0], Access(frame, symbols, False, True, typ=IntType())) 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 visitCallExpr(self, ast, o): return self.handleCall(ast, o.frame, o.sym, isStmt=False, typ=o.typ) def visitBinaryOp(self, ast, o): frame = o.frame op = ast.op if op in ['&&', '||']: o.typ = BoolType() frame = o.frame buffer = [] labelT = frame.getNewLabel() labelF = frame.getNewLabel() lCode = self.visit(ast.left, o)[0] buffer.append(lCode) if ast.op == '||': buffer.append(self.emit.emitIFTRUE(labelT, frame)) else: buffer.append(self.emit.emitIFFALSE(labelF, frame)) rCode = self.visit(ast.right, o)[0] buffer.append(rCode) if ast.op == '||': buffer.append(self.emit.emitIFTRUE(labelT, frame)) buffer.append(self.emit.emitPUSHICONST("False", frame)) buffer.append(self.emit.emitGOTO(labelF, frame)) buffer.append(self.emit.emitLABEL(labelT, frame)) buffer.append(self.emit.emitPUSHICONST("True", frame)) buffer.append(self.emit.emitLABEL(labelF, frame)) else: buffer.append(self.emit.emitIFFALSE(labelF, frame)) buffer.append(self.emit.emitPUSHICONST("True", frame)) buffer.append(self.emit.emitGOTO(labelT, frame)) buffer.append(self.emit.emitLABEL(labelF, frame)) buffer.append(self.emit.emitPUSHICONST("False", frame)) buffer.append(self.emit.emitLABEL(labelT, frame)) return "".join(buffer), BoolType() if op in ['+', '-', '*', '\\', '%', '==', '!=', '>', '<', '>=', '<=']: o.typ = IntType() else: o.typ = FloatType() lCode, lType = self.visit(ast.left, o) rCode, rType = self.visit(ast.right, o) if op in ['+', '-', '+.', '-.']: return lCode + rCode + self.emit.emitADDOP(op, lType, frame), lType if op in ['*', '\\', '%', '*.', '\\.']: return lCode + rCode + self.emit.emitMULOP(op, lType, frame), lType if op in [ '==', '!=', '>', '<', '>=', '<=', '=/=', '>.', '<.', '>=.', '<=.' ]: return lCode + rCode + self.emit.emitREOP(op, lType, frame), BoolType() def visitUnaryOp(self, ast, o): frame = o.frame op = ast.op bCode, bType = self.visit(ast.body, o) if op == '-': o.typ = IntType() if op == '-.': o.typ = FloatType() if op == '!': o.typ = BoolType() if op in ['-', '-.']: return bCode + self.emit.emitNEGOP(bType, frame), bType if op == '!': return bCode + self.emit.emitNOT(bType, frame), bType def visitIntLiteral(self, ast, o): return self.emit.emitPUSHICONST(ast.value, o.frame), IntType() def visitFloatLiteral(self, ast, o): return self.emit.emitPUSHFCONST(str(ast.value), o.frame), FloatType() def visitBooleanLiteral(self, ast, o): return self.emit.emitPUSHICONST(str(ast.value), o.frame), BoolType() def visitStringLiteral(self, ast, o): return self.emit.emitPUSHCONST(ast.value.replace("'\"", '\\"'), StringType(), o.frame), StringType() def visitArrayLiteral(self, ast, o): listEle = Utils.listElements(ast) frame = o.frame idx = frame.getNewIndex() eletype = self.getTypeVar(listEle[0]) code = self.emit.emitInitNewLocalArray(idx, len(listEle), eletype, frame) astr = "" if type(eletype) is FloatType: astr = "fastore" elif type(eletype) is IntType: astr = "iastore" elif type(eletype) is BoolType: astr = "bastore" else: astr = "aastore" astore = "\t" + astr + "\n" aload = "" if idx >= 0 and idx <= 3: aload = "\t" + "aload_" + str(idx) + "\n" else: aload = "\t" + "aload" + str(idx) + "\n" for i in range(len(listEle)): code += aload code += self.emit.emitPUSHICONST(i, frame) rhsCode, rhsType = self.visit( listEle[i], Access(o.frame, o.sym, False, True, typ=eletype)) code += rhsCode + astore code += aload return code, Utils.getArrayType(ast)
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")
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: Program, c): # 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, 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) [self.visit(x, e) for x in ast.decl if type(x) is FuncDecl] # generate default constructor self.genMETHOD(FuncDecl(Id("<init>"), list(), list(), list(), None), c, Frame("<init>", VoidType)) self.emit.emitEPILOG() return c def visitFuncDecl(self, ast: FuncDecl, o: SubBody): subctxt = o frame = Frame(ast.name.name, ast.returnType) self.genMETHOD(ast, subctxt.sym, frame) def visitVarDecl(self, ast: VarDecl, o: SubBody): subctxt = o frame = o.frame isGlobal = o.isGlobal varName = ast.variable.name varType = ast.varType if isGlobal: self.emit.printout(self.emit.emitATTRIBUTE(varName, varType, False, "")) return Symbol(varName, varType) # params 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))] + subctxt.sym) def genMETHOD(self, decl: FuncDecl, o, frame: Frame): # o: Any glenv = o isInit = decl.returnType is None isMain = decl.name.name == "main" and len(decl.param) == 0 and type(decl.returnType) is VoidType returnType = VoidType() if isInit else decl.returnType isProc = type(returnType) is VoidType methodName = "<init>" if isInit else decl.name.name intype = [ArrayPointerType(StringType())] if isMain else [x.varType for x in decl.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)) varList = SubBody(frame, glenv) for x in decl.param + decl.local: varList = self.visit(x, varList) 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, varList), decl.body)) 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() # ================ Visit Statements ================= # Param: o: SubBody(frame, sym) def visitCallStmt(self, ast: CallStmt, o: SubBody): ctxt = o frame = ctxt.frame symbols = ctxt.sym self.handleCall(ast, frame, symbols, isStmt=True) def handleCall(self, ast, frame, symbols, isStmt=False): # ast: CallStmt | CallExpr sym = self.lookup(ast.method.name.lower(), symbols, lambda x: x.name.lower()) cname = sym.value.value ctype = sym.mtype paramTypes = ctype.partype paramsCode = "" idx = 0 for x in ast.param: pCode, pType = self.visit(x, Access(frame, symbols, False, True)) if type(paramTypes[idx]) is FloatType and type(pType) is IntType: pCode = pCode + self.emit.emitI2F(frame) paramsCode = paramsCode + pCode idx = idx + 1 code = paramsCode + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame) if isStmt: self.emit.printout(code) else: return code, ctype.rettype def visitAssign(self, ast: Assign, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym # Visit LHS: Id || ArrayCell, return name, type, index lhsName, lhsType, lhsIndex = self.visit(ast.lhs, Access(frame, nenv, True, True)) expCode, expType = self.visit(ast.exp, Access(frame, nenv, False, True)) if type(lhsType) is FloatType and type(expType) is IntType: expCode = expCode + self.emit.emitI2F(frame) self.emit.printout(expCode) if lhsIndex is None: # global var - static field self.emit.printout(self.emit.emitPUTSTATIC(self.className + "/" + lhsName, lhsType, frame)) else: self.emit.printout(self.emit.emitWRITEVAR(lhsName, lhsType, lhsIndex.value, frame)) def visitIf(self, ast: If, o: SubBody): ctxt = o frame = ctxt.frame nenv = ctxt.sym returnType = frame.returnType expCode, expType = self.visit(ast.expr, Access(frame, nenv, False, True)) isProc = type(returnType) is VoidType self.emit.printout(expCode) 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.emitPUSHICONST("false", frame)) # push true [self.visit(x, o) for x in ast.elseStmt] self.emit.printout(self.emit.emitGOTO(labelE, frame)) # go to end self.emit.printout(self.emit.emitLABEL(labelT, frame)) self.emit.printout(self.emit.emitPUSHICONST("true", frame)) [self.visit(x, o) for x in ast.thenStmt] self.emit.printout(self.emit.emitLABEL(labelE, frame)) # ================ Visit Expression ================= # Param: o: Access(frame, sym, isLeft, isFirst) # Return: (code, type) def visitBinaryOp(self, ast: BinaryOp, o: Access): ctxt = o frame = ctxt.frame op = str(ast.op).lower() lCode, lType = self.visit(ast.left, ctxt) rCode, rType = self.visit(ast.right, ctxt) if ExpUtils.isOpForNumber(op): # for number type mType = ExpUtils.mergeNumberType(lType, rType) if op == '/': mType = FloatType() # mergeType >= lType, rType lCode, rCode = (c if type(t) == type(mType) else c+self.emit.emitI2F(frame) \ for c,t in [(lCode, lType), (rCode, rType)]) if ExpUtils.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 == 'div': return lCode + rCode + self.emit.emitDIV(frame), mType if op == 'mod': return lCode + rCode + self.emit.emitMOD(frame), mType else: # op to boolean: > <= = <>, ... return lCode + rCode + self.emit.emitREOP(op, mType, frame), BoolType() else: # for boolean type mType = BoolType() if op == 'or': return lCode + rCode + self.emit.emitOROP(frame), mType if op == 'and': return lCode + rCode + self.emit.emitANDOP(frame), mType if op == 'orelse': return self.emit.emitORELSE(frame, lCode, rCode), mType if op == 'andthen': return self.emit.emitANDTHEN(frame, lCode, rCode), mType 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 sym = self.lookup(ast.name.lower(), symbols, lambda x: x.name.lower()) if isLeft: return sym.name, sym.mtype, sym.value if sym.value is None: # not index -> global var - static field return self.emit.emitGETSTATIC(self.className + "/" + sym.name, sym.mtype, frame), sym.mtype return self.emit.emitREADVAR(sym.name, sym.mtype, sym.value.value, frame), sym.mtype def visitCallExpr(self, ast: CallExpr, o: Access): ctxt = o frame = ctxt.frame symbols = ctxt.sym return self.handleCall(ast, frame, symbols, isStmt=False) 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 = "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): 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") 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): 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 = "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") 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_): #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") 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, 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, 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) var_lst = [x for x in ast.decl if type(x) is VarDecl] func_lst = [x for x in ast.decl if type(x) is FuncDecl] for x in var_lst: e = self.visit(x, e) for i in func_lst: lst = [x.varType for x in i.param] e.sym.append( Symbol(i.name.name, MType(lst, i.returnType), CName(self.className))) for x in func_lst: 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) 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)) for x in consdecl.param + consdecl.local: glenv = self.visit(x, SubBody(frame, glenv.sym)) 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.sym)), 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): #ast: FuncDecl #o: Any if ast.name.name.lower() == "main": ast.name.name = "main" subctxt = o frame = Frame(ast.name, ast.returnType) self.genMETHOD(ast, subctxt, frame) # return SubBody(None, [Symbol(ast.name, MType(lst, ast.returnType), CName(self.className))] + subctxt.sym) def visitVarDecl(self, ast, o): ctxt = o if ctxt.frame is not None: frame = ctxt.frame index = frame.getNewIndex() txt = self.emit.emitVAR(index, ast.variable.name, ast.varType, frame.getStartLabel(), frame.getEndLabel(), frame) self.emit.printout(txt) return SubBody(ctxt.frame, [Symbol(ast.variable.name, ast.varType, index)] + ctxt.sym) else: txt = self.emit.emitATTRIBUTE(ast.variable.name, ast.varType, False, None) self.emit.printout(txt) return SubBody( None, ctxt.sym + [ Symbol(ast.variable.name, ast.varType, CName( self.className)) ]) def visitWhile(self, ast, o): ctxt = o frame = o.frame sym = o.sym frame.enterLoop() self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) expcode, exptyp = self.visit(ast.exp, Access(frame, sym, False, True)) self.emit.printout(expcode) self.emit.printout(self.emit.jvm.emitIFEQ(frame.getBreakLabel())) list(map(lambda x: self.visit(x, SubBody(frame, sym)), 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, o): #id:Id #expr1,expr2:Expr #loop:list(Stmt) #up:Boolean #True => increase; False => decrease ctxt = o frame = ctxt.frame frame.enterLoop() exp1, exp1typ = self.visit(ast.expr1, Access(frame, ctxt.sym, False, False)) self.emit.printout(exp1) idstore, idtyp = self.visit(ast.id, Access(frame, ctxt.sym, True, False)) self.emit.printout(idstore) idload, idtypnew = self.visit(ast.id, Access(frame, ctxt.sym, False, False)) # Lan dau tien self.emit.printout(idload + self.emit.emitPUSHICONST(1, frame)) #if up -1, if downto +1 if ast.up: self.emit.printout(self.emit.emitADDOP('-', IntType(), frame)) else: self.emit.printout(self.emit.emitADDOP('+', IntType(), frame)) self.emit.printout(idstore) self.emit.printout(self.emit.emitLABEL(frame.getContinueLabel(), frame)) exp2, exp2typ = self.visit(ast.expr2, Access(frame, ctxt.sym, False, False)) if ast.up: self.emit.printout(idload + self.emit.emitPUSHICONST(1, frame) + self.emit.emitADDOP('+', IntType(), frame)) self.emit.printout(idstore) else: self.emit.printout(idload + self.emit.emitPUSHICONST(1, frame) + self.emit.emitADDOP('-', IntType(), frame)) self.emit.printout(idstore) if ast.up: self.emit.printout(idload + exp2 + self.emit.emitREOP("<=", IntType(), frame)) else: self.emit.printout(idload + exp2 + self.emit.emitREOP(">=", IntType(), frame)) self.emit.printout(self.emit.jvm.emitIFEQ(frame.getBreakLabel())) list(map(lambda x: self.visit(x, SubBody(frame, ctxt.sym)), ast.loop)) self.emit.printout(self.emit.emitGOTO(frame.getContinueLabel(), frame)) self.emit.printout(self.emit.emitLABEL(frame.getBreakLabel(), frame)) frame.exitLoop() def visitIf(self, ast, o): ctxt = o frame = ctxt.frame labelExit = frame.getNewLabel() exprcode, exptyp = self.visit(ast.expr, Access(frame, ctxt.sym, False, False)) self.emit.printout(exprcode) flagThen = self.checkFuncNoReturn(ast.thenStmt) if len(ast.elseStmt) == 0: self.emit.printout(self.emit.jvm.emitIFEQ(labelExit)) list( map(lambda x: self.visit(x, SubBody(frame, ctxt.sym)), ast.thenStmt)) if not flagThen: self.emit.printout(self.emit.emitGOTO(labelExit, frame)) else: labelElse = frame.getNewLabel() flagElse = self.checkFuncNoReturn(ast.elseStmt) self.emit.printout(self.emit.jvm.emitIFEQ(labelElse)) list( map(lambda x: self.visit(x, SubBody(frame, ctxt.sym)), ast.thenStmt)) if not flagThen: self.emit.printout(self.emit.emitGOTO(labelExit, frame)) self.emit.printout(self.emit.emitLABEL(labelElse, frame)) list( map(lambda x: self.visit(x, SubBody(frame, ctxt.sym)), ast.elseStmt)) if not flagElse: self.emit.printout(self.emit.emitGOTO(labelExit, frame)) self.emit.printout(self.emit.emitLABEL(labelExit, frame)) def checkFuncNoReturn(self, list): check = False for i in list: if type(i) is If: a = self.checkFuncNoReturn(i.thenStmt) b = self.checkFuncNoReturn( i.elseStmt) if i.elseStmt != [] else False check = a and b if type(i) is With: check = self.checkFuncNoReturn(i.stmt) if type(i) is Return: check = True return check def visitCallStmt(self, ast, o): #ast: CallStmt #o: Any ctxt = o frame = ctxt.frame sym = self.lookup(ast.method.name.lower(), ctxt.sym, lambda x: x.name.lower()) for x in ctxt.sym: if x.name.lower() == sym.name.lower(): ast.method.name = x.name # print(ast.method.name) cname = sym.value.value ctype = sym.mtype i = 0 in_ = ("", list()) for x in ast.param: str1, typ1 = self.visit(x, Access(frame, ctxt.sym, False, True)) if type(typ1) is IntType and type( sym.mtype.partype[i]) is FloatType: in_ = (in_[0] + str1 + self.emit.emitI2F(frame), in_[1] + [typ1]) else: in_ = (in_[0] + str1, in_[1] + [typ1]) i += 1 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 sym = self.lookup(ast.method.name.lower(), ctxt.sym, lambda x: x.name.lower()) for x in ctxt.sym: if x.name.lower() == sym.name.lower(): ast.method.name = x.name cname = sym.value.value ctype = sym.mtype i = 0 in_ = ("", list()) for x in ast.param: str1, typ1 = self.visit(x, Access(frame, ctxt.sym, False, True)) if type(typ1) is IntType and type( sym.mtype.partype[i]) is FloatType: in_ = (in_[0] + str1 + self.emit.emitI2F(frame), in_[1] + [typ1]) else: in_ = (in_[0] + str1, in_[1] + [typ1]) i += 1 return in_[0] + self.emit.emitINVOKESTATIC(cname + "/" + sym.name, ctype, frame), ctype.rettype def visitBreak(self, ast, o): ctxt = o frame = ctxt.frame brkLabel = frame.getBreakLabel() self.emit.printout(self.emit.emitGOTO(brkLabel, frame)) def visitContinue(self, ast, o): ctxt = o frame = ctxt.frame conLabel = frame.getContinueLabel() self.emit.printout(self.emit.emitGOTO(conLabel, frame)) def visitAssign(self, ast, o): ctxt = o frame = ctxt.frame nenv = ctxt.sym right, righttyp = self.visit(ast.exp, Access(frame, nenv, False, True)) left, lefttyp = self.visit(ast.lhs, Access(frame, nenv, True, False)) self.emit.printout(right) if type(righttyp) is IntType and type(lefttyp) is FloatType: self.emit.printout(self.emit.emitI2F(frame)) self.emit.printout(left) return def visitBinaryOp(self, ast, o): ctxt = o frame = ctxt.frame #lexeme = ast.op leftcode, lefttyp = self.visit(ast.left, o) rightcode, righttyp = self.visit(ast.right, o) retyp = lefttyp result = "" if ast.op in ['+', '-']: if type(lefttyp) is type(righttyp): return leftcode + rightcode + self.emit.emitADDOP( ast.op, lefttyp, frame), retyp else: retyp = FloatType() if type(lefttyp) is IntType: return leftcode + self.emit.emitI2F( frame) + rightcode + self.emit.emitADDOP( ast.op, retyp, frame), retyp else: return leftcode + rightcode + self.emit.emitI2F( frame) + self.emit.emitADDOP(ast.op, retyp, frame), retyp elif ast.op == '*': if type(lefttyp) is type(righttyp): return leftcode + rightcode + self.emit.emitMULOP( ast.op, lefttyp, frame), retyp else: retyp = FloatType() if type(lefttyp) is IntType: return leftcode + self.emit.emitI2F( frame) + rightcode + self.emit.emitMULOP( ast.op, retyp, frame), retyp else: return leftcode + rightcode + self.emit.emitI2F( frame) + self.emit.emitMULOP(ast.op, retyp, frame), retyp elif ast.op == '/': retyp = FloatType() if type(lefttyp) is type(righttyp): if type(lefttyp) is IntType: return leftcode + self.emit.emitI2F( frame) + rightcode + self.emit.emitI2F( frame) + self.emit.emitMULOP(ast.op, retyp, frame), retyp else: return leftcode + rightcode + self.emit.emitMULOP( ast.op, retyp, frame), retyp else: if type(lefttyp) is IntType: return leftcode + self.emit.emitI2F( frame) + rightcode + self.emit.emitMULOP( ast.op, retyp, frame), retyp else: return leftcode + rightcode + self.emit.emitI2F( frame) + self.emit.emitMULOP(ast.op, retyp, frame), retyp elif ast.op.lower() == "div": return leftcode + rightcode + self.emit.emitDIV(frame), IntType() elif ast.op.lower() == "mod": return leftcode + rightcode + self.emit.emitMOD(frame), IntType() elif ast.op.lower() == "and": return leftcode + rightcode + self.emit.emitANDOP(frame), BoolType( ) elif ast.op.lower() == "or": return leftcode + rightcode + self.emit.emitOROP(frame), BoolType() elif ast.op in ['>', '>=', '<', '<=', '<>', '=']: retyp = BoolType() if type(lefttyp) is type(righttyp): return leftcode + rightcode + self.emit.emitREOP( ast.op, lefttyp, frame), retyp else: if type(lefttyp) is IntType: return leftcode + self.emit.emitI2F( frame) + rightcode + self.emit.emitREOP( ast.op, FloatType(), frame), retyp else: return leftcode + rightcode + self.emit.emitI2F( frame) + self.emit.emitREOP(ast.op, FloatType(), frame), retyp #TODO andthen & orelse #if 5 > 3 and then 2 > 1 elif ast.op.lower() == 'andthen': retyp = BoolType() labelLz = frame.getNewLabel() # labelTh = frame.getNewLabel() result += leftcode result += self.emit.emitDUP(frame) result += self.emit.jvm.emitIFEQ(labelLz) result += rightcode result += self.emit.emitANDOP(frame) result += self.emit.emitLABEL(labelLz, frame) return result, retyp elif ast.op.lower() == 'orelse': retyp = BoolType() labelLz = frame.getNewLabel() result += leftcode result += self.emit.emitDUP(frame) result += self.emit.jvm.emitIFNE(labelLz) result += rightcode result += self.emit.emitOROP(frame) result += self.emit.emitLABEL(labelLz, frame) return result, retyp # TODO: visitWith def visitWith(self, ast, o): ctxt = o frame = ctxt.frame sym = ctxt.sym frame.enterScope(False) labelSta = frame.getStartLabel() labelEnd = frame.getEndLabel() for x in ast.decl: # print(type(sym)) if type(sym) is SubBody: sym = self.visit(x, SubBody(frame, sym.sym)) else: sym = self.visit(x, SubBody(frame, sym)) self.emit.printout(self.emit.emitLABEL(labelSta, frame)) list(map(lambda x: self.visit(x, SubBody(frame, sym.sym)), ast.stmt)) self.emit.printout(self.emit.emitLABEL(labelEnd, frame)) frame.exitScope() def visitUnaryOp(self, ast, o): ctxt = o frame = ctxt.frame unacode, unatyp = self.visit(ast.body, o) if ast.op is '-': return unacode + self.emit.emitNEGOP(unatyp, frame), unatyp if ast.op.lower() == 'not': return unacode + self.emit.emitNOT(BoolType(), frame), unatyp 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): #ast: BooleanLiteral #o: Any 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), StringType() def visitReturn(self, ast, o): ctxt = o frame = ctxt.frame refunctyp = frame.returnType if ast.expr: expcode, exptyp = self.visit(ast.expr, Access(frame, o.sym, False, True)) self.emit.printout(expcode) if type(exptyp) is not type( refunctyp) and type(refunctyp) is FloatType: self.emit.printout(self.emit.emitI2F(frame)) self.emit.printout(self.emit.emitRETURN(refunctyp, frame)) def visitId(self, ast, o): ctxt = o frame = ctxt.frame isLeft = ctxt.isLeft sym = self.lookup(ast.name.lower(), ctxt.sym, lambda x: x.name.lower()) if isLeft: if type(sym.value) is CName: name = self.className + "/" + sym.name return self.emit.emitPUTSTATIC(name, sym.mtype, frame), sym.mtype else: return self.emit.emitWRITEVAR(sym.name, sym.mtype, sym.value, frame), sym.mtype else: if type(sym.value) is CName: name = self.className + "/" + sym.name return self.emit.emitGETSTATIC(name, sym.mtype, frame), sym.mtype else: return self.emit.emitREADVAR(sym.name, sym.mtype, sym.value, frame), sym.mtype