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