Exemplo n.º 1
0
def p_type_id(p):
    'type :  ID'
    global current_type
    baseclass = ast.lookup(ast.classtable, p[1])
    if (baseclass == None):
        signal_error('Class {0} does not exist!'.format(p[1]), p.lineno(1))
    p[0] = current_type = ast.Type(baseclass.name)
Exemplo n.º 2
0
def p_extends_id(p):
    'extends : EXTENDS ID '
    cid = ast.lookup(ast.classtable, p[2])
    if (not cid):
        signal_error('Class {0} does not exist!'.format(p[2]), p.lineno(2))
    p[0] = cid
    pass
Exemplo n.º 3
0
def p_primary_newobj(p):
    'primary : NEW ID LPAREN args_opt RPAREN'
    cname = p[2]
    c = ast.lookup(ast.classtable, cname)
    if (c != None):
        p[0] = ast.NewObjectExpr(c, p[4], p.lineno(1))
    else:
        signal_error('Class "{0}" in "new" not defined (yet?)'.format(cname), p.lineno(2))
Exemplo n.º 4
0
def p_class_decl_head(p):
    'class_decl_head : CLASS ID extends'
    global current_class, current_context
    cid = p[2]
    sc = p[3]
    c = ast.lookup(ast.classtable, cid)
    if (c != None):
        signal_error('Class {0} already exists!'.format(cid), p.lineno(2))
    else:
        c = ast.Class(cid, sc)
        ast.addtotable(ast.classtable, cid, c)
    current_class = c
    current_context = 'class'
    pass
Exemplo n.º 5
0
def p_field_access_id(p):
    'field_access : ID'
    vname = p[1]
    v = current_vartable.find_in_scope(vname)
    if (v != None):
        # local variable in current scope
        p[0] = ast.VarExpr(v, p.lineno(1))
    else:
        c = ast.lookup(ast.classtable, vname)
        if (c != None):
            # there is a class with this name
            p[0] = ast.ClassReferenceExpr(c, p.lineno(1))
        else:
            # reference to a non-local var; assume field
            p[0] = ast.FieldAccessExpr(ast.ThisExpr(p.lineno(1)), vname, p.lineno(1))
Exemplo n.º 6
0
def isSubtype(type1, type2):
    #if types are same
    if str(type1) == str(type2):
        return True
    # predefined int float relationship
    elif str(type1) == 'int' and str(type2) == 'float':
        return True
    # checking subtype relation between two class objects if
    # type2 is superclass of type1
    elif "user" in str(type1) and "user" in str(type2):
        A = str(type1)[5:-1]
        B = str(type2)[5:-1]
        classA = ast.lookup(ast.classtable, A)
        if (classA != None and classA.superclass != None
                and classA.superclass.name == B):
            return True
    #null is subtype of class object
    elif str(type1) == 'null' and "user" in str(type2):
        return True
    #if a is subclass of b then class-leteral of a is subtype of class-literal of b
    elif 'class-literal' in str(type1) and 'class-literal' in str(type2):
        A = str(type1)[14:-1]
        B = str(type2)[14:-1]
        classA = ast.lookup(ast.classtable, A)
        if (classA != None and classA.superclass.name == B):
            return True
    #recursively check if array types are same by stripping of the array( part
    elif 'array(' in str(type1) and 'array(' in str(type2):
        A = str(type1)[6:-1]
        B = str(type2)[6:-1]
        if (isSubtype(A, B)):
            return True
    elif str(type1) == 'null' and 'array(' in str(type2):
        return True

    return False
