#include #include #include #include #include "dictionary.h" #include "expression.h" #include "compile.h" int current_scope; dictionary *local_variables[MAX_SCOPE]; dictionary global_variables; unsigned int num_labels = 0; unsigned int current_string = 0; static unsigned int order_of_operations[] = {0, 9, 9, 10, 10, 1, 7, 7, 7, 7, 6, 6, 5, 4, 9, 3, 2, 8, 8}; unsigned char do_print; //Wrapper to fprintf to control whether we actually write to a file void fileprint(FILE *fp, const char *format, ...){ va_list ap; if(do_print){ va_start(ap, format); vfprintf(fp, format, ap); va_end(ap); } } void operation_none_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ snprintf(error_message, sizeof(error_message), "Unrecognized operation"); do_error(1); } void operation_add_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ value *pointer_value; char *integer_reg; unsigned int pointer_size; if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){ snprintf(error_message, sizeof(error_message), "Addition of function type is undefined"); do_error(1); } if(peek_type(&(value_a->data_type)) == type_pointer){ if(peek_type(&(value_b->data_type)) == type_pointer){ snprintf(warning_message, sizeof(warning_message), "Adding two pointers together. Treating them as integers instead"); do_warning(); fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = value_a->data_type; return; } pointer_value = value_a; integer_reg = reg_b; } else { if(peek_type(&(value_b->data_type)) == type_pointer){ pointer_value = value_b; integer_reg = reg_a; } else { fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; return; } } pointer_size = type_size(&(pointer_value->data_type), 1); if(pointer_size == 4){ fileprint(output_file, "sll %s, %s, 2\n", integer_reg, integer_reg); } else if(pointer_size != 1){ fileprint(output_file, "li $t2, %d\n", pointer_size); fileprint(output_file, "mult %s, $t2\n", integer_reg); fileprint(output_file, "mflo %s\n", integer_reg); } fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = pointer_value->data_type; } void operation_subtract_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ type *pointer_type; type *pointer_type2; value *pointer_value; char *integer_reg; unsigned int pointer_size; if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){ snprintf(error_message, sizeof(error_message), "Subtraction of function type is undefined"); do_error(1); } if(peek_type(&(value_a->data_type)) == type_pointer){ if(peek_type(&(value_b->data_type)) == type_pointer){ pointer_type = &(value_a->data_type); pointer_type2 = &(value_b->data_type); if(!types_equal(pointer_type, pointer_type2)){ snprintf(error_message, sizeof(error_message), "Cannot subtract pointers to different types"); do_error(1); } fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b); if(type_size(pointer_type, 1) == 4){ fileprint(output_file, "sra %s, %s, 2\n", reg_a, reg_a); } else if(type_size(pointer_type, 1) != 1){ fileprint(output_file, "li $t2, %d\n", type_size(pointer_type, 1)); fileprint(output_file, "div %s, $t2\n", reg_a); fileprint(output_file, "mflo %s\n", reg_a); } *output_type = INT_TYPE; return; } pointer_value = value_a; integer_reg = reg_b; } else { if(peek_type(&(value_b->data_type)) == type_pointer){ pointer_value = value_b; integer_reg = reg_a; } else { fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; return; } } pointer_size = type_size(&(pointer_value->data_type), 1); if(pointer_size == 4){ fileprint(output_file, "sll %s, %s, 2\n", integer_reg, integer_reg); } else if(pointer_size != 1){ fileprint(output_file, "li $t2, %d\n", pointer_size); fileprint(output_file, "mult %s, $t2\n", integer_reg); fileprint(output_file, "mflo %s\n", integer_reg); } fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = pointer_value->data_type; } void operation_multiply_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot multiply non-int types"); do_error(1); } fileprint(output_file, "mult %s, %s\n", reg_a, reg_b); fileprint(output_file, "mflo %s\n", reg_a); *output_type = INT_TYPE; } void operation_divide_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot divide non-int types"); do_error(1); } fileprint(output_file, "div %s, %s\n", reg_a, reg_b); fileprint(output_file, "mflo %s\n", reg_a); *output_type = INT_TYPE; } void operation_modulo_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot modulo non-int types"); do_error(1); } fileprint(output_file, "div %s, %s\n", reg_a, reg_b); fileprint(output_file, "mfhi %s\n", reg_a); *output_type = INT_TYPE; } void operation_assign_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if(!value_a->is_reference){ snprintf(error_message, sizeof(error_message), "Cannot assign to r-value"); do_error(1); } pop_type(&(value_a->data_type)); if(peek_type(&(value_a->data_type)) == type_function){ snprintf(error_message, sizeof(error_message), "Cannot assign to function"); do_error(1); } if(type_size(&(value_a->data_type), 0) == 4){ fileprint(output_file, "sw %s, 0(%s)\n", reg_b, reg_a); } else if(type_size(&(value_a->data_type), 0) == 1){ fileprint(output_file, "sb %s, 0(%s)\n", reg_b, reg_a); } fileprint(output_file, "move %s, %s\n", reg_a, reg_b); *output_type = value_b->data_type; } void operation_less_than_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '<'"); do_error(1); } fileprint(output_file, "slt %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void operation_greater_than_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '>'"); do_error(1); } fileprint(output_file, "sgt %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void operation_less_than_or_equal_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '<='"); do_error(1); } fileprint(output_file, "sgt %s, %s, %s\n", reg_a, reg_a, reg_b); fileprint(output_file, "seq %s, %s, $zero\n", reg_a, reg_a); *output_type = INT_TYPE; } void operation_greater_than_or_equal_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '>='"); do_error(1); } fileprint(output_file, "slt %s, %s, %s\n", reg_a, reg_a, reg_b); fileprint(output_file, "seq %s, %s, $zero\n", reg_a, reg_a); *output_type = INT_TYPE; } void operation_equals_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){ snprintf(error_message, sizeof(error_message), "Cannot compare function types"); do_error(1); } if(peek_type(&(value_a->data_type)) == type_pointer){ if(peek_type(&(value_b->data_type)) == type_pointer){ pop_type(&(value_a->data_type)); pop_type(&(value_b->data_type)); if(!types_equal(&(value_a->data_type), &(value_b->data_type))){ snprintf(warning_message, sizeof(warning_message), "Comparing incompatible data types"); do_warning(); } fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } else { snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types"); do_warning(); fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } } else { if(peek_type(&(value_b->data_type)) == type_pointer){ snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types"); do_warning(); } fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } } void operation_not_equals_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){ snprintf(error_message, sizeof(error_message), "Cannot compare function types"); do_error(1); } if(peek_type(&(value_a->data_type)) == type_pointer){ if(peek_type(&(value_b->data_type)) == type_pointer){ pop_type(&(value_a->data_type)); pop_type(&(value_b->data_type)); if(!types_equal(&(value_a->data_type), &(value_b->data_type))){ snprintf(warning_message, sizeof(warning_message), "Comparing incompatible data types"); do_warning(); } fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } else { snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types"); do_warning(); fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } } else { if(peek_type(&(value_b->data_type)) == type_pointer){ snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types"); do_warning(); } fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } } void operation_and_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot '&' non-int types"); do_error(1); } fileprint(output_file, "and %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void operation_or_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot '|' non-int types"); do_error(1); } fileprint(output_file, "or %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void operation_shift_left_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot '<<' non-arithmetic types"); do_error(1); } fileprint(output_file, "sllv %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void operation_shift_right_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){ if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){ snprintf(error_message, sizeof(error_message), "Cannot '>>' non-arithmetic types"); do_error(1); } fileprint(output_file, "srav %s, %s, %s\n", reg_a, reg_a, reg_b); *output_type = INT_TYPE; } void (*operation_functions[])(char *, char *, value *, value *, FILE *, type *) = {operation_none_func, operation_add_func, operation_subtract_func, operation_multiply_func, operation_divide_func, operation_assign_func, operation_less_than_func, operation_greater_than_func, operation_less_than_or_equal_func, operation_greater_than_or_equal_func, operation_equals_func, operation_not_equals_func, operation_and_func, operation_or_func, operation_modulo_func, operation_none_func, operation_none_func, operation_shift_left_func, operation_shift_right_func}; int type_size(type *t, unsigned int start_entry){ uint64_t d0; uint64_t d1; uint64_t d2; unsigned int index; unsigned int current_entry = 0; int entry; int output = 1; d0 = t->d0; d1 = t->d1; d2 = t->d2; index = t->current_index; while(1){ entry = 0; if(d0&1){ entry |= 1; } if(d1&1){ entry |= 2; } if(d2&1){ entry |= 4; } if(current_entry >= start_entry){ switch(entry){ case type_void: return output*VOID_SIZE; case type_int: return output*INT_SIZE; case type_char: return output*CHAR_SIZE; case type_pointer: return output*POINTER_SIZE; case type_function: return output*POINTER_SIZE; case type_list: index--; output *= t->list_indicies[index]; break; default: return 0; } } else if(entry == type_list){ index--; } d0 >>= 1; d1 >>= 1; d2 >>= 1; current_entry++; } } static void free_var(void *v){ variable *var; var = (variable *) v; free(var->varname); free(var); } void free_global_variables(){ free_dictionary(global_variables, free_var); } void free_local_variables(){ int i; for(i = current_scope; i >= 0; i--){ if(local_variables[i]){ free_dictionary(*local_variables[i], free_var); free(local_variables[i]); local_variables[i] = NULL; } } variables_size = 0; } static int var_stack_position(variable *var){ return saved_stack_size + variables_size - var->stack_pos - 4; } unsigned int align4(unsigned int size){ unsigned int remainder; remainder = size%4; if(remainder){ size += 4 - remainder; } return size; } void compile_variable_initializer(char **c){ variable *var; char varname_buf[32]; type vartype; vartype = EMPTY_TYPE; parse_type(&vartype, c, varname_buf, NULL, 32, 0); var = malloc(sizeof(variable)); var->varname = malloc(sizeof(char)*32); var->var_type = vartype; strcpy(var->varname, varname_buf); variables_size += align4(type_size(&(var->var_type), 0)); var->stack_pos = variables_size - 4; if(read_dictionary(*local_variables[current_scope], var->varname, 0)){ free(var->varname); free(var); snprintf(error_message, sizeof(error_message), "Duplicate local variable definition"); do_error(1); } write_dictionary(local_variables[current_scope], var->varname, var, 0); skip_whitespace(c); if(**c != ';'){ snprintf(error_message, sizeof(error_message), "Expected ';'"); do_error(1); } ++*c; } void compile_integer(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ int int_value; output->data = allocate(force_stack); int_value = strtol(*c, c, 0); if(output->data.type == data_register){ fileprint(output_file, "li $s%d, %d\n", output->data.reg, int_value); } else if(output->data.type == data_stack){ fileprint(output_file, "li $t0, %d\nsw $t0, %d($sp)\n", int_value, get_stack_pos(output->data)); } output->data_type = INT_TYPE; output->is_reference = 0; } static void compile_local_variable(value *output, variable *var, unsigned char dereference, unsigned char force_stack, FILE *output_file){ data_entry data; type data_type; data_type = var->var_type; data = allocate(force_stack); output->data_type = data_type; output->data = data; if(dereference){ if(peek_type(&(var->var_type)) == type_list){ if(data.type == data_register){ fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var)); } else if(data.type == data_stack){ fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var)); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } pop_type(&(output->data_type)); output->data_type.current_index--; add_type_entry(&(output->data_type), type_pointer); } else { if(data.type == data_register){ switch(type_size(&data_type, 0)){ case 1: fileprint(output_file, "lb $s%d, %d($sp)\n", data.reg, var_stack_position(var)); break; case 4: fileprint(output_file, "lw $s%d, %d($sp)\n", data.reg, var_stack_position(var)); break; } } else if(data.type == data_stack){ switch(type_size(&data_type, 0)){ case 1: fileprint(output_file, "lb $t0, %d($sp)\n", var_stack_position(var)); fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(data)); break; case 4: fileprint(output_file, "lw $t0, %d($sp)\n", var_stack_position(var)); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); break; } } } } else { if(peek_type(&(var->var_type)) == type_list){ if(data.type == data_register){ fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var)); } else if(data.type == data_stack){ fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var)); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } } else { if(data.type == data_register){ fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var)); } else if(data.type == data_stack){ fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var)); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } } add_type_entry(&(output->data_type), type_pointer); } output->is_reference = !dereference; } static void compile_global_variable(value *output, variable *var, unsigned char dereference, unsigned char force_stack, FILE *output_file){ data_entry data; type data_type; data_type = var->var_type; data = allocate(force_stack); if(data.type == data_register){ fileprint(output_file, "la $s%d, %s\n", data.reg, var->varname); } else { fileprint(output_file, "la $t0, %s\n", var->varname); } output->data = data; output->is_reference = !dereference; if(dereference && !var->leave_as_address){ if(peek_type(&data_type) == type_list){ pop_type(&data_type); data_type.current_index--; add_type_entry(&data_type, type_pointer); if(data.type == data_stack){ fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } } else { if(data.type == data_register){ fileprint(output_file, "lw $s%d, 0($s%d)\n", data.reg, data.reg); } else if(data.type == data_stack){ fileprint(output_file, "lw $t0, 0($t0)\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } } } else { add_type_entry(&data_type, type_pointer); if(data.type == data_stack){ fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data)); } } output->data_type = data_type; } void compile_variable(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ char *start; char varname[32] = {0}; unsigned int varname_length = 0; variable *var; int i; skip_whitespace(c); start = *c; while(alphanumeric(**c) && varname_length < 31){ ++*c; varname_length++; } memcpy(varname, start, varname_length); varname[31] = '\0'; for(i = current_scope; i >= 0; i--){ var = read_dictionary(*local_variables[i], varname, 0); if(var){ break; } } if(!var){ var = read_dictionary(global_variables, varname, 0); if(!var){ snprintf(error_message, sizeof(error_message), "Unrecognized variable '%s'", varname); do_error(1); } compile_global_variable(output, var, dereference, force_stack, output_file); } else { compile_local_variable(output, var, dereference, force_stack, output_file); } } void compile_expression(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file); void cast(value *v, type t, unsigned char do_warn, FILE *output_file){ type t_copy; type_entry entry1; type_entry entry2; if(types_equal(&(v->data_type), &VOID_TYPE) && !types_equal(&t, &VOID_TYPE)){ snprintf(error_message, sizeof(error_message), "Can't cast void type to non-void type"); do_error(1); } if(peek_type(&t) == type_list){ snprintf(error_message, sizeof(error_message), "Can't cast to an array"); do_error(1); } if(type_size(&(v->data_type), 0) == 4 && type_size(&t, 0) == 1){ if(v->data.type == data_register){ fileprint(output_file, "sll $s%d, $s%d, 24\n", v->data.reg, v->data.reg); fileprint(output_file, "sra $s%d, $s%d, 24\n", v->data.reg, v->data.reg); } else if(v->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data)); fileprint(output_file, "sll $t0, $t0, 24\n"); fileprint(output_file, "sra $t0, $t0, 24\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } } else if(type_size(&(v->data_type), 0) == 1 && type_size(&t, 0) == 4){ if(v->data.type == data_stack){ fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data)); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } } t_copy = t; entry1 = pop_type(&t_copy); entry2 = pop_type(&(v->data_type)); if((entry1 == type_pointer) != (entry2 == type_pointer) && do_warn){ snprintf(warning_message, sizeof(warning_message), "Casting between pointer and non-pointer types"); do_warning(); } else if(entry1 == type_pointer && !types_equal(&t_copy, &(v->data_type)) && !types_equal(&t_copy, &VOID_TYPE) && !types_equal(&(v->data_type), &VOID_TYPE) && do_warn){ snprintf(warning_message, sizeof(warning_message), "Casting between incompatible pointer types"); do_warning(); } v->data_type = t; } void compile_dereference(value *v, FILE *output_file){ type data_type; data_type = v->data_type; if(pop_type(&data_type) != type_pointer){ snprintf(error_message, sizeof(error_message), "Cannot dereference non-pointer type"); do_error(1); } if(peek_type(&data_type) == type_void){ snprintf(error_message, sizeof(error_message), "Cannot dereference void pointer"); do_error(1); } if(peek_type(&data_type) == type_list){ pop_type(&data_type); data_type.current_index--; add_type_entry(&data_type, type_pointer); } else if(peek_type(&data_type) != type_function){ if(v->data.type == data_register){ if(type_size(&data_type, 0) == 1){ fileprint(output_file, "lb $s%d, 0($s%d)\n", v->data.reg, v->data.reg); } else if(type_size(&data_type, 0) == 4){ fileprint(output_file, "lw $s%d, 0($s%d)\n", v->data.reg, v->data.reg); } } else if(v->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data)); if(type_size(&data_type, 0) == 1){ fileprint(output_file, "lb $t0, 0($t0)\n"); fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(v->data)); } else if(type_size(&data_type, 0) == 4){ fileprint(output_file, "lw $t0, 0($t0)\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } } } v->data_type = data_type; v->is_reference = 0; } void compile_function_call(char **c, value *func, FILE *output_file){ reg_list reg_state; data_entry return_data; data_entry return_address_data; type current_argument_type; value current_argument_value; unsigned int label_num; int func_stack_pos = 0; int any_args = 0; if(peek_type(&(func->data_type)) == type_pointer){ pop_type(&(func->data_type)); } if(pop_type(&(func->data_type)) != type_function){ snprintf(error_message, sizeof(error_message), "Can't call non-function type"); do_error(1); } label_num = num_labels; num_labels++; reg_state = push_registers(output_file); if(func->data.type == data_register){ func_stack_pos = get_reg_stack_pos(reg_state, func->data.reg); } return_address_data = allocate(1); return_data = allocate(1); fileprint(output_file, "la $t0, __L%d\n", label_num); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(return_address_data)); if(peek_type(&(func->data_type)) == type_returns){ skip_whitespace(c); if(**c != ')'){ snprintf(error_message, sizeof(error_message), "Expected ')'"); do_error(1); } ++*c; } while(peek_type(&(func->data_type)) != type_returns){ any_args = 1; current_argument_type = get_argument_type(&(func->data_type)); compile_expression(¤t_argument_value, c, 1, 1, output_file); if(**c != ',' && peek_type(&(func->data_type)) != type_returns){ snprintf(error_message, sizeof(error_message), "Expected ','"); do_error(1); } else if(**c != ')' && peek_type(&(func->data_type)) == type_returns){ snprintf(error_message, sizeof(error_message), "Expected ')'"); do_error(1); } ++*c; cast(¤t_argument_value, current_argument_type, 1, output_file); } pop_type(&(func->data_type)); if(func->data.type == data_register){ fileprint(output_file, "lw $t0, %d($sp)\n", func_stack_pos); if(any_args) fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(current_argument_value.data)); else fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(return_data)); fileprint(output_file, "jr $t0\n\n"); } else if(func->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(func->data)); if(any_args) fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(current_argument_value.data)); else fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(return_data)); fileprint(output_file, "jr $t0\n\n"); } fileprint(output_file, "__L%d:\n", label_num); if(any_args) fileprint(output_file, "addi $sp, $sp, %d\n", -get_stack_pos(current_argument_value.data)); else fileprint(output_file, "addi $sp, $sp, %d\n", -get_stack_pos(return_data)); fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(return_data)); deallocate(return_data); deallocate(return_address_data); pull_registers(reg_state, output_file); if(func->data.type == data_register){ fileprint(output_file, "move $s%d, $t0\n", func->data.reg); } else if(func->data.type == data_stack){ fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(func->data)); } } void compile_list_index(char **c, value *address, unsigned char dereference, FILE *output_file){ value index; type address_type; address_type = address->data_type; if(pop_type(&address_type) != type_pointer){ snprintf(error_message, sizeof(error_message), "Cannot address non-pointer type"); do_error(1); } ++*c; compile_expression(&index, c, 1, 0, output_file); if(**c != ']'){ snprintf(error_message, sizeof(error_message), "Expected closing ']'"); do_error(1); } ++*c; cast(&index, INT_TYPE, 1, output_file); if(index.data.type == data_register){ if(type_size(&address_type, 0) == 4){ fileprint(output_file, "sll $s%d, $s%d, 2\n", index.data.reg, index.data.reg); } else if(type_size(&address_type, 0) != 1){ fileprint(output_file, "li $t0, %d\n", (int) type_size(&address_type, 0)); fileprint(output_file, "mult $s%d, $t0\n", index.data.reg); fileprint(output_file, "mflo $s%d\n", index.data.reg); } if(address->data.type == data_register){ fileprint(output_file, "add $s%d, $s%d, $s%d\n", address->data.reg, address->data.reg, index.data.reg); if(dereference && peek_type(&address_type) != type_list){ if(type_size(&address_type, 0) == 4){ fileprint(output_file, "lw $s%d, 0($s%d)\n", address->data.reg, address->data.reg); } else if(type_size(&address_type, 0) == 1){ fileprint(output_file, "lb $s%d, 0($s%d)\n", address->data.reg, address->data.reg); } else { snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size"); do_error(1); } } } else if(address->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(address->data)); fileprint(output_file, "add $t0, $t0, $s%d\n", index.data.reg); if(dereference && peek_type(&address_type) != type_list){ if(type_size(&address_type, 0) == 4){ fileprint(output_file, "lw $t0, 0($t0)\n"); } else if(type_size(&address_type, 0) == 1){ fileprint(output_file, "lb $t0, 0($t0)\n"); } else { snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size"); do_error(1); } } fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(address->data)); } } else if(index.data.type == data_stack){ fileprint(output_file, "lw $t1, %d($sp)\n", get_stack_pos(index.data)); if(type_size(&address_type, 0) == 4){ fileprint(output_file, "sll $t1, $t1, 2\n"); } else if(type_size(&address_type, 0) != 1){ fileprint(output_file, "li $t0, %d\n", (int) type_size(&address_type, 0)); fileprint(output_file, "mult $t1, $t0\n"); fileprint(output_file, "mflo $t1\n"); } if(address->data.type == data_register){ fileprint(output_file, "add $s%d, $s%d, $t1\n", address->data.reg, address->data.reg); if(dereference && peek_type(&address_type) != type_list){ if(type_size(&address_type, 0) == 4){ fileprint(output_file, "lw $s%d, 0($s%d)\n", address->data.reg, address->data.reg); } else if(type_size(&address_type, 0) == 1){ fileprint(output_file, "lb $s%d, 0($s%d)\n", address->data.reg, address->data.reg); } } } else if(address->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(address->data)); fileprint(output_file, "add $t0, $t0, $t1\n"); if(dereference && peek_type(&address_type) != type_list){ if(type_size(&address_type, 0) == 4){ fileprint(output_file, "lw $t0, 0($t0)\n"); } else if(type_size(&address_type, 0) == 1){ fileprint(output_file, "lb $t0, 0($t0)\n"); } } fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(address->data)); } } deallocate(index.data); if(dereference){ pop_type(&(address->data_type)); if(peek_type(&(address->data_type)) == type_list){ pop_type(&(address->data_type)); address->data_type.current_index--; add_type_entry(&(address->data_type), type_pointer); } } address->is_reference = !dereference; } void match_brackets(char **c); void skip_string(char **c){ while(**c && **c != '\"'){ if(**c == '\\'){ *c += 2; } else { ++*c; } } if(**c){ ++*c; } } void match_parentheses(char **c){ while(**c && **c != ')' && **c != ']'){ if(**c == '"'){ ++*c; skip_string(c); skip_whitespace(c); continue; } if(**c == '('){ ++*c; match_parentheses(c); } else if(**c == '['){ ++*c; match_brackets(c); } else { ++*c; } skip_whitespace(c); } if(!**c || **c == ']'){ snprintf(error_message, sizeof(error_message), "Expected ')'"); do_error(1); } ++*c; } void match_brackets(char **c){ while(**c && **c != ']' && **c != ')'){ if(**c == '"'){ ++*c; skip_string(c); skip_whitespace(c); continue; } if(**c == '('){ ++*c; match_parentheses(c); } else if(**c == '['){ ++*c; match_brackets(c); } else { ++*c; } skip_whitespace(c); } if(!**c || **c == ')'){ snprintf(error_message, sizeof(error_message), "Expected ']'"); do_error(1); } ++*c; } void skip_comment(char **c){ ++*c; if(**c == '/'){ while(**c && **c != '\n'){ ++*c; } if(**c){ ++*c; } } else { ++*c; while(**c && (**c != '*' || (*c)[1] != '/')){ ++*c; } if(**c){ *c += 2; } } } unsigned char is_cast(char *c){ if(*c != '('){ return 0; } c++; return parse_datatype(NULL, &c); } void skip_value(char **c){ skip_whitespace(c); while(**c == '*' || **c == '&' || **c == '!' || **c == '~' || **c == '-' || is_cast(*c) || is_whitespace(*c)){ if(**c == '('){//ie if we are casting ++*c; match_parentheses(c); } else if(**c == '/'){ skip_comment(c); } else { ++*c; } } while(**c == '('){ ++*c; match_parentheses(c); skip_whitespace(c); } if(digit(**c)){ while(digit(**c)){ ++*c; } } else if(alpha(**c)){ while(alphanumeric(**c)){ ++*c; } } else if(**c == '\"'){ ++*c; skip_string(c); } else if(**c == '\''){ ++*c; if(**c == '\\'){ ++*c; } while(**c && **c != '\''){ ++*c; } if(**c){ ++*c; } } skip_whitespace(c); while(**c == '[' || **c == '('){ if(**c == '('){ ++*c; match_parentheses(c); } else if(**c == '['){ ++*c; match_brackets(c); } skip_whitespace(c); skip_whitespace(c); } } void compile_string(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ ++*c; skip_string(c); output->data = allocate(force_stack); if(output->data.type == data_register){ fileprint(output_file, "la $s%d, __str%d\n", output->data.reg, current_string); } else if(output->data.type == data_stack){ fileprint(output_file, "la $t0, __str%d\n", current_string); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(output->data)); } if(do_print) current_string++; output->data_type = CHAR_TYPE; add_type_entry(&(output->data_type), type_pointer); output->is_reference = 0; } void compile_character(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ int char_constant = 0; char escape_sequences[] = {'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\'', '\"', '\?'}; int escape_values[] = {0x07, 0x08, 0x1B, 0x0C, 0x0A, 0x0D, 0x09, 0x0B, 0x5C, 0x27, 0x22, 0x3F}; unsigned char i; ++*c; if(**c == '\\'){ ++*c; for(i = 0; i < sizeof(escape_sequences)/sizeof(char); i++){ if(**c == escape_sequences[i]){ char_constant = escape_values[i]; } } if(!char_constant){ snprintf(error_message, sizeof(error_message), "Unrecognized escape sequence\n"); do_error(1); } } else { char_constant = **c; } ++*c; if(**c != '\''){ snprintf(error_message, sizeof(error_message), "Expected closing '\n"); do_error(1); } ++*c; output->data = allocate(force_stack); if(output->data.type == data_register){ fileprint(output_file, "li $s%d, %d\n", output->data.reg, char_constant); } else if(output->data.type == data_stack){ fileprint(output_file, "li $t0, %d\n", char_constant); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(output->data)); } output->data_type = INT_TYPE; output->is_reference = 0; } void compile_logical_not(value *v, FILE *output_file){ int size; if(v->data.type == data_register){ fileprint(output_file, "seq $s%d, $s%d, $zero\n", v->data.reg, v->data.reg); } else if(v->data.type == data_stack){ size = type_size(&(v->data_type), 0); if(size == 4){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data)); } else if(size == 1){ fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data)); } fileprint(output_file, "seq $t0, $t0, $zero\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } v->data_type = INT_TYPE; } void compile_not(value *v, FILE *output_file){ int size; if(!types_equal(&(v->data_type), &INT_TYPE) && !types_equal(&(v->data_type), &CHAR_TYPE)){ snprintf(error_message, sizeof(error_message), "Can't perform bitwise not of non-numerical type"); do_error(1); } if(v->data.type == data_register){ fileprint(output_file, "nor $s%d, $s%d, $s%d\n", v->data.reg, v->data.reg, v->data.reg); } else if(v->data.type == data_stack){ size = type_size(&(v->data_type), 0); if(size == 4){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data)); } else if(size == 1){ fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data)); } fileprint(output_file, "nor $t0, $t0, $t0\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } v->data_type = INT_TYPE; } void compile_negate(value *v, FILE *output_file){ int size; if(!types_equal(&(v->data_type), &INT_TYPE) && !types_equal(&(v->data_type), &CHAR_TYPE)){ snprintf(error_message, sizeof(error_message), "Can't negate non-numerical type"); do_error(1); } if(v->data.type == data_register){ fileprint(output_file, "sub $s%d, $zero, $s%d\n", v->data.reg, v->data.reg); } else if(v->data.type == data_stack){ size = type_size(&(v->data_type), 0); if(size == 4){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data)); } else if(size == 1){ fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data)); } fileprint(output_file, "sub $t0, $zero, $t0\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data)); } v->data_type = INT_TYPE; } void compile_value(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ char *temp_c; type cast_type; skip_whitespace(c); if(**c == '*'){ ++*c; compile_value(output, c, 1, force_stack, output_file); if(dereference){ compile_dereference(output, output_file); } output->is_reference = !dereference; return; } else if(**c == '&'){ ++*c; if(dereference){ compile_value(output, c, 0, force_stack, output_file); } else { snprintf(error_message, sizeof(error_message), "Can't get address of r-value"); do_error(1); } output->is_reference = 0; return; } else if(**c == '!'){ ++*c; if(dereference){ compile_value(output, c, 1, force_stack, output_file); compile_logical_not(output, output_file); } else { snprintf(error_message, sizeof(error_message), "Can't get address of r-value"); do_error(1); } output->is_reference = 0; return; } else if(**c == '~'){ ++*c; if(dereference){ compile_value(output, c, 1, force_stack, output_file); compile_not(output, output_file); } else { snprintf(error_message, sizeof(error_message), "Can't get address of r-value"); do_error(1); } output->is_reference = 0; return; } else if(**c == '-' && !digit((*c)[1])){ ++*c; if(dereference){ compile_value(output, c, 1, force_stack, output_file); compile_negate(output, output_file); } else { snprintf(error_message, sizeof(error_message), "Can't get address of r-value"); do_error(1); } output->is_reference = 0; return; } if(**c == '('){ ++*c; skip_whitespace(c); temp_c = *c; //Type casting if(parse_datatype(NULL, &temp_c)){ cast_type = EMPTY_TYPE; parse_type(&cast_type, c, NULL, NULL, 0, 0); if(**c != ')'){ snprintf(error_message, sizeof(error_message), "Expected ')'"); do_error(1); } ++*c; compile_value(output, c, 1, force_stack, output_file); cast(output, cast_type, 0, output_file); //Associative parentheses } else { compile_expression(output, c, dereference, force_stack, output_file); if(**c == ')'){ ++*c; } else { snprintf(error_message, sizeof(error_message), "Expected closing ')'"); do_error(1); } } } else if(**c == '-' || digit(**c)){ compile_integer(output, c, dereference, force_stack, output_file); } else if(alpha(**c)){ compile_variable(output, c, dereference, force_stack, output_file); } else if(**c == '\"'){ compile_string(output, c, dereference, force_stack, output_file); } else if(**c == '\''){ compile_character(output, c, dereference, force_stack, output_file); } else { snprintf(error_message, sizeof(error_message), "Unrecognized expression value"); do_error(1); } skip_whitespace(c); while(**c == '[' || **c == '('){ if(**c == '['){ if(output->is_reference){ compile_dereference(output, output_file); } compile_list_index(c, output, dereference, output_file); } else if(**c == '('){ ++*c; if(output->is_reference){ compile_dereference(output, output_file); } compile_function_call(c, output, output_file); } skip_whitespace(c); } } operation peek_operation(char *c){ switch(*c){ case '+': return operation_add; case '-': return operation_subtract; case '*': return operation_multiply; case '/': return operation_divide; case '%': return operation_modulo; case '=': if(c[1] == '='){ return operation_equals; } else { return operation_assign; } case '!': if(c[1] == '='){ return operation_not_equals; } else { return operation_none; } case '>': if(c[1] == '>'){ return operation_shift_right; } else if(c[1] == '='){ return operation_greater_than_or_equal; } else { return operation_greater_than; } case '<': if(c[1] == '<'){ return operation_shift_left; } else if(c[1] == '='){ return operation_less_than_or_equal; } else { return operation_less_than; } case '&': if(c[1] == '&'){ return operation_logical_and; } else { return operation_and; } case '|': if(c[1] == '|'){ return operation_logical_or; } else { return operation_or; } } return operation_none; } operation get_operation(char **c){ operation output; skip_whitespace(c); switch(**c){ case '+': output = operation_add; break; case '-': output = operation_subtract; break; case '*': output = operation_multiply; break; case '/': output = operation_divide; break; case '%': output = operation_modulo; break; case '=': if((*c)[1] == '='){ output = operation_equals; ++*c; } else { output = operation_assign; } break; case '!': if((*c)[1] == '='){ output = operation_not_equals; ++*c; } else { output = operation_none; } break; case '>': if((*c)[1] == '>'){ output = operation_shift_right; ++*c; } else if((*c)[1] == '='){ output = operation_greater_than_or_equal; ++*c; } else { output = operation_greater_than; } break; case '<': if((*c)[1] == '<'){ output = operation_shift_left; ++*c; } else if((*c)[1] == '='){ output = operation_less_than_or_equal; ++*c; } else { output = operation_less_than; } break; case '&': if((*c)[1] == '&'){ output = operation_logical_and; ++*c; } else { output = operation_and; } break; case '|': if((*c)[1] == '|'){ output = operation_logical_or; ++*c; } else { output = operation_or; } break; default: output = operation_none; break; } ++*c; return output; } void compile_operation(value *first_value, value *next_value, operation op, FILE *output_file){ char reg0_str_buffer[5] = {0, 0, 0, 0, 0}; char reg1_str_buffer[5] = {0, 0, 0, 0, 0}; char *reg0_str = ""; char *reg1_str = ""; type output_type; if(types_equal(&(first_value->data_type), &VOID_TYPE) || types_equal(&(next_value->data_type), &VOID_TYPE)){ snprintf(error_message, sizeof(error_message), "Can't operate on void value"); do_error(1); } if(first_value->data.type == data_register){ snprintf(reg0_str_buffer, sizeof(reg0_str_buffer)/sizeof(char), "$s%d", first_value->data.reg); reg0_str = reg0_str_buffer; } else if(first_value->data.type == data_stack){ reg0_str = "$t0"; if(type_size(&(first_value->data_type), 0) == 4){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data)); } else if(type_size(&(first_value->data_type), 0) == 1){ fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(first_value->data)); } else { snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&(first_value->data_type), 0)); do_error(1); } } if(next_value->data.type == data_register){ snprintf(reg1_str_buffer, sizeof(reg1_str_buffer)/sizeof(char), "$s%d", next_value->data.reg); reg1_str = reg1_str_buffer; } else if(next_value->data.type == data_stack){ reg1_str = "$t1"; if(type_size(&(next_value->data_type), 0) == 4){ fileprint(output_file, "lw $t1, %d($sp)\n", get_stack_pos(next_value->data)); } else if(type_size(&(next_value->data_type), 0) == 1){ fileprint(output_file, "lb $t1, %d($sp)\n", get_stack_pos(next_value->data)); } else { snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&(next_value->data_type), 0)); do_error(1); } } operation_functions[op](reg0_str, reg1_str, first_value, next_value, output_file, &output_type); deallocate(next_value->data); if(first_value->data.type == data_stack){ if(type_size(&output_type, 0) == 4){ fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data)); } else if(type_size(&output_type, 0) == 1){ fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(first_value->data)); } else { snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&output_type, 0)); do_error(1); } } first_value->data_type = output_type; first_value->is_reference = 0; } static void compile_expression_recursive(value *first_value, char **c, FILE *output_file){ operation current_operation; operation next_operation; unsigned int label_num = 0; value next_value; char *temp_c; type cast_to; int current_line_temp; skip_whitespace(c); current_operation = get_operation(c); if(current_operation == operation_none){ snprintf(error_message, sizeof(error_message), "Unrecognized operation"); do_error(1); } else if(current_operation == operation_logical_or){ label_num = num_labels; num_labels++; cast(first_value, INT_TYPE, 0, output_file); if(first_value->data.type == data_register){ fileprint(output_file, "sne $s%d, $s%d, $zero\n", first_value->data.reg, first_value->data.reg); fileprint(output_file, "bne $s%d, $zero, __L%d\n", first_value->data.reg, label_num); } else if(first_value->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data)); fileprint(output_file, "sne $t0, $t0, $zero\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data)); fileprint(output_file, "bne $t0, $zero, __L%d\n", label_num); } } else if(current_operation == operation_logical_and){ label_num = num_labels; num_labels++; cast(first_value, INT_TYPE, 0, output_file); if(first_value->data.type == data_register){ fileprint(output_file, "beq $s%d, $zero, __L%d\n", first_value->data.reg, label_num); } else if(first_value->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data)); fileprint(output_file, "beq $t0, $zero, __L%d\n", label_num); } } temp_c = *c; current_line_temp = current_line; skip_value(&temp_c); current_line = current_line_temp; next_operation = peek_operation(temp_c); if(next_operation == operation_assign && order_of_operations[operation_assign] > order_of_operations[current_operation]){ compile_value(&next_value, c, 0, 0, output_file); } else { compile_value(&next_value, c, 1, 0, output_file); } skip_whitespace(c); while(order_of_operations[next_operation] > order_of_operations[current_operation]){ compile_expression_recursive(&next_value, c, output_file); skip_whitespace(c); next_operation = peek_operation(*c); } if(current_operation == operation_assign){ cast_to = first_value->data_type; pop_type(&cast_to); cast(&next_value, cast_to, 1, output_file); compile_operation(first_value, &next_value, current_operation, output_file); } else if(current_operation == operation_logical_or || current_operation == operation_logical_and){ cast(&next_value, INT_TYPE, 0, output_file); if(next_value.data.type == data_register){ fileprint(output_file, "sne $s%d, $s%d, $zero\n", next_value.data.reg, next_value.data.reg); if(first_value->data.type == data_register){ fileprint(output_file, "move $s%d, $s%d\n", first_value->data.reg, next_value.data.reg); } else if(first_value->data.type == data_stack){ fileprint(output_file, "sw $s%d, %d($sp)\n", next_value.data.reg, get_stack_pos(first_value->data)); } } else if(next_value.data.type == data_stack){ if(first_value->data.type == data_register){ fileprint(output_file, "lw $s%d, %d($sp)\n", first_value->data.reg, get_stack_pos(next_value.data)); fileprint(output_file, "sne $s%d, $s%d, $zero\n", first_value->data.reg, first_value->data.reg); } else if(first_value->data.type == data_stack){ fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(next_value.data)); fileprint(output_file, "sne $t0, $t0, $zero\n"); fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data)); } } deallocate(next_value.data); fileprint(output_file, "\n__L%d:\n", label_num); } else { compile_operation(first_value, &next_value, current_operation, output_file); } skip_whitespace(c); } void compile_expression(value *first_value, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ char *temp_c; int current_line_temp; operation next_operation; temp_c = *c; current_line_temp = current_line; skip_value(&temp_c); current_line = current_line_temp; next_operation = peek_operation(temp_c); if(peek_operation(temp_c) == operation_assign){ compile_value(first_value, c, 0, force_stack, output_file); } else { compile_value(first_value, c, dereference || next_operation != operation_none, force_stack, output_file); } while(**c && **c != ';' && **c != ',' && **c != ')' && **c != ']'){ compile_expression_recursive(first_value, c, output_file); } } void determine_stack_size(value *first_value, char **c, unsigned char dereference, unsigned char force_stack){ char *temp_c; do_print = 0; saved_stack_size = 0; temp_c = *c; compile_expression(first_value, c, dereference, force_stack, NULL); *c = temp_c; do_print = 1; } void compile_root_expression(value *first_value, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){ determine_stack_size(first_value, c, dereference, force_stack); deallocate(first_value->data); if(saved_stack_size != 0){ fprintf(output_file, "addi $sp, $sp, %d\n", -saved_stack_size); } compile_expression(first_value, c, dereference, force_stack, output_file); } //THIS MUST ALWAYS BE CALLED AFTER COMPILE_ROOT_EXPRESSION IS RUN AGAIN! //It is not included in compile_root_expression just in case the caller wants to first cast the return value of compile_root_expression //If compile_root_expression did do that, then such a cast either would not work or would be past the bounds of the stack void reset_stack_pos(value *first_value, FILE *output_file){ if(first_value->data.type == data_stack){ fprintf(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data)); } if(saved_stack_size != 0){ fprintf(output_file, "addi $sp, $sp, %d\n", saved_stack_size); } }