Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <stdio.h>
3 : : #include <string.h>
4 : : #include "dictionary.h"
5 : : #include "expression.h"
6 : : #include "allocate.h"
7 : : #include "compile.h"
8 : :
9 : : #define MAX_SOURCEFILES 32
10 : :
11 : : int num_vars = 0;
12 : : int num_args = 0;
13 : : int num_strs = 0;
14 : : int current_line;
15 : : type return_type;
16 : : static char *program;
17 : : static char *program_beginning;
18 : : static char *program_pointer;
19 : : static char *source_files[MAX_SOURCEFILES] = {NULL};
20 : : static char **current_source_file;
21 : : static FILE *output_file;
22 : :
23 : : static int continue_label = -1;
24 : : static int break_label = -1;
25 : : static int loop_variables_size;
26 : :
27 : : char warning_message[256] = {0};
28 : : char error_message[256] = {0};
29 : :
30 : : enum cmd_argtype{
31 : : cmd_source_file,
32 : : cmd_output_file
33 : : };
34 : :
35 : 0 : static void print_line(){
36 : 0 : char *line_pointer;
37 : 0 : char *line_beginning;
38 : :
39 : 0 : line_pointer = program_pointer;
40 : 0 : fprintf(stderr, "Line %d in %s:\n", current_line, *current_source_file);
41 [ # # # # ]: 0 : while(line_pointer != program_beginning && line_pointer[-1] != '\n'){
42 : 0 : line_pointer--;
43 : : }
44 [ # # # # : 0 : while(*line_pointer && line_pointer != program_pointer && (*line_pointer == ' ' || *line_pointer == '\t')){
# # # # ]
45 : 0 : line_pointer++;
46 : : }
47 : 0 : line_beginning = line_pointer;
48 [ # # # # ]: 0 : while(*line_pointer && *line_pointer != '\n'){
49 : 0 : fputc(*line_pointer, stderr);
50 : 0 : line_pointer++;
51 : : }
52 : 0 : fputc('\n', stderr);
53 [ # # ]: 0 : while(line_beginning != program_pointer){
54 : 0 : fputc(' ', stderr);
55 : 0 : line_beginning++;
56 : : }
57 : 0 : fprintf(stderr, "^\n");
58 : 0 : }
59 : :
60 : 0 : void do_warning(){
61 [ # # ]: 0 : if(do_print){
62 : 0 : warning_message[255] = '\0';
63 : 0 : print_line();
64 : 0 : fprintf(stderr, "Warning: %s\n", warning_message);
65 : : }
66 : 0 : }
67 : :
68 : :
69 : 0 : void do_error(int status){
70 : 0 : fclose(output_file);
71 : 0 : error_message[255] = '\0';
72 : 0 : print_line();
73 : 0 : fprintf(stderr, "Error: %s\n", error_message);
74 : 0 : free(program);
75 : 0 : free_local_variables();
76 : 0 : free_global_variables();
77 : 0 : exit(status);
78 : : }
79 : :
80 : 0 : void compile_file(char *program, char *identifier_name, char *arguments, unsigned int identifier_length, unsigned int num_arguments, FILE *output_file){
81 : 0 : int current_line_temp;
82 : :
83 : 0 : program_pointer = program;
84 : 0 : program_beginning = program;
85 : 0 : fprintf(output_file, ".data\n");
86 : 0 : current_line = 1;
87 : 0 : skip_whitespace(&program_pointer);
88 : 0 : current_line_temp = current_line;
89 : 0 : compile_string_constants(program_pointer, output_file);
90 : 0 : current_line = current_line_temp;
91 : 0 : fprintf(output_file, ".text\n\n");
92 [ # # ]: 0 : while(*program_pointer){
93 : 0 : compile_function(&program_pointer, identifier_name, arguments, identifier_length, num_arguments, output_file);
94 : 0 : free_local_variables();
95 : 0 : skip_whitespace(&program_pointer);
96 : : }
97 : 0 : }
98 : :
99 : 0 : void compile_function(char **c, char *identifier_name, char *arguments, unsigned int identifier_length, unsigned int num_arguments, FILE *output_file){
100 : 0 : variable *var;
101 : 0 : variable *local_var;
102 : 0 : unsigned int current_argument = 0;
103 : :
104 : 0 : num_vars = 0;
105 : 0 : variables_size = 0;
106 : 0 : return_type = EMPTY_TYPE;
107 : 0 : parse_type(&return_type, c, identifier_name, arguments, identifier_length, num_arguments);
108 : :
109 [ # # ]: 0 : if(!identifier_name){
110 : 0 : snprintf(error_message, sizeof(error_message), "Expected identifier name");
111 : 0 : do_error(1);
112 : : }
113 : 0 : skip_whitespace(c);
114 [ # # ]: 0 : if(peek_type(&return_type) != type_function){
115 : 0 : skip_whitespace(c);
116 [ # # ]: 0 : if(**c != ';'){
117 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
118 : 0 : do_error(1);
119 : : }
120 : 0 : ++*c;
121 : 0 : var = read_dictionary(global_variables, identifier_name, 0);
122 [ # # ]: 0 : if(var){
123 : 0 : snprintf(error_message, sizeof(error_message), "Duplicate definitions of non-function data");
124 : 0 : do_error(1);
125 : : }
126 : 0 : var = malloc(sizeof(variable));
127 : 0 : var->var_type = return_type;
128 : 0 : var->varname = malloc(strlen(identifier_name) + 1);
129 : 0 : var->leave_as_address = 0;
130 : 0 : strcpy(var->varname, identifier_name);
131 : 0 : write_dictionary(&global_variables, var->varname, var, 0);
132 : 0 : fprintf(output_file, ".data\n.align 2\n%s:\n.space %d\n.text\n", identifier_name, align4(type_size(&return_type, 0)));
133 : : } else {
134 [ # # ]: 0 : if(!*identifier_name){
135 : 0 : snprintf(error_message, sizeof(error_message), "Expected function name");
136 : 0 : do_error(1);
137 : : }
138 : 0 : var = read_dictionary(global_variables, identifier_name, 0);
139 [ # # ]: 0 : if(!var){
140 : 0 : var = malloc(sizeof(variable));
141 : 0 : var->var_type = return_type;
142 : 0 : var->varname = malloc(strlen(identifier_name) + 1);
143 : 0 : var->leave_as_address = 1;
144 : 0 : strcpy(var->varname, identifier_name);
145 : 0 : write_dictionary(&global_variables, var->varname, var, 0);
146 : : } else {
147 [ # # ]: 0 : if(!types_equal(&(var->var_type), &return_type)){
148 : 0 : snprintf(error_message, sizeof(error_message), "Incompatible function definitions");
149 : 0 : do_error(1);
150 : : }
151 : : }
152 [ # # ]: 0 : if(**c != '{'){
153 [ # # ]: 0 : if(**c != ';'){
154 : 0 : snprintf(error_message, sizeof(error_message), "Expected '{' or ';' instead of '%c'", **c);
155 : 0 : do_error(1);
156 : : }
157 : 0 : ++*c;
158 : 0 : return;
159 : : }
160 : 0 : ++*c;
161 : 0 : local_variables[0] = malloc(sizeof(dictionary));
162 : 0 : *local_variables[0] = create_dictionary(NULL);
163 : 0 : fprintf(output_file, "\n.globl %s\n%s:\n", identifier_name, identifier_name);
164 : 0 : pop_type(&return_type);
165 [ # # ]: 0 : while(peek_type(&return_type) != type_returns){
166 [ # # ]: 0 : if(current_argument >= num_arguments){
167 : 0 : snprintf(error_message, sizeof(error_message), "Too many arguments!");
168 : 0 : do_error(1);
169 : : }
170 [ # # ]: 0 : if(read_dictionary(*local_variables[0], arguments, 0)){
171 : 0 : snprintf(error_message, sizeof(error_message), "Duplicate argument names");
172 : 0 : do_error(1);
173 : : }
174 : 0 : local_var = malloc(sizeof(variable));
175 : 0 : local_var->var_type = get_argument_type(&return_type);
176 : 0 : local_var->varname = malloc(strlen(arguments) + 1);
177 : 0 : strcpy(local_var->varname, arguments);
178 : 0 : local_var->stack_pos = variables_size;
179 : 0 : write_dictionary(local_variables[0], local_var->varname, local_var, 0);
180 : 0 : variables_size += 4;
181 : 0 : arguments += identifier_length;
182 : 0 : current_argument++;
183 : 0 : num_vars++;
184 : : }
185 : 0 : pop_type(&return_type);
186 [ # # ]: 0 : if(peek_type(&return_type) == type_function){
187 : 0 : snprintf(error_message, sizeof(error_message), "Function cannot return function");
188 : 0 : do_error(1);
189 : : }
190 : 0 : num_args = num_vars;
191 : 0 : compile_block(c, 1, output_file);
192 : 0 : ++*c;
193 : 0 : var->num_args = num_vars;
194 : 0 : fprintf(output_file, "lw $ra, %d($sp)\n", 4 + num_args*4);
195 : 0 : fprintf(output_file, "jr $ra\n");
196 : : }
197 : : }
198 : :
199 : 0 : static void free_var(void *v){
200 : 0 : variable *var;
201 : :
202 : 0 : var = (variable *) v;
203 : 0 : free(var->varname);
204 : 0 : free(var);
205 : 0 : }
206 : :
207 : 0 : void compile_block(char **c, unsigned char function_beginning, FILE *output_file){
208 : 0 : char *temp;
209 : 0 : unsigned char new_scope = 0;
210 : 0 : int variables_size_before;
211 : :
212 : 0 : variables_size_before = variables_size;
213 : 0 : skip_whitespace(c);
214 : 0 : temp = *c;
215 [ # # # # ]: 0 : if(function_beginning || parse_datatype(NULL, &temp)){
216 : 0 : new_scope = 1;
217 : 0 : current_scope++;
218 [ # # ]: 0 : if(current_scope >= MAX_SCOPE){
219 : 0 : snprintf(error_message, sizeof(error_message), "Scope depth too large");
220 : 0 : do_error(1);
221 : : }
222 [ # # ]: 0 : if(!local_variables[current_scope]){
223 : 0 : local_variables[current_scope] = malloc(sizeof(dictionary));
224 : 0 : *local_variables[current_scope] = create_dictionary(NULL);
225 : : }
226 : : }
227 : 0 : temp = *c;
228 [ # # ]: 0 : while(parse_datatype(NULL, &temp)){
229 : 0 : compile_variable_initializer(c);
230 : 0 : skip_whitespace(c);
231 : 0 : temp = *c;
232 : 0 : num_vars++;
233 : : }
234 : :
235 [ # # ]: 0 : if(new_scope){
236 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", -variables_size + variables_size_before);
237 : : }
238 : :
239 [ # # ]: 0 : while(**c != '}'){
240 : 0 : compile_statement(c, output_file);
241 : 0 : skip_whitespace(c);
242 : : }
243 : :
244 [ # # ]: 0 : if(new_scope){
245 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", variables_size - variables_size_before);
246 : 0 : free_dictionary(*local_variables[current_scope], free_var);
247 : 0 : free(local_variables[current_scope]);
248 : 0 : local_variables[current_scope] = NULL;
249 : 0 : current_scope--;
250 : 0 : variables_size = variables_size_before;
251 : : }
252 : 0 : }
253 : :
254 : 0 : void compile_statement(char **c, FILE *output_file){
255 : 0 : value expression_output;
256 : 0 : unsigned int label_num0;
257 : 0 : unsigned int label_num1;
258 : 0 : unsigned int label_num2;
259 : 0 : unsigned int label_num3;
260 : 0 : int prev_break_label;
261 : 0 : int prev_continue_label;
262 : 0 : int prev_loop_variables_size;
263 : :
264 : 0 : skip_whitespace(c);
265 [ # # # # ]: 0 : if(!strncmp(*c, "if", 2) && !alphanumeric((*c)[2])){
266 : 0 : *c += 2;
267 : 0 : skip_whitespace(c);
268 [ # # ]: 0 : if(**c != '('){
269 : 0 : snprintf(error_message, sizeof(error_message), "Expected '('");
270 : 0 : do_error(1);;
271 : : }
272 : 0 : ++*c;
273 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
274 : 0 : cast(&expression_output, INT_TYPE, 0, output_file);
275 : 0 : reset_stack_pos(&expression_output, output_file);
276 : 0 : label_num0 = num_labels;
277 : 0 : num_labels++;
278 [ # # ]: 0 : if(expression_output.data.type == data_register){
279 : 0 : fprintf(output_file, "beq $s%d, $zero, __L%d\n", expression_output.data.reg, label_num0);
280 [ # # ]: 0 : } else if(expression_output.data.type == data_stack){
281 : 0 : fprintf(output_file, "beq $t0, $zero, __L%d\n", label_num0);
282 : : }
283 : 0 : deallocate(expression_output.data);
284 : 0 : skip_whitespace(c);
285 [ # # ]: 0 : if(**c != ')'){
286 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
287 : 0 : do_error(1);
288 : : }
289 : 0 : ++*c;
290 : 0 : skip_whitespace(c);
291 : 0 : compile_statement(c, output_file);
292 : 0 : skip_whitespace(c);
293 [ # # # # ]: 0 : if(!strncmp(*c, "else", 2) && !alphanumeric((*c)[4])){
294 : 0 : *c += 4;
295 : 0 : label_num1 = num_labels;
296 : 0 : num_labels++;
297 : 0 : fprintf(output_file, "j __L%d\n", label_num1);
298 : 0 : fprintf(output_file, "\n__L%d:\n", label_num0);
299 : 0 : skip_whitespace(c);
300 : 0 : compile_statement(c, output_file);
301 : 0 : fprintf(output_file, "\n__L%d:\n", label_num1);
302 : : } else {
303 : 0 : fprintf(output_file, "\n__L%d:\n", label_num0);
304 : : }
305 [ # # # # ]: 0 : } else if(!strncmp(*c, "while", 5) && !alphanumeric((*c)[5])){
306 : 0 : *c += 5;
307 : 0 : skip_whitespace(c);
308 [ # # ]: 0 : if(**c != '('){
309 : 0 : snprintf(error_message, sizeof(error_message), "Expected '('");
310 : 0 : do_error(1);
311 : : }
312 : 0 : ++*c;
313 : 0 : label_num0 = num_labels;
314 : 0 : label_num1 = num_labels + 1;
315 : 0 : num_labels += 2;
316 : :
317 : 0 : prev_break_label = break_label;
318 : 0 : prev_continue_label = continue_label;
319 : 0 : prev_loop_variables_size = loop_variables_size;
320 : 0 : break_label = label_num1;
321 : 0 : continue_label = label_num0;
322 : 0 : loop_variables_size = variables_size;
323 : :
324 : 0 : fprintf(output_file, "\n__L%d:\n", label_num0);
325 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
326 : 0 : cast(&expression_output, INT_TYPE, 0, output_file);
327 : 0 : reset_stack_pos(&expression_output, output_file);
328 [ # # ]: 0 : if(expression_output.data.type == data_register){
329 : 0 : fprintf(output_file, "beq $s%d, $zero, __L%d\n", expression_output.data.reg, label_num1);
330 [ # # ]: 0 : } else if(expression_output.data.type == data_stack){
331 : 0 : fprintf(output_file, "beq $t0, $zero, __L%d\n", label_num1);
332 : : }
333 : 0 : deallocate(expression_output.data);
334 : 0 : skip_whitespace(c);
335 [ # # ]: 0 : if(**c != ')'){
336 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
337 : 0 : do_error(1);
338 : : }
339 : 0 : ++*c;
340 : 0 : skip_whitespace(c);
341 : 0 : compile_statement(c, output_file);
342 : 0 : fprintf(output_file, "j __L%d\n", label_num0);
343 : 0 : fprintf(output_file, "\n__L%d:\n", label_num1);
344 : :
345 : 0 : loop_variables_size = prev_loop_variables_size;
346 : 0 : break_label = prev_break_label;
347 : 0 : continue_label = prev_continue_label;
348 [ # # # # ]: 0 : } else if(!strncmp(*c, "for", 3) && !alphanumeric((*c)[3])){
349 : 0 : *c += 3;
350 : 0 : skip_whitespace(c);
351 [ # # ]: 0 : if(**c != '('){
352 : 0 : snprintf(error_message, sizeof(error_message), "Expected '('");
353 : 0 : do_error(1);
354 : : }
355 : 0 : ++*c;
356 : 0 : label_num0 = num_labels;
357 : 0 : label_num1 = num_labels + 1;
358 : 0 : label_num2 = num_labels + 2;
359 : 0 : label_num3 = num_labels + 3;
360 : 0 : num_labels += 4;
361 : :
362 : 0 : prev_break_label = break_label;
363 : 0 : prev_continue_label = continue_label;
364 : 0 : prev_loop_variables_size = loop_variables_size;
365 : 0 : break_label = label_num1;
366 : 0 : continue_label = label_num3;
367 : 0 : loop_variables_size = variables_size;
368 : :
369 : 0 : skip_whitespace(c);
370 [ # # ]: 0 : if(**c != ';'){
371 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
372 : 0 : reset_stack_pos(&expression_output, output_file);
373 : 0 : deallocate(expression_output.data);
374 : 0 : skip_whitespace(c);
375 [ # # ]: 0 : if(**c != ';'){
376 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
377 : 0 : do_error(1);
378 : : }
379 : : }
380 : 0 : ++*c;
381 : 0 : fprintf(output_file, "\n__L%d:\n", label_num0);
382 : 0 : skip_whitespace(c);
383 [ # # ]: 0 : if(**c != ';'){
384 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
385 : 0 : cast(&expression_output, INT_TYPE, 0, output_file);
386 : 0 : reset_stack_pos(&expression_output, output_file);
387 [ # # ]: 0 : if(expression_output.data.type == data_register){
388 : 0 : fprintf(output_file, "beq $s%d, $zero, __L%d\n", expression_output.data.reg, label_num1);
389 [ # # ]: 0 : } else if(expression_output.data.type == data_stack){
390 : 0 : fprintf(output_file, "beq $t0, $zero, __L%d\n", label_num1);
391 : : }
392 : 0 : deallocate(expression_output.data);
393 : 0 : skip_whitespace(c);
394 [ # # ]: 0 : if(**c != ';'){
395 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
396 : 0 : do_error(1);
397 : : }
398 : : }
399 : 0 : ++*c;
400 : 0 : fprintf(output_file, "j __L%d\n\n__L%d:\n", label_num2, label_num3);
401 : 0 : skip_whitespace(c);
402 [ # # ]: 0 : if(**c != ')'){
403 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
404 : 0 : reset_stack_pos(&expression_output, output_file);
405 : 0 : deallocate(expression_output.data);
406 : 0 : skip_whitespace(c);
407 [ # # ]: 0 : if(**c != ')'){
408 : 0 : snprintf(error_message, sizeof(error_message), "Expected '('");
409 : 0 : do_error(1);
410 : : }
411 : : }
412 : 0 : ++*c;
413 : 0 : fprintf(output_file, "j __L%d\n\n__L%d:\n", label_num0, label_num2);
414 : 0 : skip_whitespace(c);
415 : 0 : compile_statement(c, output_file);
416 : 0 : fprintf(output_file, "j __L%d\n\n__L%d:\n", label_num3, label_num1);
417 : :
418 : 0 : loop_variables_size = prev_loop_variables_size;
419 : 0 : break_label = prev_break_label;
420 : 0 : continue_label = prev_continue_label;
421 [ # # # # ]: 0 : } else if(!strncmp(*c, "return", 6) && !alphanumeric((*c)[6])){
422 : 0 : *c += 6;
423 : 0 : skip_whitespace(c);
424 [ # # ]: 0 : if(types_equal(&return_type, &VOID_TYPE)){
425 [ # # ]: 0 : if(**c != ';'){
426 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';' for return in void function");
427 : 0 : do_error(1);
428 : : }
429 : 0 : ++*c;
430 : : } else {
431 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
432 [ # # ]: 0 : if(**c != ';'){
433 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
434 : 0 : do_error(1);
435 : : }
436 : 0 : ++*c;
437 : 0 : cast(&expression_output, return_type, 1, output_file);
438 : 0 : reset_stack_pos(&expression_output, output_file);
439 [ # # ]: 0 : if(expression_output.data.type == data_register){
440 : 0 : fprintf(output_file, "sw $s%d, %d($sp)\n", expression_output.data.reg, variables_size);
441 [ # # ]: 0 : } else if(expression_output.data.type == data_stack){
442 : 0 : fprintf(output_file, "sw $t0, %d($sp)\n", variables_size);
443 : : }
444 : 0 : deallocate(expression_output.data);
445 : : }
446 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", variables_size - num_args*4);
447 : 0 : fprintf(output_file, "lw $ra, %d($sp)\n", 4 + num_args*4);
448 : 0 : fprintf(output_file, "jr $ra\n");
449 [ # # # # ]: 0 : } else if(!strncmp(*c, "break", 5) && !alphanumeric((*c)[5])){
450 : 0 : *c += 5;
451 : 0 : skip_whitespace(c);
452 [ # # ]: 0 : if(**c != ';'){
453 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';' after break");
454 : 0 : do_error(1);
455 : : }
456 [ # # ]: 0 : if(break_label < 0){
457 : 0 : snprintf(error_message, sizeof(error_message), "No loop to break out of");
458 : 0 : do_error(1);
459 : : }
460 [ # # ]: 0 : if(variables_size != loop_variables_size)
461 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", variables_size - loop_variables_size);
462 : 0 : fprintf(output_file, "j __L%d\n", break_label);
463 [ # # # # ]: 0 : } else if(!strncmp(*c, "continue", 8) && !alphanumeric((*c)[8])){
464 : 0 : *c += 8;
465 : 0 : skip_whitespace(c);
466 [ # # ]: 0 : if(**c != ';'){
467 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';' after continue");
468 : 0 : do_error(1);
469 : : }
470 [ # # ]: 0 : if(continue_label < 0){
471 : 0 : snprintf(error_message, sizeof(error_message), "No loop to continue in");
472 : 0 : do_error(1);
473 : : }
474 [ # # ]: 0 : if(variables_size != loop_variables_size)
475 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", variables_size - loop_variables_size);
476 : 0 : fprintf(output_file, "j __L%d\n", continue_label);
477 [ # # ]: 0 : } else if(**c == ';'){
478 : : //Empty statement, so pass
479 : 0 : ++*c;
480 [ # # ]: 0 : } else if(**c == '{'){
481 : 0 : ++*c;
482 : 0 : compile_block(c, 0, output_file);
483 [ # # ]: 0 : if(**c != '}'){
484 : 0 : snprintf(error_message, sizeof(error_message), "Expected '}'");
485 : 0 : do_error(1);
486 : : }
487 : 0 : ++*c;
488 : : } else {
489 : 0 : compile_root_expression(&expression_output, c, 1, 0, output_file);
490 : 0 : reset_stack_pos(&expression_output, output_file);
491 : 0 : deallocate(expression_output.data);
492 [ # # ]: 0 : if(**c == ';'){
493 : 0 : ++*c;
494 : : } else {
495 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
496 : 0 : do_error(1);
497 : : }
498 : : }
499 : 0 : }
500 : :
501 : 0 : void place_string_constant(char **c, FILE *output_file){
502 : 0 : unsigned char ignore_next = 0;
503 : 0 : char *beginning;
504 : :
505 : 0 : beginning = *c;
506 : :
507 [ # # # # : 0 : while(**c && (**c != '"' || ignore_next)){
# # ]
508 : 0 : fprintf(output_file, "%c", **c);
509 [ # # ]: 0 : if(**c == '\\'){
510 : 0 : ignore_next = 1;
511 : : } else {
512 : 0 : ignore_next = 0;
513 : : }
514 [ # # ]: 0 : if(**c == '\n'){
515 : 0 : program_pointer = *c;
516 : 0 : snprintf(error_message, sizeof(error_message), "Expected closing '\"'");
517 : 0 : do_error(1);
518 : : }
519 : 0 : ++*c;
520 : : }
521 : :
522 [ # # ]: 0 : if(!**c){
523 : 0 : program_pointer = beginning;
524 : 0 : snprintf(error_message, sizeof(error_message), "Expected closing '\"'");
525 : 0 : do_error(1);
526 : : }
527 : 0 : fprintf(output_file, "\"");
528 : 0 : ++*c;
529 : 0 : }
530 : :
531 : 0 : void compile_string_constants(char *c, FILE *output_file){
532 : 0 : unsigned char ignore;
533 : :
534 : 0 : ignore = 0;
535 : 0 : skip_whitespace(&c);
536 [ # # ]: 0 : while(*c){
537 [ # # # # ]: 0 : if(ignore || *c != '"'){
538 : 0 : ignore = 0;
539 [ # # # # ]: 0 : if(*c == '\\' || *c == '\''){
540 : 0 : ignore = 1;
541 [ # # ]: 0 : } else if(*c == '\n'){
542 : 0 : current_line++;
543 : : }
544 : 0 : c++;
545 : : } else {
546 : 0 : c++;
547 : 0 : fprintf(output_file, "__str%d:\n", num_strs);
548 : 0 : fprintf(output_file, ".asciiz \"");
549 : 0 : place_string_constant(&c, output_file);
550 : 0 : fprintf(output_file, "\n");
551 : 0 : num_strs++;
552 : : }
553 : 0 : skip_whitespace(&c);
554 : : }
555 : 0 : }
556 : :
557 : 349891 : void parse_arguments(int argc, char **argv, char *filenames[], unsigned int num_filenames, char **output_filename){
558 : 349891 : unsigned int current_arg;
559 : 349891 : unsigned int current_filename = 0;
560 : 349891 : enum cmd_argtype argtype = cmd_source_file;
561 : :
562 [ + - ]: 349891 : for(current_arg = 1; current_arg < argc; current_arg++){
563 [ + - - ]: 349891 : switch(argtype){
564 : 349891 : case cmd_source_file:
565 [ + - ]: 349891 : if(argv[current_arg][0] == '-'){
566 [ + - - + : 349891 : if(argv[current_arg][1] == 'h' || (argv[current_arg][1] == '-' && argv[current_arg][2] == 'h')){//Display help message
- - ]
567 : 0 : printf("Arguments:\n-h --help Displays this help message\n-o Specify output file\n\nTo compile:\nmcc [SOURCE1] [SOURCE2] [SOURCE3] ... -o [OUTPUT_FILE]\n");
568 : 0 : exit(1);
569 [ + - ]: 349891 : } else if(argv[current_arg][1] == 'o'){
570 : 0 : argtype = cmd_output_file;
571 : : } else {
572 : 349891 : fprintf(stderr, "Unrecognized option '%s'\n", argv[current_arg]);
573 : 349891 : exit(1);
574 : : }
575 : : } else {
576 [ # # ]: 0 : if(current_filename < num_filenames){
577 : 0 : filenames[current_filename] = argv[current_arg];
578 : 0 : current_filename++;
579 : : } else {
580 : 0 : fprintf(stderr, "Too many source files\n");
581 : 0 : exit(1);
582 : : }
583 : : }
584 : 0 : break;
585 : 0 : case cmd_output_file:
586 [ # # ]: 0 : if(argv[current_arg][0] == '-'){
587 : 0 : fprintf(stderr, "Expected output file name after '-o'\n");
588 : 0 : exit(1);
589 : : }
590 : 0 : *output_filename = argv[current_arg];
591 : 0 : argtype = cmd_source_file;
592 : 0 : break;
593 : : }
594 : 0 : }
595 : 0 : }
596 : :
597 : 349891 : int main(int argc, char **argv){
598 : 349891 : char identifier_name[32];
599 : 349891 : char arguments[32*32];
600 : 349891 : FILE *fp;
601 : 349891 : unsigned int file_size;
602 : 349891 : char *output_filename = NULL;
603 : :
604 [ - + ]: 349891 : if(argc < 2){
605 : 0 : printf("Minimal C Compiler for MIPS\nby Ben Jones\n2/29/2020\n");
606 : 0 : return 0;
607 : : }
608 : 349891 : parse_arguments(argc, argv, source_files, MAX_SOURCEFILES - 1, &output_filename);
609 [ # # ]: 0 : if(!output_filename){
610 : 0 : output_filename = "a.s";
611 : : }
612 : 0 : output_file = fopen(output_filename, "w");
613 [ # # ]: 0 : if(!output_file){
614 : 0 : fprintf(stderr, "Could not open file '%s' for writing\n", output_filename);
615 : 0 : exit(1);
616 : : }
617 : 0 : global_variables = create_dictionary(NULL);
618 : 0 : current_source_file = source_files;
619 : 0 : current_scope = -1;
620 : 0 : memset(local_variables, 0, sizeof(local_variables));
621 [ # # ]: 0 : while(*current_source_file){
622 : 0 : fp = fopen(*current_source_file, "rb");
623 [ # # ]: 0 : if(!fp){
624 : 0 : fprintf(stderr, "Could not open file '%s' for reading\n", *current_source_file);
625 : 0 : free_global_variables();
626 : 0 : exit(1);
627 : : }
628 : 0 : fseek(fp, 0, SEEK_END);
629 : 0 : file_size = ftell(fp);
630 : 0 : rewind(fp);
631 : 0 : program = calloc(file_size + 1, sizeof(char));
632 [ # # # # ]: 0 : if(fread(program, sizeof(char), file_size, fp) < file_size){
633 : 0 : fclose(fp);
634 : 0 : fprintf(stderr, "Failed to read file '%s'\n", *current_source_file);
635 : 0 : free_global_variables();
636 : 0 : exit(1);
637 : : }
638 : 0 : fclose(fp);
639 : 0 : initialize_register_list();
640 : 0 : compile_file(program, identifier_name, arguments, 32, 32, output_file);
641 : 0 : free(program);
642 : 0 : current_source_file++;
643 : : }
644 : 0 : fclose(output_file);
645 : 0 : free_global_variables();
646 : :
647 : 0 : return 0;
648 : : }
649 : :
|