Exemplo n.º 7
0
def expr_error(expr):
    '''Return whether or not the expression has a type or resolution error.

    Also ensures that the type of the expression is calculated. Call this
    first if you need to use the type of an expression.'''
    expr.type = None

    if isinstance(expr, ast.ConstantExpr):
        if expr.kind == 'int' or expr.kind == 'float' or expr.kind == 'string':
            expr.type = ast.Type(expr.kind)
        elif expr.kind == 'Null':
            expr.type = ast.Type('null')
        elif expr.kind == 'True' or expr.kind == 'False':
            expr.type = ast.Type('boolean')
        else:
            expr.type = ast.Type('error')
            signal_error('Unknown type {}'.format(expr.type), expr.lines)

    elif isinstance(expr, ast.VarExpr):
        expr.type = expr.var.type

    elif isinstance(expr, ast.UnaryExpr):
        arg = expr.arg
        arg_err = expr_error(arg)
        if arg_err:
            expr.type = ast.Type('error')
        elif expr.uop == 'uminus':
            if arg.type.is_numeric():
                expr.type = arg.type
            else:
                signal_error(
                    'Expecting an integer or float argument to unary '
                    'minus. Found {}'.format(arg.type), expr.lines)
                expr.type = ast.Type('error')
        elif expr.uop == 'neg':
            if arg.type == ast.Type('boolean'):
                expr.type = arg.type
            else:
                signal_error(
                    'Expecting a boolean argument to ! (negation). '
                    'Found {}'.format(arg.type), expr.lines)
                expr.type = ast.Type('error')

    elif isinstance(expr, ast.BinaryExpr):
        op_names = {
            'add': '+',
            'sub': '-',
            'mul': '*',
            'div': '/',
            'and': '&&',
            'or': '||',
            'eq': '==',
            'neq': '!=',
            'lt': '<',
            'leq': '<=',
            'gt': '>',
            'geq': '>='
        }
        bop = expr.bop
        arg1 = expr.arg1
        arg2 = expr.arg2
        arg1_err = expr_error(arg1)
        arg2_err = expr_error(arg2)
        if arg1_err or arg2_err:
            expr.type = ast.Type('error')
        elif bop == 'add' or bop == 'sub' or bop == 'mul' or bop == 'div':
            type1 = arg1.type
            type2 = arg2.type
            if type1.is_numeric() and type2.is_numeric():
                if type1 == ast.Type('float') or type2 == ast.Type('float'):
                    expr.type = ast.Type('float')
                else:
                    expr.type = ast.Type('int')
            else:
                signal_error(
                    'Expecting float or integer arguments for the '
                    'operator "{}". Found {} on the left and {} on '
                    'the right.'.format(op_names[bop], type1, type2),
                    expr.lines)
                expr.type = ast.Type('error')
        elif bop == 'and' or bop == 'or':
            type1 = arg1.type
            type2 = arg2.type
            if type1 == ast.Type('boolean') and type2 == ast.Type('boolean'):
                expr.type = ast.Type('boolean')
            else:
                signal_error(
                    'Expecting boolean arguments for the operator '
                    '"{}". Found {} on the left and {} on the '
                    'right.'.format(op_names[bop], type1, type2), expr.lines)
        elif bop == 'lt' or bop == 'leq' or bop == 'gt' or bop == 'geq':
            type1 = arg1.type
            type2 = arg2.type
            if type1.is_numeric() and type2.is_numeric():
                expr.type = ast.Type('boolean')
            else:
                signal_error(
                    'Expecting int or float arguments for the'
                    'operator "{}". Found {} on the left and {} on '
                    'the right.'.format(op_names[bop], type1, type2),
                    expr.lines)
                expr.type = ast.Type('error')
        elif bop == 'eq' or bop == 'neq':
            type1 = arg1.type
            type2 = arg2.type
            if type1.subtype_of(type2) or type2.subtype_of(type1):
                expr.type = ast.Type('boolean')
            else:
                signal_error(
                    'Expecting compatible arguments for the operator '
                    '"{}". One argument must be the subtype of the '
                    'other. Found {} on the left and {} on the '
                    'right.'.format(op_names[bop], type1, type2), expr.lines)
                expr.type = ast.Type('error')

    elif isinstance(expr, ast.FieldAccessExpr):

        err = expr_error(expr.base)
        if err:
            expr.type = ast.Type('error')
            return True

        cls = ast.lookup(ast.classtable, expr.base.type.typename)

        cur_cls = cls
        while cur_cls is not None:
            field = ast.lookup(cur_cls.fields, expr.fname)
            if field is not None:

                # Ensure it's not static, and not accessed by Class.foo, and it's accessable
                if (expr.base.type.kind == 'class') and (field.storage != 'static') \
                        and ((field.visibility != 'private') or (expr.base.type.typename == current_class.name)):
                    break

                # Ensure it's static, and accessed by Class.foo, and it's accessable
                if (expr.base.type.kind == 'class-literal') and (field.storage == 'static') \
                        and ((field.visibility != 'private') or (expr.base.type.typename == current_class.name)):
                    break
            field = None
            cur_cls = cur_cls.superclass

        if field is None:
            signal_error('Could not resolve field {}'.format(expr.fname),
                         expr.lines)
            expr.type = ast.Type('error')
            return True

        expr.type = ast.Type(field.type)

    elif isinstance(expr, ast.ThisExpr):
        expr.type = ast.Type(current_class.name)

    elif isinstance(expr, ast.MethodInvocationExpr):

        err = expr_error(expr.base)
        if err:
            expr.type = ast.Type('error')
            return True

        cls = ast.lookup(ast.classtable, expr.base.type.typename)
        method = None
        cur_cls = cls

        while cur_cls is not None:
            for i in cur_cls.methods:
                if expr.mname == i.name:
                    method = i
                    break

            if method is not None:
                if (expr.base.type.kind == 'class') and (method.storage != 'static') \
                        and ((method.visibility != 'private') or (expr.base.type.typename == current_class.name)):
                    break

                if (expr.base.type.kind == 'class-literal') and (method.storage == 'static') \
                        and ((method.visibility != 'private') or (expr.base.type.typename == current_class.name)):
                    break
            method = None
            cur_cls = cur_cls.superclass

        if method is None:
            expr.type = ast.Type('error')
            signal_error('Could not resolve method \'{}\''.format(expr.mname),
                         expr.lines)
            return True

        method_params = method.vars.vars[0].values()

        # Ensure number of params match
        if len(method_params) != len(expr.args):
            expr.type = ast.Type('error')
            signal_error(
                'Method \'{}\' expects {} args, received {}'.format(
                    method.name, len(method_params), len(expr.args)),
                expr.lines)
            return True

        for i in range(0, len(method_params)):

            arg_err = expr_error(expr.args[i])
            if arg_err:
                expr.type = ast.Type('error')
                return True

            nth_param = ast.Type(method_params[i].type)
            nth_arg = ast.Type(expr.args[i].type)

            if not nth_arg.subtype_of(nth_param):
                expr.type = ast.Type('error')
                signal_error(
                    'Method argument number {0} is not a subtype '
                    'of construtor parameter number {0}. Expects \'{1}\', received \'{2}\'.'
                    .format(i + 1, nth_param.typename,
                            nth_arg.typename), expr.lines)
                return True

        expr.type = ast.Type(method.rtype)

    elif isinstance(expr, ast.AssignExpr):

        lhs_err = expr_error(expr.lhs)
        rhs_err = expr_error(expr.rhs)

        if lhs_err or rhs_err:
            expr.type = ast.Type('error')
            return True

        lhs = ast.Type(expr.lhs.type)
        rhs = ast.Type(expr.rhs.type)

        if not rhs.subtype_of(lhs):
            expr.type = ast.Type('error')
            signal_error('{} not a subtype of {}'.format(rhs, lhs), expr.lines)
        else:
            expr.type = ast.Type(rhs)

    elif isinstance(expr, ast.NewObjectExpr):

        cls = ast.lookup(ast.classtable, expr.classref.name)

        expr.constr_id = None

        # After ensuring the # of args match, if there's no constructor, allow it
        if len(cls.constructors) == 0 and len(expr.args) == 0:
            expr.type = ast.Type(expr.classref.name)
            return False

        if cls.constructors[0].visibility == 'private':
            expr.type = ast.Type('error')
            signal_error(
                'Constructor for class {} is private'.format(cls.name),
                expr.lines)
            return True

        # Ensure number of args match
        if len(cls.constructors[0].vars.vars[0]) != len(expr.args):
            expr.type = ast.Type('error')
            signal_error(
                'Constructor for class {} expects {} arguments, received {}'.
                format(cls.name, len(cls.constructors[0].vars.vars[0]),
                       len(expr.args)), expr.lines)
            return True

        constr_params = cls.constructors[0].vars.vars[0].values()
        # Ensure each arg is a subtype of each param
        for i in range(0, len(constr_params)):

            arg_err = expr_error(expr.args[i])
            if arg_err:
                expr.type = ast.Type('error')
                return True

            nth_param = ast.Type(constr_params[i].type)
            nth_arg = ast.Type(expr.args[i].type)

            if not nth_arg.subtype_of(nth_param):
                expr.type = ast.Type('error')
                signal_error(
                    'Constructor argument number {0} is not a subtype '
                    'of construtor parameter number {0}. Expects \'{1}\', received \'{2}\'.'
                    .format(i + 1, nth_param.typename,
                            nth_arg.typename), expr.lines)
                return True

        expr.constr_id = cls.constructors[0].id

        expr.type = ast.Type(expr.classref.name)

    elif isinstance(expr, ast.ClassReferenceExpr):
        expr.type = ast.Type(expr.classref.name, None, True)

    elif isinstance(expr, ast.SuperExpr):
        if current_class.superclass is None:
            signal_error(
                'Class {} has no superclass.'.format(current_class.name),
                expr.lines)
            expr.type = ast.Type('error')
        else:
            expr.type = ast.Type(current_class.superclass.name)

    elif isinstance(expr, ast.AutoExpr):

        err = expr_error(expr.arg)
        if err:
            expr.type = ast.Type('error')
            return True

        if expr.arg.type.is_numeric():
            expr.type = ast.Type(expr.arg.type)
        else:
            expr.type = ast.Type('error')
            signal_error(
                'Auto expression must be int or float; received {}'.format(
                    expr.arg.type), expr.lines)

    elif isinstance(expr, ast.ArrayAccessExpr) or isinstance(
            expr, ast.NewArrayExpr):
        expr.type = ast.Type('error')
        signal_error("Array expression found, this is not supported!",
                     expr.lines)

    return expr.type.is_error()
