Пример #1
0
class InterpreterRecc:
    def __init__(self, goal, test = False, actual_code_lines = [], no_command = True):
        sys.setrecursionlimit(10000)
        self.test = test
        self.actual_code_lines = actual_code_lines
        self.no_command = no_command
        self.frame = Frame()
        self.command = Command(self.frame, self.no_command, self.actual_code_lines)
        self.func_depth = {}
        self.proper_exit = False
        self.exit_code = -1
        self.states = []
        self.stuffs = []

        try:
            self.handle_goal(goal)
            if self.proper_exit:
                print("... Program finished with exit code:", self.exit_code)
            while not self.no_command:
                self.command.command()
        except RTException:
            pass
        except CmdException:
            pass

    def report_rt_err(self, line_num, string):
        if self.test:
            print("At line ", line_num, ", ", string, ", SmileyFace", sep='')
            print(self.actual_code_lines[line_num - 1])
        else:
            print("Run-time error : line", line_num)
        raise RTException

    def test_something(self, to_test, line_num, string):
        if to_test: return
        self.report_rt_err(line_num, string)
        assert(False)

    def test_Err(self, to_test, line_num, string):
        self.test_something(not isinstance(to_test, Err), line_num, string)
        return to_test.value

    def handle_func(self, func):
        self.test_Err(self.frame.declare_function(func.name, func), func.line_num, "Already function with that name")
        self.func_depth[func.name] = 0

    def handle_goal(self, goal):
        for func in goal.funcs:
            self.handle_func(func)

        main = self.frame.get_function(MAIN)
        main = self.test_Err(main, len(self.actual_code_lines), "Found no main()")
        self.test_something(len(main.arguments) == 0, main.line_num, "main() should have no arguments for our stupid implementation")

        self.exit_code = int(self.doit(main).num)
        self.proper_exit = True

    def beginners_luck(self, pi):
        tt = pi.type
        self.states.append(tt)
        if tt < 13:
            if tt < 10:
                if tt < 7:
                    if tt < 4:
                        if tt == PitStmt2: #forst (forst, init=3/cond=0/stmt=1/update=2, init'd)
                            self.stuffs.append([pi, 3, False])
                        else: #PitStmt3 ifst (ifst, calcd_cond, ran_stmt)
                            self.stuffs.append([pi, False, False])
                    elif tt == PitStmt4: #cmpdst (stmt4, next_stmt)
                        self.stuffs.append([pi, 0])
                    else: #PitStmt5 retst (retst, calcd_return_value)
                        self.stuffs.append([pi, False])
                elif tt < 9:
                    if tt == PitDecl:
                        self.stuffs.append([pi])
                    else: #PitInst3 expr
                        self.stuffs.append([pi])
                else: #PitInst4 noop
                    self.stuffs.append([pi])
            elif tt < 12:
                if tt == PitExpr1: #arithmetic, (expr1, lhs, last_index)
                    #rax = IInt(0)
                    self.stuffs.append([pi, IInt(0), 0])
                else: #PitExpr2 assignment (expr2, calcd_rhs, calcd_index, index)
                    self.stuffs.append([pi, False, False, 0])
            else: #PitTerm (term, lhs, last_index)
                #rax = IInt(1)
                self.stuffs.append([pi, IInt(1), 0])
        elif tt < 16:
            if tt < 15:
                if tt == PitFactor1: #lhs/++lhs/lhs++
                    self.stuffs.append([pi, False])
                else: #PitFactor2 function call, (factor2, args_done, calc'd_args, back_ttf, func)
                    self.stuffs.append([pi, 0, [], 0, None])
            else: #PitFactor3 int
                self.stuffs.append([pi])
        elif tt < 18:
            if tt == PitFactor4: #float
                self.stuffs.append([pi])
            else: #PitFactor5 (expr)
                self.stuffs.append([pi])
        elif tt == PitFactor6: #unary +/- (factor6, calcd)
            self.stuffs.append([pi, False])
        elif tt == PitFF: #execute function??
            self.stuffs.append(pi.stuff+[0])
        else: #(0arguments, 1line_num, 2formatted, 3next_index, 4how_to_print, 5string_blocks, 6arg_values, 7done)
            self.stuffs.append(pi.stuff+[False, 1, [], [], [], False])
            

    def doit(self, main):
        rax = IInt(0xcccc)
        self.frame.into_function()
        self.beginners_luck(FakeParsedItem(main, [], 0, True))
        self.command.skip_lines(main.line_num, True)

        while True:
            exe = self.stuffs[-1]
            tt = self.states[-1]
            try:
                if tt < 13:
                    if tt < 10:
                        if tt < 7:
                            if tt < 4:
                                if tt == PitStmt2: #(forst, init=3/cond=0/stmt=1/update=2, init'd)
                                    if exe[1] == 0:
                                        if rax.num != 0:
                                            exe[1] = 1
                                            self.beginners_luck(exe[0].stmt)
                                            continue
                                        
                                        forst = exe[0]
                                        to_line = forst.stmt.end_ln if forst.stmt.type == PitStmt4 else forst.stmt.line_num
                                        self.command.skip_lines(to_line)
                                        self.frame.escape_bracket()
                                        self.states.pop()
                                        self.stuffs.pop()
                                        continue
                                    
                                    elif exe[1] == 1:
                                        exe[1] = 2
                                        self.command.skip_lines(exe[0].line_num, True)
                                        self.beginners_luck(exe[0].update)
                                        continue
                                    elif exe[1] == 2:
                                        exe[1] = 0
                                        self.beginners_luck(exe[0].condition)
                                        continue
                                    elif exe[2]:
                                        exe[1] = 0
                                        self.beginners_luck(exe[0].condition)
                                        continue
                                    else:
                                        exe[2] = True
                                        self.command.feed_line(exe[0].line_num)
                                        self.frame.into_bracket()
                                        self.beginners_luck(exe[0].initialize)
                                        continue

                                else: #PitStmt3 ifst (stmts, calcd_cond, ran_stmt)
                                    if not exe[1]:
                                        self.command.feed_line(exe[0].line_num)
                                        exe[1] = True
                                        self.beginners_luck(exe[0].condition)
                                        continue

                                    if not exe[2]:
                                        exe[2] = True
                                        if rax.num != 0:
                                            self.beginners_luck(exe[0].stmt)
                                            continue
                                    
                                    ifst = exe[0]
                                    to_line = ifst.stmt.end_ln if ifst.stmt.type == PitStmt4 else ifst.stmt.line_num
                                    self.command.skip_lines(to_line)
                                    self.states.pop()
                                    self.stuffs.pop()
                                    continue
                            
                            elif tt == PitStmt4: #cmpdst (stmts, next_stmt)
                                if exe[1] == 0:
                                    self.command.feed_line(exe[0].line_num)
                                    self.frame.into_bracket()
                                try:
                                    stmt = exe[0].stmts[exe[1]]
                                    self.beginners_luck(stmt)
                                    exe[1] = exe[1] + 1
                                    continue
                                except IndexError:
                                    pass
                                
                                self.frame.escape_bracket()
                                self.command.feed_line(exe[0].end_ln)
                                self.states.pop()
                                self.stuffs.pop()
                                continue

                            
                            else: #PitStmt5 retst = exe[0], calcd = exe[1]
                                if not exe[1]:
                                    exe[1] = True
                                    self.command.feed_line(exe[0].line_num)
                                    self.beginners_luck(exe[0].expr)
                                    continue
                                raise ReturnException()

                        elif tt < 9:
                            if tt == PitDecl:
                                decl = exe[0]
                                self.command.feed_line(decl.line_num)
                                for thing in decl.declarations:
                                    if thing[1] == None:
                                        result = self.frame.declare_direct(thing[0], decl.line_num, decl.declares_int)
                                        self.test_Err(result, decl.line_num, "Declaration went wrong")
                                        continue
                                    result = self.frame.declare_array(thing[0], decl.line_num, decl.declares_int, thing[1])
                                    self.test_Err(result, decl.line_num, "Declaration went wrong")
                                
                                self.states.pop()
                                self.stuffs.pop()
                                continue
                            
                            else: #PitInst3 expr
                                self.command.feed_line(exe[0].line_num)
                                self.states.pop()
                                self.stuffs.pop()
                                self.beginners_luck(exe[0].expr)
                                continue
                        
                        else: #PitInst4 noop
                            self.command.feed_line(exe[0].line_num)
                            self.states.pop()
                            self.stuffs.pop()
                            continue
                    
                    elif tt < 12:
                        if tt == PitExpr1: #arithmetic expr1 = exe[0], lhs = exe[1], next_index = exe[2]
                            expr1 = exe[0]
                            if exe[2] != 0:
                                lhs, rhs = exe[1], rax
                                op = expr1.terms_and_ops[exe[2]-3]
                                self.test_something(not isinstance(lhs, IAdd), expr1.line_num, "Pointer arithmetic")
                                lhn, rhn = lhs.num, rhs.num
                                if op == 0: result = lhn + rhn
                                elif op == 1: result = lhn - rhn
                                elif op == 2: result = 1 if (lhn > rhn) else 0
                                else: result = 1 if (lhn < rhn) else 0
                                if isinstance(rhs, IAdd):
                                    exe[1] = IAdd(result)
                                elif isinstance(lhs, IFlt) or isinstance(rhs, IFlt):
                                    exe[1] = IFlt(result)
                                else:
                                    exe[1] = IInt(result)

                            if exe[2] == 0 or op < 2:
                                try:
                                    next_term = expr1.terms_and_ops[exe[2]]
                                    next_op = expr1.terms_and_ops[exe[2]-1]
                                    exe[2] = exe[2] + 2
                                    if next_op < 2:
                                        self.beginners_luck(next_term)
                                        continue
                                    pexpr = ParsedExpr1(expr1.line_num)
                                    pexpr.terms_and_ops = expr1.terms_and_ops[exe[2]-2:]
                                    self.beginners_luck(pexpr)
                                    
                                    continue
                                except IndexError:
                                    pass
                            
                            rax = exe[1]
                            self.states.pop()
                            self.stuffs.pop()
                            continue
                            
                        else: #PitExpr2 assignment, expr2 = exe[0], calcd_rhs = exe[1], calcd_actual_index = exe[2], actual_index = exe[3]
                            expr2 = exe[0]
                            name, index = expr2.lhs
                            if not exe[2]:
                                exe[2] = True
                                if index != None:
                                    self.beginners_luck(index)
                                    continue
                            
                            if not exe[1]:
                                if index != None:
                                    self.test_something(not isinstance(rax, IFlt), index.line_num, "Float index to array")
                                    exe[3] = rax.num

                                exe[1] = True
                                self.beginners_luck(expr2.expr)
                                continue
                            
                            if index != None:
                                index = exe[3]
                            is_int, is_pointer = self.test_Err(self.frame.get_type(name), expr2.line_num, "No such symbol maybe?")
                            rhs = rax
                            if not isinstance(rhs, IAdd):
                                self.test_Err(self.frame.update_value(name, expr2.line_num, rhs.num, index), expr2.line_num, "Idk probably index out of bounds")
                                rax = IInt(rhs.num) if is_int else IFlt(rhs.num)
                            elif is_pointer and index == None:
                                self.test_Err(self.frame.update_value(name, expr2.line_num, rhs.num), expr2.line_num, "Probably because I disabled pointer assignment as well")
                                rax = rhs		
                            else:
                                self.report_rt_err(expr2.line_num, "Hmm probably symbol didn't exist or assigned pointer to non pointer")

                            self.states.pop()
                            self.stuffs.pop()
                            continue
                    
                    else: #PitTerm, term = exe[0], lhs = exe[1], next_index = exe[2]
                        
                        # This explicitly bans pointer arithmetic forever
                        term = exe[0]
                        if exe[2] != 0:
                            lhs, rhs = exe[1], rax
                            self.test_something(not isinstance(lhs, IAdd), term.line_num, "Pointer arithmetic")
                            lhn, rhn = lhs.num, rhs.num
                            op = term.factors_and_ops[exe[2]-3]
                            if op == 0: result = lhn * rhn
                            else: result = lhn / rhn if rhn != 0 else self.report_rt_err(term.line_num, "Zero division")
                            if isinstance(rhs, IAdd):
                                exe[1] = IAdd(result)
                            elif isinstance(lhs, IFlt) or isinstance(rhs, IFlt):
                                exe[1] = IFlt(result)
                            else:
                                exe[1] = IInt(result)
                            
                        try:
                            next_factor = term.factors_and_ops[exe[2]]
                            exe[2] = exe[2] + 2
                            self.beginners_luck(next_factor)
                            continue
                        except IndexError:
                            pass
                        
                        rax = exe[1]
                        self.states.pop()
                        self.stuffs.pop()
                        continue
                
                elif tt < 16:
                    if tt < 15:
                        if tt == PitFactor1: #lhs/++lhs/lhs++ (factor1, calcd_real_index)
                            factor1 = exe[0]
                            name, index = factor1.lhs
                            if not exe[1]:
                                exe[1] = True
                                if index != None:
                                    self.beginners_luck(index)
                                    continue
                            
                            if index != None:
                                self.test_something(not isinstance(rax, IFlt), index.line_num, "Float index to array")
                                index = rax.num
                            is_int, is_pointer, value = self.test_Err(self.frame.get_value(name, index), factor1.line_num, "No such symbol or something")
                            value = 0 if value == None else value

                            op = factor1.op
                            if op == 0:
                                if is_pointer:
                                    rax = IAdd(value)
                                else:
                                    rax = IInt(value) if is_int else IFlt(value)
                            
                            else:
                                self.test_something(not is_pointer, factor1.line_num, "Pointer increment")
                                self.frame.update_value(name, factor1.line_num, value + 1, index)
                                raxv = value + 1 if op == 1 else value
                                rax = IInt(raxv) if is_int else IFlt(raxv)
                            
                            self.states.pop()
                            self.stuffs.pop()
                            continue
                        
                        else: #PitFactor2 (factor2, args_done, calcd_args, bttf, func)
                            args_done = exe[1]
                            factor2 = exe[0]
                            if args_done > 0:
                                exe[2].append(rax)
                                if args_done < len(factor2.call):
                                    self.beginners_luck(factor2.call[args_done])
                                    exe[1] = exe[1] + 1
                                    continue

                            else:
                                self.test_something(isinstance(self.frame.get_type(factor2.func_name), Err), factor2.line_num, "Not a function in this scope")
                                func = self.frame.get_function(factor2.func_name)
                                if isinstance(func, Err):
                                    self.test_something(factor2.func_name == "printf", factor2.line_num, "No such function")
                                    #handle printf
                                    somethin2 = FakeParsedIte2(factor2.call, factor2.line_num)
                                    self.states.pop()
                                    self.stuffs.pop()
                                    self.beginners_luck(somethin2)
                                    continue
                                
                                func = func.value
                                exe[4] = func
                                exe[3] = self.command.current_line
                                self.command.skip_lines(func.start_ln, True)
                                if len(func.arguments) != len(factor2.call):
                                    self.report_rt_err(func.line_num, "Function call argument length mismatch")

                                if len(func.arguments) > 0:
                                    self.beginners_luck(factor2.call[0])
                                    exe[1] = 1
                                    continue
                            
                            func = exe[4]
                            arg_values = exe[2]
                            self.frame.into_function()
                            self.func_depth[factor2.func_name] += 1
                            if self.func_depth[factor2.func_name] > MAX_DEPTH:
                                self.report_rt_err(factor2.line_num, "Max function recursion depth "+str(MAX_DEPTH)+" reached for "+factor2.func_name)
                            #rax = IInt(0) if func.returns_int else IFlt(0)
                            for i in range(len(func.arguments)):
                                is_int, is_pointer, arg_name = func.arguments[i]
                                num = arg_values[i].num
                                if is_pointer and isinstance(arg_values[i], IAdd):
                                    result = self.frame.declare_pointer(arg_name, func.line_num, is_int, num)
                                    self.test_Err(result, func.line_num, "Pointer argument error")
                                elif not is_pointer and not isinstance(arg_values[i], IAdd):
                                    result = self.frame.declare_direct(arg_name, func.line_num, is_int, num)
                                    self.test_Err(result, func.line_num, "Non-pointer argument error")
                                else:
                                    print(is_pointer, isinstance(arg_values[i], IAdd))
                                    self.report_rt_err(func.line_num, "Argument type mismatch")

                            something = FakeParsedItem(exe[4], exe[2], exe[3])
                            self.states.pop()
                            self.stuffs.pop()
                            self.beginners_luck(something)
                            continue
                            
                    else: #PitFactor3 int
                        rax = IInt(exe[0].num)
                        self.states.pop()
                        self.stuffs.pop()
                        continue
                
                elif tt < 18:
                    if tt == PitFactor4: #float
                        rax = IFlt(exe[0].num)
                        self.states.pop()
                        self.stuffs.pop()
                        continue
                    
                    else: #PitFactor5 (expr)
                        factor5 = exe[0]
                        self.states.pop()
                        self.stuffs.pop()
                        self.beginners_luck(factor5.expr)
                        continue
                
                elif tt == PitFactor6: #unary +/-
                    factor6 = exe[0]
                    if exe[1]:
                        inum = rax
                        self.test_something(not isinstance(inum, IAdd), factor6.line_num, "Pointer unary op")
                        inum.num = inum.num if factor6.op == 0 else -inum.num
                        rax = inum

                        self.states.pop()
                        self.stuffs.pop()
                        continue
                    exe[1] = True
                    self.beginners_luck(factor6.factor)
                    continue
                
                elif tt == PitFF: #execute function (func, call, bttf, mainmain, executed)
                    try:
                        stmt = exe[0].stmts[exe[4]]
                        self.beginners_luck(stmt)
                        exe[4] = exe[4] + 1
                        continue
                    except IndexError:
                        pass
                    
                    self.command.feed_line(exe[0].end_ln)
                    raise ReturnException()

                else: #execute printf (0arguments, 1line_num, 2formatted, 3next_index, 4how_to_print, 5string_blocks, 6arg_values, 7done)
                    arguments = exe[0]
                    line_num = exe[1]
                    if exe[7]:
                        how_to_print = exe[4]
                        string_blocks = exe[5]
                        arg_values = exe[6]

                        string = string_blocks[0]
                        for i in range(len(how_to_print)):
                            if how_to_print[0]:
                                string = string + str(int(arg_values[i].num))
                            else:
                                string = string + str(float(arg_values[i].num))
                            string = string + string_blocks[i + 1]

                        print(string, end='')
                        rax = IInt(len(string))
                        self.states.pop()
                        self.stuffs.pop()
                        continue
                    
                    elif exe[2]:
                        exe[6].append(rax)
                        next_index = exe[3]
                        if next_index < len(arguments):
                            exe[3] = exe[3] + 1
                            arg = arguments[next_index]
                            self.test_something(not isinstance(arg, str), line_num, "Non primary string argument for printf")
                            self.beginners_luck(arg)
                            continue
                        exe[7] = True
                        continue

                    else:
                        exe[2] = True
                        self.test_something(len(arguments) > 0, line_num, "Too few arguments to printf")
                        self.test_something(isinstance(arguments[0], str), line_num, "Non string first arg to printf")

                        i = 0
                        top = arguments[0]
                        l = len(top)
                        how_to_print = []
                        string_blocks = [top]
                        while True:
                            
                            i = sub_count(top, sub_isn_spch, l, i)
                            if i == l: break
                            if top[i] == '\\':
                                if top[i+1] == 'n': top = top[:i] + '\n' + top[i+2:]
                                elif top[i+1] == '\\': top = top[:i] + '\\' + top[i+2:]
                                else: self.report_rt_err(line_num, "undefined use of \\")
                                i = i + 1
                                l = l - 1
                                string_blocks[-1] = top
                            elif top[i] == '%':
                                if top[i+1] == '%':
                                    top = top[:i] + '%' + top[i+2:]
                                    i = i + 1
                                    l = l - 1
                                    string_blocks[-1] = top
                                    continue
                                if top[i+1] == 'd' or top[i+1] == 'f':
                                    how_to_print.append(top[i+1] == 'd')
                                    top_left = top[:i]
                                    top = top[i+2:]
                                    l = l - i - 2
                                    i = 0
                                    string_blocks[-1] = top_left
                                    string_blocks.append(top)
                                else: self.report_rt_err(line_num, "undefined use of %")
                        
                        self.test_something(len(how_to_print) == len(arguments) - 1, line_num, "printf format argument mismatch")
                        exe[4] = how_to_print
                        exe[5] = string_blocks
                        if len(arguments) > 1:
                            exe[3] = exe[3] + 1
                            arg = arguments[1]
                            self.test_something(not isinstance(arg, str), line_num, "Non primary string argument for printf")
                            self.beginners_luck(arg)
                        else:
                            exe[7] = True
                        continue


            except ReturnException:
                while self.states[-1] != PitFF:
                    self.states.pop()
                    self.stuffs.pop()
                exe = self.stuffs[-1]
                func = exe[0]

                if not exe[3]:
                    self.frame.escape_function()
                    self.command.skip_lines(exe[2])

                self.func_depth[func.name] -= 1
                rax = IInt(rax.num) if func.returns_int else IFlt(rax.num)
                self.states.pop()
                self.stuffs.pop()
                if len(self.states) == 0:
                    break
        
        return rax
