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
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