Exemplo n.º 8
0
def gen_code(stmt):
    global current_loop_continue_label, current_enter_then_label, current_break_out_else_label
    # stmt.end_reg is the destination register for each expression
    stmt.end_reg = None
    push_labels()

    if isinstance(stmt, ast.BlockStmt):
        for stmt_line in stmt.stmtlist:
            gen_code(stmt_line)

    elif isinstance(stmt, ast.ExprStmt):
        gen_code(stmt.expr)

    elif isinstance(stmt, ast.AssignExpr):
        gen_code(stmt.rhs)
        gen_code(stmt.lhs)

        if stmt.lhs.type == ast.Type('float') and stmt.rhs.type == ast.Type('int'):
            conv = absmc.ConvertInstr('itof', stmt.rhs.end_reg)
            stmt.rhs.end_reg = conv.dst

        if not isinstance(stmt.lhs, ast.FieldAccessExpr):
            absmc.MoveInstr('move', stmt.lhs.end_reg, stmt.rhs.end_reg)
        else:
            absmc.HeapInstr('hstore', stmt.lhs.base.end_reg, stmt.lhs.offset_reg, stmt.rhs.end_reg)

    elif isinstance(stmt, ast.VarExpr):
        stmt.end_reg = stmt.var.reg

    elif isinstance(stmt, ast.ConstantExpr):
        reg = absmc.Register()

        if stmt.kind == 'int':
            absmc.MoveInstr('move_immed_i', reg, stmt.int, True)
        elif stmt.kind == 'float':
            absmc.MoveInstr('move_immed_f', reg, stmt.float, True)
        elif stmt.kind == 'string':
            pass
        elif stmt.kind == 'True':
            absmc.MoveInstr('move_immed_i', reg, 1, True)
        elif stmt.kind == 'False':
            absmc.MoveInstr('move_immed_i', reg, 0, True)
        elif stmt.kind == 'Null':
            absmc.MoveInstr('move_immed_i', reg, 'Null', True)


        stmt.end_reg = reg

    elif isinstance(stmt, ast.BinaryExpr):
        if stmt.bop not in ['and', 'or']:
            gen_code(stmt.arg1)
            gen_code(stmt.arg2)

            reg = absmc.Register()
            flt = ast.Type('float')
            intg = ast.Type('int')
            if stmt.arg1.type == flt or stmt.arg2.type == flt:
                expr_type = 'f'
            else:
                expr_type = 'i'

            if stmt.arg1.type == intg and stmt.arg2.type == flt:
                conv = absmc.Convert('itof', stmt.arg1.end_reg)
                stmt.arg1.end_reg = conv.dst
            elif stmt.arg1.type == flt and stmt.arg2.type == intg:
                conv = absmc.Convert('itof', stmt.arg2.end_reg)
                stmt.arg2.end_reg = conv.dst

            if stmt.bop in ['add', 'sub', 'mul', 'div', 'gt', 'geq', 'lt', 'leq']:
                absmc.ArithInstr(stmt.bop, reg, stmt.arg1.end_reg, stmt.arg2.end_reg, expr_type)

            elif stmt.bop == 'eq' or stmt.bop == 'neq':
                absmc.ArithInstr('sub', reg, stmt.arg1.end_reg, stmt.arg2.end_reg, expr_type)

            if stmt.bop == 'eq':

                # check if r2 == r3
                # 1. perform sub r1, r2, r3 (done above)
                # 2. branch to set_one if r1 is zero
                # 3. else, fall through and set r1 to zero
                # 4. jump out so we don't set r1 to one by accident

                ieq_set = absmc.BranchLabel(stmt.lines, 'SET_EQ')
                ieq_out = absmc.BranchLabel(stmt.lines, 'SET_EQ_OUT')

                absmc.BranchInstr('bz', ieq_set, reg)
                absmc.MoveInstr('move_immed_i', reg, 0, True)
                absmc.BranchInstr('jmp', ieq_out)

                ieq_set.add_to_code()
                absmc.MoveInstr('move_immed_i', reg, 1, True)

                ieq_out.add_to_code()

        if stmt.bop == 'and':
            and_skip = absmc.BranchLabel(stmt.lines, 'AND_SKIP')
            gen_code(stmt.arg1)
            reg = absmc.Register()
            absmc.MoveInstr('move', reg, stmt.arg1.end_reg)
            absmc.BranchInstr('bz', and_skip, stmt.arg1.end_reg)
            gen_code(stmt.arg2)
            absmc.MoveInstr('move', reg, stmt.arg2.end_reg)
            and_skip.add_to_code()

        if stmt.bop == 'or':
            or_skip = absmc.BranchLabel(stmt.lines, 'OR_SKIP')
            gen_code(stmt.arg1)
            reg = absmc.Register()
            absmc.MoveInstr('move', reg, stmt.arg1.end_reg)
            absmc.BranchInstr('bnz', or_skip, stmt.arg1.end_reg)
            gen_code(stmt.arg2)
            absmc.MoveInstr('move', reg, stmt.arg2.end_reg)
            or_skip.add_to_code()

        stmt.end_reg = reg

    elif isinstance(stmt, ast.ForStmt):

        # for-loop:
        # for (i = 0; i < 10; i++) {
        #   body
        # }

        # set i's reg equal to 0
        # create a label after this, as this is where we jump back to at end of loop
        # also create the 'out' label which is what we jump to when breaking out of loop
        # generate code for the 'cond' (test if i's reg is less than 10's reg)
        # test if the cond evaluated to false with 'bz', if so, break out of loop
        # else, fall through into the body of the for-loop
        # when body is over, generate code to update the var (i++)
        # jump unconditionally back to the cond_label, where we eval if i is still < 10
        gen_code(stmt.init)

        cond_label = absmc.BranchLabel(stmt.lines, 'FOR_COND')
        current_enter_then_label = entry_label = absmc.BranchLabel(stmt.lines, 'FOR_ENTRY')
        current_loop_continue_label = continue_label = absmc.BranchLabel(stmt.lines, 'FOR_UPDATE')
        current_break_out_else_label = out_label = absmc.BranchLabel(stmt.lines, 'FOR_OUT')

        cond_label.add_to_code()

        gen_code(stmt.cond)
        absmc.BranchInstr('bz', out_label, stmt.cond.end_reg)

        entry_label.add_to_code()
        gen_code(stmt.body)

        continue_label.add_to_code()
        gen_code(stmt.update)

        absmc.BranchInstr('jmp', cond_label)

        out_label.add_to_code()

    elif isinstance(stmt, ast.AutoExpr):
        gen_code(stmt.arg)

        if stmt.when == 'post':
            tmp_reg = absmc.Register()
            absmc.MoveInstr('move', tmp_reg, stmt.arg.end_reg)

        one_reg = absmc.Register()

        # Load 1 into a register
        absmc.MoveInstr('move_immed_i', one_reg, 1, True)

        absmc.ArithInstr('add' if stmt.oper == 'inc' else 'sub', stmt.arg.end_reg, stmt.arg.end_reg, one_reg)

        if stmt.when == 'post':
            stmt.end_reg = tmp_reg
        else:
            stmt.end_reg = stmt.arg.end_reg

    elif isinstance(stmt, ast.SkipStmt):
        pass

    elif isinstance(stmt, ast.ReturnStmt):
        current_method.returned = True
        if stmt.expr is None:
            absmc.ProcedureInstr('ret')
            return
        gen_code(stmt.expr)

        # Load the result into a0
        absmc.MoveInstr('move', absmc.Register('a', 0), stmt.expr.end_reg)

        # Return to caller
        absmc.ProcedureInstr('ret')

    elif isinstance(stmt, ast.WhileStmt):

        current_loop_continue_label = cond_label = absmc.BranchLabel(stmt.lines, 'WHILE_COND')
        current_enter_then_label = entry_label = absmc.BranchLabel(stmt.lines, 'WHILE_ENTRY')
        current_break_out_else_label = out_label = absmc.BranchLabel(stmt.lines, 'WHILE_OUT')

        cond_label.add_to_code()

        gen_code(stmt.cond)

        absmc.BranchInstr('bz', out_label, stmt.cond.end_reg)

        entry_label.add_to_code()

        gen_code(stmt.body)

        absmc.BranchInstr('jmp', cond_label)

        out_label.add_to_code()

    elif isinstance(stmt, ast.BreakStmt):
        absmc.BranchInstr('jmp', current_break_out_else_label)

    elif isinstance(stmt, ast.ContinueStmt):
        absmc.BranchInstr('jmp', current_loop_continue_label)

    elif isinstance(stmt, ast.IfStmt):

        # if (x == y)
        #   ++x;
        # else
        #   --x;

        # generate 2 labels, for the else part, and the out part
        # test if x == y
        # if not true, jump to the else part
        # if true, we're falling through to the then part, then must jump
        # out right before hitting the else part straight to the out part

        current_enter_then_label = then_part = absmc.BranchLabel(stmt.lines, 'THEN_PART')
        current_break_out_else_label = else_part = absmc.BranchLabel(stmt.lines, 'ELSE_PART')
        out_label = absmc.BranchLabel(stmt.lines, 'IF_STMT_OUT')

        gen_code(stmt.condition)

        absmc.BranchInstr('bz', else_part, stmt.condition.end_reg)

        then_part.add_to_code()
        gen_code(stmt.thenpart)

        absmc.BranchInstr('jmp', out_label)

        else_part.add_to_code()

        gen_code(stmt.elsepart)

        out_label.add_to_code()

    elif isinstance(stmt, ast.FieldAccessExpr):
        gen_code(stmt.base)

        cls = ast.lookup(ast.classtable, stmt.base.type.typename)
        field = ast.lookup(cls.fields, stmt.fname)

        offset_reg = absmc.Register()
        ret_reg = absmc.Register()

        absmc.MoveInstr('move_immed_i', offset_reg, field.offset, True)
        absmc.HeapInstr('hload', ret_reg, stmt.base.end_reg, offset_reg)

        stmt.offset_reg = offset_reg
        stmt.end_reg = ret_reg

    elif isinstance(stmt, ast.ClassReferenceExpr):
        stmt.end_reg = absmc.Register('sap')

    elif isinstance(stmt, ast.NewObjectExpr):
        recd_addr_reg = absmc.Register()
        size_reg = absmc.Register()
        absmc.MoveInstr('move_immed_i', size_reg, stmt.classref.size, True)
        absmc.HeapInstr('halloc', recd_addr_reg, size_reg)

        if stmt.constr_id is None:
            stmt.end_reg = recd_addr_reg
            return

        saved_regs = []

        saved_regs.append(recd_addr_reg)

        # add a0 if the current method is not static
        if current_method.storage != 'static':
            saved_regs.append(absmc.Register('a', 0))

        # for each var in each block of the current method, add to save list
        for block in range(0, len(current_method.vars.vars)):
            for var in current_method.vars.vars[block].values():
                saved_regs.append(var.reg)

        # save each reg in the saved list
        for reg in saved_regs:
            absmc.ProcedureInstr('save', reg)

        absmc.MoveInstr('move', absmc.Register('a', 0), recd_addr_reg)

        arg_reg_index = 1

        for arg in stmt.args:
            gen_code(arg)
            absmc.MoveInstr('move', absmc.Register('a', arg_reg_index), arg.end_reg)
            arg_reg_index += 1

        absmc.ProcedureInstr('call', 'C_{}'.format(stmt.constr_id))

        # restore regs from the now-reversed save list
        for reg in reversed(saved_regs):
            absmc.ProcedureInstr('restore', reg)

        stmt.end_reg = recd_addr_reg

    elif isinstance(stmt, ast.ThisExpr):
        stmt.end_reg = absmc.Register('a', 0)

    elif isinstance(stmt, ast.MethodInvocationExpr):
        gen_code(stmt.base)

        cls = ast.lookup(ast.classtable, stmt.base.type.typename)
        for method in cls.methods:
            if stmt.mname == method.name:
                break

        saved_regs = []

        arg_reg_index = 0

        # first arg goes into a1 if desired method is not static
        if method.storage != 'static':
            arg_reg_index += 1

        # add a0 if the current method is not static
        if current_method.storage != 'static':
            saved_regs.append(absmc.Register('a', 0))

        # for each var in each block of the current method, add to save list
        for block in range(0, len(current_method.vars.vars)):
            for var in current_method.vars.vars[block].values():
                saved_regs.append(var.reg)

        # save each reg in the saved list
        for reg in saved_regs:
            absmc.ProcedureInstr('save', reg)

        if method.storage != 'static':
            absmc.MoveInstr('move', absmc.Register('a', 0), stmt.base.end_reg)

        for arg in stmt.args:
            gen_code(arg)
            absmc.MoveInstr('move', absmc.Register('a', arg_reg_index), arg.end_reg)
            arg_reg_index += 1

        absmc.ProcedureInstr('call', 'M_{}_{}'.format(method.name, method.id))

        # Store the result in a temporary register
        stmt.end_reg = absmc.Register()
        absmc.MoveInstr('move', stmt.end_reg, absmc.Register('a', 0))

        # restore regs from the reversed save list
        for reg in reversed(saved_regs):
            absmc.ProcedureInstr('restore', reg)

    elif isinstance(stmt, ast.UnaryExpr):
        gen_code(stmt.arg)

        ret = absmc.Register()
        if stmt.uop == 'uminus':
            zero_reg = absmc.Register()
            if stmt.arg.type == ast.Type('float'):
                prefix = 'f'
            else:
                prefix = 'i'
            # if uminus, put 0 - <reg> into the return reg
            absmc.MoveInstr('move_immed_{}'.format(prefix), zero_reg, 0, True)
            absmc.ArithInstr('sub', ret, zero_reg, stmt.arg.end_reg, prefix)
        else:
            # if it's a 0, branch to set 1
            # if it's a 1, we're falling through, setting to 0, and jumping out
            set_one_label = absmc.BranchLabel(stmt.lines, 'SET_ONE')
            out_label = absmc.BranchLabel(stmt.lines, 'UNARY_OUT')

            absmc.BranchInstr('bz', set_one_label, stmt.arg.end_reg)
            absmc.MoveInstr('move_immed_i', ret, 0, True)
            absmc.BranchInstr('jmp', out_label)

            set_one_label.add_to_code()

            absmc.MoveInstr('move_immed_i', ret, 1, True)

            out_label.add_to_code()

        stmt.end_reg = ret

    elif isinstance(stmt, ast.SuperExpr):
        stmt.end_reg = absmc.Register('a', 0)

    elif isinstance(stmt, ast.ArrayAccessExpr):
        # Create fake register.
        stmt.end_reg = absmc.Register('n', 0)
        print 'Found an array access. Arrays are not supported.'

    elif isinstance(stmt, ast.NewArrayExpr):
        # Create fake register.
        stmt.end_reg = absmc.Register('n', 0)
        print 'Found an array creation. Arrays are not supported.'

    else:
        print 'need instance ' + str(type(stmt))

    pop_labels()
