22extern size_t fread(
void *restrict ptr,
size_t size,
size_t nitems, FILE *restrict stream);
23extern int fprintf(FILE *restrict stream,
const char *restrict format, ...);
24extern int printf(
const char *restrict format, ...);
25extern int fseek(FILE *stream,
long offset,
int whence);
26extern long ftell(FILE *stream);
27extern FILE *fopen(
const char *restrict filename,
const char *restrict mode);
28extern int fclose(FILE *stream);
29extern void *malloc(
size_t size);
30extern void free(
void *ptr);
31extern int strcmp(
const char *s1,
const char *s2);
35#include "preprocessor.h"
36#include "symbol_table.h"
39struct Parser *parser = NULL;
41void print_usage(
const char *program_name) {
42 printf(
"KCC - Kayte C Compiler v%s\n\n", KCC_VERSION);
43 printf(
"Usage: %s [options] <input_file>\n\n", program_name);
45 printf(
" -o <file> Specify output file\n");
46 printf(
" -v, --verbose Enable verbose output\n");
47 printf(
" -d, --debug Enable debug mode\n");
48 printf(
" -O Enable optimization\n");
49 printf(
" -S Keep assembly output\n");
50 printf(
" -E Run preprocessor only\n");
51 printf(
" --no-preprocess Skip preprocessing step\n");
52 printf(
" -h, --help Show this help message\n");
53 printf(
" --version Show version information\n");
54 printf(
"\nExamples:\n");
55 printf(
" %s hello.c\n", program_name);
56 printf(
" %s -o hello hello.c\n", program_name);
57 printf(
" %s -v -O hello.c\n", program_name);
58 printf(
" %s -E macros.c > preprocessed.c\n", program_name);
61void print_version(
void) {
62 printf(
"KCC (Kayte C Compiler) version %s\n", KCC_VERSION);
63 printf(
"Copyright (c) 2025 KCC Contributors\n");
64 printf(
"This is free software; see the source for copying conditions.\n");
69bool error_has_errors(
void);
75int compile_file(
const char *input_file,
const char *output_file,
CompilerOptions *opts) {
76 printf(
"DEBUG: Starting compilation of '%s'\n", input_file);
79 const char *final_output = output_file ? output_file :
"a.out";
82 FILE *test_file = fopen(input_file,
"r");
84 fprintf(stderr,
"Error: Cannot open input file '%s'\n", input_file);
88 printf(
"DEBUG: File '%s' is readable\n", input_file);
91 printf(
"DEBUG: Creating preprocessor...\n");
94 fprintf(stderr,
"Error: Failed to create preprocessor\n");
97 printf(
"DEBUG: Preprocessor created successfully\n");
99 printf(
"DEBUG: Processing file...\n");
100 char *preprocessed_source = preprocessor_process_file(preprocessor, input_file);
101 if (!preprocessed_source) {
102 fprintf(stderr,
"Error: Preprocessing failed\n");
103 preprocessor_destroy(preprocessor);
107 printf(
"DEBUG: Preprocessed source length: %zu\n", strlen(preprocessed_source));
110 printf(
"DEBUG: Creating lexer...\n");
111 Lexer *lexer = lexer_create(preprocessed_source, input_file);
113 fprintf(stderr,
"Error: Failed to create lexer\n");
114 free(preprocessed_source);
115 preprocessor_destroy(preprocessor);
118 printf(
"DEBUG: Lexer created successfully\n");
121 printf(
"DEBUG: Creating parser...\n");
122 Parser *parser = parser_create(lexer);
124 fprintf(stderr,
"Error: Failed to create parser\n");
125 lexer_destroy(lexer);
126 free(preprocessed_source);
127 preprocessor_destroy(preprocessor);
130 printf(
"DEBUG: Parser created successfully\n");
133 printf(
"DEBUG: Parsing AST...\n");
134 ASTNode *ast = parser_parse_program(parser);
136 fprintf(stderr,
"Error: Parsing failed\n");
137 parser_destroy(parser);
138 lexer_destroy(lexer);
139 free(preprocessed_source);
140 preprocessor_destroy(preprocessor);
145 if (opts && opts->verbose) {
151 char *asm_file = malloc(strlen(final_output) + 16);
153 fprintf(stderr,
"Error: Memory allocation failed\n");
155 parser_destroy(parser);
156 lexer_destroy(lexer);
157 free(preprocessed_source);
158 preprocessor_destroy(preprocessor);
161 snprintf(asm_file, strlen(final_output) + 16,
"%s.s", final_output);
164 printf(
"DEBUG: Generating assembly code to '%s'...\n", asm_file);
167 fprintf(stderr,
"Error: Failed to create code generator for '%s'\n", asm_file);
170 parser_destroy(parser);
171 lexer_destroy(lexer);
172 free(preprocessed_source);
173 preprocessor_destroy(preprocessor);
177 if (!codegen_generate(codegen, ast)) {
178 fprintf(stderr,
"Error: Code generation failed\n");
179 codegen_destroy(codegen);
182 parser_destroy(parser);
183 lexer_destroy(lexer);
184 free(preprocessed_source);
185 preprocessor_destroy(preprocessor);
189 printf(
"DEBUG: Assembly code generation completed\n");
190 codegen_destroy(codegen);
193 if (opts && opts->keep_asm) {
194 printf(
"Assembly file generated: %s\n", asm_file);
197 parser_destroy(parser);
198 lexer_destroy(lexer);
199 free(preprocessed_source);
200 preprocessor_destroy(preprocessor);
205 printf(
"DEBUG: Assembling and linking to create '%s'...\n", final_output);
208 char *obj_file = malloc(strlen(final_output) + 16);
210 fprintf(stderr,
"Error: Memory allocation failed for object file name\n");
214 parser_destroy(parser);
215 lexer_destroy(lexer);
216 free(preprocessed_source);
217 preprocessor_destroy(preprocessor);
220 snprintf(obj_file, strlen(final_output) + 16,
"%s.o", final_output);
223 char *as_cmd = malloc(strlen(asm_file) + strlen(obj_file) + 64);
225 fprintf(stderr,
"Error: Memory allocation failed for assembler command\n");
230 parser_destroy(parser);
231 lexer_destroy(lexer);
232 free(preprocessed_source);
233 preprocessor_destroy(preprocessor);
238 snprintf(as_cmd, strlen(asm_file) + strlen(obj_file) + 64,
239 "clang -c '%s' -o '%s'", asm_file, obj_file);
241 printf(
"DEBUG: Running assembler: %s\n", as_cmd);
242 int as_result = system(as_cmd);
245 if (as_result != 0) {
246 fprintf(stderr,
"Error: Assembly failed (assembler returned %d)\n", as_result);
251 parser_destroy(parser);
252 lexer_destroy(lexer);
253 free(preprocessed_source);
254 preprocessor_destroy(preprocessor);
259 char *ld_cmd = malloc(strlen(obj_file) + strlen(final_output) + 128);
261 fprintf(stderr,
"Error: Memory allocation failed for linker command\n");
267 parser_destroy(parser);
268 lexer_destroy(lexer);
269 free(preprocessed_source);
270 preprocessor_destroy(preprocessor);
275 snprintf(ld_cmd, strlen(obj_file) + strlen(final_output) + 128,
276 "clang '%s' -o '%s' -Wl,-e,_main -nostartfiles", obj_file, final_output);
278 printf(
"DEBUG: Running linker: %s\n", ld_cmd);
279 int ld_result = system(ld_cmd);
282 if (ld_result != 0) {
283 fprintf(stderr,
"Error: Linking failed (linker returned %d)\n", ld_result);
289 parser_destroy(parser);
290 lexer_destroy(lexer);
291 free(preprocessed_source);
292 preprocessor_destroy(preprocessor);
297 if (!opts || !opts->keep_asm) {
302 printf(
"Compilation successful: %s -> %s\n", input_file, final_output);
308 parser_destroy(parser);
309 lexer_destroy(lexer);
310 free(preprocessed_source);
311 preprocessor_destroy(preprocessor);
317int main(
int argc,
char *argv[]) {
319 print_usage(argv[0]);
324 opts.input_file = NULL;
325 opts.output_file =
"a.out";
326 opts.verbose =
false;
328 opts.optimize =
false;
329 opts.keep_asm =
false;
330 opts.no_preprocess =
false;
331 opts.preprocess_only =
false;
334 for (
int i = 1; i < argc; i++) {
335 if (strcmp(argv[i],
"-h") == 0 || strcmp(argv[i],
"--help") == 0) {
336 print_usage(argv[0]);
338 }
else if (strcmp(argv[i],
"--version") == 0) {
341 }
else if (strcmp(argv[i],
"-v") == 0 || strcmp(argv[i],
"--verbose") == 0) {
343 }
else if (strcmp(argv[i],
"-d") == 0 || strcmp(argv[i],
"--debug") == 0) {
345 }
else if (strcmp(argv[i],
"-O") == 0) {
346 opts.optimize =
true;
347 }
else if (strcmp(argv[i],
"-S") == 0) {
348 opts.keep_asm =
true;
349 }
else if (strcmp(argv[i],
"-E") == 0) {
350 opts.preprocess_only =
true;
351 }
else if (strcmp(argv[i],
"--no-preprocess") == 0) {
352 opts.no_preprocess =
true;
353 }
else if (strcmp(argv[i],
"-o") == 0) {
355 fprintf(stderr,
"Error: -o requires an output filename\n");
358 opts.output_file = argv[++i];
360 else if (argv[i][0] ==
'-') {
361 fprintf(stderr,
"Error: Unknown option '%s'\n", argv[i]);
362 print_usage(argv[0]);
365 if (opts.input_file) {
366 fprintf(stderr,
"Error: Multiple input files specified\n");
369 opts.input_file = argv[i];
373 if (!opts.input_file) {
374 fprintf(stderr,
"Error: No input file specified\n");
375 print_usage(argv[0]);
379 return compile_file(opts.input_file, opts.output_file, &opts);