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