Exemplo n.º 9
0
 def lookup_field(self, fname):
     return ast.lookup(self.fields, fname)
Exemplo n.º 10
0
def checkExpr(expr, Class):
    # check type errors fo constant expr
    if isinstance(expr, ConstantExpr):
        kind = expr.kind
        if kind == 'int':
            expr.type = 'int'
        elif kind == 'float':
            expr.type = 'float'
        elif kind == 'string':
            expr.type = 'string'
        elif kind == 'True' or kind == 'False':
            expr.type = 'boolean'
        elif kind == 'Null':
            expr.type = 'null'
    # check type errors for Var Expression
    elif isinstance(expr, VarExpr):
        var = expr.var
        expr.type = var.type
    # check type errors for Unary Expressions
    elif isinstance(expr, UnaryExpr):
        uop = expr.uop
        arg = expr.arg
        checkExpr(arg, Class)
        if str(arg.type) == 'int' and uop == 'uminus':
            expr.type = 'int'
        elif str(arg.type) == 'float' and uop == 'uminus':
            expr.type = 'float'
        elif str(arg.type) == 'boolean' and uop == 'neg':
            expr.type = 'boolean'
        else:
            expr.type = 'error'
            print "UnaryExpr Error at line %s: '%s' operation found invalid argument '%s'" % (
                expr.lines, uop, arg.type)
    elif isinstance(expr, BinaryExpr):
        bop = expr.bop
        arg1 = expr.arg1
        arg2 = expr.arg2
        checkExpr(arg1, Class)
        checkExpr(arg2, Class)

        if bop == 'add' or bop == 'sub' or bop == 'mul' or bop == 'div':
            if (str(arg1.type) == 'int' and str(arg2.type) == 'int'):
                expr.type = 'int'
            elif (str(arg1.type) == 'int' or str(arg1.type) == 'float') and (
                    str(arg2.type) == 'int' or str(arg2.type) == 'float'):
                expr.type = 'float'
            else:
                expr.type = 'error'
                print "BinaryExpr Error at line %s: '%s' operation found invalid arguments '%s', '%s'" % (
                    expr.lines, bop, arg1.type, arg2.type)
        elif bop == 'and' or bop == 'or':
            if str(arg1.type) == 'boolean' and str(arg2.type) == 'boolean':
                expr.type = 'boolean'
            else:
                expr.type = 'error'
                print "BinaryExpr Error at line %s: '%s' operation found invalid arguments '%s', '%s'" % (
                    expr.lines, bop, arg1.type, arg2.type)
        elif bop == 'lt' or bop == 'leq' or bop == 'gt' or bop == 'geq':
            if (str(arg1.type) == 'int' or str(arg1.type) == 'float') and (str(
                    arg2.type) == 'int' or str(arg2.type) == 'float'):
                expr.type = 'boolean'
            else:
                expr.type = 'error'
                print "BinaryExpr Error at line %s: '%s' operation found invalid arguments '%s', '%s'" % (
                    expr.lines, bop, arg1.type, arg2.type)
        elif bop == 'eq' or bop == 'neq':
            if isSubtype(arg1.type, arg2.type) or isSubtype(
                    arg2.type, arg1.type):
                expr.type = 'boolean'
            else:
                expr.type = 'error'
                print "BinaryExpr Error at line %s: '%s' operation found invalid arguments '%s', '%s'" % (
                    expr.lines, bop, arg1.type, arg2.type)
    elif isinstance(expr, AssignExpr):
        lhs = expr.lhs
        rhs = expr.rhs
        checkExpr(lhs, Class)
        checkExpr(rhs, Class)
        if str(lhs.type) != 'error' and str(rhs.type) != 'error' and isSubtype(
                rhs.type, lhs.type):
            expr.type = rhs.type
        else:
            expr.type = 'error'
            if str(lhs.type) != 'error' and str(rhs.type) != 'error':
                print "AssignExpr Error at line %s: '%s' expression found when '%s' is expected" % (
                    expr.lines, rhs.type, lhs.type)
    elif isinstance(expr, AutoExpr):
        arg = expr.arg
        checkExpr(arg, Class)
        if str(arg.type) == 'int' or str(arg.type) == 'float':
            expr.type = arg.type
        else:
            expr.type = 'error'
            print "AutoExpr Error at line %s: '%s' found int or float expected" % (
                expr.lines, arg.type)
    elif isinstance(expr, FieldAccessExpr):
        base = expr.base
        fname = expr.fname
        checkExpr(base, Class)
        if 'user' in str(base.type):
            A = str(base.type)[5:-1]
            storage = 'instance'
        elif 'class-literal' in str(base.type):
            A = str(base.type)[14:-1]
            storage = 'staic'

        classA = ast.lookup(ast.classtable, A)
        inSuperClass = False
        while (classA is not None):
            fields = classA.fields
            if fname in fields and fields[fname].storage is storage and (
                    not inSuperClass or fields[fname].visibility is 'public'):
                expr.resolvedID = fields[fname].id
                expr.type = fields[fname].type
                break
            else:
                classA = classA.superclass
                inSuperClass = True
        if classA is None:
            expr.type = 'error'
            expr.resolvedID = None
            print "FieldAccessExpr Error at line %s:, couldn't find field '%s'" % (
                expr.lines, fname)
    elif isinstance(expr, MethodInvocationExpr):
        base = expr.base
        checkExpr(base, Class)
        mname = expr.mname
        args = expr.args

        if 'user' in str(base.type):
            A = str(base.type)[5:-1]
            storage = 'instance'
        elif 'class-literal' in str(base.type):
            A = str(base.type)[14:-1]
            storage = 'static'

        classA = ast.lookup(ast.classtable, A)
        inSuperClass = False
        argMatch = True
        methodFound = False
        isAllSubtype = True
        while (classA is not None):
            methods = classA.methods
            for m in methods:
                if m.name == mname and m.storage is storage and (
                    (not inSuperClass and str(classA.name) == str(Class.name))
                        or m.visibility is 'public'):
                    formalPar = m.vars.vars[0]
                    if len(args) == len(formalPar):
                        argMatch = True
                        for ID in range(0, len(formalPar)):
                            for fp in formalPar:
                                if formalPar[fp].id == ID + 1:
                                    checkExpr(args[ID], Class)
                                    if not isStrictSubtype(
                                            args[ID].type, formalPar[fp].type):
                                        ID = len(formalPar)
                                        argMatch = False
                                        break
                        if argMatch and methodFound:
                            expr.type = 'error'
                            expr.resolvedID = None
                        elif argMatch:
                            methodFound = True
                            expr.type = m.rtype
                            expr.resolvedID = m.id
            if not methodFound:
                classA = classA.superclass
                inSuperClass = True
            else:
                break
        if not methodFound:
            classA = ast.lookup(ast.classtable, A)
            while (classA is not None):
                methods = classA.methods
                for m in methods:
                    if m.name == mname and m.storage is storage and (
                            not inSuperClass or m.visibility is 'public'):
                        formalPar = m.vars.vars[0]
                        if len(args) == len(formalPar):
                            argMatch = True
                            isAllSubtype = True
                            for ID in range(0, len(formalPar)):
                                for fp in formalPar:
                                    if formalPar[fp].id == ID + 1:
                                        checkExpr(args[ID], Class)
                                        #if isStrictSubtype(args[ID].type, formalPar[fp].type):
                                        isAllSubtype = False
                                        if not isSubtype(
                                                args[ID].type,
                                                formalPar[fp].type):
                                            ID = len(formalPar)
                                            argMatch = False
                                            break
                            if argMatch and methodFound and not isAllSubtype:
                                expr.type = 'error'
                                expr.resolvedID = None
                            elif argMatch and not isAllSubtype:
                                methodFound = True
                                expr.type = m.rtype
                                expr.resolvedID = m.id
                if not methodFound:
                    classA = classA.superclass
                    inSuperClass = True
                else:
                    break

        if classA is None:
            expr.type = 'error'
            print "MethodInvocationExpr Error at line %s: couldn't find method with name '%s'" % (
                expr.lines, mname)
        elif expr.type == 'error':
            print "MethodInvocationExpr Error at line %s: couldn't find valid method with name '%s'" % (
                expr.lines, mname)
    elif isinstance(expr, NewObjectExpr):
        classref = expr.classref
        args = expr.args

        argMatch = True
        constructorFound = False
        inSuperClass = False
        constructors = classref.constructors
        for c in constructors:
            if c.visibility is 'public' or Class.name == classref.name:
                formalPar = c.vars.vars[0]
                if len(args) == len(formalPar):
                    argMatch = True
                    for ID in range(0, len(formalPar)):
                        for fp in formalPar:
                            if formalPar[fp].id == ID + 1:
                                checkExpr(args[ID], Class)
                                if not isStrictSubtype(args[ID].type,
                                                       formalPar[fp].type):
                                    ID = len(formalPar)
                                    argMatch = False
                                    break
                    if argMatch and constructorFound:
                        expr.type = 'error'
                        expr.resolvedID = None
                    elif argMatch:
                        constructorFound = True
                        expr.resolvedID = c.id
                        expr.type = 'user(' + classref.name + ')'
        if not constructorFound:
            for c in constructors:
                if c.visibility is 'public' or Class.name == classref.name:
                    formalPar = c.vars.vars[0]
                    if len(args) == len(formalPar):
                        argMatch = True
                        isAllSubtype = True
                        for ID in range(0, len(formalPar)):
                            for fp in formalPar:
                                if formalPar[fp].id == ID + 1:
                                    checkExpr(args[ID], Class)
                                    #                                    if isStrictSubtype(args[ID].type, formalPar[fp].type):
                                    isAllSubtype = False
                                    if not isSubtype(args[ID].type,
                                                     formalPar[fp].type):
                                        ID = len(formalPar)
                                        argMatch = False
                                        break
                        if argMatch and constructorFound and not isAllSubtype:
                            expr.type = 'error'
                            expr.resolvedID = None
                        elif argMatch and not isAllSubtype:
                            constructorFound = True
                            expr.resolvedID = c.id
                            expr.type = 'user(' + classref.name + ')'
        if not constructorFound:
            expr.type = 'error'
            print "NewObjectExpr Error at line %s: couldn't find valid class with name '%s'" % (
                expr.lines, classref.name)
    elif isinstance(expr, ThisExpr):
        expr.type = 'user(' + Class.name + ')'
    elif isinstance(expr, SuperExpr):
        if Class.superclass.name is not None:
            expr.type = 'user(' + Class.superclass.name + ')'
        else:
            expr.type = 'error'
            print "ThisExpr Error at line %s" % (expr.lines)
    elif isinstance(expr, ClassReferenceExpr):
        classref = expr.classref
        expr.type = 'class-literal(' + classref.name + ')'
    elif isinstance(expr, ArrayAccessExpr):
        base = expr.base
        index = expr.index
        checkExpr(base, Class)
        checkExpr(index, Class)
        baseType = str(base.type)
        if 'array(' in baseType and index.type is 'int':
            expr.type = baseType[6:-1]
        else:
            expr.type = 'error'
            if index.type is not 'int':
                print "ArrayAccessExpr Error at line %s: 'int' index expected found %s" % (
                    expr.lines, index.type)
            else:
                print "ArrayAccessExpr Error at line %s: 'array(' base type expected found %s" % (
                    expr.lines, baseType)
    elif isinstance(expr, NewArrayExpr):
        baseType = expr.basetype
        args = expr.args
        checkExpr(baseType, Class)
        type = str(baseType)
        for arg in args:
            checkExpr(arg, Class)
            if str(arg.type) is 'int':
                type = 'array(' + type + ')'
            else:
                type = 'error'
                print "NewArrayExpr Error at line %s: 'int' argument expected found %s" % (
                    expr.lines, arg.type)
                break
        expr.type = type