KCC - Kayte C Compiler 1.10.0
A C compiler implementation with preprocessor, lexer, parser, and code generator
Loading...
Searching...
No Matches
main.c
1// Ensure we have GNU extensions available
2#ifndef _GNU_SOURCE
3#define _GNU_SOURCE
4#endif
5
6// Standard C library includes - be very explicit
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <stdbool.h>
11#include <stdarg.h>
12#include <stdint.h>
13#include <ctype.h>
14#include <errno.h>
15#include <assert.h>
16#include <unistd.h>
17
18// Explicit function declarations to work around macOS issues
19extern FILE *stderr;
20extern FILE *stdout;
21extern FILE *stdin;
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);
32
33// Project-specific includes
34#include "kcc.h"
35#include "preprocessor.h"
36#include "symbol_table.h"
37#include "parser.h"
38
39struct Parser *parser = NULL;
40
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);
44 printf("Options:\n");
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);
59}
60
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");
65}
66
67// Forward declarations
68void error_init(void);
69bool error_has_errors(void);
70int error_count(void);
71//struct Parser *parser = parser_create(debug_lexer);
72
73
74
75int compile_file(const char *input_file, const char *output_file, CompilerOptions *opts) {
76 printf("DEBUG: Starting compilation of '%s'\n", input_file);
77
78 // Set default output file if not provided
79 const char *final_output = output_file ? output_file : "a.out";
80
81 // Check if file exists and is readable
82 FILE *test_file = fopen(input_file, "r");
83 if (!test_file) {
84 fprintf(stderr, "Error: Cannot open input file '%s'\n", input_file);
85 return 1;
86 }
87 fclose(test_file);
88 printf("DEBUG: File '%s' is readable\n", input_file);
89
90 // Read and preprocess
91 printf("DEBUG: Creating preprocessor...\n");
92 Preprocessor *preprocessor = preprocessor_create();
93 if (!preprocessor) {
94 fprintf(stderr, "Error: Failed to create preprocessor\n");
95 return 1;
96 }
97 printf("DEBUG: Preprocessor created successfully\n");
98
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);
104 return 1;
105 }
106
107 printf("DEBUG: Preprocessed source length: %zu\n", strlen(preprocessed_source));
108
109 // Create lexer
110 printf("DEBUG: Creating lexer...\n");
111 Lexer *lexer = lexer_create(preprocessed_source, input_file);
112 if (!lexer) {
113 fprintf(stderr, "Error: Failed to create lexer\n");
114 free(preprocessed_source);
115 preprocessor_destroy(preprocessor);
116 return 1;
117 }
118 printf("DEBUG: Lexer created successfully\n");
119
120 // Create parser
121 printf("DEBUG: Creating parser...\n");
122 Parser *parser = parser_create(lexer);
123 if (!parser) {
124 fprintf(stderr, "Error: Failed to create parser\n");
125 lexer_destroy(lexer);
126 free(preprocessed_source);
127 preprocessor_destroy(preprocessor);
128 return 1;
129 }
130 printf("DEBUG: Parser created successfully\n");
131
132 // Parse AST
133 printf("DEBUG: Parsing AST...\n");
134 ASTNode *ast = parser_parse_program(parser);
135 if (!ast) {
136 fprintf(stderr, "Error: Parsing failed\n");
137 parser_destroy(parser);
138 lexer_destroy(lexer);
139 free(preprocessed_source);
140 preprocessor_destroy(preprocessor);
141 return 1;
142 }
143
144 // Print AST if verbose
145 if (opts && opts->verbose) {
146 printf("AST:\n");
147 ast_print(ast, 0);
148 }
149
150 // Create temporary assembly file name
151 char *asm_file = malloc(strlen(final_output) + 16);
152 if (!asm_file) {
153 fprintf(stderr, "Error: Memory allocation failed\n");
154 ast_destroy(ast);
155 parser_destroy(parser);
156 lexer_destroy(lexer);
157 free(preprocessed_source);
158 preprocessor_destroy(preprocessor);
159 return 1;
160 }
161 snprintf(asm_file, strlen(final_output) + 16, "%s.s", final_output);
162
163 // Generate assembly code
164 printf("DEBUG: Generating assembly code to '%s'...\n", asm_file);
165 CodeGenerator *codegen = codegen_create(asm_file);
166 if (!codegen) {
167 fprintf(stderr, "Error: Failed to create code generator for '%s'\n", asm_file);
168 free(asm_file);
169 ast_destroy(ast);
170 parser_destroy(parser);
171 lexer_destroy(lexer);
172 free(preprocessed_source);
173 preprocessor_destroy(preprocessor);
174 return 1;
175 }
176
177 if (!codegen_generate(codegen, ast)) {
178 fprintf(stderr, "Error: Code generation failed\n");
179 codegen_destroy(codegen);
180 free(asm_file);
181 ast_destroy(ast);
182 parser_destroy(parser);
183 lexer_destroy(lexer);
184 free(preprocessed_source);
185 preprocessor_destroy(preprocessor);
186 return 1;
187 }
188
189 printf("DEBUG: Assembly code generation completed\n");
190 codegen_destroy(codegen);
191
192 // Stop here if user only wants assembly
193 if (opts && opts->keep_asm) {
194 printf("Assembly file generated: %s\n", asm_file);
195 free(asm_file);
196 ast_destroy(ast);
197 parser_destroy(parser);
198 lexer_destroy(lexer);
199 free(preprocessed_source);
200 preprocessor_destroy(preprocessor);
201 return 0;
202 }
203
204 // Now assemble and link to create executable
205 printf("DEBUG: Assembling and linking to create '%s'...\n", final_output);
206
207 // Create object file name
208 char *obj_file = malloc(strlen(final_output) + 16);
209 if (!obj_file) {
210 fprintf(stderr, "Error: Memory allocation failed for object file name\n");
211 remove(asm_file);
212 free(asm_file);
213 ast_destroy(ast);
214 parser_destroy(parser);
215 lexer_destroy(lexer);
216 free(preprocessed_source);
217 preprocessor_destroy(preprocessor);
218 return 1;
219 }
220 snprintf(obj_file, strlen(final_output) + 16, "%s.o", final_output);
221
222 // Step 1: Assemble (.s -> .o) - Use clang for macOS compatibility
223 char *as_cmd = malloc(strlen(asm_file) + strlen(obj_file) + 64);
224 if (!as_cmd) {
225 fprintf(stderr, "Error: Memory allocation failed for assembler command\n");
226 remove(asm_file);
227 free(obj_file);
228 free(asm_file);
229 ast_destroy(ast);
230 parser_destroy(parser);
231 lexer_destroy(lexer);
232 free(preprocessed_source);
233 preprocessor_destroy(preprocessor);
234 return 1;
235 }
236
237 // Use clang as assembler for better macOS compatibility
238 snprintf(as_cmd, strlen(asm_file) + strlen(obj_file) + 64,
239 "clang -c '%s' -o '%s'", asm_file, obj_file);
240
241 printf("DEBUG: Running assembler: %s\n", as_cmd);
242 int as_result = system(as_cmd);
243 free(as_cmd);
244
245 if (as_result != 0) {
246 fprintf(stderr, "Error: Assembly failed (assembler returned %d)\n", as_result);
247 remove(asm_file);
248 free(obj_file);
249 free(asm_file);
250 ast_destroy(ast);
251 parser_destroy(parser);
252 lexer_destroy(lexer);
253 free(preprocessed_source);
254 preprocessor_destroy(preprocessor);
255 return 1;
256 }
257
258 // Step 2: Link (.o -> executable) - Use clang as linker for macOS
259 char *ld_cmd = malloc(strlen(obj_file) + strlen(final_output) + 128);
260 if (!ld_cmd) {
261 fprintf(stderr, "Error: Memory allocation failed for linker command\n");
262 remove(obj_file);
263 remove(asm_file);
264 free(obj_file);
265 free(asm_file);
266 ast_destroy(ast);
267 parser_destroy(parser);
268 lexer_destroy(lexer);
269 free(preprocessed_source);
270 preprocessor_destroy(preprocessor);
271 return 1;
272 }
273
274 // Use clang as linker with proper entry point for macOS
275 snprintf(ld_cmd, strlen(obj_file) + strlen(final_output) + 128,
276 "clang '%s' -o '%s' -Wl,-e,_main -nostartfiles", obj_file, final_output);
277
278 printf("DEBUG: Running linker: %s\n", ld_cmd);
279 int ld_result = system(ld_cmd);
280 free(ld_cmd);
281
282 if (ld_result != 0) {
283 fprintf(stderr, "Error: Linking failed (linker returned %d)\n", ld_result);
284 remove(obj_file);
285 remove(asm_file);
286 free(obj_file);
287 free(asm_file);
288 ast_destroy(ast);
289 parser_destroy(parser);
290 lexer_destroy(lexer);
291 free(preprocessed_source);
292 preprocessor_destroy(preprocessor);
293 return 1;
294 }
295
296 // Clean up temporary files (unless user wants to keep them)
297 if (!opts || !opts->keep_asm) {
298 remove(asm_file);
299 remove(obj_file);
300 }
301
302 printf("Compilation successful: %s -> %s\n", input_file, final_output);
303
304 // Cleanup
305 free(obj_file);
306 free(asm_file);
307 ast_destroy(ast);
308 parser_destroy(parser);
309 lexer_destroy(lexer);
310 free(preprocessed_source);
311 preprocessor_destroy(preprocessor);
312
313 return 0;
314}
315
316
317int main(int argc, char *argv[]) {
318 if (argc < 2) {
319 print_usage(argv[0]);
320 return 1;
321 }
322
323 CompilerOptions opts = {0};
324 opts.input_file = NULL;
325 opts.output_file = "a.out";
326 opts.verbose = false;
327 opts.debug = false;
328 opts.optimize = false;
329 opts.keep_asm = false;
330 opts.no_preprocess = false;
331 opts.preprocess_only = false;
332
333 // Parse command line arguments
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]);
337 return 0;
338 } else if (strcmp(argv[i], "--version") == 0) {
339 print_version();
340 return 0;
341 } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
342 opts.verbose = true;
343 } else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0) {
344 opts.debug = true;
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) {
354 if (i + 1 >= argc) {
355 fprintf(stderr, "Error: -o requires an output filename\n");
356 return 1;
357 }
358 opts.output_file = argv[++i];
359 }
360 else if (argv[i][0] == '-') {
361 fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]);
362 print_usage(argv[0]);
363 return 1;
364 } else {
365 if (opts.input_file) {
366 fprintf(stderr, "Error: Multiple input files specified\n");
367 return 1;
368 }
369 opts.input_file = argv[i];
370 }
371 }
372
373 if (!opts.input_file) {
374 fprintf(stderr, "Error: No input file specified\n");
375 print_usage(argv[0]);
376 return 1;
377 }
378
379 return compile_file(opts.input_file, opts.output_file, &opts);
380}
AST Node structure.
Definition types.h:333
CodeGenerator structure.
Definition types.h:528
Lexer structure.
Definition types.h:499
Parser structure.
Definition types.h:516