Esempio n. 1
0
class CodeGen(Transformer):
    def __init__(self,functions,globalVariables,structure):
        self.label_num = 0
        self.data_name_num = 0
        self.break_num = 0
        self.data_code = ''
        self.Stack = Stack(globalVariables)
        self.Functions = functions
        self.structure = structure
        self.whereAmI = 0
        self.dataCodeGlobalVariables(globalVariables)

    # [--------------------------------------------------------- Assets ---------------------------------------------------------]
    def isClassMethod(self , name):
         # Search function if its defined in the class
         if self.inClass():
             this = self.Stack.getVar("this")
             c = Class.searchClass(this.type)
             if c is None:
                 raise Exception("Class with name " + this.type + " not exists !")
             if c.methodExists(name):
                 return True
         return False

    def function_type(self , name):
        # Search function if its defined in the class
        if self.inClass():
            this = self.Stack.getVar("this")
            c = Class.searchClass(this.type)
            if c is None:
                raise Exception("Class with name " + this.type + " not exists !")
            if c.methodExists(name):
                return c.getMethod(name)['type']
        # Search in global scope
        for function in self.Functions:
            if function['name'] == name:
                return function['type']
        raise Exception("function ( " + name + " ) not found !!!")

    def getFunctionLabel(self , name):
        # Search function if its defined in the class
        if self.inClass():
            this = self.Stack.getVar("this")
            c = Class.searchClass(this.type)
            if c is None:
                raise Exception("Class with name " + this.type + " not exists !")
            if c.methodExists(name):
                return c.name + "_" + name
        # Search in global scope
        for function in self.Functions:
            if function['name'] == name:
                return name
        raise Exception("function ( " + name + " ) not found !!!")

    def in_break_labels(self , arr , name):
        for item in arr:
            if item['name'] == name:
                return True
        return False

    def get_count_break_label(self , arr , name):
        for item in arr:
            if item['name'] == name:
                return item['count']
        raise Exception("no label found for " + name)

    def dataCodeGlobalVariables(self , vars):
        for var in vars:
            if var['type'] == 'double':
                self.data_code += "data_" + var['id'] + " : .float 0.0\n"
            else:
                self.data_code += "data_" + var['id'] + " : .word 0\n"

    def inClass(self):
        if self.structure[self.whereAmI]['type'] == 'class':
            return True
        return False

    def label_generator(self):
        newLabel = "L" + str(self.label_num)
        self.label_num = self.label_num + 1
        return newLabel
    def data_name_generator(self):
        new_name = 'D' + str(self.data_name_num)
        self.data_name_num += 1
        return new_name
    def break_generator(self):
        new_break = 'break' + str(self.break_num)
        self.break_num += 1;
        return new_break
    #[--------------------------------------------------------- Debugging tools ---------------------------------------------------------]
    def log_code(self,code):
        dirname = os.path.dirname(__file__)
        file = open(dirname + "/code.s","w")
        file.write(code)
        file.close()
    #[--------------------------------------------------------- Semantic Actions ---------------------------------------------------------]
    ############# Program #############
    def start(self, args):
        dirname = os.path.dirname(__file__)
        file = open(dirname + "/Compiler_Functions.txt", "r")
        default_functions = file.read()
        file.close()
        code = '.text\n'
        code += '.globl main\n'
        code += default_functions
        code += Class.getConstructors()
        code += args[0]['code']
        self.data_code += "str_false : .asciiz \"false\" \n"
        self.data_code += "str_true : .asciiz \"true\" \n"
        self.data_code += "str_bool : .word str_false , str_true\n"
        self.data_code += "obj_null : .word 61235\n"
        self.data_code += Class.getVtables()
        self.log_code(code + "\n\n.data\n" + self.data_code)
        return args
    def program(self, args):
        decl = args[0]
        decl_more = args[1]
        code = decl['code'] + decl_more['code']
        return {'code': code}
    def decl_more(self, args):
        decl = args[0]
        decl_more = args[1]
        code = decl['code'] + decl_more['code']
        return {'code' : code}
    def decl_more_empty(self, args):
        return {'code' : ''}
    ######################################################### Variable Declaration #########################################################
    def variable(self, args):
        id = args[1].children[0]
        type = args[0]
        return {'id' : id , 'type' : type}
    def variable_decl(self, args):
        return args[0]
    def decl_variable_decl(self , args):
        return {'code' : ''}
    ############# Types #############
    def type_int(self, args):
        return "int"
    def type_double(self, args):
        return "double"
    def type_bool(self, args):
        return "bool"
    def type_string(self, args):
        return "string"
    def type_array(self, args):
        return args[0] + "[]"
    def type_id(self , args):
        return args[0].children[0]
    ############### Variables of Block Statement ###############
    def variable_decls_empty(self, args):
        return {'variable_count' : 0}
    def variable_decls(self, args):
        var_type = args[1]['type']
        var_id = args[1]['id']
        self.Stack.push(Var(var_id,var_type))
        return {'variable_count': args[0]['variable_count'] + 1}
    ######################################################### Expressions #########################################################
    ############### Expr More ###############
    def expr_more(self , args):
        expr = args[0]
        expr_more = args[1]
        return {'code' : expr['code'] + expr_more['code'] , 'variable_count' : expr_more['variable_count'] + 1}
    def expr_more_empty(self , args):
        return {'code' : '' , 'variable_count' : 0}
    ############### Expr Optional ###############
    def stmt_expr_optional(self, args):
        code = args[0]['code']
        if code != '':
            code += "# End of Expression Optional\n"
            code += "addi $sp , $sp 4\n"
            return {'code' : code , 'break_labels' : []}
        return {'code' : '', 'break_labels' : []}
    def expr_optional(self, args):
        return args[0]
    def expr_optional_empty(self, args):
        return {'code': ''}
    def expr(self, args):
        return args[0]
    ############### Assign ###############
    def expr_assign(self, args):
        if args[0]['value_type'] != args[1]['value_type'] and not Class.areConvertable(args[0]['value_type'],args[1]['value_type']):
            raise Exception("Types of Right Hand Side of Assign is not the same as Left Side" )
        value_type = args[0]['value_type']
        code = "# Left Hand Side Assign\n"
        code += args[0]['code']
        code += "# Right Hand Side Assign\n"
        code += args[1]['code']
        code += "# Assign Right Side to Left\n"
        code += "lw $t0 , 8($sp)\n"
        if value_type == 'double':
            code += "l.s $f0 , 4($sp)\n"
            code += "s.s $f0 , 0($t0)\n"
            code += "s.s $f0 , 8($sp)\n"
        else:
            code += "lw $t1 , 4($sp)\n"
            code += "sw $t1 , 0($t0)\n"
            code += "sw $t1 , 8($sp)\n"
        code += "addi $sp , $sp , 4\n"
        return {'code' : code,
                'value_type' : value_type}
    def expr_assign_pass(self, args):
        return args[0]
    ############### Or ###############
    def expr_or(self, args):
        value_type = args[0]['value_type']
        code = "# Or Expression\n"
        if value_type != 'bool':
            raise Exception("Unhandled Type for Or !")
        code += "lw $t0 , 8($sp)\n"
        code += "lw $t1 , 4($sp)\n"
        code += "or $t0 , $t0 , $t1\n"
        code += "sw $t0 , 8($sp)\n"
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    def expr_or_pass(self, args):
        return args[0]
    ############### And ###############
    def expr_and(self, args):
        value_type = args[0]['value_type']
        code = "# And Expression\n"
        if value_type != 'bool':
            raise Exception("Unhandled Type for And !")
        code += "lw $t0 , 8($sp)\n"
        code += "lw $t1 , 4($sp)\n"
        code += "and $t0 , $t0 , $t1\n"
        code += "sw $t0 , 8($sp)\n"
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    def expr_and_pass(self, args):
        return args[0]
    ############### Equal ###############
    def expr_equality_equal(self, args):
        value_type = args[0]['value_type']
        code = "# Equal Expression\n"
        if value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.eq.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first and second are equal\n"
            code += "li $t0 , 0\n"
            code += "j " + labelEnd + " # Jump to Storing This NE Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 1\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'string':
            code += "lw $a0 , 8($sp)\n"
            code += "lw $a1 , 4($sp)\n"
            code += "addi $sp , $sp , -8\n"
            code += "sw $fp , 8($sp)\n"
            code += "sw $ra , 4($sp)\n"
            code += "jal StringsEquality # Calling Function to Check Equality of two Strings\n"
            code += "lw $fp , 8($sp)\n"
            code += "lw $ra , 4($sp)\n"
            code += "addi $sp , $sp , 8\n"
            code += "sw $v0 , 8($sp) # Saving Result of Equality of two Strings\n"
        else:
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "seq $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    ############### Not Equal ###############
    def expr_equality_not_equal(self, args):
        value_type = args[0]['value_type']
        code = "# Not Equal Expression\n"
        if value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.eq.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first and second are equal\n"
            code += "li $t0 , 1\n"
            code += "j " + labelEnd + " # Jump to Storing This NE Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 0\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'string':
            code += "lw $a0 , 8($sp)\n"
            code += "lw $a1 , 4($sp)\n"
            code += "addi $sp , $sp , -8\n"
            code += "sw $fp , 8($sp)\n"
            code += "sw $ra , 4($sp)\n"
            code += "jal StringsInequality # Calling Function to Check inEquality of two Strings\n"
            code += "lw $fp , 8($sp)\n"
            code += "lw $ra , 4($sp)\n"
            code += "addi $sp , $sp , 8\n"
            code += "sw $v0 , 8($sp) # Saving Result of inEquality of two Strings\n"
        else:
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "seq $t0 , $t0 , $t1\n"
            code += "nor $t0 , $t0 , $t0\n"
            code += 'addi $t0 , $t0 , 2\n'
            code += "sw $t0 , 8($sp)\n"
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    def expr_equality_pass(self, args):
        return args[0]
    ############### Less ###############
    def expr_compare_l(self, args):
        value_type = args[0]['value_type']
        code = "# Less Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "slt $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.lt.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first is less than second\n"
            code += "li $t0 , 0\n"
            code += "j " + labelEnd + " # Jump to Storing This L Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 1\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for E !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    ############### Less or Equal ###############
    def expr_compare_le(self, args):
        value_type = args[0]['value_type']
        code = "# Less or Equal Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "sle $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.le.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first is less ( or equal ) than second\n"
            code += "li $t0 , 0\n"
            code += "j " + labelEnd + " # Jump to Storing This LE Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 1\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for LE !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    ############### Greater ###############
    def expr_compare_g(self, args):
        value_type = args[0]['value_type']
        code = "# Greater Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "sgt $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.le.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first is less ( or equal ) than second\n"
            code += "li $t0 , 1\n"
            code += "j " + labelEnd + " # Jump to Storing This G Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 0\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for G !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    ############### Greater or Equal ###############
    def expr_compare_ge(self, args):
        value_type = args[0]['value_type']
        code = "# Greater or Equal Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "sge $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            labelLower = self.label_generator()
            labelEnd = self.label_generator()
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "c.lt.s $f0 , $f1\n"
            code += "bc1t " + labelLower + " # if first is less than second\n"
            code += "li $t0 , 1\n"
            code += "j " + labelEnd + " # Jump to Storing This GE Result to Stack\n"
            code += labelLower + ":\n"
            code += "li $t0 , 0\n"
            code += labelEnd + ":\n"
            code += "sw $t0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for GE !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'bool'}
    def expr_compare_pass(self, args):
        return args[0]
    ############### Addition ###############
    def expr_add_sub_plus(self, args):
        value_type = args[0]['value_type']
        code = "# Add Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "add $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "add.s $f0 , $f0 , $f1\n"
            code += "s.s $f0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for Add !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': value_type}
    ############### Subtraction ###############
    def expr_add_sub_minus(self, args):
        value_type = args[0]['value_type']
        code = "# Sub Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "sub $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "sub.s $f0 , $f0 , $f1\n"
            code += "s.s $f0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for Sub !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': value_type}
    def expr_add_sub_pass(self, args):
        return args[0]
    ############### Multiplication ###############
    def expr_mul_div_mul(self, args):
        value_type = args[0]['value_type']
        code = "# Mul Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "mul $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "mul.s $f0 , $f0 , $f1\n"
            code += "s.s $f0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for Mul !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': value_type}
    ############### Division ###############
    def expr_mul_div_div(self, args):
        value_type = args[0]['value_type']
        code = "# Div Expression\n"
        if value_type == 'int':
            code += "lw $t0 , 8($sp)\n"
            code += "lw $t1 , 4($sp)\n"
            code += "div $t0 , $t0 , $t1\n"
            code += "sw $t0 , 8($sp)\n"
        elif value_type == 'double':
            code += "l.s $f0 , 8($sp)\n"
            code += "l.s $f1 , 4($sp)\n"
            code += "div.s $f0 , $f0 , $f1\n"
            code += "s.s $f0 , 8($sp)\n"
        else:
            raise Exception("Unhandled Type for Div !")
        code += "addi $sp , $sp , 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': value_type}
    ############### Mod ###############
    def expr_mul_div_mod(self, args):
        if args[0]['value_type'] != 'int':
            raise Exception("Unhandled Type for Mod !")
        code = "# mod Expression\n"
        code += "lw $t0 , 8($sp)\n"
        code += "lw $t1 , 4($sp)\n"
        code += "rem $t0 , $t0 , $t1\n"
        code += "sw $t0, 8($sp)\n"
        code += "addi $sp, $sp, 4\n"
        return {'code': args[0]['code'] + args[1]['code'] + code,
                'value_type': 'int'}
    def expr_mul_div_mod_pass(self, args):
        return args[0]
    ############### Not ###############
    def expr_not_negative_not(self, args):
        if args[0]['value_type'] != 'bool':
            raise Exception("Unhandled Type for Not !")
        code = args[0]['code']
        code += "lw $t0, 4($sp)\n"
        code += "xori $t0, $t0, 1\n"
        code += "sw $t0, 4($sp)\n"
        return {'code': code,
                'value_type': 'bool'}
    ############### Negative ###############
    def expr_not_negative_negative(self, args):
        value_type = args[0]['value_type']
        code = args[0]['code']
        if value_type == 'double':
            code += "l.s $f0 , 4($sp)\n"
            code += "neg.s $f0 , $f0\n"
            code += "s.s $f0 , 4($sp)\n"
        elif value_type == 'int':
            code += "lw $t0 , 4($sp)\n"
            code += "neg $t0 , $t0\n"
            code += "sw $t0 , 4($sp)\n"
        else:
            raise Exception("Unhandled Type for Negative !")
        return {'code': code,
                'value_type': value_type}
    def expr_not_negative_pass(self , args):
        return args[0]
    ############### Parentheses ###############
    def expr_par(self, args):
        return args[0]
    ######################################################### Atomic Expressions #########################################################
    ############### New ###############
    def expr_atomic_new(self, args):
        id = args[0].children[0]
        code = "# new object of type : " + id + "\n"
        code += "sw $ra , 0($sp)\n"
        code += "addi $sp , $sp , -4\n"
        code += "jal " + id + "_Constructor\n"
        code += "lw $ra , 4($sp)\n"
        code += "sw $v0 , 4($sp) # Pushing address of object in Heap to Stack\n"
        return {'code' : code, 'value_type' : id}
    ############### This ###############
    def expr_atomic_this(self , args):
        code = "# Loading Address of : this\n"
        code += self.Stack.getAddress('this')
        code += "lw $s7 , 0($s7)\n"
        code += "sw $s7 , 0($sp)\n"
        code += "addi $sp , $sp , -4\n"
        return {'code' : code , 'value_type' : self.Stack.getVar('this').type}
    ############### Accessing Variable inside Object ###############
    def left_value_obj_var(self , args):
        expr_atomic = args[0]
        varID = args[1].children[0]
        obj_type = expr_atomic['value_type']
        c = Class.searchClass(obj_type);
        if c == None:
            raise Exception("Trying to access an object of Type (" + obj_type + ") that the class does not exists")
        if not c.variableExists(varID):
            raise Exception("Trying to access a variable name (" + varID + ") inside class (" + obj_type + ") that does not exists")
        varOffset = c.variableOffset(varID);
        code = "# Loading Variable of Object\n"
        code += expr_atomic['code']
        code += "lw $t0 , 4($sp)\n"
        code += "addi $t0 , $t0 , " + str(varOffset) + " # add offset of variable to object address\n"
        code += "sw $t0 , 4($sp)\n"
        return {'code' : code , 'value_type' : c.getVariable(varID)['type']}
    ############### Left Value ###############
    def expr_atomic_left_value(self, args):
        code = "# Loading Address of Array"
        if 'name' in args[0]:
            code = "# Load Value from Address of ID : " + args[0]['name'] + "\n"
        code += "lw $t0, 4($sp)\n"
        code += "lw $t0 , 0($t0)\n"
        code += "sw $t0 , 4($sp) "
        if 'name' in args[0]:
            code += "# Value of " + args[0]['name'] + " Pushed to Stack\n"
        else:
            code += "# Value of Array address Pushed to Stack\n"
        args[0]['code'] += code
        return args[0]
    ############### New Array ###############
    def expr_atomic_new_array(self, args):
        code = "# Expression of Array Size\n"
        code += args[0]['code']
        code += "# NewArray of Type : " + args[1] + "\n"
        code += "lw $t0, 4($sp)\n"
        code += "addi $t0 , $t0 , 1 # Allocate space for Storing Array Length\n"
        code += "sll $a0 , $t0 , 2\n"
        code += "li $v0, 9\n"
        code += "syscall\n"
        code += "addi $t0 , $t0 , -1 # Array Size\n"
        code += "sw $t0 , 0($v0) # Storing Array size in index 0\n"
        code += "sw $v0, 4($sp)\n"
        return {'code': code,
                'value_type': args[1] + "[]"}
    ############### Accessing Array ###############
    def left_value_array_access(self , args):
        base_arr = args[0]
        index = args[1]
        code = "# Get Array index\n"
        code += "# Base Address of Array\n"
        code += base_arr['code']
        code += "# Expression index of Array\n"
        code += index['code']
        code += "lw $t0 , 8($sp) # base Address of Array\n"
        code += "lw $t1 , 4($sp) # index of Array\n"
        code += "addi $sp , $sp , 4\n"
        code += "addi $t1 , $t1 , 1\n"
        code += "sll $t1 , $t1 , 2\n"
        code += "add $t0 , $t0 , $t1\n"
        code += "sw $t0 , 4($sp) # Pushing address of arr[index] result to Stack\n"
        return {'code' : code , 'value_type' : base_arr['value_type'][0:-2]}
    ############### Read Integer ###############
    def expr_atomic_read_integer(self, args):
        code = "# Read Integer ( Decimal or Hexadecimal ) : \n"
        code = "# Read Line : \n"
        code += "addi $sp , $sp , -8\n"
        code += "sw $fp , 8($sp)\n"
        code += "sw $ra , 4($sp)\n"
        code += "jal ReadLine # Calling Read Line Function \n"
        code += "move $a0 , $v0 # Moving address of string to $a0\n"
        code += "jal readInteger # Read Integer Function\n"
        code += "lw $fp , 8($sp)\n"
        code += "lw $ra , 4($sp)\n"
        code += "addi $sp , $sp , 4\n"
        code += "sw $v0 , 4($sp) # Saving Result Read Integer to Stack\n"
        return {'code': code, 'value_type': 'int'}
    ############### Read Line ###############
    def expr_atomic_read_line(self, args):
        code = "# Read Line : \n"
        code += "addi $sp , $sp , -8\n"
        code += "sw $fp , 8($sp)\n"
        code += "sw $ra , 4($sp)\n"
        code += "jal ReadLine # Calling Read Line Function \n"
        code += "lw $fp , 8($sp)\n"
        code += "lw $ra , 4($sp)\n"
        code += "addi $sp , $sp , 4\n"
        code += "sw $v0 , 4($sp)# Saving String Address ( Saved in Heap ) in Stack\n"
        return {'code': code, 'value_type': 'string'}
    ############### Call ###############
    def expr_atomic_call(self , args):
        return args[0]
    ######################################################### Left Value #########################################################
    ############### Left Value ID ###############
    def left_value_id(self, args):
        name = args[0].children[0].value
        value_type = self.Stack.getVar(name).type
        code = "# Loading Address of ID : " + name + "\n"
        code += self.Stack.getAddress(name)
        code += 'sw $s7, 0($sp)' + ' # Push Address of ' + name + ' to Stack\n'
        code += 'addi $sp, $sp, -4\n'
        return {'code': code,
                'name': name,
                'value_type': value_type}
    ######################################################### Constants #########################################################
    def expr_atomic_constant(self , args):
        return args[0]
    ############### Integer Constant ###############
    def constant_int(self , args):
        val = int(args[0].value,0)
        code = "# Int Constant : " + str(val) + "\n"
        code += "li $t0 , " + str(val) + "\n"
        code += 'sw $t0 , 0($sp)\n'
        code += 'addi $sp, $sp, -4\n'
        return {'code': code,
                'value_type': 'int'}
    ############### Double Constant ###############
    def constant_double(self, args):
        val = float(args[0].value)
        code = "# Double Constant : " + str(val) + "\n"
        code += "li.s $f0, " + str(val) + "\n"
        code += "s.s $f0, 0($sp)\n"
        code += "addi $sp, $sp, -4\n"
        return {'code': code,
                'value_type': 'double'}
    ############### Bool Constant ###############
    def constant_bool(self, args):
        code = "# Bool Constant : " + str(args[0].value) + "\n"
        if str(args[0].value) == 'true':
            code += 'li $t0 , 1\n'
        elif str(args[0].value) == 'false':
            code += 'li $t0, 0\n'
        code += 'sw $t0 , 0($sp)\n'
        code += 'addi $sp, $sp, -4\n'
        return {'code': code,
                'value_type': 'bool'}
    ############### String Constant ###############
    def constant_string(self, args):
        name = self.data_name_generator()
        code = "# String Constant : " + args[0].value + "\n"
        code += 'la $t0 , ' + name + '\n'
        code += 'sw $t0 , 0($sp)\n'
        code += 'addi $sp , $sp , -4\n'
        self.data_code += name + ': .asciiz ' + args[0].value + '\n'
        return {'code': code,
                'value_type' : 'string'}
    ############### String Constant ###############
    def constant_null(self , args):
        code = "la $t0 , obj_null # Null Object\n"
        code += "sw $t0 , 0($sp)\n"
        code += "addi $sp , $sp , -4\n"
        return {'code' : code , 'value_type' : 'null_type'}
    ######################################################### Statement #########################################################
    ############### Statement Block ###############
    def stmt_block(self , args):
        variable_decls = args[0]
        stmts = args[1]
        code = "# Begin of Statement Block\n"
        code += "addi $sp , $sp , -" + str(variable_decls['variable_count'] * 4) + " # Allocate From Stack For Block Statement Variables\n"
        code += "addi $fp , $sp , 4\n"
        code += stmts['code']
        code += "addi $sp , $sp , " + str( variable_decls['variable_count'] * 4) + " # UnAllocate Stack Area (Removing Block Statement Variables)\n"
        code += "addi $fp ,$sp , 4\n"
        code += "# End of Statement Block\n"
        self.Stack.pop(variable_decls['variable_count'])

        # Handling breaks ...
        break_labels = stmts['break_labels']
        pattern = re.compile(r'@(break\d+)@')
        for break_label in re.findall(pattern, code):
            if not self.in_break_labels(break_labels, break_label):
                break_labels.append({'name' : break_label , 'count' : 0})
        for item in break_labels:
            item['count'] += variable_decls['variable_count']
        return {'code' : code , 'break_labels' : break_labels}
    def stmts(self, args):
        code = args[0]['code'] + args[1]['code']
        break_labels = args[0]['break_labels'] + args[1]['break_labels']
        return {'code': code , 'break_labels': break_labels}
    def stmts_empty(self, args):
        return {'code': '' , 'break_labels' : []}
    def stmt_stmt_block(self, args):
        return args[0]

    ############### Print ###############
    def stmt_print_stmt(self, args):
        args[0]['break_labels'] = []
        return args[0]
    def print_stmt(self, args):
        code = "li $a0 , 10 # '\\n'\n"
        code += "li $v0 , 11\n"
        code += "syscall\n"
        return {'code': args[0]['code'] + code}
    def print_exprs(self, args):
        expr = args[0]
        expr_type = expr['value_type']
        code = expr['code']
        code += "# Print expr : \n"
        code += "addi $sp , $sp , 4 # Pop Expression of Print\n"
        if expr_type == "string":
            code += "lw $a0 , 0($sp)\n"
            code += "li $v0 , 4\n"
        elif expr_type == "double":
            code += "l.s $f12 , 0($sp)\n"
            code += "li $v0 , 2\n"
        elif expr_type == "bool":
            code += "lw $a0 , 0($sp)\n"
            code += "la $t0 , str_bool\n"
            code += "sll $a0 , $a0 , 2\n"
            code += "add $a0 , $a0 , $t0\n"
            code += "lw $a0 , 0($a0)\n"
            code += "li $v0 , 4\n"
        else:
            code += "lw $a0 , 0($sp)\n"
            code += "li $v0 , 1\n"
        code += "syscall\n"
        return {'code': code + args[1]['code']}
    def print_expr_more_empty(self, args):
        return {'code': ''}
    ############### if Statement ###############
    def stmt_if_stmt(self , args):
        return args[0]
    def if_stmt_ms(self , args):
        return args[0]
    def if_stmt_us(self , args):
        return args[0]
    def ms(self , args):
        expr = args[0]
        stmt1 = args[1]
        stmt2 = args[2]
        elseLabel = self.label_generator()
        endLabel = self.label_generator()
        code = "# Calculating IF Condition\n"
        code += expr['code']
        code += "# Loading IF Condition Result\n"
        code += "addi $sp , $sp , 4\n"
        code += "lw $t0 , 0($sp)\n"
        code += "beqz $t0 , " + elseLabel + " # Jumping to else label if expression is false\n"
        code += "# IF Statement Body\n"
        code += stmt1['code']
        code += "j " + endLabel + " # Jump to end of if_stmt\n"
        code += "# Else Statement Body\n"
        code += elseLabel + ":\n"
        code += stmt2['code']
        code += endLabel + ":\n"
        return {'code' : code , 'break_labels' : stmt1['break_labels'] + stmt2['break_labels']}
    def us(self , args):
        expr = args[0]
        stmt = args[1]
        endLabel = self.label_generator()
        code = "# Calculating IF Condition\n"
        code += expr['code']
        code += "# Loading IF Condition\n"
        code += "addi $sp , $sp , 4\n"
        code += "lw $t0 , 0($sp)\n"
        code += "beqz $t0 , " + endLabel + " # Jumping to end label if expression is false\n"
        code += "# IF Statement Body\n"
        code += stmt['code']
        code += endLabel + ":\n"
        return {'code' : code , 'break_labels' : stmt['break_labels']}
    ############### while loop ###############
    def stmt_while_stmt(self , args):
        return args[0]
    def while_stmt(self , args):
        expr = args[0]
        stmt = args[1]
        startLabel = self.label_generator()
        endLabel = self.label_generator()

        # Handling breaks ...
        break_labels = stmt['break_labels']
        pattern = re.compile(r'@(break\d+)@')
        for break_label in re.findall(pattern, stmt['code']):
            count = self.get_count_break_label(break_labels , break_label)
            code_for_break = "addi $sp , $sp , " + str(count * 4) + " # Pop elements before\n"
            code_for_break += "addi $fp , $sp , 4 # Set Frame Pointer\n"
            code_for_break += "j " + endLabel + " # Break from loop while\n"
            stmt['code'] = stmt['code'].replace("@" + break_label + "@" , code_for_break)

        code = startLabel + ": # Starting While Loop Body\n"
        code += "# Calculating While Condition\n"
        code += expr['code']
        code += "# Loading While Condition Result\n"
        code += "addi $sp , $sp , 4\n"
        code += "lw $t0 , 0($sp)\n"
        code += "beqz $t0 , " + endLabel + " # Jumping to end label if expression is false\n"
        code += stmt['code']
        code += "j " + startLabel + " # Jumping to beggining of while loop\n"
        code += endLabel + ":\n"
        return {'code' : code , 'break_labels' : []}
    ############### for loop ###############
    def stmt_for_stmt(self , args):
        return args[0]
    def for_stmt(self , args):
        expr_initialization = args[0]
        expr_condition = args[1]
        expr_step = args[2]
        stmt = args[3]
        startLabel = self.label_generator()
        endLabel = self.label_generator()

        # Handling breaks ...
        break_labels = stmt['break_labels']
        pattern = re.compile(r'@(break\d+)@')
        for break_label in re.findall(pattern, stmt['code']):
            count = self.get_count_break_label(break_labels, break_label)
            code_for_break = "addi $sp , $sp , " + str(count * 4) + " # Pop elements before\n"
            code_for_break += "addi $fp , $sp , 4 # Set framepointer\n"
            code_for_break += "j " + endLabel + " # Break from loop for\n"
            stmt['code'] = stmt['code'].replace("@" + break_label + "@", code_for_break)

        code = "# Initialization Expression of Loop for\n"
        code += expr_initialization['code']
        if expr_initialization['code'] != '':
            code += "addi $sp , $sp , 4 # pop init expr of loop for\n"
        code += startLabel + ": # Starting for Loop Body\n"
        code += "# Calculating For Loop Condition\n"
        code += expr_condition['code']
        code += "# Loading For Loop Condition Result\n"
        code += "addi $sp , $sp , 4\n"
        code += "lw $t0 , 0($sp)\n"
        code += "beqz $t0 , " + endLabel + " # Jumping to end label if Condition Expression of for loop is false\n"
        code += stmt['code']
        code += "# Step Expression of For loop \n"
        code += expr_step['code']
        if expr_step['code'] != '':
            code += "addi $sp , $sp , 4 # pop step expr of loop for\n"
        code += "j " + startLabel + " # Jumping to beggining of while loop\n"
        code += endLabel + ":\n"
        return {'code' : code , 'break_labels' : []}
    ############### Break ###############
    def stmt_break_stmt(self , args):
        args[0]['break_labels'] = [{'name' : args[0]['code'][1:-2] , 'count' : 0}]
        return args[0]
    def break_stmt(self , args):
        code = "@" + self.break_generator() + "@\n"
        return {'code' : code}
    ######################################################### Function #########################################################
    ############### Formals and Variables ###############
    def formals(self , args):
        variable = args[0]
        more_variables = args[1]
        variables = [{'id' : variable['id'] , 'type' : variable['type']}] + more_variables['variables']
        for var in variables:
            self.Stack.push(Var(var['id'], var['type']))
        if self.inClass():
            self.Stack.push(Var("this", self.structure[self.whereAmI]['name']))
        return {'variable_count' : len(variables)}
    def formals_empty(self , args):
        if self.inClass():
            self.Stack.push(Var("this",self.structure[self.whereAmI]['name']))
        return {'variable_count' : 0}
    def more_variables(self , args):
        variable = args[0]
        variable_obj = [ {'type' : variable['type'], 'id' : variable['id']} ]
        more_variables = args[1]
        return {'variables' : variable_obj + more_variables['variables']}
    def more_variables_empty(self , args):
        return {'variables' : []}
    ############### Function Declaration ###############
    def decl_function_decl(self , args):
        self.whereAmI += 1
        return args[0]
    def function_decl(self , args):
        returnType = args[0]
        functionName = args[1].children[0]
        formals = args[2]
        stmt_block = args[3]
        label_end = functionName + "_end"
        code = functionName + ": # Start function\n"
        code += "addi $s5 , $sp , 0 # Storing $sp of function at beginning in $s5\n"
        code += "# Function Body :\n"
        code += stmt_block['code']
        code += label_end + ":\n"
        code += "jr $ra\n\n"
        self.Stack.pop(formals['variable_count']);
        if self.inClass():
            self.Stack.pop(1)
        return {'code' : code , 'name' : functionName}
    def function_decl_void(self , args):
        functionName = args[0].children[0]
        formals = args[1]
        stmt_block = args[2]
        label_end = functionName + "_end"
        code = functionName + ": # Start function body\n"
        code += "addi $s5 , $sp , 0 # Storing $sp of function at beginning in $s5\n"
        code += "addi $fp , $sp , 0 # Set Frame Pointer of function\n"
        code += "# Function Body :\n"
        code += stmt_block['code']
        code += label_end + ":\n"
        code += "jr $ra\n\n"
        self.Stack.pop(formals['variable_count']);
        if self.inClass():
            self.Stack.pop(1)
        return {'code': code , 'name' : functionName}
    ############### return ###############
    def stmt_return_stmt(self, args):
        args[0]['break_labels'] = []
        return args[0]
    def return_stmt(self, args):
        exprOptional = args[0]
        code = ''
        if exprOptional['code'] != '':
            code = exprOptional['code']
            if exprOptional['value_type'] == 'double':
                code += 'l.s $f0 , 4($sp) # Loading Return Value of function\n'
            else:
                code += 'lw $v0 , 4($sp) # Loading Return Value of function\n'
            code += "addi $sp , $sp , 4\n"
        code += "move $sp , $s5\n"
        code += "jr $ra # Return Function\n"
        return {'code' : code}
    ############### Function Call ###############
    def call(self , args):
        id = args[0].children[0]
        value_type = self.function_type(id)
        actuals = args[1]
        if not self.isClassMethod(id):
            code = "# Storing Frame Pointer and Return Address Before Calling the function : " + id + "\n"
            code += "addi $sp , $sp , -12\n"
            code += "sw $fp , 4($sp)\n"
            code += "sw $ra , 8($sp)\n"
            code += "sw $s5 , 12($sp)\n"
            code += "# Function Arguments\n"
            code += actuals['code']
            code += "jal " + self.getFunctionLabel(id) + " # Calling Function\n"
            code += "# Pop Arguments of function\n"
            code += "addi $sp , $sp , " + str(actuals['variable_count']*4) + "\n"
            code += "# Load Back Frame Pointer and Return Address After Function call\n"
            code += "lw $fp , 4($sp)\n"
            code += "lw $ra , 8($sp)\n"
            code += "lw $s5 , 12($sp)\n"
            code += "addi $sp , $sp , 8\n"
            if value_type == 'double':
                code += "s.s $f0 , 4($sp) # Push Return Value from function to Stack\n"
            else:
                code += "sw $v0 , 4($sp) # Push Return Value from function to Stack\n"
            return {'code': code , 'value_type' : value_type}
        object_type = self.Stack.getVar("this").type;
        c = Class.searchClass(object_type)
        methodOffset = c.methodOffset(id)
        value_type = c.getMethod(id)['type']
        code = "# Caliing Method of class\n"
        code += "# Storing Frame Pointer and Return Address Before Calling the Method : " + id + "\n"
        code += "addi $sp , $sp , -12\n"
        code += "sw $fp , 4($sp)\n"
        code += "sw $ra , 8($sp)\n"
        code += "sw $s5 , 12($sp)\n"
        code += "# Function Arguments\n"
        code += actuals['code']
        code += "# Pushing \"this\" to Method's Arguments\n"
        code += self.Stack.getAddress("this")
        code += "lw $s7 , 0($s7)\n"
        code += "sw $s7 , 0($sp) # Push \"this\"\n"
        code += "addi $sp , $sp , -4\n"
        code += "lw $s7 , 0($s7) # Loading Vtable of this\n"
        code += "addi $s7 , $s7 , " + str(methodOffset) + " # Method offset\n"
        code += "lw $s7 , 0($s7)\n"
        code += "jal $s7 # Calling Method of this\n"
        code += "# Pop Arguments of function\n"
        code += "addi $sp , $sp , " + str(actuals['variable_count'] * 4 + 4) + "\n"
        code += "# Load Back Frame Pointer and Return Address After Function call\n"
        code += "lw $fp , 4($sp)\n"
        code += "lw $ra , 8($sp)\n"
        code += "lw $s5 , 12($sp)\n"
        code += "addi $sp , $sp , 8\n"
        if value_type == 'double':
            code += "s.s $f0 , 4($sp) # Push Return Value from function to Stack\n"
        else:
            code += "sw $v0 , 4($sp) # Push Return Value from function to Stack\n"
        return {'code': code, 'value_type': value_type}
    def actuals(self , args):
        expr = args[0]
        expr_more = args[1]
        return {'variable_count' : expr_more['variable_count'] + 1 , 'code' : expr['code'] + expr_more['code'] }
    def actuals_empty(self , args):
        return {'variable_count': 0, 'code': ''}
    ############### Object Method Call ###############
    def call_obj_method(self , args):
        obj_expr = args[0]
        function_id = args[1].children[0]
        actuals = args[2]
        object_type = obj_expr['value_type']
        if object_type[-2:] == "[]" and function_id == 'length':
            code = "# Array Length\n"
            code += "# Array Expr\n"
            code += obj_expr['code']
            code += "lw $t0 , 4($sp)\n"
            code += "lw $t0 , 0($t0)\n"
            code += "sw $t0 , 4($sp) # Pushing length of array to stack\n"
            return {'code' : code , 'value_type' : 'int'}
        c = Class.searchClass(object_type)
        methodOffset = c.methodOffset(function_id)
        value_type = c.getMethod(function_id)['type']
        code = "# Calling Method of Object\n"
        code += "# Object Expression\n"
        code += obj_expr['code']
        code += "lw $t0 , 4($sp)\n"
        code += "lw $t0 , 0($t0) # Loading Vtable\n"
        code += "addi $t0 , $t0 , " + str(methodOffset) + " # Adding offset of Method in Vtable\n"
        code += "lw $t0 , 0($t0) # t0 now contains the address of function\n"
        code += "sw $t0 , 0($sp) # Storing Function Address in Stack \n"
        code += "addi $sp , $sp , -4\n"
        code += "# Storing Frame Pointer and Return Address Before Calling the object's method : " + function_id + "\n"
        code += "addi $sp , $sp , -12\n"
        code += "sw $fp , 4($sp)\n"
        code += "sw $ra , 8($sp)\n"
        code += "sw $s5 , 12($sp)\n"
        code += "# Method\'s Arguments \n"
        code += actuals['code']
        code += "lw $t0 , " + str(actuals['variable_count']*4 + 12 + 4 + 4) + "($sp) # Loading Object being called\n"
        code += "sw $t0 , 0($sp) # Pushing object as \"this\" as first argument of method\n"
        code += "lw $t0 , " + str(actuals['variable_count']*4 + 12 + 4) + "($sp) # Loading Method of object\n"
        code += "addi $sp , $sp , -4\n"
        code += "jal $t0 # Calling Object's method\n"
        code += "addi $sp , $sp , " + str(actuals['variable_count'] * 4 + 4) + " # Pop Arguments of Method\n"
        code += "# Load Back Frame Pointer and Return Address After Function call\n"
        code += "lw $fp , 4($sp)\n"
        code += "lw $ra , 8($sp)\n"
        code += "lw $s5 , 12($sp)\n"
        code += "addi $sp , $sp , 16\n"
        if value_type == 'double':
            code += "s.s $f0 , 4($sp) # Push Return Value from Method to Stack\n"
        else:
            code += "sw $v0 , 4($sp) # Push Return Value from Method to Stack\n"
        return {'code': code , 'value_type': value_type}
    ######################################################### Class #########################################################
    ############### Class Extends ###############
    def extends_optional(self , args):
        id = args[0].children[0]
        return {'extends' : id}
    def extends_optional_empty(self , args):
        return {'extends' : None}
    ############### Class Declaration ###############
    def decl_class_decl(self , args):
        self.whereAmI += 1
        return args[0]
    def class_decl(self , args):
        return args[3]
    ############### Fields ###############
    def fields(self , args):
        return {'code' : args[0]['code'] + args[1]['code']}
    def fields_empty(self , args):
        return {'code' : ''}
    def field_function(self , args):
        prefix = self.structure[self.whereAmI]['name']
        args[0]['code'] = args[0]['code'].replace( args[0]['name'] + "_end:" , prefix + "_" + args[0]['name'] + "_end:" )
        args[0]['code'] = args[0]['code'].replace( args[0]['name'] + ":" , prefix + "_" + args[0]['name'] + ":" )
        return args[0]
    def field_variable(self , args):
        return {'code' : ''}