示例#1
0
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()
示例#2
0
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()
示例#4
0
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()