class Emitter(): def __init__(self, filename): self.filename = filename self.buff = list() self.jvm = JasminCode() def getJVMType(self, inType): typeIn = type(inType) if typeIn is IntType: return "I" elif typeIn is FloatType: return "F" elif typeIn is StringType: return "Ljava/lang/String;" elif typeIn is BoolType: return "Z" elif typeIn is VoidType: return "V" elif typeIn is ArrayPointerType: return "[" + self.getJVMType(inType.eleType) elif typeIn is MType: return "(" + "".join( list(map(lambda x: self.getJVMType(x), inType.partype))) + ")" + self.getJVMType( inType.rettype) elif typeIn is cgen.ClassType: return "L" + inType.cname + ";" def getFullType(inType): typeIn = type(inType) if typeIn is IntType: return "int" elif typeIn is StringType: return "java/lang/String" elif typeIn is VoidType: return "void" elif typeIn is FloatType: return "float" elif typeIn is BoolType: return "boolean" def emitPUSHICONST(self, in_, frame): #in: Int or String #frame: Frame frame.push() if type(in_) is int: i = in_ if i >= -1 and i <= 5: return self.jvm.emitICONST(i) elif i >= -128 and i <= 127: return self.jvm.emitBIPUSH(i) elif i >= -32768 and i <= 32767: return self.jvm.emitSIPUSH(i) else: return self.jvm.emitLDC(str(i)) elif type(in_) is str: if in_ == "true": return self.emitPUSHICONST(1, frame) elif in_ == "false": return self.emitPUSHICONST(0, frame) else: return self.emitPUSHICONST(int(in_), frame) def emitPUSHFCONST(self, in_, frame): #in_: String #frame: Frame f = float(in_) frame.push() rst = "{0:.4f}".format(f) if rst == "0.0" or rst == "1.0" or rst == "2.0": return self.jvm.emitFCONST(rst) else: return self.jvm.emitLDC(in_) ''' * generate code to push a constant onto the operand stack. * @param in the lexeme of the constant * @param typ the type of the constant ''' def emitPUSHCONST(self, in_, typ, frame): #in_: String #typ: Type #frame: Frame if type(typ) is IntType: return self.emitPUSHICONST(in_, frame) elif type(typ) is FloatType: return self.emitPUSHFCONST(in_, frame) elif type(typ) is BoolType: return self.emitPUSHICONST(in_, frame) elif type(typ) is StringType: frame.push() return self.jvm.emitLDC(in_) else: raise IllegalOperandException(in_) ############################################################## def emitALOAD(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... frame.pop() if type(in_) is IntType: return self.jvm.emitIALOAD() elif type(in_) is ArrayPointerType or type( in_) is cgen.ClassType or type(in_) is StringType: return self.jvm.emitAALOAD() else: raise IllegalOperandException(str(in_)) def emitASTORE(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... frame.pop() frame.pop() frame.pop() if type(in_) is IntType: return self.jvm.emitIASTORE() elif type(in_) is ArrayPointerType or type( in_) is cgen.ClassType or type(in_) is StringType: return self.jvm.emitAASTORE() else: raise IllegalOperandException(str(in_)) ''' generate the var directive for a local variable. * @param in the index of the local variable. * @param varName the name of the local variable. * @param inType the type of the local variable. * @param fromLabel the starting label of the scope where the variable is active. * @param toLabel the ending label of the scope where the variable is active. ''' def emitVAR(self, in_, varName, inType, fromLabel, toLabel, frame): #in_: Int #varName: String #inType: Type #fromLabel: Int #toLabel: Int #frame: Frame return self.jvm.emitVAR(in_, varName, self.getJVMType(inType), fromLabel, toLabel) def emitREADVAR(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #... -> ..., value frame.push() if type(inType) is IntType or type(inType) is BoolType: return self.jvm.emitILOAD(index) elif type(inType) is FloatType: return self.jvm.emitFLOAD(index) elif type(inType) is ArrayPointerType or type( inType) is cgen.ClassType or type(inType) is StringType: return self.jvm.emitALOAD(index) else: raise IllegalOperandException(name) ''' generate the second instruction for array cell access * ''' def emitREADVAR2(self, name, typ, frame): #name: String #typ: Type #frame: Frame #... -> ..., value #frame.push() raise IllegalOperandException(name) ''' * generate code to pop a value on top of the operand stack and store it to a block-scoped variable. * @param name the symbol entry of the variable. ''' def emit(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #..., value -> ... frame.pop() if type(inType) is IntType or type(inType) is BoolType: return self.jvm.emitISTORE(index) elif type(inType) is FloatType: return self.jvm.emitFSTORE(index) elif type(inType) is ArrayPointerType or type( inType) is cgen.ClassType or type(inType) is StringType: return self.jvm.emitASTORE(index) else: raise IllegalOperandException(name) ''' generate the second instruction for array cell access * ''' def emit2(self, name, typ, frame): #name: String #typ: Type #frame: Frame #..., value -> ... #frame.push() raise IllegalOperandException(name) ''' generate the field (static) directive for a class mutable or immutable attribute. * @param lexeme the name of the attribute. * @param in the type of the attribute. * @param isFinal true in case of constant; false otherwise ''' def emitATTRIBUTE(self, lexeme, in_, isFinal, value): #lexeme: String #in_: Type #isFinal: Boolean #value: String return self.jvm.emitSTATICFIELD(lexeme, self.getJVMType(in_), isFinal) def emitGETSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.push() return self.jvm.emitGETSTATIC(lexeme, self.getJVMType(in_)) def emitPUTSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.pop() return self.jvm.emitPUTSTATIC(lexeme, self.getJVMType(in_)) def emitGETFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame return self.jvm.emitGETFIELD(lexeme, self.getJVMType(in_)) def emitPUTFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.pop() frame.pop() return self.jvm.emitPUTFIELD(lexeme, self.getJVMType(in_)) ''' generate code to invoke a static method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame typ = in_ list(map(lambda x: frame.pop(), typ.partype)) if not type(typ.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESTATIC(lexeme, self.getJVMType(in_)) ''' generate code to invoke a special method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESPECIAL(self, frame, lexeme=None, in_=None): #lexeme: String #in_: Type #frame: Frame if not lexeme is None and not in_ is None: typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESPECIAL(lexeme, self.getJVMType(in_)) elif lexeme is None and in_ is None: frame.pop() return self.jvm.emitINVOKESPECIAL() ''' generate code to invoke a virtual method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKEVIRTUAL(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ) is VoidType: frame.push() return self.jvm.emitINVOKEVIRTUAL(lexeme, self.getJVMType(in_)) ''' * generate ineg, fneg. * @param in the type of the operands. ''' def emitNEGOP(self, in_, frame): #in_: Type #frame: Frame #..., value -> ..., result if type(in_) is IntType: return self.jvm.emitINEG() else: return self.jvm.emitFNEG() def emitNOT(self, in_, frame): #in_: Type #frame: Frame label1 = frame.getNewLabel() label2 = frame.getNewLabel() result = list() result.append(self.emitIFTRUE(label1, frame)) result.append(self.emitPUSHCONST("true", in_, frame)) result.append(self.emitGOTO(label2, frame)) result.append(self.emitLABEL(label1, frame)) result.append(self.emitPUSHCONST("false", in_, frame)) result.append(self.emitLABEL(label2, frame)) return ''.join(result) ''' * generate iadd, isub, fadd or fsub. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitADDOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result frame.pop() if lexeme == "+": if in_ is IntType: return self.jvm.emitIADD() else: return self.jvm.emitFADD() else: if in_ is IntType: return self.jvm.emitISUB() else: return self.jvm.emitFSUB() ''' * generate imul, idiv, fmul or fdiv. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitMULOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result frame.pop() if lexeme == "*": if type(in_) is IntType: return self.jvm.emitIMUL() else: return self.jvm.emitFMUL() elif lexeme == "/": if type(in_) is IntType: return self.jvm.emitIDIV() else: return self.jvm.emitFDIV() else: raise Exception("Not supposed to enter emitMULOP with lemexe: " + lexeme) def emitDIV(self, frame): #frame: Frame frame.pop() return self.jvm.emitIDIV() def emitMOD(self, frame): #frame: Frame frame.pop() return self.jvm.emitIREM() ''' * generate iand ''' def emitANDOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIAND() ''' * generate ior ''' def emitOROP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIOR() def emitREOP(self, op, in_, frame): #op: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result result = list() labelF = frame.getNewLabel() labelO = frame.getNewLabel() frame.pop() frame.pop() if type(in_) is IntType or type(in_) is BoolType: if op == ">": result.append(self.jvm.emitIFICMPLE(labelF)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(labelF)) elif op == "<": result.append(self.jvm.emitIFICMPGE(labelF)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(labelF)) elif op == "!=": result.append(self.jvm.emitIFICMPEQ(labelF)) elif op == "==": result.append(self.jvm.emitIFICMPNE(labelF)) if type(in_) is FloatType: result.append(self.jvm.emitFCMPL()) if op == ">": result.append(self.jvm.emitIFLE(labelF)) elif op == ">=": result.append(self.jvm.emitIFLT(labelF)) elif op == "<": result.append(self.jvm.emitIFGE(labelF)) elif op == "<=": result.append(self.jvm.emitIFGT(labelF)) result.append(self.emitPUSHCONST("1", IntType(), frame)) frame.pop() result.append(self.emitGOTO(labelO, frame)) result.append(self.emitLABEL(labelF, frame)) result.append(self.emitPUSHCONST("0", IntType(), frame)) result.append(self.emitLABEL(labelO, frame)) return ''.join(result) def emitRELOP(self, op, in_, trueLabel, falseLabel, frame): #op: String #in_: Type #trueLabel: Int #falseLabel: Int #frame: Frame #..., value1, value2 -> ..., result result = list() frame.pop() frame.pop() if op == ">": result.append(self.jvm.emitIFICMPLE(falseLabel)) result.append(self.emitGOTO(trueLabel)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(falseLabel)) elif op == "<": result.append(self.jvm.emitIFICMPGE(falseLabel)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(falseLabel)) elif op == "!=": result.append(self.jvm.emitIFICMPEQ(falseLabel)) elif op == "==": result.append(self.jvm.emitIFICMPNE(falseLabel)) result.append(self.jvm.emitGOTO(trueLabel)) return ''.join(result) ''' generate the method directive for a function. * @param lexeme the qualified name of the method(i.e., class-name/method-name). * @param in the type descriptor of the method. * @param isStatic <code>true</code> if the method is static; <code>false</code> otherwise. ''' def emitMETHOD(self, lexeme, in_, isStatic, frame): #lexeme: String #in_: Type #isStatic: Boolean #frame: Frame return self.jvm.emitMETHOD(lexeme, self.getJVMType(in_), isStatic) ''' generate the end directive for a function. ''' def emitENDMETHOD(self, frame): #frame: Frame buffer = list() buffer.append(self.jvm.emitLIMITSTACK(frame.getMaxOpStackSize())) buffer.append(self.jvm.emitLIMITLOCAL(frame.getMaxIndex())) buffer.append(self.jvm.emitENDMETHOD()) return ''.join(buffer) def getConst(self, ast): #ast: Literal if type(ast) is IntLiteral: return (str(ast.value), IntType()) ''' generate code to initialize a local array variable.<p> * @param index the index of the local variable. * @param in the type of the local array variable. ''' ''' generate code to initialize local array variables. * @param in the list of symbol entries corresponding to local array variable. ''' ''' generate code to jump to label if the value on top of operand stack is true.<p> * ifgt label * @param label the label where the execution continues if the value on top of stack is true. ''' def emitIFTRUE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFGT(label) ''' * generate code to jump to label if the value on top of operand stack is false.<p> * ifle label * @param label the label where the execution continues if the value on top of stack is false. ''' def emitIFFALSE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFLE(label) def emitIFICMPGT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPGT(label) def emitIFICMPLT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPLT(label) ''' generate code to duplicate the value on the top of the operand stack.<p> * Stack:<p> * Before: ...,value1<p> * After: ...,value1,value1<p> ''' def emitDUP(self, frame): #frame: Frame frame.push() return self.jvm.emitDUP() def emitPOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitPOP() ''' generate code to exchange an integer on top of stack to a floating-point number. ''' def emitI2F(self, frame): #frame: Frame return self.jvm.emitI2F() ''' generate code to return. * <ul> * <li>ireturn if the type is IntegerType or BooleanType * <li>freturn if the type is RealType * <li>return if the type is null * </ul> * @param in the type of the returned expression. ''' def emitRETURN(self, in_, frame): #in_: Type #frame: Frame if type(in_) is IntType: frame.pop() return self.jvm.emitIRETURN() if type(in_) is FloatType: frame.pop() return self.jvm.emitFRETURN() if type(in_) is StringType: frame.pop() return self.jvm.emitARETURN() if type(in_) is BoolType: frame.pop() return self.jvm.emitIRETURN() elif type(in_) is VoidType: return self.jvm.emitRETURN() ''' generate code that represents a label * @param label the label * @return code Label<label>: ''' def emitLABEL(self, label, frame): #label: Int #frame: Frame return self.jvm.emitLABEL(label) ''' generate code to jump to a label * @param label the label * @return code goto Label<label> ''' def emitGOTO(self, label, frame): #label: Int #frame: Frame return self.jvm.emitGOTO(str(label)) ''' generate some starting directives for a class.<p> * .source MPC.CLASSNAME.java<p> * .class public MPC.CLASSNAME<p> * .super java/lang/Object<p> ''' def emitPROLOG(self, name, parent): #name: String #parent: String result = list() result.append(self.jvm.emitSOURCE(name + ".java")) result.append(self.jvm.emitCLASS("public " + name)) result.append( self.jvm.emitSUPER("java/land/Object" if parent == "" else parent)) return ''.join(result) def emitLIMITSTACK(self, num): #num: Int return self.jvm.emitLIMITSTACK(num) def emitLIMITLOCAL(self, num): #num: Int return self.jvm.emitLIMITLOCAL(num) def emitEPILOG(self): file = open(self.filename, "w") file.write(''.join(self.buff)) file.close() ''' print out the code to screen * @param in the code to be printed out ''' def printout(self, in_): #in_: String self.buff.append(in_) def clearBuff(self): self.buff.clear()
class Emitter(): def __init__(self, filename): self.filename = filename self.buff = list() self.jvm = JasminCode() def getJVMType(self, inType): typeIn = type(inType) if typeIn is IntType: return "I" elif typeIn is cgen.StringType: return "Ljava/lang/String;" elif typeIn is VoidType: return "V" elif typeIn is FloatType: return "F" elif typeIn is BoolType: return "Z" elif typeIn is cgen.ArrayPointerType: return "[" + self.getJVMType(inType.eleType) elif typeIn is MType: return "(" + "".join(list(map(lambda x: self.getJVMType(x), inType.partype))) + ")" + self.getJVMType(inType.rettype) elif typeIn is cgen.ClassType: return "L" + inType.cname + ";" def getFullType(inType): typeIn = type(inType) if typeIn is IntType: return "int" elif typeIn is cgen.StringType: return "java/lang/String" elif typeIn is VoidType: return "void" elif typeIn is BoolType: return "boolean" elif typeIn is FloatType: return "float" #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------LOAD & SOTRE INSTRUCTIONS---------------------------------------------------# ''' * generate code to push a constant onto the operand stack. * @param in the lexeme of the constant * @param typ the type of the constant ''' def emitPUSHSTATIC(self, in_): pass def emitPUSHCONST(self, in_, typ, frame): #in_: String #typ: Type #frame: Frame if type(typ) is IntType: return self.emitPUSHICONST(in_, frame) elif type(typ) is BoolType: return self.emitPUSHICONST(str(in_), frame) elif type(typ) is FloatType: return self.emitPUSHFCONST(str(in_),frame) elif type(typ) is StringType: frame.push() return self.jvm.emitLDC("\"" + in_ + "\"") else: raise IllegalOperandException(in_) def emitPUSHICONST(self, in_, frame): #in: Int or Sring #frame: Frame frame.push(); if type(in_) is int: # INTEGER i = in_ if i >= -1 and i <=5: return self.jvm.emitICONST(i) elif i >= -128 and i <= 127: return self.jvm.emitBIPUSH(i) elif i >= -32768 and i <= 32767: return self.jvm.emitSIPUSH(i) else: return self.jvm.emitLDC(str(i)) elif type(in_) is str: # BOOLEAN if in_.lower() == "true": return self.emitPUSHICONST(1, frame) elif in_.lower() == "false": return self.emitPUSHICONST(0, frame) else: return self.emitPUSHICONST(int(in_), frame) def emitPUSHFCONST(self, in_, frame): #chu y phep cong khong chinh xac #in_: String #frame: Frame frame.push() f = float(in_) rst = "{0:.4f}".format(f) if rst == "0.0" or rst == "1.0" or rst == "2.0": return self.jvm.emitFCONST(rst) else: return self.jvm.emitLDC(in_) #---------------------------------------------------------------------# ''' * generate code to push a local variable onto the operand stack. ''' def emitALOAD(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... frame.pop() if type(in_) is IntType: return self.jvm.emitIALOAD() elif type(in_) is FloatType: return self.jvm.emitFALOAD() elif type(in_) is BoolType: return self.jvm.emitBALOAD() elif type(in_) in [cgen.ArrayPointerType, cgen.ClassType, StringType]: return self.jvm.emitAALOAD() else: raise IllegalOperandException(str(in_)) def emitREADVAR(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #... -> ..., value frame.push() if type(inType) in [IntType, BoolType]: return self.jvm.emitILOAD(index) if type(inType) is FloatType: return self.jvm.emitFLOAD(index) elif type(inType) in [cgen.ArrayPointerType, cgen.ClassType, StringType]: return self.jvm.emitALOAD(index) else: raise IllegalOperandException(name) #---------------------------------------------------------------------# ''' * generate code to pop a value on top of the operand stack and store it to a block-scoped variable. ''' def emitASTORE(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... frame.pop() # array address frame.pop() # index array frame.pop() # value if type(in_) is IntType: return self.jvm.emitIASTORE() elif type(in_) is FloatType: return self.jvm.emitFASTORE() elif type(in_) is BoolType: return self.jvm.emitBASTORE() elif type(in_) in [cgen.ArrayPointerType, cgen.ClassType, StringType]: return self.jvm.emitAASTORE() else: raise IllegalOperandException(str(in_)) def emitWRITEVAR(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #..., value -> ... frame.pop() if type(inType) in [IntType, BoolType]: return self.jvm.emitISTORE(index) elif type(inType) is FloatType: return self.jvm.emitFSTORE(index) elif type(inType) in [ cgen.ClassType, StringType]: return self.jvm.emitASTORE(index) elif type(inType) is cgen.ArrayPointerType: return self.jvm.emitIASTORE() else: raise IllegalOperandException(name) #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------ARITHMETIC INSTRUCTIONS-----------------------------------------------------# ''' * generate ineg, fneg. * @param in the type of the operands. ''' def emitNEGOP(self, in_, frame): #in_: Type #frame: Frame #..., value -> ..., result if type(in_) is IntType: return self.jvm.emitINEG() else: return self.jvm.emitFNEG() def emitNOT(self, in_, frame): #in_: Type #frame: Frame label1 = frame.getNewLabel() label2 = frame.getNewLabel() result = list() result.append(self.emitIFTRUE(label1, frame)) result.append(self.emitPUSHCONST("true", in_, frame)) result.append(self.emitGOTO(label2, frame)) result.append(self.emitLABEL(label1, frame)) result.append(self.emitPUSHCONST("false", in_, frame)) result.append(self.emitLABEL(label2, frame)) return ''.join(result) ''' * generate iadd, isub, fadd or fsub. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitADDOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result frame.pop() if lexeme == "+": if type(in_) is IntType: return self.jvm.emitIADD() else: return self.jvm.emitFADD() else: if type(in_) is IntType: return self.jvm.emitISUB() else: return self.jvm.emitFSUB() ''' * generate imul, idiv, fmul or fdiv. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitMULOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result frame.pop() if lexeme == "*": if type(in_) is IntType: return self.jvm.emitIMUL() else: return self.jvm.emitFMUL() else: if type(in_) is IntType: return self.jvm.emitIDIV() else: return self.jvm.emitFDIV() def emitDIV(self, frame): #frame: Frame frame.pop() return self.jvm.emitIDIV() def emitMOD(self, frame): #frame: Frame frame.pop() return self.jvm.emitIREM() def emitANDOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIAND() def emitOROP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIOR() def emitREOP(self, op, in_, frame): #op: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result result = list() labelF = frame.getNewLabel() labelO = frame.getNewLabel() frame.pop() frame.pop() compareF = self.jvm.emitFCMPL() if op == ">": result.append(self.jvm.emitIFICMPLE(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFLE(labelF)) # <= elif op == ">=": result.append(self.jvm.emitIFICMPLT(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFLT(labelF)) # > elif op == "<": result.append(self.jvm.emitIFICMPGE(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFGE(labelF)) # >= elif op == "<=": result.append(self.jvm.emitIFICMPGT(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFGT(labelF)) # > elif op == "!=": result.append(self.jvm.emitIFICMPEQ(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFEQ(labelF)) # = elif op == "==": result.append(self.jvm.emitIFICMPNE(labelF) if type(in_) is IntType else compareF + self.jvm.emitIFNE(labelF)) # <> result.append(self.emitPUSHCONST("1", IntType(), frame)) frame.pop() result.append(self.emitGOTO(labelO, frame)) result.append(self.emitLABEL(labelF, frame)) result.append(self.emitPUSHCONST("0", IntType(), frame)) result.append(self.emitLABEL(labelO, frame)) return ''.join(result) def emitRELOP(self, op, in_, trueLabel, falseLabel, frame): #op: String #in_: Type #trueLabel: Int #falseLabel: Int #frame: Frame #..., value1, value2 -> ..., result result = list() frame.pop() frame.pop() if op == ">": result.append(self.jvm.emitIFICMPLE(falseLabel)) result.append(self.emitGOTO(trueLabel)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(falseLabel)) elif op == "<": result.append(self.jvm.emitIFICMPGE(falseLabel)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(falseLabel)) elif op == "!=": result.append(self.jvm.emitIFICMPEQ(falseLabel)) elif op == "==": result.append(self.jvm.emitIFICMPNE(falseLabel)) result.append(self.jvm.emitGOTO(trueLabel)) return ''.join(result) #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------CONTROL TRANFER INSTRUCTIONS------------------------------------------------# ''' generate code to jump to label if the value on top of operand stack is true.<p> * ifgt label * @param label the label where the execution continues if the value on top of stack is true. ''' def emitIFTRUE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFGT(label) ''' * generate code to jump to label if the value on top of operand stack is false.<p> * ifle label * @param label the label where the execution continues if the value on top of stack is false. ''' def emitIFFALSE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFEQ(label) def emitIFICMPGT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPGT(label) def emitIFICMPLT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPLT(label) ''' generate code to jump to a label * @param label the label * @return code goto Label<label> ''' def emitGOTO(self, label, frame): #label: Int #frame: Frame return self.jvm.emitGOTO(str(label)) #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------TYPE CONVERSION INSTRUCTIONS------------------------------------------------# ''' generate code to exchange an integer on top of stack to a floating-point number. ''' def emitI2F(self, frame): #frame: Frame return self.jvm.emitI2F() #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------OPERAND STACK MANAGEMENT INSTRUCTIONS---------------------------------------# ''' generate code to duplicate the value on the top of the operand stack.<p> * Stack:<p> * Before: ...,value1<p> * After: ...,value1,value1<p> ''' def emitDUP(self, frame): #frame: Frame frame.push() return self.jvm.emitDUP() def emitPOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitPOP() #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------OPJECT CREATION AND MANIPULATION INSTRUCTIONS-------------------------------# #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------FIELD INSTRUCTIONS----------------------------------------------------------# def emitGETSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.push() return self.jvm.emitGETSTATIC(lexeme, self.getJVMType(in_))#load def emitPUTSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.pop() return self.jvm.emitPUTSTATIC(lexeme, self.getJVMType(in_))#store def emitGETFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame return self.jvm.emitGETFIELD(lexeme, self.getJVMType(in_)) def emitPUTFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame frame.pop() frame.pop() return self.jvm.emitPUTFIELD(lexeme, self.getJVMType(in_)) #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------METHOD INVOCATION INSTRUCTIONS----------------------------------------------# ''' generate code to invoke a static method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame typ = in_ list(map(lambda x: frame.pop(), typ.partype)) if not type(typ.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESTATIC(lexeme, self.getJVMType(in_)) ''' generate code to invoke a special method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESPECIAL(self, frame, lexeme=None, in_=None): #lexeme: String #in_: Type #frame: Frame if not lexeme is None and not in_ is None: typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESPECIAL(lexeme, self.getJVMType(in_)) elif lexeme is None and in_ is None: frame.pop() return self.jvm.emitINVOKESPECIAL() ''' generate code to invoke a virtual method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKEVIRTUAL(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ) is VoidType: frame.push() return self.jvm.emitINVOKEVIRTUAL(lexeme, self.getJVMType(in_)) #-----------------------------------------------------------------------------------------------------------------------# #-------------------------------------------JASMIN DIRECTIVES-----------------------------------------------------------# ''' generate the method directive for a function. * @param lexeme the qualified name of the method(i.e., class-name/method-name). * @param in the type descriptor of the method. * @param isStatic <code>true</code> if the method is static; <code>false</code> otherwise. ''' def emitMETHOD(self, lexeme, in_, isStatic, frame): #lexeme: String #in_: Type #isStatic: Boolean #frame: Frame return self.jvm.emitMETHOD(lexeme, self.getJVMType(in_), isStatic) ''' generate the end directive for a function. ''' def emitENDMETHOD(self, frame): #frame: Frame buffer = list() buffer.append(self.jvm.emitLIMITSTACK(frame.getMaxOpStackSize())) buffer.append(self.jvm.emitLIMITLOCAL(frame.getMaxIndex())) buffer.append(self.jvm.emitENDMETHOD()) return ''.join(buffer) ''' generate some starting directives for a class.<p> * .source MPC.CLASSNAME.java<p> * .class public MPC.CLASSNAME<p> * .super java/lang/Object<p> ''' ''' generate the var directive for a local variable. * @param in the index of the local variable. * @param varName the name of the local variable. * @param inType the type of the local variable. * @param fromLabel the starting label of the scope where the variable is active. * @param toLabel the ending label of the scope where the variable is active. ''' def emitVAR(self, in_, varName, inType, fromLabel, toLabel, frame): #in_: Int #varName: String #inType: Type #fromLabel: Int #toLabel: Int #frame: Frame return self.jvm.emitVAR(in_, varName, self.getJVMType(inType), fromLabel, toLabel) def emitATTRIBUTE(self, lexeme, in_, isFinal, value): #lexeme: String #in_: Type #isFinal: Boolean #value: String return self.jvm.emitSTATICFIELD(lexeme, self.getJVMType(in_), False) def emitPROLOG(self, name, parent): #name: String #parent: String result = list() result.append(self.jvm.emitSOURCE(name + ".java")) result.append(self.jvm.emitCLASS("public " + name)) result.append(self.jvm.emitSUPER("java/land/Object" if parent == "" else parent)) return ''.join(result) def emitLIMITSTACK(self, num): #num: Int return self.jvm.emitLIMITSTACK(num) def emitLIMITLOCAL(self, num): #num: Int return self.jvm.emitLIMITLOCAL(num) def emitEPILOG(self): file = open(self.filename, "w") file.write(''.join(self.buff)) file.close() #-----------------------------------------------------------------------------------------------------------------------# #--------------------------------------------OTHERS---------------------------------------------------------------------# ''' generate code to return. * <ul> * <li>ireturn if the type is IntegerType or BooleanType * <li>freturn if the type is RealType * <li>return if the type is null * </ul> * @param in the type of the returned expression. ''' def emitRETURN(self, in_, frame): #in_: Type #frame: Frame if type(in_) in [IntType, BoolType]: frame.pop() return self.jvm.emitIRETURN() elif type(in_) is FloatType: frame.pop() return self.jvm.emitFRETURN() elif type(in_) is VoidType: return self.jvm.emitRETURN() else: frame.pop() return self.jvm.emitARETURN() ''' generate code that represents a label * @param label the label * @return code Label<label>: ''' def emitLABEL(self, label, frame): #label: Int #frame: Frame return self.jvm.emitLABEL(label) def getConst(self, ast): #ast: Literal if type(ast) is IntLiteral: return (str(ast.value), IntType()) ''' print out the code to screen * @param in the code to be printed out ''' def printout(self, in_): #in_: String self.buff.append(in_) def clearBuff(self): self.buff.clear() ################################ new array def emitNEWARRAY(self, intype, index): #type: Type int boolean float Ljava/lang/String t = "" if intype is IntType: t ="int" elif intype is FloatType: t = "float" elif intype is BoolType: t= "boolean" elif intype is StringType: t ="java/lang/String" if t=="java/lang/String": return self.jvm.emitANEWARRAY(t) + self.jvm.emitASTORE(index) else : return self.jvm.emitNEWARRAY(t) + self.jvm.emitASTORE(index)
class Emitter(): def __init__(self, filename): self.filename = filename self.buff = list() self.jvm = JasminCode() def getJVMType(self, inType): typeIn = type(inType) if typeIn is cgen.IntType: return "I" elif typeIn is cgen.FloatType: return "F" elif typeIn is cgen.StringType: return "Ljava/lang/String;" elif typeIn is cgen.BoolType: return "Z" elif typeIn is cgen.VoidType: return "V" elif typeIn is cgen.ArrayType: return ("["*len(inType.dimen) if inType.dimen else '[') + self.getJVMType(inType.eleType) elif typeIn is cgen.MType: return "(" + "".join(list(map(lambda x: self.getJVMType(x), inType.partype))) + ")" + self.getJVMType(inType.rettype) elif typeIn is cgen.ClassType: return "L" + inType.cname + ";" else: return "" def getFullType(self, inType): typeIn = type(inType) if typeIn is cgen.IntType: return "int" elif typeIn is cgen.StringType: return "java/lang/String" elif typeIn is cgen.VoidType: return "void" elif typeIn is cgen.FloatType: return "float" elif typeIn is cgen.BoolType: return "boolean" @staticmethod def getIndexOfMultiDimenArray(flattenIdx, dimensions): result = [0]*len(dimensions) for i in range(len(dimensions))[::-1]: result[i] = flattenIdx % dimensions[i] flattenIdx //= dimensions[i-1] return result def emitCOMMENT(self, content): return f' ; {content}\n' def emitPUSHICONST(self, in_, frame): #in: Int or Sring #frame: Frame """Push a number if in_ is a number, 0 or 1 if in_ is string and value="true" or "false" Args: in_ (int or str): [description] frame ([type]): [description] Returns: [type]: [description] """ frame.push(); if type(in_) is int: i = in_ if i >= -1 and i <=5: return self.jvm.emitICONST(i) elif i >= -128 and i <= 127: return self.jvm.emitBIPUSH(i) elif i >= -32768 and i <= 32767: return self.jvm.emitSIPUSH(i) elif type(in_) is str: if in_ == "true": return self.emitPUSHICONST(1, frame) elif in_ == "false": return self.emitPUSHICONST(0, frame) else: return self.emitPUSHICONST(int(in_), frame) def emitPUSHFCONST(self, in_, frame): #in_: String #frame: Frame """ push float constatnt on top of stack Args: in_ (float): float value frame ([type]): [description] Returns: [type]: [description] """ if type(in_) is str: in_ = float(in_) frame.push() rst = "{0:.4f}".format(in_) if rst == "0.0" or rst == "1.0" or rst == "2.0": return self.jvm.emitFCONST(rst) else: return self.jvm.emitLDC(rst) ''' * generate code to push a constant onto the operand stack. * @param in the lexeme of the constant * @param typ the type of the constant ''' def emitPUSHCONST(self, in_, typ, frame): #in_: int, float, str or bool in python #typ: Type #frame: Frame """[summary] Args: in_ ([type]): [description] typ ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] Returns: [type]: [description] """ if type(typ) is cgen.IntType: return self.emitPUSHICONST(in_, frame) elif type(typ) is cgen.FloatType: return self.emitPUSHFCONST(in_, frame) elif type(typ) is cgen.BoolType: return self.emitPUSHICONST("true" if in_ else "false", frame) elif type(typ) is cgen.StringType: return self.emitLDC(in_, frame) else: raise IllegalOperandException(in_) def emitLDC(self, in_, frame): """[summary] Args: in_ (str): string constant frame ([type]): [description] Returns: [type]: [description] """ frame.push() if isinstance(in_, str): value = f'"{in_}"' else: value = in_ return self.jvm.emitLDC(value) ############################################################## def emitAALOAD(self, frame): """ Args: frame ([type]): [description] """ frame.pop() return self.jvm.emitAALOAD() def emitALOAD(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... """ in_: Type frame: Frame ..., arrayref, index, value -> ... Args: in_ ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] Returns: [type]: [description] """ frame.pop() if type(in_) is cgen.IntType: return self.jvm.emitIALOAD() elif type(in_) is cgen.ArrayType or type(in_) is cgen.ClassType or type(in_) is cgen.StringType: return self.jvm.emitAALOAD() elif type(in_) is cgen.BoolType: return self.jvm.emitBALOAD() elif type(in_) is cgen.FloatType: return self.jvm.emitFALOAD() else: raise IllegalOperandException(str(in_)) def emitASTORE(self, in_, frame): #in_: Type #frame: Frame #..., arrayref, index, value -> ... """ #in_: Type #frame: Frame #..., arrayref, index, value -> ... If in_ is IntType->IASTORE, in_ is ArrayType->AASTORE Args: in_ ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] Returns: [type]: [description] """ frame.pop() frame.pop() frame.pop() if (type(in_) is cgen.IntType): return self.jvm.emitIASTORE() elif type(in_) is cgen.FloatType: return self.jvm.emitFASTORE() elif type(in_) is cgen.ArrayType or type(in_) is cgen.ClassType or type(in_) is cgen.StringType: return self.jvm.emitAASTORE() elif type(in_) is cgen.BoolType: return self.jvm.emitBASTORE() else: raise IllegalOperandException(str(in_)) ''' generate the var directive for a local variable. * @param in the index of the local variable. * @param varName the name of the local variable. * @param inType the type of the local variable. * @param fromLabel the starting label of the scope where the variable is active. * @param toLabel the ending label of the scope where the variable is active. ''' def emitVAR(self, in_, varName, inType, fromLabel, toLabel, frame): #in_: Int #varName: String #inType: Type #fromLabel: Int #toLabel: Int #frame: Frame """ Args: in_ ([int]): [description] varName ([str]): [description] inType ([Type]): [description] fromLabel ([int]): [description] toLabel ([int]): [description] frame ([Frame]): [description] Returns: [type]: [description] """ return self.jvm.emitVAR(in_, varName, self.getJVMType(inType), fromLabel, toLabel) def emitREADVAR(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #... -> ..., value """[summary] Args: name ([type]): [description] inType ([type]): [description] index ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] Returns: [type]: [description] """ frame.push() if type(inType) is cgen.IntType or type(inType) is cgen.BoolType: return self.jvm.emitILOAD(index) elif type(inType) is cgen.FloatType: return self.jvm.emitFLOAD(index) elif type(inType) is cgen.ArrayType or type(inType) is cgen.ClassType or type(inType) is cgen.StringType: return self.jvm.emitALOAD(index) else: raise IllegalOperandException(name) ''' generate the second instruction for array cell access * ''' def emitREADVAR2(self, name, typ, frame): #name: String #typ: Type #frame: Frame #... -> ..., value """[summary] Args: name ([type]): [description] typ ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] """ #frame.push() raise IllegalOperandException(name) ''' * generate code to pop a value on top of the operand stack and store it to a block-scoped variable. * @param name the symbol entry of the variable. ''' def emitWRITEVAR(self, name, inType, index, frame): #name: String #inType: Type #index: Int #frame: Frame #..., value -> ... """[summary] Args: name ([type]): [description] inType ([type]): [description] index ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] Returns: [type]: [description] """ frame.pop() if (type(inType) is cgen.IntType) or (type(inType) is cgen.BoolType): return self.jvm.emitISTORE(index) elif type(inType) is cgen.FloatType: return self.jvm.emitFSTORE(index) elif type(inType) is cgen.ArrayType or type(inType) is cgen.ClassType or type(inType) is cgen.StringType: return self.jvm.emitASTORE(index) else: raise IllegalOperandException(name) ''' generate the second instruction for array cell access * ''' def emitWRITEVAR2(self, name, typ, frame): #name: String #typ: Type #frame: Frame #..., value -> ... """[summary] Args: name ([type]): [description] typ ([type]): [description] frame ([type]): [description] Raises: IllegalOperandException: [description] """ frame.pop() frame.pop() frame.pop() inType = type(typ) if inType is cgen.IntType: return self.jvm.emitIASTORE() elif inType is cgen.FloatType: return self.jvm.emitFASTORE() elif inType is cgen.BoolType: return self.jvm.emitBASTORE() elif inType is cgen.StringType: return self.jvm.emitAASTORE() else: raise IllegalOperandException(name) ''' generate the field (static) directive for a class mutable or immutable attribute. * @param lexeme the name of the attribute. * @param in the type of the attribute. * @param isFinal true in case of constant; false otherwise ''' def emitATTRIBUTE(self, lexeme, in_, isFinal, value): #lexeme: String #in_: Type #isFinal: Boolean #value: String """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] isFinal (bool): [description] value ([type]): [description] Returns: [type]: [description] """ return self.jvm.emitSTATICFIELD(lexeme, self.getJVMType(in_), False) def emitGETSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ frame.push() return self.jvm.emitGETSTATIC(lexeme, self.getJVMType(in_)) def emitPUTSTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme (str): name of attribute in_ (Type): type of attribute frame ([type]): [description] Returns: [type]: [description] """ frame.pop() return self.jvm.emitPUTSTATIC(lexeme, self.getJVMType(in_)) def emitGETFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ return self.jvm.emitGETFIELD(lexeme, self.getJVMType(in_)) def emitPUTFIELD(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ frame.pop() frame.pop() return self.jvm.emitPUTFIELD(lexeme, self.getJVMType(in_)) ''' generate code to invoke a static method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESTATIC(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme (str): method name in_ (MType): method description frame ([type]): [description] Returns: [type]: [description] """ typ = in_ list(map(lambda x: frame.pop(), typ.partype)) if not type(typ.rettype) is cgen.VoidType: frame.push() return self.jvm.emitINVOKESTATIC(lexeme, self.getJVMType(in_)) ''' generate code to invoke a special method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESPECIAL(self, frame, lexeme=None, in_=None): #lexeme: String #in_: Type #frame: Frame """[summary] Args: frame ([type]): [description] lexeme ([type], optional): [description]. Defaults to None. in_ ([type], optional): [description]. Defaults to None. Returns: [type]: [description] """ if not lexeme is None and not in_ is None: typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ.rettype) is cgen.VoidType: frame.push() return self.jvm.emitINVOKESPECIAL(lexeme, self.getJVMType(in_)) elif lexeme is None and in_ is None: frame.pop() return self.jvm.emitINVOKESPECIAL() ''' generate code to invoke a virtual method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKEVIRTUAL(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ) is cgen.VoidType: frame.push() return self.jvm.emitINVOKEVIRTUAL(lexeme, self.getJVMType(in_)) ''' * generate ineg, fneg. * @param in the type of the operands. ''' def emitNEGOP(self, in_, frame): #in_: Type #frame: Frame #..., value -> ..., result """[summary] Args: in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ if type(in_) is cgen.IntType: return self.jvm.emitINEG() else: return self.jvm.emitFNEG() def emitNOT(self, in_, frame): #in_: Type #frame: Frame """[summary] Args: in_ ([Type]): [description] frame ([type]): [description] Returns: [type]: [description] """ label1 = frame.getNewLabel() label2 = frame.getNewLabel() result = list() result.append(self.emitIFTRUE(label1, frame)) result.append(self.emitPUSHCONST(True, in_, frame)) result.append(self.emitGOTO(label2, frame)) result.append(self.emitLABEL(label1, frame)) result.append(self.emitPUSHCONST(False, in_, frame)) result.append(self.emitLABEL(label2, frame)) return ''.join(result) ''' * generate iadd, isub, fadd or fsub. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitADDOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result """[summary] Args: lexeme (str): Operator string in_ (Type): Type of operand frame ([type]): [description] Returns: [type]: [description] """ frame.pop() if lexeme == "+": if type(in_) is cgen.IntType: return self.jvm.emitIADD() else: return self.jvm.emitFADD() else: if type(in_) is cgen.IntType: return self.jvm.emitISUB() else: return self.jvm.emitFSUB() ''' * generate imul, idiv, fmul or fdiv. * @param lexeme the lexeme of the operator. * @param in the type of the operands. ''' def emitMULOP(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ frame.pop() if lexeme == "*": if type(in_) is cgen.IntType: return self.jvm.emitIMUL() else: return self.jvm.emitFMUL() else: if type(in_) is cgen.IntType: return self.jvm.emitIDIV() else: return self.jvm.emitFDIV() def emitDIV(self, frame): #frame: Frame frame.pop() return self.jvm.emitIDIV() def emitMOD(self, frame): #frame: Frame frame.pop() return self.jvm.emitIREM() ''' * generate iand ''' def emitANDOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIAND() ''' * generate ior ''' def emitOROP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIOR() def emitREOP(self, op, in_, frame): #op: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result """ emit relation op Args: op ([type]): [description] in_ ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ result = list() labelF = frame.getNewLabel() labelO = frame.getNewLabel() frame.pop() frame.pop() if op == ">": result.append(self.jvm.emitIFICMPLE(labelF)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(labelF)) elif op == "<": result.append(self.jvm.emitIFICMPGE(labelF)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(labelF)) elif op == "!=": result.append(self.jvm.emitIFICMPEQ(labelF)) elif op == "==": result.append(self.jvm.emitIFICMPNE(labelF)) result.append(self.emitPUSHCONST("1", cgen.IntType(), frame)) frame.pop() result.append(self.emitGOTO(labelO, frame)) result.append(self.emitLABEL(labelF, frame)) result.append(self.emitPUSHCONST("0", cgen.IntType(), frame)) result.append(self.emitLABEL(labelO, frame)) return ''.join(result) def emitFREOP(self, op, in_, frame): """ emit relation expression for float type Args: op ([type]): [description] in_ ([type]): [description] frame ([type]): [description] """ result = list() labelF = frame.getNewLabel() labelO = frame.getNewLabel() frame.pop() frame.pop() if op == ">.": result.append(self.jvm.emitFCMPL()) result.append(self.emitPUSHICONST(0, frame)) result.append(self.jvm.emitIFICMPLE(labelF)) elif op == ">=.": # true if 0 and 1, false is -1 result.append(self.jvm.emitFCMPL()) result.append(self.emitPUSHICONST(0, frame)) result.append(self.jvm.emitIFICMPLT(labelF)) elif op == "<.": # true if -1, false if 0 and 1 result.append(self.jvm.emitFCMPL()) result.append(self.emitPUSHICONST(0, frame)) result.append(self.jvm.emitIFICMPGE(labelF)) elif op == "<=.": # true if -1, 0, false if 1 result.append(self.jvm.emitFCMPL()) result.append(self.emitPUSHICONST(0, frame)) result.append(self.jvm.emitIFICMPGT(labelF)) elif op == "=/=": # true if 0, false if -1 and 1 result.append(self.jvm.emitFCMPL()) result.append(self.emitPUSHICONST(0, frame)) result.append(self.jvm.emitIFICMPEQ(labelF)) result.append(self.emitPUSHCONST("1", cgen.IntType(), frame)) frame.pop() result.append(self.emitGOTO(labelO, frame)) result.append(self.emitLABEL(labelF, frame)) result.append(self.emitPUSHCONST("0", cgen.IntType(), frame)) result.append(self.emitLABEL(labelO, frame)) return ''.join(result) def emitRELOP(self, op, in_, trueLabel, falseLabel, frame): #op: String #in_: Type #trueLabel: Int #falseLabel: Int #frame: Frame #..., value1, value2 -> ..., result """ emit relation operator and jump instruction Args: op ([type]): [description] in_ ([type]): [description] trueLabel ([type]): [description] falseLabel ([type]): [description] frame ([type]): [description] Returns: [type]: [description] """ result = list() frame.pop() frame.pop() if op == ">": result.append(self.jvm.emitIFICMPLE(falseLabel)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(falseLabel)) elif op == "<": result.append(self.jvm.emitIFICMPGE(falseLabel)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(falseLabel)) elif op == "!=": result.append(self.jvm.emitIFICMPEQ(falseLabel)) elif op == "==": result.append(self.jvm.emitIFICMPNE(falseLabel)) result.append(self.jvm.emitGOTO(trueLabel)) return ''.join(result) ''' generate the method directive for a function. * @param lexeme the qualified name of the method(i.e., class-name/method-name). * @param in the type descriptor of the method. * @param isStatic <code>true</code> if the method is static; <code>false</code> otherwise. ''' def emitMETHOD(self, lexeme, in_, isStatic, frame): #lexeme: String #in_: Type #isStatic: Boolean #frame: Frame """[summary] Args: lexeme ([type]): [description] in_ ([type]): [description] isStatic (bool): [description] frame ([type]): [description] Returns: [type]: [description] """ return self.jvm.emitMETHOD(lexeme, self.getJVMType(in_), isStatic) ''' generate the end directive for a function. ''' def emitENDMETHOD(self, frame): #frame: Frame """[summary] Args: frame ([type]): [description] Returns: [type]: [description] """ buffer = list() buffer.append(self.jvm.emitLIMITSTACK(frame.getMaxOpStackSize())) buffer.append(self.jvm.emitLIMITLOCAL(frame.getMaxIndex())) buffer.append(self.jvm.emitENDMETHOD()) return ''.join(buffer) def getConst(self, ast): #ast: Literal if type(ast) is IntLiteral: return (str(ast.value), cgen.IntType()) ''' generate code to initialize a local array variable.<p> * @param index the index of the local variable. * @param in the type of the local array variable. ''' def emitARRAY(self, typ, values, dimensions, frame): """ Initialize a local array variable and all of its element value Args: in (Type): [description] values (List[int]): flatten list of value, if array is multidimension with size n1*n2*.., then length of values is product of all dimensions dimensions (List[int]): dimemsions of this array Returns: [type]: [description] """ result = list() if len(dimensions) == 1: eleType = typ.eleType result.append(self.emitPUSHICONST(dimensions[0], frame)) if type(eleType) is cgen.StringType: result.append(self.jvm.emitANEWARRAY(self.getFullType(eleType))) else: result.append(self.jvm.emitNEWARRAY(self.getFullType(eleType))) for _ in range(dimensions[0]): result.append(self.emitDUP(frame)) for idx, val in enumerate(values): result.append(self.emitPUSHICONST(idx, frame)) result.append(self.emitPUSHCONST(val, eleType, frame)) result.append(self.emitASTORE(eleType, frame)) else: #TODO for dimen in dimensions: result.append(self.emitPUSHICONST(dimen, frame)) frame.push() result.append(self.jvm.emitMULTIANEWARRAY(self.getJVMType(typ), str(len(dimensions)))) # Initialize values _ = [result.append(self.emitDUP(frame)) for _ in range(len(values))] for idx, val in enumerate(values): idxs = Emitter.getIndexOfMultiDimenArray(idx, dimensions) for idx_val in idxs[:-1]: result.append(self.emitPUSHICONST(idx_val, frame)) frame.pop() result.append(self.jvm.emitAALOAD()) result.append(self.emitPUSHICONST(idxs[-1], frame)) result.append(self.emitPUSHCONST(val, typ.eleType, frame)) result.append(self.emitASTORE(typ.eleType, frame)) return ''.join(result) ''' generate code to initialize local array variables. * @param in the list of symbol entries corresponding to local array variable. ''' ''' generate code to jump to label if the value on top of operand stack is true.<p> * ifgt label * @param label the label where the execution continues if the value on top of stack is true. ''' def emitIFTRUE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFGT(label) ''' * generate code to jump to label if the value on top of operand stack is false.<p> * ifle label * @param label the label where the execution continues if the value on top of stack is false. ''' def emitIFFALSE(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFLE(label) def emitIFICMPGT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPGT(label) def emitIFICMPLT(self, label, frame): #label: Int #frame: Frame frame.pop() return self.jvm.emitIFICMPLT(label) ''' generate code to duplicate the value on the top of the operand stack.<p> * Stack:<p> * Before: ...,value1<p> * After: ...,value1,value1<p> ''' def emitDUP(self, frame): #frame: Frame frame.push() return self.jvm.emitDUP() def emitPOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitPOP() ''' generate code to exchange an integer on top of stack to a floating-point number. ''' def emitI2F(self, frame): #frame: Frame return self.jvm.emitI2F() ''' generate code to return. * <ul> * <li>ireturn if the type is IntegerType or BooleanType * <li>freturn if the type is RealType * <li>return if the type is null * </ul> * @param in the type of the returned expression. ''' def emitRETURN(self, in_, frame): #in_: Type #frame: Frame if type(in_) is cgen.IntType or type(in_) is cgen.BoolType: frame.pop() return self.jvm.emitIRETURN() elif type(in_) is cgen.FloatType: frame.pop() return self.jvm.emitFRETURN() elif type(in_) is cgen.StringType or type(in_) is cgen.ArrayType: frame.pop() return self.jvm.emitARETURN() elif type(in_) is cgen.VoidType: return self.jvm.emitRETURN() ''' generate code that represents a label * @param label the label * @return code Label<label>: ''' def emitLABEL(self, label, frame): #label: Int #frame: Frame return self.jvm.emitLABEL(label) ''' generate code to jump to a label * @param label the label * @return code goto Label<label> ''' def emitGOTO(self, label, frame): #label: Int #frame: Frame return self.jvm.emitGOTO(label) ''' generate some starting directives for a class.<p> * .source MPC.CLASSNAME.java<p> * .class public MPC.CLASSNAME<p> * .super java/lang/Object<p> ''' def emitPROLOG(self, name, parent): #name: String #parent: String result = list() result.append(self.jvm.emitSOURCE(name + ".java")) result.append(self.jvm.emitCLASS("public " + name)) result.append(self.jvm.emitSUPER("java/land/Object" if parent == "" else parent)) return ''.join(result) def emitLIMITSTACK(self, num): #num: Int return self.jvm.emitLIMITSTACK(num) def emitLIMITLOCAL(self, num): #num: Int return self.jvm.emitLIMITLOCAL(num) def emitEPILOG(self): file = open(self.filename, "w") file.write(''.join(self.buff)) file.close() ''' print out the code to screen * @param in the code to be printed out ''' def printout(self, in_): #in_: String self.buff.append(in_) def clearBuff(self): self.buff.clear()
class Emitter(): def __init__(self, filename): self.filename = filename self.buff = list() self.jvm = JasminCode() def getJVMType(self, inType): typeIn = type(inType) if typeIn is IntType: return "I" elif typeIn is FloatType: return "F" elif typeIn is BoolType: return "Z" elif typeIn is cgen.StringType: return "Ljava/lang/String;" elif typeIn is VoidType: return "V" elif typeIn is cgen.ArrayPointerType: return "[" + self.getJVMType(inType.eleType) elif typeIn is MType: return "(" + "".join(list(map(lambda x: self.getJVMType(x), inType.partype))) + ")" + self.getJVMType(inType.rettype) elif typeIn is cgen.ClassType: return "L" + inType.cname + ";" else: raise IllegalOperandException(str(inType)) # def getFullType(inType): # typeIn = type(inType) # if typeIn is IntType: # return "int" # elif typeIn is cgen.StringType: # return "java/lang/String" # elif typeIn is VoidType: # return "void" def emitPUSHICONST(self, in_, frame): #in: Int or Sring #frame: Frame if type(in_) is int: frame.push(); i = in_ if i >= -1 and i <=5: return self.jvm.emitICONST(i) elif i >= -128 and i <= 127: return self.jvm.emitBIPUSH(i) elif i >= -32768 and i <= 32767: return self.jvm.emitSIPUSH(i) else: return self.jvm.emitLDC(str(i)) elif type(in_) is str: if in_.lower() == "true": return self.emitPUSHICONST(1, frame) elif in_.lower() == "false": return self.emitPUSHICONST(0, frame) else: return self.emitPUSHICONST(int(in_), frame) def emitPUSHFCONST(self, in_, frame): #in_: String #frame: Frame f = float(in_) frame.push() if f in (0.0, 1.0, 2.0): rst = "{0:.1f}".format(f) return self.jvm.emitFCONST(rst) else: return self.jvm.emitLDC(in_) # generate code to push a constant onto the operand stack. # @param in_: the lexeme (String) of the constant # @param typ: the type of the constant def emitPUSHCONST(self, in_, typ, frame): #in_: String #typ: Type #frame: Frame if type(typ) is IntType: return self.emitPUSHICONST(in_, frame) elif type(typ) is StringType: frame.push() return self.jvm.emitLDC('"' + in_ + '"') else: raise IllegalOperandException(in_) ################################################################ # Unary Operators ################################################################ # generate ineg, fneg. # @param in_: the type of the operands. # ..., value -> ..., result def emitNEGOP(self, in_, frame): if type(in_) is IntType: return self.jvm.emitINEG() else: return self.jvm.emitFNEG() def emitNOT(self, frame): label1 = frame.getNewLabel() label2 = frame.getNewLabel() result = list() result.append(self.emitIFTRUE(label1, frame)) result.append(self.emitPUSHICONST("true", frame)) result.append(self.emitGOTO(label2, frame)) result.append(self.emitLABEL(label1, frame)) result.append(self.emitPUSHICONST("false", frame)) result.append(self.emitLABEL(label2, frame)) return ''.join(result) ################################################################ ## Binary Operators ################################################################ # generate iadd, isub, fadd or fsub. # @param lexeme: the lexeme (String) of the operator. # @param in_: the type of the operands. # ..., value1, value2 -> result def emitADDOP(self, lexeme, in_, frame): frame.pop() if lexeme == "+": if type(in_) is IntType: return self.jvm.emitIADD() else: return self.jvm.emitFADD() else: if type(in_) is IntType: return self.jvm.emitISUB() else: return self.jvm.emitFSUB() # generate imul, idiv, fmul or fdiv. # @param lexeme: the lexeme (String) of the operator. # @param in_: the type of the operands. # ..., value1, value2 -> result def emitMULOP(self, lexeme, in_, frame): frame.pop() if lexeme == "*": if type(in_) is IntType: return self.jvm.emitIMUL() else: return self.jvm.emitFMUL() else: if type(in_) is IntType: return self.jvm.emitIDIV() else: return self.jvm.emitFDIV() def emitDIV(self, frame): #frame: Frame frame.pop() return self.jvm.emitIDIV() def emitMOD(self, frame): #frame: Frame frame.pop() return self.jvm.emitIREM() def emitANDOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIAND() def emitOROP(self, frame): #frame: Frame frame.pop() return self.jvm.emitIOR() def emitREOP(self, op, in_, frame): #op: String #in_: Type #frame: Frame #..., value1, value2 -> ..., result result = list() labelFalse = frame.getNewLabel() labelOut = frame.getNewLabel() frame.pop() frame.pop() if type(in_) is IntType: if op == ">": result.append(self.jvm.emitIFICMPLE(labelFalse)) elif op == ">=": result.append(self.jvm.emitIFICMPLT(labelFalse)) elif op == "<": result.append(self.jvm.emitIFICMPGE(labelFalse)) elif op == "<=": result.append(self.jvm.emitIFICMPGT(labelFalse)) elif op == "<>": result.append(self.jvm.emitIFICMPEQ(labelFalse)) elif op == "=": result.append(self.jvm.emitIFICMPNE(labelFalse)) else: result.append(self.jvm.emitFCMPL()) if op == ">": result.append(self.jvm.emitIFLE(labelFalse)) elif op == ">=": result.append(self.jvm.emitIFLT(labelFalse)) elif op == "<": result.append(self.jvm.emitIFGE(labelFalse)) elif op == "<=": result.append(self.jvm.emitIFGT(labelFalse)) elif op == "<>": result.append(self.jvm.emitIFEQ(labelFalse)) elif op == "=": result.append(self.jvm.emitIFNE(labelFalse)) result.append(self.emitPUSHCONST("1", IntType(), frame)) result.append(self.emitGOTO(labelOut, frame)) result.append(self.emitLABEL(labelFalse, frame)) result.append(self.emitPUSHCONST("0", IntType(), frame)) result.append(self.emitLABEL(labelOut, frame)) frame.pop() # only "1" or "0" return ''.join(result) # def emitRELOP(self, op, in_, trueLabel, falseLabel, frame): # #op: String # #in_: Type # #trueLabel: Int # #falseLabel: Int # #frame: Frame # #..., value1, value2 -> ..., result # result = list() # frame.pop() # frame.pop() # if op == ">": # result.append(self.jvm.emitIFICMPLE(falseLabel)) # elif op == ">=": # result.append(self.jvm.emitIFICMPLT(falseLabel)) # elif op == "<": # result.append(self.jvm.emitIFICMPGE(falseLabel)) # elif op == "<=": # result.append(self.jvm.emitIFICMPGT(falseLabel)) # elif op == "<>": # result.append(self.jvm.emitIFICMPEQ(falseLabel)) # elif op == "=": # result.append(self.jvm.emitIFICMPNE(falseLabel)) # result.append(self.jvm.emitGOTO(trueLabel)) # return ''.join(result) ################################################################ ## Labeling and Jumping ################################################################ # generate code to jump to label if the value on top of operand stack is true # ifgt label # @param label: the label (Int) where the execution continues if the value on top of stack is true def emitIFTRUE(self, label, frame): frame.pop() return self.jvm.emitIFGT(label) # generate code to jump to label if the value on top of operand stack is false # ifle label # @param label: the label (Int) where the execution continues if the value on top of stack is false def emitIFFALSE(self, label, frame): frame.pop() return self.jvm.emitIFLE(label) # ..., value1, value2 -> ... # generate code to jump to label if value1 > value2 # label: Int def emitIFICMPGT(self, label, frame): frame.pop() frame.pop() return self.jvm.emitIFICMPGT(label) # ..., value1, value2 -> ... # generate code to jump to label if value1 < value2 # label: Int def emitIFICMPLT(self, label, frame): frame.pop() frame.pop() return self.jvm.emitIFICMPLT(label) # @return code goto Label<label> # @param label: Int def emitGOTO(self, label, frame): return self.jvm.emitGOTO(str(label)) # @return code Label<label> # @param label: Int def emitLABEL(self, label, frame): return self.jvm.emitLABEL(label) ################################################################ ## No Arrays ################################################################ # def emitALOAD(self, in_, frame): # #in_: Type # #frame: Frame # #..., arrayref, index, value -> ... # frame.pop() # if type(in_) is IntType: # return self.jvm.emitIALOAD() # elif type(in_) is cgen.ArrayPointerType or type(in_) is cgen.ClassType or type(in_) is StringType: # return self.jvm.emitAALOAD() # else: # raise IllegalOperandException(str(in_)) # def emitASTORE(self, in_, frame): # #in_: Type # #frame: Frame # #..., arrayref, index, value -> ... # frame.pop() # frame.pop() # frame.pop() # if type(in_) is IntType: # return self.jvm.emitIASTORE() # elif type(in_) is cgen.ArrayPointerType or type(in_) is cgen.ClassType or type(in_) is StringType: # return self.jvm.emitAASTORE() # else: # raise IllegalOperandException(str(in_)) ################################################################ ## Declarations ################################################################ # generate the var directive for a local variable. # @param in_: Int the index of the local variable. # @param varName: String the name of the local variable. # @param inType: Type the type of the local variable. # @param fromLabel: Int the starting label of the scope where the variable is active. # @param toLabel: Int the ending label of the scope where the variable is active. def emitVAR(self, in_, varName, inType, fromLabel, toLabel, frame): return self.jvm.emitVAR(in_, varName, self.getJVMType(inType), fromLabel, toLabel) # generate the field (static) directive for a class mutable or immutable attribute. # @param lexeme: the name of the attribute. # @param in_: the type of the attribute. # @param isFinal: true in case of constant, false otherwise def emitATTRIBUTE(self, lexeme, in_, isFinal, value): return self.jvm.emitSTATICFIELD(lexeme, self.getJVMType(in_), False) # iload, fload, aload # push a value to stack def emitREADVAR(self, name, inType, index, frame): frame.push() if type(inType) in (IntType, BoolType): return self.jvm.emitILOAD(index) elif type(inType) is FloatType: return self.jvm.emitFLOAD(index) elif type(inType) is cgen.ArrayPointerType or type(inType) is cgen.ClassType or type(inType) is StringType: return self.jvm.emitALOAD(index) else: raise IllegalOperandException(name) # istore, fstore, astore # pop a value from stack def emitWRITEVAR(self, name, inType, index, frame): frame.pop() if type(inType) in (IntType, BoolType): return self.jvm.emitISTORE(index) elif type(inType) is FloatType: return self.jvm.emitFSTORE(index) elif type(inType) is cgen.ArrayPointerType or type(inType) is cgen.ClassType or type(inType) is StringType: return self.jvm.emitASTORE(index) else: raise IllegalOperandException(name) # getstatic # push a value to stack def emitGETSTATIC(self, lexeme, in_, frame): frame.push() return self.jvm.emitGETSTATIC(lexeme, self.getJVMType(in_)) # putstatic # pop a value from stack def emitPUTSTATIC(self, lexeme, in_, frame): frame.pop() return self.jvm.emitPUTSTATIC(lexeme, self.getJVMType(in_)) # def emitGETFIELD(self, lexeme, in_, frame): # frame.push() # return self.jvm.emitGETFIELD(lexeme, self.getJVMType(in_)) # def emitPUTFIELD(self, lexeme, in_, frame): # frame.pop() # return self.jvm.emitPUTFIELD(lexeme, self.getJVMType(in_)) ################################################################ ## Functions ################################################################ # generate code to invoke a static method # @param lexeme the qualified name of the method(i.e., class-name/method-name) # @param in_ the type descriptor of the method. def emitINVOKESTATIC(self, lexeme, in_, frame): mtype = in_ list(map(lambda x: frame.pop(), mtype.partype)) if not type(mtype.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESTATIC(lexeme, self.getJVMType(in_)) # return, ireturn, freturn def emitRETURN(self, in_, frame): if type(in_) in (IntType, BoolType): frame.pop() return self.jvm.emitIRETURN() elif type(in_) is FloatType: frame.pop() return self.jvm.emitFRETURN() elif type(in_) is StringType: frame.pop() return self.jvm.emitARETURN() elif type(in_) is VoidType: return self.jvm.emitRETURN() else: raise IllegalOperandException(str(in_)) # remove the last occurrence of "ele" in the list "buff" def reversedremove(self, ele): if ele in self.buff: del self.buff[-self.buff[::-1].index(ele) - 1] ################################################################################################################################ ''' generate code to invoke a special method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKESPECIAL(self, frame, lexeme=None, in_=None): #lexeme: String #in_: Type #frame: Frame if not lexeme is None and not in_ is None: typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ.rettype) is VoidType: frame.push() return self.jvm.emitINVOKESPECIAL(lexeme, self.getJVMType(in_)) elif lexeme is None and in_ is None: frame.pop() return self.jvm.emitINVOKESPECIAL() ''' generate code to invoke a virtual method * @param lexeme the qualified name of the method(i.e., class-name/method-name) * @param in the type descriptor of the method. ''' def emitINVOKEVIRTUAL(self, lexeme, in_, frame): #lexeme: String #in_: Type #frame: Frame typ = in_ list(map(lambda x: frame.pop(), typ.partype)) frame.pop() if not type(typ) is VoidType: frame.push() return self.jvm.emitINVOKEVIRTUAL(lexeme, self.getJVMType(in_)) ''' generate the method directive for a function. * @param lexeme the qualified name of the method(i.e., class-name/method-name). * @param in the type descriptor of the method. * @param isStatic <code>true</code> if the method is static; <code>false</code> otherwise. ''' def emitMETHOD(self, lexeme, in_, isStatic, frame): #lexeme: String #in_: Type #isStatic: Boolean #frame: Frame return self.jvm.emitMETHOD(lexeme, self.getJVMType(in_), isStatic) ''' generate the end directive for a function. ''' def emitENDMETHOD(self, frame): #frame: Frame buffer = list() buffer.append(self.jvm.emitLIMITSTACK(frame.getMaxOpStackSize())) buffer.append(self.jvm.emitLIMITLOCAL(frame.getMaxIndex())) buffer.append(self.jvm.emitENDMETHOD()) return ''.join(buffer) def getConst(self, ast): #ast: Literal if type(ast) is IntLiteral: return (str(ast.value), IntType()) ''' generate code to initialize a local array variable.<p> * @param index the index of the local variable. * @param in the type of the local array variable. ''' ''' generate code to initialize local array variables. * @param in the list of symbol entries corresponding to local array variable. ''' ''' generate code to duplicate the value on the top of the operand stack.<p> * Stack:<p> * Before: ...,value1<p> * After: ...,value1,value1<p> ''' def emitDUP(self, frame): #frame: Frame frame.push() return self.jvm.emitDUP() def emitPOP(self, frame): #frame: Frame frame.pop() return self.jvm.emitPOP() ''' generate code to exchange an integer on top of stack to a floating-point number. ''' def emitI2F(self, frame): #frame: Frame return self.jvm.emitI2F() ''' generate some starting directives for a class.<p> * .source MPC.CLASSNAME.java<p> * .class public MPC.CLASSNAME<p> * .super java/lang/Object<p> ''' def emitPROLOG(self, name, parent): #name: String #parent: String result = list() result.append(self.jvm.emitSOURCE(name + ".java")) result.append(self.jvm.emitCLASS("public " + name)) result.append(self.jvm.emitSUPER("java/land/Object" if parent == "" else parent)) return ''.join(result) def emitLIMITSTACK(self, num): #num: Int return self.jvm.emitLIMITSTACK(num) def emitLIMITLOCAL(self, num): #num: Int return self.jvm.emitLIMITLOCAL(num) def emitEPILOG(self): file = open(self.filename, "w") file.write(''.join(self.buff)) file.close() def printout(self, in_): self.buff.append(in_) def clearBuff(self): self.buff.clear()