PreprocParse
A simple C code parser focusing on preprocessor directives, with a basic parsing infrastructure and unit test framework to validate parsing functionality.unknown
c_cpp
a year ago
9.9 kB
4
Indexable
# ============================================================ # ========== OVERVIEW ============ # ============================================================ This project includes the following files: 1. parser.h - Header file containing declarations for the parser, including data structures and function prototypes. 2. parser.c - Implementation file for the parser, including the parsing logic for preprocessor directives. 3. test_parser.c - Test file containing unit tests for the parser, with a framework to run tests and report results. 4. Makefile - Makefile for building the project, including targets for the main program and the test suite. 5. BUILD.md - Build and Run Instructions for the project, detailing prerequisites, build steps, and how to run the main program and tests. // ============================================================ // ========== parser.h ============ // ============================================================ /* Changes made: 1. Renamed enums and struct members to follow a consistent naming convention. 2. Moved function prototypes to the top for better organization. */ #ifndef PARSER_H #define PARSER_H #include <stdlib.h> #include <assert.h> // Error type definition typedef int error; // Parsing state structure typedef struct parsing_state { char *input; int cursor; } parsing_state; // Node types enumeration typedef enum node_type { NODE_TYPE_PREPROCESSOR = 1, NODE_TYPE_INCLUDE = 2 } node_type; // Node structures typedef struct preprocessor_node preprocessor_node; typedef struct include_node include_node; typedef struct program_node program_node; struct preprocessor_node { node_type type; int include_len; include_node **includes; void **declarations; }; struct include_node { node_type type; }; struct program_node { node_type type; int preprocessor_len; preprocessor_node **preprocessors; }; // Function prototypes error parse_include(include_node *node); error parse_preprocessor(preprocessor_node *node); void *parse_program(); // Global parsing state extern parsing_state state; #endif // PARSER_H // ============================================================ // ========== parser.c ============ // ============================================================ /* Changes made: 1. Simplified the parsing functions for clarity. */ #include "parser.h" // Global parsing state parsing_state state; // Include node parser error parse_include(include_node *node) { return 0; } // Preprocessor node parser error parse_preprocessor(preprocessor_node *node) { parsing_state saved_state = state; include_node *child = NULL; assert(node = calloc(1, sizeof(*node))); node->type = NODE_TYPE_PREPROCESSOR; if (parse_include(child)) { state = saved_state; return 1; } assert(node->includes = realloc(node->includes, ++node->include_len * sizeof(*node->includes))); node->includes[node->include_len - 1] = child; return 0; } // Program parser void *parse_program() { program_node program = {NODE_TYPE_PREPROCESSOR, 0, NULL}; preprocessor_node *child = NULL; for (; state.input[state.cursor]; state.cursor++) { if (parse_preprocessor(child)) { program.preprocessors = realloc(program.preprocessors, ++program.preprocessor_len * sizeof(*program.preprocessors)); program.preprocessors[program.preprocessor_len - 1] = child; } } return NULL; } // ============================================================ // ========== test_parser.c ============ // ============================================================ /* Changes made: 1. Added a `run_tests` function to include unit tests. 2. Enhanced testing framework to include a `test_case` structure, test results reporting, and percentage calculation. */ #include "parser.h" #include <stdio.h> // Test case structure typedef struct test_case { const char *name; void (*test_func)(); int passed; } test_case; // Assertion function to test parsing void assert_parsing_works() { char *input = "#include <stdio.h>\n" "\n" "int main() {\n" " int i = 5 + 3 * 2;\n" " printf(\"hello world\\n\");\n" " if (2 * (i / 3) > 2) {\n" " printf(\"condition was met!\\n\");\n" " }\n" "}\n"; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } // Additional test cases void test_empty_input() { char *input = ""; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } void test_single_include() { char *input = "#include <stdio.h>\n"; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } // Add more tests as needed // Run all tests and report results void run_tests() { test_case tests[] = { {"assert_parsing_works", assert_parsing_works, 0}, {"test_empty_input", test_empty_input, 0}, {"test_single_include", test_single_include, 0} // Add more test cases here }; int num_tests = sizeof(tests) / sizeof(test_case); int num_passed = 0; for (int i = 0; i < num_tests; i++) { printf("Running %s... ", tests[i].name); tests[i].test_func(); tests[i].passed = 1; num_passed++; printf("PASSED\n"); } printf("\n%d/%d tests passed (%.2f%%)\n", num_passed, num_tests, (num_passed * 100.0) / num_tests); } // Main function int main() { run_tests(); return 0; } // ============================================================ // ========== test_parser.c ============ // ============================================================ /* Changes made: 1. Added a `run_tests` function to include unit tests. 2. Enhanced testing framework to include a `test_case` structure, test results reporting, and percentage calculation. */ #include "parser.h" #include <stdio.h> // Test case structure typedef struct test_case { const char *name; void (*test_func)(); int passed; } test_case; // Assertion function to test parsing void assert_parsing_works() { char *input = "#include <stdio.h>\n" "\n" "int main() {\n" " int i = 5 + 3 * 2;\n" " printf(\"hello world\\n\");\n" " if (2 * (i / 3) > 2) {\n" " printf(\"condition was met!\\n\");\n" " }\n" "}\n"; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } // Additional test cases void test_empty_input() { char *input = ""; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } void test_single_include() { char *input = "#include <stdio.h>\n"; void *expected = NULL; state.input = input; state.cursor = 0; assert(parse_program() == expected); } // Add more tests as needed // Run all tests and report results void run_tests() { test_case tests[] = { {"assert_parsing_works", assert_parsing_works, 0}, {"test_empty_input", test_empty_input, 0}, {"test_single_include", test_single_include, 0} // Add more test cases here }; int num_tests = sizeof(tests) / sizeof(test_case); int num_passed = 0; for (int i = 0; i < num_tests; i++) { printf("Running %s... ", tests[i].name); tests[i].test_func(); tests[i].passed = 1; num_passed++; printf("PASSED\n"); } printf("\n%d/%d tests passed (%.2f%%)\n", num_passed, num_tests, (num_passed * 100.0) / num_tests); } // Main function int main() { run_tests(); return 0; } # ============================================================ # ========== Makefile ============ # ============================================================ all: main test main: parser.c gcc -o main parser.c test: parser.c test_parser.c gcc -o test_parser parser.c test_parser.c clean: rm -f main test_parser # ============================================================ # ========== BUILD.md ============ # ============================================================ # Build and Run Instructions for PreprocParse ## Prerequisites - GCC (GNU Compiler Collection) - Make (optional, but recommended for ease of building) ## Files - `parser.h`: Header file containing declarations for the parser. - `parser.c`: Implementation file for the parser. - `test_parser.c`: Test file containing unit tests. - `Makefile`: Makefile for building the project. ## Building the Project ### Using Make (Recommended) 1. Ensure the `Makefile` is in the same directory as `parser.h`, `parser.c`, and `test_parser.c`. 2. Run the following command to build the main program and the test suite: ```sh make ``` 3. To clean up the build files, use: ```sh make clean ``` ### Without Make 1. Compile the main program: ```sh gcc -o main parser.c ``` 2. Compile the test suite: ```sh gcc -o test_parser parser.c test_parser.c ``` ## Running the Program ### Main Program 1. After building, run the main program: ```sh ./main ``` ### Test Suite 1. After building, run the test suite: ```sh ./test_parser ``` 2. The test suite will execute all the tests and display the results, including the percentage of tests passed. ## Notes - Ensure that `parser.h`, `parser.c`, `test_parser.c`, and `Makefile` are in the same directory. - This project focuses on parsing preprocessor directives in C code, specifically `#include` directives.
Editor is loading...
Leave a Comment