def main(): ## # WRITE YOUR C PROGRAM IN THIS STRING! ## your_c_program = """ // your program here! int main() { int my_3d_array[1][2][3][4]; return 0; } """ compiler_state = CompilerState() ast = compiler_state.parse(your_c_program) ast.to_3ac(include_source=True)
class TestParser(unittest.TestCase): def setUp(self): self.debug = True self.compiler_state = CompilerState() def tearDown(self): self.compiler_state.teardown() self.compiler_state = None def test_plain_main(self): data = """ int main() { return 0; } int i; // Needed to clone the symbol table at the correct time !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'main', 0, 'int main()') def test_declare_primitive_variable(self): self.enable_parser_debugging() data = """ int main() { int i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') symbol, _ = symbol_table_clone.find('i') self.assertEqual(0, symbol.activation_frame_offset) def test_declare_and_assign_primitive_variable(self): data = """ int main() { int i = 5; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_declare_multiple_primitive_variable(self): # self.enable_parser_debugging() data = """ int main() { int i, j, k; i = 0; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') self.check_correct_element(symbol_table_clone, 'j', 2, 'int j') self.check_correct_element(symbol_table_clone, 'k', 2, 'int k') i_symbol, _ = symbol_table_clone.find('i') j_symbol, _ = symbol_table_clone.find('j') k_symbol, _ = symbol_table_clone.find('k') self.assertEqual(0, i_symbol.activation_frame_offset) self.assertEqual(4, j_symbol.activation_frame_offset) self.assertEqual(8, k_symbol.activation_frame_offset) def test_modify_primitive_variable(self): self.enable_parser_debugging() data = """ int main() { int i = 0; i += 5; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_declare_pointer_variable(self): self.enable_parser_debugging() data = """ int main() { int* i; i = 0; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int * i') def test_declare_deep_pointer_variable(self): data = """ int main() { int*** i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] print(symbol_table_clone) self.check_correct_element(symbol_table_clone, 'i', 2, 'int *** i') def test_declare_global_constant(self): self.enable_parser_debugging() data = """ const int GLOBAL_CONSTANT = 5; int main() { int i = GLOBAL_CONSTANT; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'GLOBAL_CONSTANT', 0, 'const int GLOBAL_CONSTANT') self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_assign_to_immutable_variable_fails(self): with self.assertRaises(CompileError): data = """ const int GLOBAL_CONSTANT = 5; int main() { GLOBAL_CONSTANT = 0; return 0; } """ self.compiler_state.parse(data) def test_plain_if(self): data = """ int main(int argc, char** argv) { if (1 != 1) { int wtf_result = -1; return wtf_result; !!C } return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'wtf_result', 3, 'int wtf_result') def test_ternary_operator(self): data = """ int main(int argc, char** argv) { return 0 == 0 ? 1 : 0; } """ self.compiler_state.parse(data) self.assertTrue(True, "No exceptions means a successful parse.") def test_plain_if_else(self): data = """ int main(int argc, char** argv) { if (1 != 1) { !!C int wtf_result = -1; return wtf_result; } else { !!C int i_guess_its_fine = 0; return i_guess_its_fine; } return 0; } """ print(data) self.compiler_state.parse(data) if_symbol_table_clone = self.compiler_state.cloned_tables[0] else_symbol_table_clone = self.compiler_state.cloned_tables[1] self.check_correct_element(if_symbol_table_clone, 'wtf_result', 3, 'int wtf_result') self.check_correct_element(else_symbol_table_clone, 'i_guess_its_fine', 3, 'int i_guess_its_fine') def test_lone_else_fails(self): with self.assertRaises(Exception): data = 'int main(int argc, char** argv) {\n' \ ' else {\n' \ ' int wtf = 0;\n' \ ' return wtf;\n' \ ' }\n' \ '\n' \ ' return 0;\n' \ '}\n' \ '' self.compiler_state.parse(data) def test_while_loop(self): data = """ int main() { while (1) {} return 0; } int i; // Needed to clone the symbol table at the correct time !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'main', 0, 'int main()') def test_for_loop(self): self.enable_parser_debugging() data = """ int main() { int i; for (i = 0; i < 3; i++) {} !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_do_while_loop(self): data = """ int main() { int i = 1; do {i++;} while(i); !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_cast_in_binary_expression(self): self.enable_parser_debugging() data = """ int main() { int i = 5; float f = -4.5; i = (int) ((float) i + f); return 0; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_declare_array(self): self.enable_parser_debugging() data = """ int main() { int my_array[10]; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') def test_declare_array_with_constant_expression_in_subscript(self): data = """ int main() { int my_array[5 + 5]; int i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') def test_access_array(self): self.enable_parser_debugging() data = """ int main() { int i = 0; int my_array[10]; int first_element = my_array[0]; int some_other_element = my_array[i]; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] print(symbol_table_clone) self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') self.check_correct_element(symbol_table_clone, 'first_element', 2, 'int first_element') self.check_correct_element(symbol_table_clone, 'some_other_element', 2, 'int some_other_element') def test_declare_function(self): self.enable_parser_debugging() data = """ int do_stuff(char c); !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] result, _ = symbol_table_clone.find('do_stuff') print(result, type(result)) assert(isinstance(result, FunctionSymbol)) p = result.named_parameters[0] print(p, type(p)) print(p.type_specifiers) self.check_correct_element(symbol_table_clone, 'do_stuff', 0, 'int do_stuff(char c)') def test_declare_function_implementation(self): data = """ int do_stuff(char c) { return c + c; } int main() { return 0; } !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'do_stuff', 0, 'int do_stuff(char c)') def test_call_function(self): self.enable_parser_debugging() data = """ int do_stuff(int c); !!C int main() { do_stuff(4); return 0; } int do_stuff(int c) { return c + c; !!C } """ self.compiler_state.parse(data) symbol_table_clone_inner = self.compiler_state.cloned_tables[0] symbol_table_clone_outer = self.compiler_state.cloned_tables[1] self.check_correct_element(symbol_table_clone_inner, 'do_stuff', 0, 'int do_stuff(int c)') self.check_correct_element(symbol_table_clone_outer, 'c', 1, 'int c') symbol, _ = symbol_table_clone_outer.find('c') self.assertEqual(0, symbol.activation_frame_offset) def test_declare_string_literal_char_star(self): self.enable_parser_debugging() data = """ char* literal_string = "hello there"; !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'literal_string', 0, 'char * literal_string') def test_declare_string_as_array(self): self.enable_parser_debugging() data = """ int main() { char array_string[] = "hey"; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'array_string', 2, 'char array_string[4]') def test_declare_segmented_string_literal(self): data = """ char literal_string[] = "hello " "world"; !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'literal_string', 0, 'char literal_string[12]') def test_bubble_sort(self): # TODO: this test is failing because we are not handling pointers as though they were arrays and vice versa # TODO: perhaps we should change our test case? Maybe this is why Fred said pointers were hard... data = """ void print(int list[], int size); void bubbleSort(int list[], int size); int main() { int list[10]; int i; //srand(time(NULL)); // create list for(i =0; i<10;i++) { //list[i] = rand() % 10 + 1; } print(list, 10); // bubble sort bubbleSort(list, 10 ); //printf( "Sorted " ); print(list, 10); !!C // return return 0; } void bubbleSort(int list[], int size) { int i, j; int temp; int swapped; for( i = 0; i < size; i++) { // swapped is false swapped = 0; for( j = 0; j < size - 1; j++) { if(list[j+1] < list[j]) { temp = list[j]; list[j] = list[j+1]; list[j+1] = temp; swapped = 1; } } if (swapped == 0) { break; } } } void print(int list[], int size) { int i; //printf("List is: "); for(i =0; i < size; i++) { //printf( "%d ", list[i] ); } //printf(""); } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') def test_recursive_factorial(self): data = """ long int recur_Fact(int number); int main() { int number; long int fact; //printf( "Enter number to get factorial of: "); //scanf( "%d", &number ); fact = recur_Fact(number); //printf("Factorial of %d is: %ld", number, fact); return 0; } long int recur_Fact( int number) { // base case if(number <= 0) return 1; // recursive case else if( number > 1 ) { return number*recur_Fact(number-1); } } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') def test_iterative_factorial(self): data = """ long int iter_Fact(int number); int main() { int number; long int fact; // printf("Enter number to get factorial of: "); // scanf( "%d", &number ); fact = iter_Fact(number); // printf("Factorial of %d is: %ld ", number, fact); return 0; } long int iter_Fact(int number) { int i; long int fact = 1; if( i < 0) { return 1; } for( i = number; i > 0; i --) { fact = fact*i; } return fact; } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') # TODO: don't put a lot of emphasis on bad cases until things are strong with the good cases def test_malformed_main_fails(self): with self.assertRaises(Exception): data = 'badmain(] {return 0;}' self.compiler_state.parse(data) # def test_declare_typedef(self): # self.enable_parser_debugging() # data = """ # typedef int GlorifiedInt; # !!C # # int main() { # return 0; # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling typedefs? # self.check_correct_element(symbol_table_clone, 'GlorifiedInt', 0, 'typedef int GlorifiedInt') # def test_declare_typedef_and_use_typedef_in_variable_declaration(self): # self.enable_parser_debugging() # # data = """ # typedef int GlorifiedInt; # # int main() { # GlorifiedInt i = 3; # return 0; # !!C # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling typedefs? # self.check_correct_element(symbol_table_clone, 'GlorifiedInt', 0, 'typedef int GlorifiedInt') # self.check_correct_element(symbol_table_clone, 'i', 1, 'GlorifiedInt') # def test_declare_struct(self): # data = """ # !!C # struct Pixel { # char r; # char g; # char b; # !!C # }; # # int main() { # struct Pixel pixel; # pixel.r = 255; # pixel.g = 255; # pixel.b = 255; # !!C # return 0; # } # """ # # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling structs? # self.check_correct_element(symbol_table_clone, 'Pixel', 0, 'struct Pixel') # self.check_correct_element(symbol_table_clone, 'r', 1, 'char r') # self.check_correct_element(symbol_table_clone, 'g', 1, 'char g') # self.check_correct_element(symbol_table_clone, 'b', 1, 'char b') # self.check_correct_element(symbol_table_clone, 'pixel', 1, 'struct Pixel pixel') # # # def test_declare_function_pointer_typedef(self): # data = """ # typedef int (*add_callback)(int a, int b); # # int add_two(int a, int b, add_callback callback); # # int normal_add(int a, int b); # int weird_add(int a, int b); # # int main() { # int x; # int y; # # x = add_two(1, 2, normal_add); # y = add_two(1, 2, weird_add); # # !!C # return 0; # } # # int add_two(int a, int b, add_callback callback) { # return callback(a, b); # } # # int normal_add(int a, int b) { # return a + b; # } # # int weird_add(int a, int b) { # return (a + b) % 4; # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: Function Pointers?? # self.check_correct_element(symbol_table_clone, 'x', 1, 'int x') def test_super_function_testing(self): data = """ !!C void do_stuff(int* array); int main() { return 0; } void do_stuff(int* array) { int* i; do_stuff(i); } """ self.compiler_state.parse(data) symbol_table = self.compiler_state.cloned_tables[0] print(symbol_table) x, y = symbol_table.find('do_stuff') self.check_correct_element(symbol_table, 'do_stuff', 0, 'void do_stuff(int * array)') def test_super_memory_allocation(self): data = """ char g_char; int g_int; float g_float; void do_stuff(char a, int b) { int c; float d; !!C return a + b; } int main() { int i = do_stuff('a', 2); return 0; } !!C """ self.compiler_state.parse(data) function_symbol_table, global_symbol_table = self.compiler_state.cloned_tables[0:2] # g_char, _ = global_symbol_table.find('g_char') # self.assertEqual(0x10010000, g_char.global_memory_location) # g_int, _ = global_symbol_table.find('g_int') # self.assertEqual(0x10010004, g_int.global_memory_location) # g_float, _ = global_symbol_table.find('g_float') # self.assertEqual(0x10010008, g_float.global_memory_location) f_a, _ = function_symbol_table.find('a') self.assertEqual(0, f_a.activation_frame_offset) f_b, _ = function_symbol_table.find('b') self.assertEqual(4, f_b.activation_frame_offset) f_c, _ = function_symbol_table.find('c') self.assertEqual(8, f_c.activation_frame_offset) f_d, _ = function_symbol_table.find('d') self.assertEqual(12, f_d.activation_frame_offset) def enable_parser_debugging(self): if self.debug: self.compiler_state.get_parser_logger().add_switch(Logger.PRODUCTION) self.compiler_state.get_parser_logger().add_switch(Logger.INFO) self.compiler_state.get_parser_logger().add_switch(Logger.SOURCE) def check_correct_element(self, symbol_table_clone, check_value, check_scope, check_string): found_symbol, in_scope = symbol_table_clone.find(check_value) self.assertEqual(check_scope, in_scope, "The symbol was not found in the expected scope") self.assertEqual(check_string, str(found_symbol), "The symbols don't match")
def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument("source", type=str, help="The C program file to compile.") arg_parser.add_argument( "-o", "--outfile", type=str, default='STDOUT', help= "The name of the output file. MUST be a .asm file! (Default: STDOUT)") arg_parser.add_argument( "-sym", "--symtable", action='store_true', help="Enables the printing of symbol table in other options.") arg_parser.add_argument( "-s", "--scandebug", type=int, choices=[0, 1, 2, 3], default=0, help= "The debug level for the scanner. \n 0: No debug \n 1: Tokens \n 2: Source Code \n " "3: Tokens and Source Code") arg_parser.add_argument( "-p", "--parsedebug", type=int, choices=[0, 1, 2, 3], default=0, help= "The debug level for the parser. \n 0: No debug \n 1: Productions \n " " 2: Productions and Source Code \n 3: Productions, Source, Misc info") arg_parser.add_argument( "-ast", "--astree", action='store_true', help="Enables the printing of the GraphViz string after parsing.") arg_parser.add_argument( "-tac", "--threeac", type=int, choices=[0, 1, 2], default=0, help="The debug level for the 3AC. \n 0: No debug \n 1: 3AC \n " " 2: 3AC + Source") arg_parser.add_argument( "-mips", "--mips", type=int, choices=[0, 1, 2, 3], default=0, help="The debug level for the MIPS. \n 0: No debug \n 1: 3AC \n " " 2: Source \n 3: 3AC + Source") arg_parser.add_argument("-w", "--warnings", action='store_true', help="Enables warnings being printed.") args = vars(arg_parser.parse_args()) # Set Symbol Table flags print_table = args['symtable'] # Set Scanner flags print_tokens, print_source_scanner = False, False if args['scandebug'] is 1: print_tokens = True elif args['scandebug'] is 2: print_source_scanner = True elif args['scandebug'] is 3: print_tokens = True print_source_scanner = True # Set Parser flags print_productions, print_source_parser, print_info = False, False, False if args['parsedebug'] is 1: print_productions = True elif args['parsedebug'] is 2: print_productions = True print_source_parser = True elif args['parsedebug'] is 3: print_productions = True print_source_parser = True print_info = True source_file = open(args['source'], 'r') data = source_file.read() compiler_state = CompilerState(print_table=print_table, print_tokens=print_tokens, print_source_scanner=print_source_scanner, print_productions=print_productions, print_source_parser=print_source_parser, print_info=print_info, print_warnings=args['warnings']) try: ast = compiler_state.parse(data) if args['astree']: print(ast.to_graph_viz_str()) if args['threeac'] is 2: source_tac, tac_as_str = ast.to_3ac(include_source=True) else: source_tac, tac_as_str = ast.to_3ac() if args['mips'] == 1: generator = generation.MipsGenerator(compiler_state, inject_source=False, inject_3ac=True) elif args['mips'] == 2: generator = generation.MipsGenerator(compiler_state, inject_source=True, inject_3ac=False) elif args['mips'] == 3: generator = generation.MipsGenerator(compiler_state, inject_source=True, inject_3ac=True) else: generator = generation.MipsGenerator(compiler_state, inject_source=False, inject_3ac=False) generator.load(source_tac) generator.translate_tac_to_mips() if args['outfile'] != 'STDOUT': fout = open(args['outfile'], 'w') fout.write(generator.dumps()) fout.close() else: print(generator.dumps()) except CompileError as error: print(error) finally: compiler_state.teardown()
class TestMipsGenerator(unittest.TestCase): def setUp(self): self.compiler_state = CompilerState(print_productions=False) self.enable_debug(False) self.generator = generation.MipsGenerator(self.compiler_state, inject_source=True, inject_3ac=True) def tearDown(self): self.compiler_state.teardown() self.compiler_state = None def enable_debug(self, enable, productions=True, source=False): if enable: prod_logger = self.compiler_state.get_parser_logger() prod_logger.add_switch(Logger.INFO) if productions: prod_logger.add_switch(Logger.PRODUCTION) if source: prod_logger.add_switch(Logger.SOURCE) def test_plain_main(self): data = """ int main() { return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_global_variable_declaration(self): data = """ int g = 5; int main() { return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_print_int(self): data = """ int main() { print_int(777); return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_declarations(self): data = """ int main() { char c; short s; int i; long long l; char arr[13]; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_simple_assignment(self): data = """ int main() { int i; i = 0; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_constant_expression(self): data = """ int main() { int i, a, b; i = a + b; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_explicit_cast(self): # self.enable_debug(True) data = """ int main() { int i; i = (int) 4.2; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_if_else(self): data = """ int main() { int i; if (i == 5) { i = 6; } else { i = 5; } } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_if_elif_else(self): data = """ int main() { int i; if (i == 1) { i = 7; } else if(i == 2) { i = 8; } else { i = 9; } } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_while_loop(self): data = """ int main() { int i; while(i < 5){} } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_array_access(self): data = """ int main() { int a[2][2]; a[0][0] = a[1][1]; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_constant_folding(self): data = """ const int a = 1 + 1; const int b = a + 2; int main() { int c = a + b; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_array_initializers(self): data = """ int main() { int a[5] = {1,2,3,4,5}; return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_function_with_param(self): data = """ int foo( int a, int b, int c); int main() { int i = foo(1,2,3); return 0; } int foo( int a, int b, int c) { return 1; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_for_loop(self): data = """ int main() { int i = 0; int j; for(i=0;i<3;i++) { j = 5; } return 0; } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_do_while_loop(self): data = """ int main() { int i; do { i = 5; } while (i > 10); } """ ast = self.compiler_state.parse(data) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_matrix_multiplication(self): test_program = """ const int ARRAY_DIM = 2; // hard code dimensions for simplicity int matrix_multiply(int C[ARRAY_DIM][ARRAY_DIM], int A[ARRAY_DIM][ARRAY_DIM], int B[ARRAY_DIM][ARRAY_DIM]); int main() { int i, j; int A[ARRAY_DIM][ARRAY_DIM], B[ARRAY_DIM][ARRAY_DIM], C[ARRAY_DIM][ARRAY_DIM]; for (i = 0; i < ARRAY_DIM; i++) { for (j = 0; j < ARRAY_DIM; j++) { A[i][j] = B[i][j] = 1; } } matrix_multiply(C, A, B); return 0; } int matrix_multiply(int C[ARRAY_DIM][ARRAY_DIM], int A[ARRAY_DIM][ARRAY_DIM], int B[ARRAY_DIM][ARRAY_DIM]) { int i, j, k; for (i = 0; i < ARRAY_DIM; i++) { for (j = 0; j < ARRAY_DIM; j++) { C[i][j] = 0; for (k = 0; k < ARRAY_DIM; k++) { C[i][j] += A[i][j + k] * B[i + k][j]; } } } } """ ast = self.compiler_state.parse(test_program) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_bubble_sort(self): test_program = """ const int N_ITEMS = 5; int bubble_sort(int items[N_ITEMS], int n_items); int main() { int items[N_ITEMS] = {5, 1, 4, 3, 2}; bubble_sort(items, 5); return 0; } int bubble_sort(int items[N_ITEMS], int n_items) { int i, j; int temp; for (i = 0; i < n_items; i++) { for (j = i; j < n_items; j++) { if (items[i] < items[j]) { temp = items[i]; items[i] = items[j]; items[j] = temp; } } } } """ ast = self.compiler_state.parse(test_program) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_recursive_factorial(self): test_program = """ int factorial(int x); int main() { int x = 5; int result = factorial(x); return 0; } int factorial(int x) { if (x > 1) { return factorial(x - 1); } else { return 1; } } """ ast = self.compiler_state.parse(test_program) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps()) def test_land_and_lor(self): test_program = """ int main() { int x = 5; x = x && 5; return 0; } """ ast = self.compiler_state.parse(test_program) source_tac, tac_str = ast.to_3ac() # print(source_tac) print('---------------------------') self.generator.load(source_tac) self.generator.translate_tac_to_mips() print(self.generator.dumps())
def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument("source", type=str, help="The C program file to compile.") arg_parser.add_argument("-o", "--outfile", type=str, default='STDOUT', help="The name of the output file. MUST be a .asm file! (Default: STDOUT)") arg_parser.add_argument("-sym", "--symtable", action='store_true', help="Enables the printing of symbol table in other options.") arg_parser.add_argument("-s", "--scandebug", type=int, choices=[0, 1, 2, 3], default=0, help="The debug level for the scanner. \n 0: No debug \n 1: Tokens \n 2: Source Code \n " "3: Tokens and Source Code") arg_parser.add_argument("-p", "--parsedebug", type=int, choices=[0, 1, 2, 3], default=0, help="The debug level for the parser. \n 0: No debug \n 1: Productions \n " " 2: Productions and Source Code \n 3: Productions, Source, Misc info") arg_parser.add_argument("-ast", "--astree", action='store_true', help="Enables the printing of the GraphViz string after parsing.") arg_parser.add_argument("-tac", "--threeac", type=int, choices=[0, 1, 2], default=0, help="The debug level for the 3AC. \n 0: No debug \n 1: 3AC \n " " 2: 3AC + Source") arg_parser.add_argument("-mips", "--mips", type=int, choices=[0, 1, 2, 3], default=0, help="The debug level for the MIPS. \n 0: No debug \n 1: 3AC \n " " 2: Source \n 3: 3AC + Source") arg_parser.add_argument("-w", "--warnings", action='store_true', help="Enables warnings being printed.") args = vars(arg_parser.parse_args()) # Set Symbol Table flags print_table = args['symtable'] # Set Scanner flags print_tokens, print_source_scanner = False, False if args['scandebug'] is 1: print_tokens = True elif args['scandebug'] is 2: print_source_scanner = True elif args['scandebug'] is 3: print_tokens = True print_source_scanner = True # Set Parser flags print_productions, print_source_parser, print_info = False, False, False if args['parsedebug'] is 1: print_productions = True elif args['parsedebug'] is 2: print_productions = True print_source_parser = True elif args['parsedebug'] is 3: print_productions = True print_source_parser = True print_info = True source_file = open(args['source'], 'r') data = source_file.read() compiler_state = CompilerState(print_table=print_table, print_tokens=print_tokens, print_source_scanner=print_source_scanner, print_productions=print_productions, print_source_parser=print_source_parser, print_info=print_info, print_warnings=args['warnings']) try: ast = compiler_state.parse(data) if args['astree']: print(ast.to_graph_viz_str()) if args['threeac'] is 2: source_tac, tac_as_str = ast.to_3ac(include_source=True) else: source_tac, tac_as_str = ast.to_3ac() if args['mips'] == 1: generator = generation.MipsGenerator(compiler_state, inject_source=False, inject_3ac=True) elif args['mips'] == 2: generator = generation.MipsGenerator(compiler_state, inject_source=True, inject_3ac=False) elif args['mips'] == 3: generator = generation.MipsGenerator(compiler_state, inject_source=True, inject_3ac=True) else: generator = generation.MipsGenerator(compiler_state, inject_source=False, inject_3ac=False) generator.load(source_tac) generator.translate_tac_to_mips() if args['outfile'] != 'STDOUT': fout = open(args['outfile'], 'w') fout.write(generator.dumps()) fout.close() else: print(generator.dumps()) except CompileError as error: print(error) finally: compiler_state.teardown()
class TestTac(unittest.TestCase): def setUp(self): self.compiler_state = CompilerState(print_productions=False) self.enable_debug(False) def tearDown(self): self.compiler_state.teardown() self.compiler_state = None def enable_debug(self, enable, productions=True, source=False): if enable: prod_logger = self.compiler_state.get_parser_logger() prod_logger.add_switch(Logger.INFO) if productions: prod_logger.add_switch(Logger.PRODUCTION) if source: prod_logger.add_switch(Logger.SOURCE) def test_plain_main(self): data = """ int main() { return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_declarations(self): data = """ int main() { char c; short s; int i; long long l; char arr[13]; return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_simple_assignment(self): data = """ int main() { int i; i = 0; return 0; } """ ast = self.compiler_state.parse(data) # print(ast.to_graph_viz_str()) ast.to_3ac() def test_constant_expression(self): data = """ int main() { int i, a, b; i = a + b; return 0; } """ ast = self.compiler_state.parse(data) # print(ast.to_graph_viz_str()) ast.to_3ac() def test_explicit_cast(self): # self.enable_debug(True) data = """ int main() { int i; i = (int) 4.2; return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_if_else(self): data = """ int main() { int i; if (i == 5) { i = 6; } else { i = 5; } } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_if_elif_else(self): data = """ int main() { int i; if (i == 1) { i = 7; } else if(i == 2) { i = 8; } else { i = 9; } } """ ast = self.compiler_state.parse(data) ast.to_3ac() # print(ast.to_graph_viz_str()) def test_while_loop(self): data = """ int main() { int i; while(i < 5){} } """ ast = self.compiler_state.parse(data) # print(ast.to_graph_viz_str()) ast.to_3ac() def test_array_access(self): data = """ int main() { int a[2][2]; a[0][0] = a[1][1]; return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_constant_folding(self): data = """ const int a = 1 + 1; const int b = a + 2; int main() { int c = a + b; return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_array_initializers(self): data = """ int main() { int a[5] = {1,2,3,4,5}; return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_function_with_param(self): data = """ int foo( int a, int b, int c); int main() { int i = foo(1,2,3); return 0; } int foo( int a, int b, int c) { return 1; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_for_loop(self): data = """ int main() { int i = 0; int j; for(i=0;i<3;i++) { j = 5; } return 0; } """ ast = self.compiler_state.parse(data) ast.to_3ac() def test_do_while_loop(self): data = """ int main() { int i; do { i = 5; } while (i > 10); } """ ast = self.compiler_state.parse(data) # print(ast.to_graph_viz_str()) ast.to_3ac() def test_matrix_multiplication(self): test_program = """ const int ARRAY_DIM = 2; // hard code dimensions for simplicity int matrix_multiply(int C[ARRAY_DIM][ARRAY_DIM], int A[ARRAY_DIM][ARRAY_DIM], int B[ARRAY_DIM][ARRAY_DIM]); int main() { int i, j; int A[ARRAY_DIM][ARRAY_DIM], B[ARRAY_DIM][ARRAY_DIM], C[ARRAY_DIM][ARRAY_DIM]; for (i = 0; i < ARRAY_DIM; i++) { for (j = 0; j < ARRAY_DIM; j++) { A[i][j] = B[i][j] = 1; } } matrix_multiply(C, A, B); return 0; } int matrix_multiply(int C[ARRAY_DIM][ARRAY_DIM], int A[ARRAY_DIM][ARRAY_DIM], int B[ARRAY_DIM][ARRAY_DIM]) { int i, j, k; for (i = 0; i < ARRAY_DIM; i++) { for (j = 0; j < ARRAY_DIM; j++) { C[i][j] = 0; for (k = 0; k < ARRAY_DIM; k++) { C[i][j] += A[i][j + k] * B[i + k][j]; } } } } """ ast = self.compiler_state.parse(test_program) ast.to_3ac() def test_bubble_sort(self): test_program = """ const int N_ITEMS = 5; int bubble_sort(int items[N_ITEMS], int n_items); int main() { int items[N_ITEMS] = {5, 1, 4, 3, 2}; bubble_sort(items, 5); return 0; } int bubble_sort(int items[N_ITEMS], int n_items) { int i, j; int temp; for (i = 0; i < n_items; i++) { for (j = i; j < n_items; j++) { if (items[i] < items[j]) { temp = items[i]; items[i] = items[j]; items[j] = temp; } } } } """ ast = self.compiler_state.parse(test_program) ast.to_3ac() def test_recursive_factorial(self): test_program = """ int factorial(int x); int main() { int x = 5; int result = factorial(x); return 0; } int factorial(int x) { if (x > 1) { return factorial(x - 1); } else { return 1; } } """ ast = self.compiler_state.parse(test_program) ast.to_3ac()
class TestAst(unittest.TestCase): def setUp(self): self.compiler_state = CompilerState() self.enable_debug(False) UUID_TICKETS.next_value = 0 LABEL_TICKETS.next_value = 0 INT_REGISTER_TICKETS.next_value = 0 FLOAT_REGISTER_TICKETS.next_value = 0 def tearDown(self): self.compiler_state.teardown() self.compiler_state = None def enable_debug(self, enable, productions=True, source=False): if enable: prod_logger = self.compiler_state.get_parser_logger() prod_logger.add_switch(Logger.INFO) if productions: prod_logger.add_switch(Logger.PRODUCTION) if source: prod_logger.add_switch(Logger.SOURCE) def test_empty_file(self): data = "" ast = self.compiler_state.parse(data) print(ast) def test_plain_main(self): data = """ int main() { return 0; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_simple_variable_declaration(self): data = """ int main() { int i; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_simple_variable_initialization(self): data = """ int main() { int i = 5; int j = i; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_const_declaration(self): data = """ int main() { const int i = 5; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_declaration(self): data = """ int main() { int i[5]; } """ ast = self.compiler_state.parse(data) result = ast.to_graph_viz_str() print(result) import re expected_solution = \ 'digraph {\n' \ '\t"FileAST\\\\n\d\d\d\d\d" -> {"FunctionDefinition\\\\nint main\\\\n\d\d\d\d\d"};\n' \ '\t"FunctionDefinition\\\\nint main\\\\n\d\d\d\d\d" -> {"CompoundStatement\\\\n\d\d\d\d\d"};\n' \ '\t"CompoundStatement\\\\n\d\d\d\d\d" -> {"ArrayDeclaration\\\\nint\[5\]\[5\] i\\\\n\d\d\d\d\d"};\n' \ '\t"ArrayDeclaration\\\\nint\[5\]\[5\] i\\\\n\d\d\d\d\d" -> {};\n' \ '}' m = re.match(expected_solution, result) print(m) self.assertTrue(True if m else False) def test_2d_array_declaration(self): data = """ int main() { int i[5][7]; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_post_plus_plus(self): data = """ int main() { int i = 0; int b = 0; b = i++; return 0; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_lone_if(self): data = """ int main() { int i; if (i == 5) { i = 6; } } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_if_else(self): data = """ int main() { int i; if (i == 5) { i = 6; } else { i = 5; } } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_if_elif_else(self): data = """ int main() { int i; if (i == 5) { i = 6; } else if(i == 6) { i = 7; } else { i = 5; } } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_simple_assign_const(self): data = """ int main() { int g; char a; float p; g = 5; a = 2; p = 1.2; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_simple_assign_var(self): data = """ int main() { int g; int G; g = 5; G = g; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_cast_in_binary_expression(self): data = """ int main() { int i = 5; float f = -4.5; i = (int) ((float) i + f); return 0; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_simple_assign(self): data = """ int main() { int a[10]; a[1] = 4; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_simple_access(self): data = """ int main() { int g; int a[10]; a[1] = 4; g = a[1]; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_access_const_expr(self): data = """ int main() { int g; int a[10]; a[6] = 4; g = a[5 + 1]; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_access_var_expr(self): data = """ int main() { int g; int a[10]; a[1] = 4; g = a[1]; g = a[g + 1]; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_array_twodim(self): data = """ int main() { int b[10][10]; b[1][1] = 5; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_for_loop_1(self): data = """ int main() { int i; for(i = 0; ;) {} } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_for_loop_2(self): data = """ int main() { int i; for(i = 0; ; i++) {} } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_for_loop_3(self): data = """ int main() { int i; for(i = 0; i < 1; i++) {} } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_while_loop(self): data = """ int main() { int i; while(i < 5){} } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_do_while_loop(self): data = """ int main() { int i; do {} while (i > 10); } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_function_decl_top_impl_bottom(self): data = """ int do_stuff(); int do_stuff() { return 5; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_function_decl_top_impl_bottom_call_middle(self): data = """ int do_stuff(); int main() { return do_stuff(); } int do_stuff() { return 5; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_function_parameters(self): # TODO: this one fails because we don't have the concept of a "dereference expression/operation", although # TODO: we aren't super worried about pointers for now. data = """ int do_stuff(int* ret, int x) { *ret = x + x; return 5; } int main() { int* ptr; int num; return do_stuff(ptr, num); } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_function_def_on_top(self): data = """ // Definition on top int do_stuff() { return 5; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_function_def_on_top_call(self): data = """ int do_stuff() { return 5; } int main() { return do_stuff(); } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_declare_const_and_var_types(self): data = """ int main(){ int x; int * y = 0; int z[10]; const int i; float j; char k = 'a'; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str())
class TestParser(unittest.TestCase): def setUp(self): self.debug = True self.compiler_state = CompilerState() def tearDown(self): self.compiler_state.teardown() self.compiler_state = None def test_plain_main(self): data = """ int main() { return 0; } int i; // Needed to clone the symbol table at the correct time !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'main', 0, 'int main()') def test_declare_primitive_variable(self): self.enable_parser_debugging() data = """ int main() { int i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') symbol, _ = symbol_table_clone.find('i') self.assertEqual(0, symbol.activation_frame_offset) def test_declare_and_assign_primitive_variable(self): data = """ int main() { int i = 5; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_declare_multiple_primitive_variable(self): # self.enable_parser_debugging() data = """ int main() { int i, j, k; i = 0; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') self.check_correct_element(symbol_table_clone, 'j', 2, 'int j') self.check_correct_element(symbol_table_clone, 'k', 2, 'int k') i_symbol, _ = symbol_table_clone.find('i') j_symbol, _ = symbol_table_clone.find('j') k_symbol, _ = symbol_table_clone.find('k') self.assertEqual(0, i_symbol.activation_frame_offset) self.assertEqual(4, j_symbol.activation_frame_offset) self.assertEqual(8, k_symbol.activation_frame_offset) def test_modify_primitive_variable(self): self.enable_parser_debugging() data = """ int main() { int i = 0; i += 5; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_declare_pointer_variable(self): self.enable_parser_debugging() data = """ int main() { int* i; i = 0; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int * i') def test_declare_deep_pointer_variable(self): data = """ int main() { int*** i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] print(symbol_table_clone) self.check_correct_element(symbol_table_clone, 'i', 2, 'int *** i') def test_declare_global_constant(self): self.enable_parser_debugging() data = """ const int GLOBAL_CONSTANT = 5; int main() { int i = GLOBAL_CONSTANT; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'GLOBAL_CONSTANT', 0, 'const int GLOBAL_CONSTANT') self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_assign_to_immutable_variable_fails(self): with self.assertRaises(CompileError): data = """ const int GLOBAL_CONSTANT = 5; int main() { GLOBAL_CONSTANT = 0; return 0; } """ self.compiler_state.parse(data) def test_plain_if(self): data = """ int main(int argc, char** argv) { if (1 != 1) { int wtf_result = -1; return wtf_result; !!C } return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'wtf_result', 3, 'int wtf_result') def test_ternary_operator(self): data = """ int main(int argc, char** argv) { return 0 == 0 ? 1 : 0; } """ self.compiler_state.parse(data) self.assertTrue(True, "No exceptions means a successful parse.") def test_plain_if_else(self): data = """ int main(int argc, char** argv) { if (1 != 1) { !!C int wtf_result = -1; return wtf_result; } else { !!C int i_guess_its_fine = 0; return i_guess_its_fine; } return 0; } """ print(data) self.compiler_state.parse(data) if_symbol_table_clone = self.compiler_state.cloned_tables[0] else_symbol_table_clone = self.compiler_state.cloned_tables[1] self.check_correct_element(if_symbol_table_clone, 'wtf_result', 3, 'int wtf_result') self.check_correct_element(else_symbol_table_clone, 'i_guess_its_fine', 3, 'int i_guess_its_fine') def test_lone_else_fails(self): with self.assertRaises(Exception): data = 'int main(int argc, char** argv) {\n' \ ' else {\n' \ ' int wtf = 0;\n' \ ' return wtf;\n' \ ' }\n' \ '\n' \ ' return 0;\n' \ '}\n' \ '' self.compiler_state.parse(data) def test_while_loop(self): data = """ int main() { while (1) {} return 0; } int i; // Needed to clone the symbol table at the correct time !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'main', 0, 'int main()') def test_for_loop(self): self.enable_parser_debugging() data = """ int main() { int i; for (i = 0; i < 3; i++) {} !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_do_while_loop(self): data = """ int main() { int i = 1; do {i++;} while(i); !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') def test_cast_in_binary_expression(self): self.enable_parser_debugging() data = """ int main() { int i = 5; float f = -4.5; i = (int) ((float) i + f); return 0; } """ ast = self.compiler_state.parse(data) print(ast.to_graph_viz_str()) def test_declare_array(self): self.enable_parser_debugging() data = """ int main() { int my_array[10]; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') def test_declare_array_with_constant_expression_in_subscript(self): data = """ int main() { int my_array[5 + 5]; int i; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') def test_access_array(self): self.enable_parser_debugging() data = """ int main() { int i = 0; int my_array[10]; int first_element = my_array[0]; int some_other_element = my_array[i]; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] print(symbol_table_clone) self.check_correct_element(symbol_table_clone, 'i', 2, 'int i') self.check_correct_element(symbol_table_clone, 'my_array', 2, 'int my_array[10]') self.check_correct_element(symbol_table_clone, 'first_element', 2, 'int first_element') self.check_correct_element(symbol_table_clone, 'some_other_element', 2, 'int some_other_element') def test_declare_function(self): self.enable_parser_debugging() data = """ int do_stuff(char c); !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] result, _ = symbol_table_clone.find('do_stuff') print(result, type(result)) assert (isinstance(result, FunctionSymbol)) p = result.named_parameters[0] print(p, type(p)) print(p.type_specifiers) self.check_correct_element(symbol_table_clone, 'do_stuff', 0, 'int do_stuff(char c)') def test_declare_function_implementation(self): data = """ int do_stuff(char c) { return c + c; } int main() { return 0; } !!C """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'do_stuff', 0, 'int do_stuff(char c)') def test_call_function(self): self.enable_parser_debugging() data = """ int do_stuff(int c); !!C int main() { do_stuff(4); return 0; } int do_stuff(int c) { return c + c; !!C } """ self.compiler_state.parse(data) symbol_table_clone_inner = self.compiler_state.cloned_tables[0] symbol_table_clone_outer = self.compiler_state.cloned_tables[1] self.check_correct_element(symbol_table_clone_inner, 'do_stuff', 0, 'int do_stuff(int c)') self.check_correct_element(symbol_table_clone_outer, 'c', 1, 'int c') symbol, _ = symbol_table_clone_outer.find('c') self.assertEqual(0, symbol.activation_frame_offset) def test_declare_string_literal_char_star(self): self.enable_parser_debugging() data = """ char* literal_string = "hello there"; !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'literal_string', 0, 'char * literal_string') def test_declare_string_as_array(self): self.enable_parser_debugging() data = """ int main() { char array_string[] = "hey"; !!C return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'array_string', 2, 'char array_string[4]') def test_declare_segmented_string_literal(self): data = """ char literal_string[] = "hello " "world"; !!C int main() { return 0; } """ self.compiler_state.parse(data) symbol_table_clone = self.compiler_state.cloned_tables[0] self.check_correct_element(symbol_table_clone, 'literal_string', 0, 'char literal_string[12]') def test_bubble_sort(self): # TODO: this test is failing because we are not handling pointers as though they were arrays and vice versa # TODO: perhaps we should change our test case? Maybe this is why Fred said pointers were hard... data = """ void print(int list[], int size); void bubbleSort(int list[], int size); int main() { int list[10]; int i; //srand(time(NULL)); // create list for(i =0; i<10;i++) { //list[i] = rand() % 10 + 1; } print(list, 10); // bubble sort bubbleSort(list, 10 ); //printf( "Sorted " ); print(list, 10); !!C // return return 0; } void bubbleSort(int list[], int size) { int i, j; int temp; int swapped; for( i = 0; i < size; i++) { // swapped is false swapped = 0; for( j = 0; j < size - 1; j++) { if(list[j+1] < list[j]) { temp = list[j]; list[j] = list[j+1]; list[j+1] = temp; swapped = 1; } } if (swapped == 0) { break; } } } void print(int list[], int size) { int i; //printf("List is: "); for(i =0; i < size; i++) { //printf( "%d ", list[i] ); } //printf(""); } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') def test_recursive_factorial(self): data = """ long int recur_Fact(int number); int main() { int number; long int fact; //printf( "Enter number to get factorial of: "); //scanf( "%d", &number ); fact = recur_Fact(number); //printf("Factorial of %d is: %ld", number, fact); return 0; } long int recur_Fact( int number) { // base case if(number <= 0) return 1; // recursive case else if( number > 1 ) { return number*recur_Fact(number-1); } } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') def test_iterative_factorial(self): data = """ long int iter_Fact(int number); int main() { int number; long int fact; // printf("Enter number to get factorial of: "); // scanf( "%d", &number ); fact = iter_Fact(number); // printf("Factorial of %d is: %ld ", number, fact); return 0; } long int iter_Fact(int number) { int i; long int fact = 1; if( i < 0) { return 1; } for( i = number; i > 0; i --) { fact = fact*i; } return fact; } """ self.compiler_state.parse(data) #symbol_table_clone = self.compiler_state.cloned_tables[0] # TODO: Determine what scopes we want to test here #self.check_correct_element(symbol_table_clone, '', 1, '') self.assertTrue(True, 'No exceptions = Parser successfully parsed.') # TODO: don't put a lot of emphasis on bad cases until things are strong with the good cases def test_malformed_main_fails(self): with self.assertRaises(Exception): data = 'badmain(] {return 0;}' self.compiler_state.parse(data) # def test_declare_typedef(self): # self.enable_parser_debugging() # data = """ # typedef int GlorifiedInt; # !!C # # int main() { # return 0; # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling typedefs? # self.check_correct_element(symbol_table_clone, 'GlorifiedInt', 0, 'typedef int GlorifiedInt') # def test_declare_typedef_and_use_typedef_in_variable_declaration(self): # self.enable_parser_debugging() # # data = """ # typedef int GlorifiedInt; # # int main() { # GlorifiedInt i = 3; # return 0; # !!C # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling typedefs? # self.check_correct_element(symbol_table_clone, 'GlorifiedInt', 0, 'typedef int GlorifiedInt') # self.check_correct_element(symbol_table_clone, 'i', 1, 'GlorifiedInt') # def test_declare_struct(self): # data = """ # !!C # struct Pixel { # char r; # char g; # char b; # !!C # }; # # int main() { # struct Pixel pixel; # pixel.r = 255; # pixel.g = 255; # pixel.b = 255; # !!C # return 0; # } # """ # # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: How are we handling structs? # self.check_correct_element(symbol_table_clone, 'Pixel', 0, 'struct Pixel') # self.check_correct_element(symbol_table_clone, 'r', 1, 'char r') # self.check_correct_element(symbol_table_clone, 'g', 1, 'char g') # self.check_correct_element(symbol_table_clone, 'b', 1, 'char b') # self.check_correct_element(symbol_table_clone, 'pixel', 1, 'struct Pixel pixel') # # # def test_declare_function_pointer_typedef(self): # data = """ # typedef int (*add_callback)(int a, int b); # # int add_two(int a, int b, add_callback callback); # # int normal_add(int a, int b); # int weird_add(int a, int b); # # int main() { # int x; # int y; # # x = add_two(1, 2, normal_add); # y = add_two(1, 2, weird_add); # # !!C # return 0; # } # # int add_two(int a, int b, add_callback callback) { # return callback(a, b); # } # # int normal_add(int a, int b) { # return a + b; # } # # int weird_add(int a, int b) { # return (a + b) % 4; # } # """ # self.compiler_state.parse(data) # symbol_table_clone = self.compiler_state.cloned_tables[0] # # # TODO: Function Pointers?? # self.check_correct_element(symbol_table_clone, 'x', 1, 'int x') def test_super_function_testing(self): data = """ !!C void do_stuff(int* array); int main() { return 0; } void do_stuff(int* array) { int* i; do_stuff(i); } """ self.compiler_state.parse(data) symbol_table = self.compiler_state.cloned_tables[0] print(symbol_table) x, y = symbol_table.find('do_stuff') self.check_correct_element(symbol_table, 'do_stuff', 0, 'void do_stuff(int * array)') def test_super_memory_allocation(self): data = """ char g_char; int g_int; float g_float; void do_stuff(char a, int b) { int c; float d; !!C return a + b; } int main() { int i = do_stuff('a', 2); return 0; } !!C """ self.compiler_state.parse(data) function_symbol_table, global_symbol_table = self.compiler_state.cloned_tables[ 0:2] # g_char, _ = global_symbol_table.find('g_char') # self.assertEqual(0x10010000, g_char.global_memory_location) # g_int, _ = global_symbol_table.find('g_int') # self.assertEqual(0x10010004, g_int.global_memory_location) # g_float, _ = global_symbol_table.find('g_float') # self.assertEqual(0x10010008, g_float.global_memory_location) f_a, _ = function_symbol_table.find('a') self.assertEqual(0, f_a.activation_frame_offset) f_b, _ = function_symbol_table.find('b') self.assertEqual(4, f_b.activation_frame_offset) f_c, _ = function_symbol_table.find('c') self.assertEqual(8, f_c.activation_frame_offset) f_d, _ = function_symbol_table.find('d') self.assertEqual(12, f_d.activation_frame_offset) def enable_parser_debugging(self): if self.debug: self.compiler_state.get_parser_logger().add_switch( Logger.PRODUCTION) self.compiler_state.get_parser_logger().add_switch(Logger.INFO) self.compiler_state.get_parser_logger().add_switch(Logger.SOURCE) def check_correct_element(self, symbol_table_clone, check_value, check_scope, check_string): found_symbol, in_scope = symbol_table_clone.find(check_value) self.assertEqual(check_scope, in_scope, "The symbol was not found in the expected scope") self.assertEqual(check_string, str(found_symbol), "The symbols don't match")