Пример #2
0
class Interpreter:
    def __init__(self,
                 goal,
                 test=False,
                 actual_code_lines=[],
                 no_command=True):
        sys.setrecursionlimit(10000)
        self.test = test
        self.actual_code_lines = actual_code_lines
        self.no_command = no_command
        self.frame = Frame()
        self.command = Command(self.frame, self.no_command,
                               self.actual_code_lines)
        self.depth = 0
        self.proper_exit = False
        self.exit_code = -1
        self.match = {
            PitStmt2: self.handle_stmt2,
            PitStmt3: self.handle_stmt3,
            PitStmt4: self.handle_stmt4,
            PitStmt5: self.handle_stmt5,
            PitDecl: self.handle_decl,
            PitInst3: self.handle_inst3,
            PitInst4: self.handle_inst4,
            PitExpr1: self.handle_expr1,
            PitExpr2: self.handle_expr2,
            PitTerm: self.handle_term,
            PitFactor1: self.handle_factor1,
            PitFactor2: self.handle_factor2,
            PitFactor3: self.handle_factor3,
            PitFactor4: self.handle_factor4,
            PitFactor5: self.handle_factor5,
            PitFactor6: self.handle_factor6
        }

        try:
            self.handle_goal(goal)
            if self.proper_exit:
                print("... Program finished with exit code:", self.exit_code)
            while not self.no_command:
                self.command.command()
        except RTException:
            pass
        except CmdException:
            pass

    def report_rt_err(self, line_num, string):
        if self.test:
            print("At line ", line_num, ", ", string, ", SmileyFace", sep='')
            print(self.actual_code_lines[line_num - 1])
        else:
            print("Run-time error : line", line_num)
        raise RTException

    def test_something(self, to_test, line_num, string):
        if to_test: return
        self.report_rt_err(line_num, string)
        assert (False)

    def test_Err(self, to_test, line_num, string):
        self.test_something(not isinstance(to_test, Err), line_num, string)
        return to_test.value

    def handle_goal(self, goal):
        for func in goal.funcs:
            self.handle_func(func)

        main = self.frame.get_function(MAIN)
        main = self.test_Err(main, len(self.actual_code_lines),
                             "Found no main()")
        self.test_something(
            len(main.arguments) == 0, main.line_num,
            "main() should have no arguments for our stupid implementation")

        self.exit_code = int(self.execute_func(main, [], True).num)
        self.proper_exit = True

    def execute_func(self, func, arguments, mainmain=False):
        back_ttf = self.command.current_line
        self.command.skip_lines(func.start_ln, True)
        if len(func.arguments) != len(arguments):
            self.report_rt_err(func.line_num,
                               "Function call argument length mismatch")

        arg_values = []
        for arg in arguments:
            self.test_something(
                not isinstance(arg, str), func.line_num,
                "String argument for non printf function call")
            arg_values.append(self.whos_that_poke(arg))

        self.depth += 1
        if self.depth > MAX_DEPTH:
            self.report_rt_err(func.line_num,
                               "Maximum function call depth exceeded")
        self.frame.into_function()

        rax = IInt(0) if func.returns_int else IFlt(0)
        for i in range(len(arguments)):
            is_int, is_pointer, arg_name = func.arguments[i]
            num = arg_values[i].num
            if is_pointer and isinstance(arg_values[i], IAdd):
                result = self.frame.declare_pointer(arg_name, func.line_num,
                                                    is_int, num)
                self.test_Err(result, func.line_num, "Pointer argument error")
            elif not is_pointer and not isinstance(arg_values[i], IAdd):
                result = self.frame.declare_direct(arg_name, func.line_num,
                                                   is_int, num)
                self.test_Err(result, func.line_num,
                              "Non-pointer argument error")
            else:
                self.report_rt_err(func.line_num, "Argument type mismatch")

        for stmt in func.stmts:
            try:
                self.whos_that_poke(stmt)
            except ReturnException as RE:
                rax = RE.Inum
                if isinstance(rax, IAdd):
                    self.report_rt_err(stmt.line_num, "Returning pointer")
                rax = IInt(rax.num) if func.returns_int else IFlt(rax.num)
                break

        if stmt.type != PitStmt5:
            self.command.feed_line(func.end_ln)

        if not mainmain:
            self.frame.escape_function()
            self.depth -= 1
            self.command.skip_lines(back_ttf)

        return rax

    def execute_printf(self, arguments, line_num):
        self.test_something(
            len(arguments) > 0, line_num, "Too few arguments to printf")
        self.test_something(isinstance(arguments[0], str), line_num,
                            "Non string first arg to printf")

        i = 0
        top = arguments[0]
        l = len(top)
        how_to_print = []
        string_blocks = [top]
        while True:
            #print(i, l, string_blocks, top)
            i = sub_count(top, sub_isn_spch, l, i)
            if i == l: break
            if top[i] == '\\':
                if top[i + 1] == 'n': top = top[:i] + '\n' + top[i + 2:]
                elif top[i + 1] == '\\': top = top[:i] + '\\' + top[i + 2:]
                else: self.report_rt_err(line_num, "undefined use of \\")
                i = i + 1
                l = l - 1
                string_blocks[-1] = top
            elif top[i] == '%':
                if top[i + 1] == '%':
                    top = top[:i] + '%' + top[i + 2:]
                    i = i + 1
                    l = l - 1
                    string_blocks[-1] = top
                    continue
                if top[i + 1] == 'd' or top[i + 1] == 'f':
                    how_to_print.append(top[i + 1] == 'd')
                    top_left = top[:i]
                    top = top[i + 2:]
                    l = l - i - 2
                    i = 0
                    string_blocks[-1] = top_left
                    string_blocks.append(top)
                else:
                    self.report_rt_err(line_num, "undefined use of %")
        self.test_something(
            len(how_to_print) == len(arguments) - 1, line_num,
            "printf format argument mismatch")

        arg_values = []
        for arg in arguments[1:]:
            self.test_something(not isinstance(arg, str), line_num,
                                "Non primary string argument for printf")
            arg_values.append(self.whos_that_poke(arg))

        string = string_blocks[0]
        for i in range(len(how_to_print)):
            if how_to_print[0]:
                string = string + str(int(arg_values[i].num))
            else:
                string = string + str(float(arg_values[i].num))
            string = string + string_blocks[i + 1]

        print(string, end='')
        return IInt(len(string))

    def whos_that_poke(self, parseditem):
        function = self.match[parseditem.type]
        return function(parseditem)

    def handle_func(self, func):
        self.test_Err(self.frame.declare_function(func.name, func),
                      func.line_num, "Already function with that name")

    # For Stmt
    def handle_stmt2(self, forst):
        self.command.feed_line(forst.line_num)
        self.frame.into_bracket()

        self.whos_that_poke(forst.initialize)
        while int(self.whos_that_poke(forst.condition).num):
            self.whos_that_poke(forst.stmt)
            self.command.skip_lines(forst.line_num, True)
            self.whos_that_poke(forst.update)

        to_line = forst.stmt.end_ln if forst.stmt.type == PitStmt4 else forst.stmt.line_num
        self.command.skip_lines(to_line)
        self.frame.escape_bracket()

    # If Stmt
    def handle_stmt3(self, ifst):
        self.command.feed_line(ifst.line_num)
        if int(self.whos_that_poke(ifst.condition).num):
            self.whos_that_poke(ifst.stmt)

        to_line = ifst.stmt.end_ln if ifst.stmt.type == PitStmt4 else ifst.stmt.line_num
        self.command.skip_lines(to_line)

    # Compound Stmt i.e. {stmt/decl*}
    def handle_stmt4(self, stmts):
        self.command.feed_line(stmts.line_num)
        self.frame.into_bracket()

        for stmt in stmts.stmts:
            self.whos_that_poke(stmt)

        self.frame.escape_bracket()
        self.command.feed_line(stmts.end_ln)

    # Return Stmt
    def handle_stmt5(self, retst):
        self.command.feed_line(retst.line_num)
        raise ReturnException(self.whos_that_poke(retst.expr))

    # Declaration
    def handle_decl(self, decl):
        self.command.feed_line(decl.line_num)
        for thing in decl.declarations:
            if thing[1] == None:
                result = self.frame.declare_direct(thing[0], decl.line_num,
                                                   decl.declares_int)
                self.test_Err(result, decl.line_num, "Declaration went wrong")
                continue
            result = self.frame.declare_array(thing[0], decl.line_num,
                                              decl.declares_int, thing[1])
            self.test_Err(result, decl.line_num, "Declaration went wrong")

    # Inst3 : Expr
    def handle_inst3(self, inst3):
        self.command.feed_line(inst3.line_num)
        self.whos_that_poke(inst3.expr)

    # Inst4 : Noop
    def handle_inst4(self, inst4):
        self.command.feed_line(inst4.line_num)

    def sub_do_arithmetic(self, lhs, rhs, op, line_num):
        self.test_something(
            not (isinstance(lhs, IAdd) or isinstance(rhs, IAdd)), line_num,
            "Pointer arithmetic")
        lhn, rhn = lhs.num, rhs.num
        result = 0
        if op == 0: result = lhn + rhn
        elif op == 1: result = lhn - rhn
        elif op == 2: result = 1 if (lhn > rhn) else 0
        else: result = 1 if (lhn < rhn) else 0
        if isinstance(lhs, IFlt) or isinstance(rhs, IFlt):
            return IFlt(result)
        else:
            return IInt(result)

    def do_arithmetic(self, tao):
        lhs = self.whos_that_poke(tao[0])
        l = (len(tao) - 1) // 2
        for i in range(l):
            op = tao[1 + 2 * i]
            if op > 1:
                rhs = self.do_arithmetic(tao[2 + 2 * i:])
                return self.sub_do_arithmetic(lhs, rhs, op, tao[0].line_num)
            else:
                rhs = self.whos_that_poke(tao[2 + 2 * i])
                lhs = self.sub_do_arithmetic(lhs, rhs, op, tao[0].line_num)

        return lhs

    # Expr1 : Arithmetic
    def handle_expr1(self, expr1):
        return self.do_arithmetic(expr1.terms_and_ops)

    def get_actual_index(self, index):
        if index != None:
            line_num = index.line_num
            index = self.whos_that_poke(index)
            self.test_something(not isinstance(index, IFlt), line_num,
                                "Float index to array")
            # a rare implicit cast of pointer to int
            index = index.num
        return index

    # Expr2 : Assignment
    def handle_expr2(self, expr2):
        name, index = expr2.lhs
        index = self.get_actual_index(index)

        is_int, is_pointer = self.test_Err(self.frame.get_type(name),
                                           expr2.line_num,
                                           "No such symbol maybe?")
        rhs = self.whos_that_poke(expr2.expr)
        if not isinstance(rhs, IAdd):
            self.test_Err(
                self.frame.update_value(name, expr2.line_num, rhs.num, index),
                expr2.line_num, "Idk probably index out of bounds")
            return IInt(rhs.num) if is_int else IFlt(rhs.num)
        if is_pointer and index == None:
            self.test_Err(
                self.frame.update_value(name, expr2.line_num,
                                        rhs.num), expr2.line_num,
                "Probably because I disabled pointer assignment as well")
            return rhs
        self.report_rt_err(
            expr2.expr,
            "Hmm probably symbol didn't exist or assigned pointer to non pointer"
        )

    def sub_do_products(self, lhs, rhs, op, line_num):
        self.test_something(
            not (isinstance(lhs, IAdd) or isinstance(rhs, IAdd)), line_num,
            "Pointer arithmetic")
        lhn, rhn = lhs.num, rhs.num
        result = 0
        if op == 0: result = lhn * rhn
        else:
            result = lhn / rhn if rhn != 0 else self.report_rt_err(
                line_num, "Zero division")
        if isinstance(lhs, IFlt) or isinstance(rhs, IFlt):
            return IFlt(result)
        else:
            return IInt(result)

    def do_products(self, fao):
        lhs = self.whos_that_poke(fao[0])
        l = (len(fao) - 1) // 2
        for i in range(l):
            op = fao[1 + 2 * i]
            rhs = self.whos_that_poke(fao[2 + 2 * i])
            lhs = self.sub_do_products(lhs, rhs, op, fao[0].line_num)

        return lhs

    # Term
    def handle_term(self, term):
        return self.do_products(term.factors_and_ops)

    # Factor1 : lhs / ++lhs / lhs++
    def handle_factor1(self, factor1):
        name, index = factor1.lhs
        index = self.get_actual_index(index)

        is_int, is_pointer, value = self.test_Err(
            self.frame.get_value(name, index), factor1.line_num,
            "No such symbol or something")
        value = 0 if value == None else value
        op = factor1.op
        if op == 0:
            if is_pointer:
                return IAdd(value)
            return IInt(value) if is_int else IFlt(value)

        self.test_something(not is_pointer, factor1.line_num,
                            "Pointer increment")
        self.frame.update_value(name, factor1.line_num, value + 1, index)
        rax = value + 1 if op == 1 else value
        return IInt(rax) if is_int else IFlt(rax)

    # Factor2 : Function call
    def handle_factor2(self, factor2):
        self.test_something(
            isinstance(self.frame.get_type(factor2.func_name), Err),
            factor2.line_num, "Not a function in this scope")
        func = self.frame.get_function(factor2.func_name)
        if isinstance(func, Err):
            self.test_something(factor2.func_name == "printf",
                                factor2.line_num, "No such function")
            return self.execute_printf(factor2.call, factor2.line_num)

        func = func.value
        return self.execute_func(func, factor2.call)

    # Factor3 : Integer
    def handle_factor3(self, factor3):
        return IInt(factor3.num)

    # Factor4 : Float
    def handle_factor4(self, factor4):
        return IFlt(factor4.num)

    # Factor5 : (Expr)
    def handle_factor5(self, factor5):
        return self.whos_that_poke(factor5.expr)

    # Factor6: Unary +/- Factor
    def handle_factor6(self, factor6):
        inum = self.whos_that_poke(factor6.factor)
        self.test_something(not isinstance(inum, IAdd), factor6.line_num,
                            "Pointer unary op")
        inum.num = inum.num if factor6.op == 0 else -inum.num
        return inum