KCC - Kayte C Compiler 1.10.0
A C compiler implementation with preprocessor, lexer, parser, and code generator
Loading...
Searching...
No Matches
utils.c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdarg.h>
5#include <sys/stat.h>
6#include "kcc.h"
7
8// Read entire file into memory
9char* read_file(const char* filename) {
10 if (!filename) {
11 return NULL;
12 }
13
14 FILE* file = fopen(filename, "r");
15 if (!file) {
16 fprintf(stderr, "Error: Could not open file '%s'\n", filename);
17 return NULL;
18 }
19
20 // Get file size
21 fseek(file, 0, SEEK_END);
22 long size = ftell(file);
23 fseek(file, 0, SEEK_SET);
24
25 if (size < 0) {
26 fprintf(stderr, "Error: Could not determine size of file '%s'\n", filename);
27 fclose(file);
28 return NULL;
29 }
30
31 // Allocate buffer
32 char* content = malloc(size + 1);
33 if (!content) {
34 fprintf(stderr, "Error: Memory allocation failed for file '%s'\n", filename);
35 fclose(file);
36 return NULL;
37 }
38
39 // Read file content
40 size_t bytes_read = fread(content, 1, size, file);
41 content[bytes_read] = '\0';
42
43 fclose(file);
44
45 if (bytes_read != (size_t)size) {
46 fprintf(stderr, "Warning: Expected to read %ld bytes from '%s', but read %zu\n",
47 size, filename, bytes_read);
48 }
49
50 return content;
51}
52
53// Safe memory allocation
54void* safe_malloc(size_t size) {
55 void* ptr = malloc(size);
56 if (!ptr) {
57 fprintf(stderr, "Memory allocation failed: %zu bytes\n", size);
58 exit(EXIT_FAILURE);
59 }
60 return ptr;
61}
62
63// Safe string copy
64bool safe_strcpy(char* dest, size_t dest_size, const char* src) {
65 if (!dest || !src || dest_size == 0) {
66 return false;
67 }
68
69 size_t src_len = strlen(src);
70 if (src_len >= dest_size) {
71 return false; // Not enough space
72 }
73
74 strcpy(dest, src);
75 return true;
76}
77
78// Safe string duplication
79char* safe_strdup(const char* src) {
80 if (!src) {
81 return NULL;
82 }
83
84 size_t len = strlen(src) + 1;
85 char* copy = safe_malloc(len);
86 strcpy(copy, src);
87 return copy;
88}
89
90// Convert token type to data type
91DataType token_to_data_type(TokenType type) {
92 switch (type) {
93 case TOKEN_VOID:
94 return TYPE_VOID;
95 case TOKEN_INT:
96 return TYPE_INT;
97 case TOKEN_FLOAT:
98 return TYPE_FLOAT;
99 case TOKEN_CHAR_KW:
100 return TYPE_CHAR;
101 default:
102 return TYPE_UNKNOWN;
103 }
104}
105
106// Convert data type to string
107const char* data_type_to_string(DataType type) {
108 switch (type) {
109 case TYPE_VOID:
110 return "void";
111 case TYPE_INT:
112 return "int";
113 case TYPE_FLOAT:
114 return "float";
115 case TYPE_CHAR:
116 return "char";
117 case TYPE_UNKNOWN:
118 default:
119 return "unknown";
120 }
121}
122
123// Convert AST node type to string
124const char* ast_node_type_to_string(ASTNodeType type) {
125 switch (type) {
126 case AST_FUNCTION_DECLARATION:
127 return "function_declaration";
128 case AST_VARIABLE_DECLARATION:
129 return "variable_declaration";
130 case AST_PARAMETER:
131 return "parameter";
132 case AST_COMPOUND_STATEMENT:
133 return "compound_statement";
134 case AST_EXPRESSION_STATEMENT:
135 return "expression_statement";
136 case AST_IF_STATEMENT:
137 return "if_statement";
138 case AST_WHILE_STATEMENT:
139 return "while_statement";
140 case AST_FOR_STATEMENT:
141 return "for_statement";
142 case AST_RETURN_STATEMENT:
143 return "return_statement";
144 case AST_BREAK_STATEMENT:
145 return "break_statement";
146 case AST_CONTINUE_STATEMENT:
147 return "continue_statement";
148 case AST_BINARY_OP:
149 return "binary_op";
150 case AST_UNARY_OP:
151 return "unary_op";
152 case AST_ASSIGNMENT:
153 return "assignment";
154 case AST_FUNCTION_CALL:
155 return "function_call";
156 case AST_IDENTIFIER:
157 return "identifier";
158 case AST_NUMBER_LITERAL:
159 return "number_literal";
160 case AST_STRING_LITERAL:
161 return "string_literal";
162 case AST_CHAR_LITERAL:
163 return "char_literal";
164 case AST_PROGRAM:
165 return "program";
166 default:
167 return "unknown";
168 }
169}
170
171// Note: token_type_to_string is defined in lexer.c to avoid duplicate symbols
172
173// Simple AST printer function
174void ast_print(ASTNode *node, int indent) {
175 if (!node) {
176 return;
177 }
178
179 // Print indentation
180 for (int i = 0; i < indent; i++) {
181 printf(" ");
182 }
183
184 printf("%s", ast_node_type_to_string(node->type));
185
186 // Print node-specific information
187 switch (node->type) {
188 case AST_IDENTIFIER:
189 if (node->data.identifier.name) {
190 printf(" (%s)", node->data.identifier.name);
191 }
192 break;
193 case AST_NUMBER_LITERAL:
194 printf(" (%d)", node->data.number.value);
195 break;
196 case AST_STRING_LITERAL:
197 if (node->data.string.value) {
198 printf(" (\"%s\")", node->data.string.value);
199 }
200 break;
201 case AST_FUNCTION_DECLARATION:
202 if (node->data.function_decl.name) {
203 printf(" (%s)", node->data.function_decl.name);
204 }
205 break;
206 case AST_VARIABLE_DECLARATION:
207 if (node->data.var_decl.name) {
208 printf(" (%s)", node->data.var_decl.name);
209 }
210 break;
211 case AST_BINARY_OP:
212 printf(" (%s)", token_type_to_string(node->data.binary_expr.operator));
213 break;
214 case AST_UNARY_OP:
215 printf(" (%s)", token_type_to_string(node->data.unary_expr.operator));
216 break;
217 default:
218 break;
219 }
220
221 printf("\n");
222
223 // Print children based on node type
224 switch (node->type) {
225 case AST_PROGRAM:
226 for (int i = 0; i < node->data.program.declaration_count; i++) {
227 ast_print(node->data.program.declarations[i], indent + 1);
228 }
229 break;
230 case AST_FUNCTION_DECLARATION:
231 for (int i = 0; i < node->data.function_decl.parameter_count; i++) {
232 ast_print(node->data.function_decl.parameters[i], indent + 1);
233 }
234 if (node->data.function_decl.body) {
235 ast_print(node->data.function_decl.body, indent + 1);
236 }
237 break;
238 case AST_COMPOUND_STATEMENT:
239 for (int i = 0; i < node->data.compound_stmt.statement_count; i++) {
240 ast_print(node->data.compound_stmt.statements[i], indent + 1);
241 }
242 break;
243 case AST_IF_STATEMENT:
244 if (node->data.if_stmt.condition) {
245 ast_print(node->data.if_stmt.condition, indent + 1);
246 }
247 if (node->data.if_stmt.then_stmt) {
248 ast_print(node->data.if_stmt.then_stmt, indent + 1);
249 }
250 if (node->data.if_stmt.else_stmt) {
251 ast_print(node->data.if_stmt.else_stmt, indent + 1);
252 }
253 break;
254 case AST_WHILE_STATEMENT:
255 if (node->data.while_stmt.condition) {
256 ast_print(node->data.while_stmt.condition, indent + 1);
257 }
258 if (node->data.while_stmt.body) {
259 ast_print(node->data.while_stmt.body, indent + 1);
260 }
261 break;
262 case AST_FOR_STATEMENT:
263 if (node->data.for_stmt.init) {
264 ast_print(node->data.for_stmt.init, indent + 1);
265 }
266 if (node->data.for_stmt.condition) {
267 ast_print(node->data.for_stmt.condition, indent + 1);
268 }
269 if (node->data.for_stmt.update) {
270 ast_print(node->data.for_stmt.update, indent + 1);
271 }
272 if (node->data.for_stmt.body) {
273 ast_print(node->data.for_stmt.body, indent + 1);
274 }
275 break;
276 case AST_BINARY_OP:
277 if (node->data.binary_expr.left) {
278 ast_print(node->data.binary_expr.left, indent + 1);
279 }
280 if (node->data.binary_expr.right) {
281 ast_print(node->data.binary_expr.right, indent + 1);
282 }
283 break;
284 case AST_UNARY_OP:
285 if (node->data.unary_expr.operand) {
286 ast_print(node->data.unary_expr.operand, indent + 1);
287 }
288 break;
289 case AST_ASSIGNMENT:
290 if (node->data.assignment.value) {
291 ast_print(node->data.assignment.value, indent + 1);
292 }
293 break;
294 case AST_FUNCTION_CALL:
295 for (int i = 0; i < node->data.call_expr.argument_count; i++) {
296 ast_print(node->data.call_expr.arguments[i], indent + 1);
297 }
298 break;
299 case AST_VARIABLE_DECLARATION:
300 if (node->data.var_decl.initializer) {
301 ast_print(node->data.var_decl.initializer, indent + 1);
302 }
303 break;
304 case AST_EXPRESSION_STATEMENT:
305 if (node->data.expression_stmt.expression) {
306 ast_print(node->data.expression_stmt.expression, indent + 1);
307 }
308 break;
309 case AST_RETURN_STATEMENT:
310 if (node->data.return_stmt.expression) {
311 ast_print(node->data.return_stmt.expression, indent + 1);
312 }
313 break;
314 default:
315 // No children to print for literals and other leaf nodes
316 break;
317 }
318}
AST Node structure.
Definition types.h:333
ASTNodeType
AST Node types.
Definition types.h:215
TokenType
Token types for lexical analysis.
Definition types.h:24
DataType
Data types supported by the compiler.
Definition types.h:193