9#include "preprocessor.h"
15 error_fatal(
"Memory allocation failed for preprocessor");
21 pp->output_capacity = 4096;
22 pp->output = malloc(pp->output_capacity);
25 error_fatal(
"Memory allocation failed for preprocessor output");
32 pp->skip_lines =
false;
35 preprocessor_add_predefined_macros(pp);
44 for (
int i = 0; i < pp->include_depth; i++) {
45 free(pp->include_stack[i].filename);
46 free(pp->include_stack[i].content);
58 free(pp->current_file);
62void preprocessor_add_predefined_macros(
Preprocessor *pp) {
64 preprocessor_define_macro(pp,
"__KCC__",
"1");
65 preprocessor_define_macro(pp,
"__VERSION__",
"\"1.0.0\"");
68 time_t now = time(NULL);
69 struct tm *tm_info = localtime(&now);
73 strftime(date_str,
sizeof(date_str),
"\"%b %d %Y\"", tm_info);
74 strftime(time_str,
sizeof(time_str),
"\"%H:%M:%S\"", tm_info);
76 preprocessor_define_macro(pp,
"__DATE__", date_str);
77 preprocessor_define_macro(pp,
"__TIME__", time_str);
80 preprocessor_define_macro(pp,
"__x86_64__",
"1");
81 preprocessor_define_macro(pp,
"__unix__",
"1");
84 preprocessor_define_macro(pp,
"__STDC__",
"1");
85 preprocessor_define_macro(pp,
"__STDC_VERSION__",
"201112L");
88 for (
int i = 0; i < pp->macro_count; i++) {
89 pp->macros[i].is_predefined =
true;
93char* preprocessor_process_file(
Preprocessor* pp,
const char* filename) {
96 char* content = read_file(filename);
101 size_t content_len = strlen(content);
103 size_t result_capacity = content_len * 2 + 1024;
104 char* result = malloc(result_capacity);
110 size_t result_len = 0;
113 char* content_copy = strdup(content);
120 char* line = strtok(content_copy,
"\n");
121 while (line != NULL) {
122 size_t line_len = strlen(line);
125 if (result_len + line_len + 2 >= result_capacity) {
127 result_capacity *= 2;
128 char* new_result = realloc(result, result_capacity);
138 if (line[0] ==
'#') {
140 if (strncmp(line + 1,
"include", 7) == 0) {
144 strcpy(result + result_len, line);
145 result_len += line_len;
146 result[result_len++] =
'\n';
147 result[result_len] =
'\0';
151 strcpy(result + result_len, line);
152 result_len += line_len;
153 result[result_len++] =
'\n';
154 result[result_len] =
'\0';
156 line = strtok(NULL,
"\n");
164char* preprocessor_process_string(
Preprocessor* pp,
const char* source,
const char* filename) {
165 pp->current_file = strdup(filename);
166 pp->current_line = 1;
168 pp->output[0] =
'\0';
170 char line[MAX_LINE_LENGTH];
171 const char* src_ptr = source;
176 while (*src_ptr && *src_ptr !=
'\n' && i < MAX_LINE_LENGTH - 1) {
177 line[i++] = *src_ptr++;
181 if (*src_ptr ==
'\n') {
186 if (preprocessor_should_skip_line(pp)) {
188 if (preprocessor_is_directive(line)) {
189 char *directive = preprocessor_get_directive_name(line);
190 if (directive && (strcmp(directive,
"endif") == 0 ||
191 strcmp(directive,
"else") == 0 ||
192 strcmp(directive,
"elif") == 0)) {
193 preprocessor_process_directive(pp, line);
198 if (preprocessor_is_directive(line)) {
199 if (!preprocessor_process_directive(pp, line)) {
200 preprocessor_error(pp,
"Error processing directive: %s", line);
204 char *expanded = preprocessor_expand_macros(pp, line);
205 preprocessor_append_output(pp, expanded);
206 preprocessor_append_output(pp,
"\n");
215 if (pp->cond_stack_depth > 0) {
216 preprocessor_error(pp,
"Unmatched conditional directive");
219 return strdup(pp->output);
222bool preprocessor_define_macro(
Preprocessor *pp,
const char *name,
const char *body) {
223 if (!pp || !name || !body) {
228 if (strlen(name) == 0) {
233 if (pp->macro_count >= MAX_MACROS) {
234 preprocessor_error(pp,
"Too many macros defined");
239 void *macro_ptr = &pp->macros[pp->macro_count++];
245 if (!safe_strcpy(macro->name,
sizeof(macro->name), name)) {
247 preprocessor_error(pp,
"Macro name too long: %.50s", name);
252 if (!safe_strcpy(macro->body,
sizeof(macro->body), body)) {
254 preprocessor_warning(pp,
"Macro body truncated: %.50s", name);
256 strncpy(macro->body, body,
sizeof(macro->body) - 1);
257 macro->body[
sizeof(macro->body) - 1] =
'\0';
260 macro->type = MACRO_OBJECT;
261 macro->param_count = 0;
262 macro->is_predefined =
false;
263 macro->line_defined = pp->current_line;
269bool preprocessor_define_function_macro(
Preprocessor *pp,
const char *name,
270 const char *params[],
int param_count,
const char *body) {
271 if (pp->macro_count >= MAX_MACROS) {
272 preprocessor_error(pp,
"Too many macros defined");
276 if (param_count > MAX_MACRO_PARAMS) {
277 preprocessor_error(pp,
"Too many macro parameters");
281 void *macro_ptr = &pp->macros[pp->macro_count++];
285 strncpy(macro->name, name,
sizeof(macro->name) - 1);
286 macro->name[
sizeof(macro->name) - 1] =
'\0';
288 strncpy(macro->body, body,
sizeof(macro->body) - 1);
289 macro->body[
sizeof(macro->body) - 1] =
'\0';
291 macro->type = MACRO_FUNCTION;
292 macro->param_count = param_count;
293 macro->is_predefined =
false;
294 macro->line_defined = pp->current_line;
297 for (
int i = 0; i < param_count; i++) {
298 strncpy(macro->params[i].name, params[i],
sizeof(macro->params[i].name) - 1);
299 macro->params[i].name[
sizeof(macro->params[i].name) - 1] =
'\0';
305bool preprocessor_undefine_macro(
Preprocessor *pp,
const char *name) {
306 for (
int i = 0; i < pp->macro_count; i++) {
308 void *macro_ptr = &pp->macros[i];
309 if (strcmp(((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->name, name) == 0) {
311 if (((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->is_predefined) {
312 preprocessor_warning(pp,
"Cannot undefine predefined macro '%s'", name);
317 if (((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->file_defined) {
318 free(((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->file_defined);
322 for (
int j = i; j < pp->macro_count - 1; j++) {
323 pp->macros[j] = pp->macros[j + 1];
333 for (
int i = 0; i < pp->macro_count; i++) {
334 Macro *macro = &pp->macros[i];
335 if (strcmp(macro->name, name) == 0) {
342bool preprocessor_is_macro_defined(
Preprocessor *pp,
const char *name) {
343 return preprocessor_find_macro(pp, name) != NULL;
346char *preprocessor_expand_macros(
Preprocessor *pp,
const char *line) {
352 const char *args[],
int arg_count) {
355 void *macro_ptr = (
void *)macro;
356 if (arg_count != ((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->param_count) {
357 preprocessor_error(pp,
"Macro '%s' expects %d arguments, got %d",
358 ((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->name, ((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->param_count, arg_count);
359 return strdup(((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->body);
362 return strdup(((
struct {
char name[64];
char body[512];
int type;
int param_count;
bool is_predefined;
int line_defined;
char *file_defined;
struct {
char name[32]; } params[16]; } *)macro_ptr)->body);
365char *preprocessor_substitute_params(
const char *body,
const char *params[],
366 const char *args[],
int param_count) {
373bool preprocessor_process_directive(
Preprocessor *pp,
const char *line) {
374 char *directive = preprocessor_get_directive_name(line);
375 if (!directive)
return false;
379 if (strcmp(directive,
"define") == 0) {
380 result = preprocessor_handle_define(pp, line);
381 }
else if (strcmp(directive,
"undef") == 0) {
382 result = preprocessor_handle_undef(pp, line);
383 }
else if (strcmp(directive,
"include") == 0) {
384 result = preprocessor_handle_include(pp, line);
386 preprocessor_error(pp,
"Unknown directive: #%s", directive);
393bool preprocessor_handle_define(
Preprocessor *pp,
const char *directive) {
394 char *args = preprocessor_get_directive_args(directive);
396 preprocessor_error(pp,
"Invalid #define directive");
400 char *name = strtok(args,
" \t");
403 preprocessor_error(pp,
"Missing macro name in #define");
408 char *body = strtok(NULL,
"");
409 if (!body) body =
"";
412 while (*body && isspace(*body)) body++;
414 bool result = preprocessor_define_macro(pp, name, body);
419bool preprocessor_handle_undef(
Preprocessor *pp,
const char *directive) {
420 char *args = preprocessor_get_directive_args(directive);
422 preprocessor_error(pp,
"Invalid #undef directive");
426 char *name = strtok(args,
" \t\n");
429 preprocessor_error(pp,
"Missing macro name in #undef");
433 bool result = preprocessor_undefine_macro(pp, name);
438bool preprocessor_handle_include(
Preprocessor *pp,
const char *directive) {
445bool preprocessor_is_directive(
const char *line) {
446 const char *ptr = line;
447 while (*ptr && isspace(*ptr)) ptr++;
451char *preprocessor_get_directive_name(
const char *line) {
452 const char *ptr = line;
453 while (*ptr && isspace(*ptr)) ptr++;
454 if (*ptr !=
'#')
return NULL;
457 while (*ptr && isspace(*ptr)) ptr++;
459 const char *start = ptr;
460 while (*ptr && (isalnum(*ptr) || *ptr ==
'_')) ptr++;
462 if (ptr == start)
return NULL;
464 char *name = malloc(ptr - start + 1);
465 strncpy(name, start, ptr - start);
466 name[ptr - start] =
'\0';
471char *preprocessor_get_directive_args(
const char *line) {
472 const char *ptr = line;
473 while (*ptr && isspace(*ptr)) ptr++;
474 if (*ptr !=
'#')
return NULL;
477 while (*ptr && isspace(*ptr)) ptr++;
480 while (*ptr && (isalnum(*ptr) || *ptr ==
'_')) ptr++;
481 while (*ptr && isspace(*ptr)) ptr++;
486char *preprocessor_trim_whitespace(
char *str) {
488 while (*str && isspace(*str)) str++;
491 char *end = str + strlen(str) - 1;
492 while (end > str && isspace(*end)) {
500char *preprocessor_stringify(
const char *text) {
501 size_t len = strlen(text);
502 char *result = malloc(len * 2 + 3);
507 for (
size_t i = 0; i < len; i++) {
508 if (text[i] ==
'"' || text[i] ==
'\\') {
520void preprocessor_append_output(
Preprocessor *pp,
const char *text) {
521 size_t text_len = strlen(text);
522 size_t needed = pp->output_size + text_len + 1;
524 if (needed > pp->output_capacity) {
525 pp->output_capacity = needed * 2;
526 pp->output = realloc(pp->output, pp->output_capacity);
528 error_fatal(
"Memory allocation failed for preprocessor output");
533 strcpy(pp->output + pp->output_size, text);
534 pp->output_size += text_len;
538 return pp->skip_lines;
542 if (pp->cond_stack_depth >= 32) {
543 preprocessor_error(pp,
"Conditional nesting too deep");
549 cond->condition_met = condition;
550 cond->else_taken =
false;
551 cond->line_number = pp->current_line;
553 pp->skip_lines = !condition;
557 if (pp->cond_stack_depth == 0) {
561 pp->cond_stack_depth--;
562 pp->skip_lines = preprocessor_should_skip_line(pp);
567int preprocessor_error(
Preprocessor* pp,
const char* format, ...) {
568 fprintf(stderr,
"Preprocessor error in %s:%d: ",
569 pp->current_file ? pp->current_file :
"unknown", pp->current_line);
572 va_start(args, format);
573 vfprintf(stderr, format, args);
576 fprintf(stderr,
"\n");
581int preprocessor_warning(
Preprocessor* pp,
const char* format, ...) {
582 fprintf(stderr,
"Preprocessor warning in %s:%d: ",
583 pp->current_file ? pp->current_file :
"unknown", pp->current_line);
586 va_start(args, format);
587 vfprintf(stderr, format, args);
590 fprintf(stderr,
"\n");
Conditional state tracking.
ConditionalType
Conditional compilation state.