def p_arithmetic_expressions(p): """arithmetic_expressions : PLUS pair | MINUS pair | MULT pair | DIV pair | MOD pair | MINUS expressions""" if p.slice[2].type == "expressions": exp_type = get_type_of_arithmetic_expression(p[1], "int", p[2]["type"], p.slice[1]) p[2] = code_array.store_boolean_expression_in_variable(p[2]) first_arg = {"value": 0, "type": "int"} second_arg = p[2] else: p[2]["first_arg"] = code_array.store_boolean_expression_in_variable( p[2]["first_arg"]) p[2]["second_arg"] = code_array.store_boolean_expression_in_variable( p[2]["second_arg"]) first_arg = p[2]["first_arg"] second_arg = p[2]["second_arg"] # pattern = r'(\*|\+|\-|\/)' # if re.match(pattern, p[1]): exp_type = get_type_of_pair_for_arithmetic_expression( p[1], p[2], p.slice[1]) p[0] = symbol_table.get_new_temp_variable(exp_type) code_array.emit(p[1], p[0], first_arg, second_arg) if (p[1] == "%" or p[1] == "/") and "value" in second_arg and second_arg["value"] == 0: raise CompilationException("division by zero!!", p.slice[2]) return
def p_qis_1(p): """qis_1 : """ code_array.emit("goto", None, None, None) p[0] = { "quad_index": code_array.get_next_quad_index(), "goto_quad_index": [code_array.get_current_quad_index()] } return
def p_default(p): """default : DEFAULT COLON qis block""" break_quad_index = code_array.get_next_quad_index() code_array.emit("goto", None, None, None) p[0] = { "starting_quad_index": p[3]["quad_index"], "break_quad_index": break_quad_index } return
def run_compiler(input_file_path, output_file_path): code = None with open(input_file_path, 'r') as input_file: code = input_file.read() parser.parse(code, lexer=lexer, debug=False, tracking=True) code_array.emit("return 0", None, None, None) code_generator = CodeGenerator() generated_code = code_generator.generate_code() with open(output_file_path, 'w') as output_file: output_file.write(generated_code) return
def p_statement_print(p): """statement : PRINT ID | PRINT ID LBRACK expressions RBRACK""" symbol_table.check_variable_declaration(p[2], p.slice[2]) if len(p) == 6: var_copy = code_array.setup_array_variable(p[2], p[4], p.slice[2]) code_array.emit("print", None, var_copy, None) else: code_array.check_variable_is_not_array(p[2], p.slice[2]) code_array.emit("print", None, p[2], None) return
def p_statement_assignment(p): """statement : ID ASSIGNMENT_SIGN expressions | ID LBRACK expressions RBRACK ASSIGNMENT_SIGN expressions""" symbol_table.check_variable_declaration(p[1], p.slice[1]) p[3] = code_array.store_boolean_expression_in_variable(p[3]) if len(p) == 4: code_array.check_variable_is_not_array(p[1], p.slice[1]) code_array.emit("=", p[1], p[3], None) else: p[6] = code_array.store_boolean_expression_in_variable(p[6]) var_copy = code_array.setup_array_variable(p[1], p[3], p.slice[1]) code_array.emit("=", var_copy, p[6], None) return
def p_bool_expressions_or(p): """bool_expressions : OR pair""" first_arg = p[2]["first_arg"] second_arg = p[2]["second_arg"] if "t_list" not in first_arg: code_array.create_simple_if_check(first_arg) if "t_list" not in second_arg: p[2]["second_quad_index"] = code_array.create_simple_if_check( second_arg) temp_var = symbol_table.get_new_temp_variable("bool") code_array.emit('=', temp_var, {"value": 1, "type": "bool"}, None) code_array.backpatch_e_list(first_arg["t_list"], code_array.get_current_quad_index()) code_array.emit('goto', None, p[2]["second_quad_index"], None) code_array.emit('=', temp_var, {"value": 0, "type": "bool"}, None) code_array.backpatch_e_list(first_arg["f_list"], code_array.get_current_quad_index()) code_array.emit('goto', None, p[2]["second_quad_index"], None) code_array.create_simple_if_check(temp_var) code_array.backpatch_e_list(second_arg["f_list"], code_array.get_current_quad_index() - 2) p[0] = { "t_list": code_array.merge_e_lists(temp_var["t_list"], second_arg["t_list"]), "f_list": temp_var["f_list"], "type": "bool" } return
def p_procedure(p): """procedure : PROCEDURE function_sign LBRACE qis_1 declarations_list block RBRACE SEMICOLON | PROCEDURE function_sign LBRACE qis_1 block RBRACE SEMICOLON""" if p[len(p) - 3] and "exit_when_quad_index" in p[len(p) - 3]: raise CompilationException( "exit when just allowed in loops!!! function: " + p[2]["place"], p.slice[2]) procedure = p[2] p[0] = procedure # goto return statements exit_procedure_statements_quad_index = code_array.get_next_quad_index() return_address_variable = symbol_table.get_new_temp_variable("void*") code_array.emit("pop", return_address_variable, None, None) code_array.emit("short jump", None, return_address_variable, None) begin_procedure_statements_quad_index = code_array.get_next_quad_index() # backpatch qis_1 with begin proc statements qis_1 = p[4] code_array.backpatch_e_list(qis_1["goto_quad_index"], begin_procedure_statements_quad_index) # load arguments for parameter in procedure["parameters"]: code_array.emit("pop", parameter, None, None) # goto beginning of proc code_array.emit("goto", None, qis_1["quad_index"], None) symbol_table.pop_scope() return
def p_case_element(p): """case_element : CASE NUMCONST COLON qis block | case_element CASE NUMCONST COLON qis block""" break_quad_index = code_array.get_next_quad_index() code_array.emit("goto", None, None, None) if len(p) == 6: p[0] = [{ "num_constraint": p[2], "starting_quad_index": p[4]["quad_index"], "break_quad_index": break_quad_index }] else: p[0] = [{ "num_constraint": p[3], "starting_quad_index": p[5]["quad_index"], "break_quad_index": break_quad_index }] + p[1] return
def p_dec(p): """dec : ID | ID LBRACK range RBRACK | ID LBRACK NUMCONST RBRACK""" p[0] = p[1] if len(p) == 2: p[0]["is_array"] = False else: p[0]["is_array"] = True if p.slice[3].type == "range": p[0]["range"] = p[3] if p.slice[3].type == "NUMCONST": from_variable = {"value": 0, "type": "int"} to_variable = symbol_table.get_new_temp_variable("int") code_array.emit("-", to_variable, p[3], { "value": 1, "type": "int" }) p[0]["range"] = {"from": from_variable, "to": to_variable} array_size_variable = symbol_table.get_new_temp_variable("int") code_array.emit("-", array_size_variable, p[0]["range"]["to"], p[0]["range"]["from"]) code_array.emit("+", array_size_variable, array_size_variable, { "value": 1, "type": "int" }) p[0]["array_size"] = array_size_variable return
def p_statement_function_return(p): """statement : RETURN expressions""" if p[2]["type"] != "int": raise CompilationException( "return value can only be in int type!! seen type: " + p[2]["type"], p.slice[2]) # goto return statements return_address_variable = symbol_table.get_new_temp_variable("void*") code_array.emit("pop", return_address_variable, None, None) code_array.emit("pop", symbol_table.get_new_temp_variable("int"), None, None) code_array.emit("push", None, p[2], None) code_array.emit("short jump", None, return_address_variable, None) return
def p_statement_switch(p): """statement : SWITCH expressions qis_1 case_element default END | SWITCH expressions qis_1 case_element END""" if p[2]["type"] == "bool" and "place" not in p[2] and "value" not in p[2]: p[2] = code_array.store_boolean_expression_in_variable(p[2]) code_array.emit("goto", None, code_array.get_next_quad_index() + 1, None) code_array.backpatch_e_list(p[3]["goto_quad_index"], code_array.get_next_quad_index()) else: code_array.backpatch_e_list(p[3]["goto_quad_index"], code_array.get_next_quad_index()) next_list = [] for case_element in p[4]: code_array.emit("==", None, p[2], case_element["num_constraint"]) code_array.emit("goto", None, case_element["starting_quad_index"], None) next_list.append(case_element["break_quad_index"]) if len(p) == 7: code_array.emit("goto", None, p[5]["starting_quad_index"], None) next_list.append(p[5]["break_quad_index"]) code_array.backpatch_e_list(next_list, code_array.get_next_quad_index()) return
def p_bool_expressions_comparator(p): """bool_expressions : LT pair | LE pair | GT pair | GE pair | EQ pair | NEQ pair""" p[0] = { "t_list": [code_array.get_next_quad_index() + 1], "f_list": [code_array.get_next_quad_index() + 2], "type": "bool" } opt = p.slice[1].type if opt == "EQ": opt = "==" elif opt == "NEQ": opt = "!=" else: opt = p[1] code_array.emit(opt, None, p[2]["first_arg"], p[2]["second_arg"]) code_array.emit("goto", None, None, None) code_array.emit("goto", None, None, None) return
def p_expressions_function_call(p): """expressions : ID LPAR arguments_list RPAR""" procedure = p[1] symbol_table.check_procedure_declaration(procedure, p.slice[1]) if len(p[3]) != len(procedure["parameters"]): raise CompilationException( "function call didn't match with function \'" + procedure["place"] + "\' declaration!", p.slice[1]) code_array.save_context() code_array.emit( "store_top", symbol_table.get_current_scope_symbol_table().top_stack_variable, None, None) code_array.emit("push", None, {"value": 0, "type": "int"}, None) return_address_variable = symbol_table.get_new_temp_variable("void*") code_array.emit("&&", return_address_variable, None, None) temp_index = code_array.get_current_quad_index() code_array.emit("push", None, return_address_variable, None) for argument in p[3]: code_array.emit("push", None, argument, None) code_array.emit("call", None, procedure["quad_index"], None) p[0] = symbol_table.get_new_temp_variable("int") code_array.emit("pop", p[0], None, None) code_array.backpatch_e_list([temp_index], code_array.get_current_quad_index()) code_array.restore_context() return
def p_statement_for(p): """statement : FOR ID ASSIGNMENT_SIGN counter DO qis_1 statement""" symbol_table.check_variable_declaration(p[2], p.slice[2]) code_array.check_variable_is_not_array(p[2], p.slice[2]) code_array.emit(p[4]["opt"], p[2], p[2], {"value": 1, "type": "int"}) code_array.emit("goto", None, code_array.get_next_quad_index() + 2, None) code_array.backpatch_e_list(p[6]["goto_quad_index"], code_array.get_next_quad_index()) code_array.emit("=", p[2], p[4]["from"], None) code_array.emit(">", None, p[2], p[4]["to"]) code_array.emit("goto", None, code_array.get_next_quad_index() + 2, None) code_array.emit("goto", None, p[6]["quad_index"], None) if p[7] and "exit_when_quad_index" in p[7]: code_array.backpatch_e_list(p[7]["exit_when_quad_index"], code_array.get_next_quad_index()) return