LCOV - code coverage report
Current view: top level - MinimalCC - compile.c (source / functions) Hit Total Coverage
Test: test.info Lines: 20 494 4.0 %
Date: 2022-06-06 21:08:49 Functions: 2 12 16.7 %
Branches: 7 213 3.3 %

           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                 :            : 

Generated by: LCOV version 1.14