static int array_check_bounds(array_t *array, size_t index, size_t within) { if (index >= (array->e_end + within)) { array_error("array bounds error: %zu (of %zu elements)", index, array->e_end); return BOUNDS_FAIL; } return BOUNDS_OK; }
static int array_check_alloc(array_t *array, size_t elements) { if (elements <= 0) elements = 1; // Is array large enough to handle <element> elements? size_t count = array->e_all; while (count <= array->e_end + elements) count += array->e_inc; // Add a block and retest if (count > array->e_all) { void *buf = realloc(array->data, count * array->e_size); if (buf == NULL) { array_error("array_check_alloc reallocation failure(%d): %s", errno, strerror(errno)); return -1; } array->data = buf; size_t added = count - array->e_all; memset(array->data + array->e_all * array->e_size, '\0', added * array->e_size); array->e_all = count; } return 0; }
//Generates code and writes it to a file void expr_codegen(struct expr *e, FILE *file) { if(!e) return; struct expr *e2; switch(e->kind) { case EXPR_ASSIGNMENT: fprintf(file, "\n\t#Assignment of %s %d right value\n", e->left->symbol->name, e->left->symbol->which); expr_codegen(e->right, file); fprintf(file, "\n\t#Assignment assign to %s %d\n", e->left->symbol->name, e->left->symbol->which); fprintf(file, "\tMOV %s, %s\n", register_name(e->right->reg), symbol_code(e->left->symbol)); e->reg = e->right->reg; register_free(e->left->reg); break; case EXPR_GE: //all of these go to the compare function case EXPR_LE: case EXPR_GT: case EXPR_LT: case EXPR_EQ: case EXPR_NE: compare(e, file); break; case EXPR_ADD: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Addition\n"); fprintf(file, "\tADD %s, %s\n", register_name(e->left->reg), register_name(e->right->reg)); e->reg = e->right->reg; register_free(e->left->reg); break; case EXPR_SUB: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Subtraction\n"); fprintf(file, "\tSUB %s, %s\n", register_name(e->right->reg), register_name(e->left->reg)); e->reg = e->left->reg; register_free(e->right->reg); break; case EXPR_MUL: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Multiplication\n"); fprintf(file, "\tMOV %s, %%rax\n", register_name(e->left->reg)); fprintf(file, "\tIMUL %s\n", register_name(e->right->reg)); fprintf(file, "\tMOV %%rax, %s\n", register_name(e->right->reg)); register_free(e->left->reg); e->reg = e->right->reg; break; case EXPR_DIV: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Division\n"); fprintf(file, "\tMOV %s, %%rax\n", register_name(e->left->reg)); fprintf(file, "\tCQO\n"); fprintf(file, "\tIDIV %s\n", register_name(e->right->reg)); fprintf(file, "\tMOV %%rax, %s\n", register_name(e->right->reg)); register_free(e->left->reg); e->reg = e->right->reg; break; case EXPR_MOD: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Modulus\n"); fprintf(file, "\tMOV %s, %%rax\n", register_name(e->left->reg)); fprintf(file, "\tCQO\n"); fprintf(file, "\tIDIV %s\n", register_name(e->right->reg)); fprintf(file, "\tMOV %%rdx, %s\n", register_name(e->right->reg)); register_free(e->left->reg); e->reg = e->right->reg; break; case EXPR_POW: expr_codegen(e->left, file); expr_codegen(e->right, file); int label_start = label_count++; int label_end = label_count++; fprintf(file, "\n\t#Exponent function\n"); fprintf(file, "\tMOV $1, %%rax\n"); fprintf(file, "L%d:\n", label_start); fprintf(file, "\tCMP $0, %s\n", register_name(e->right->reg)); fprintf(file, "\tJE L%d\n", label_end); fprintf(file, "\tSUB $1, %s\n", register_name(e->right->reg)); fprintf(file, "\tMUL %s\n", register_name(e->left->reg)); fprintf(file, "\tJMP L%d\n", label_start); fprintf(file, "L%d:\n", label_end); register_free(e->left->reg); register_free(e->right->reg); e->reg = register_alloc(); fprintf(file, "\tMOV %%rax, %s\n", register_name(e->reg)); break; case EXPR_LOGICAL_NOT: expr_codegen(e->right, file); fprintf(file, "\n\t#Logical Not\n"); e->reg = e->right->reg; fprintf(file, "\tCMPQ $0, %s\n", register_name(e->reg)); fprintf(file, "\tJNE L%d\n", label_count); fprintf(file, "\tMOV $1, %s\n", register_name(e->reg)); fprintf(file, "\tJMP L%d\n", label_count+1); fprintf(file, "L%d:\n", label_count++); fprintf(file, "\tMOV $0, %s\n", register_name(e->reg)); fprintf(file, "L%d:\n", label_count++); break; case EXPR_LOGICAL_AND: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Logical And\n"); fprintf(file, "\tAND %s, %s\n", register_name(e->left->reg), register_name(e->right->reg)); e->reg = e->right->reg; register_free(e->left->reg); break; case EXPR_LOGICAL_OR: expr_codegen(e->left, file); expr_codegen(e->right, file); fprintf(file, "\n\t#Logical Or\n"); fprintf(file, "\tOR %s, %s\n", register_name(e->left->reg), register_name(e->right->reg)); e->reg = e->right->reg; register_free(e->left->reg); break; case EXPR_POSTFIX_PLUS: expr_codegen(e->left, file); fprintf(file, "\n\t#Increment\n"); e->reg = register_alloc(); fprintf(file, "\tMOV %s, %s\n", register_name(e->left->reg), register_name(e->reg)); fprintf(file, "\tADD $1, %s\n", register_name(e->left->reg)); fprintf(file, "\tMOV %s, %s\n", register_name(e->left->reg), symbol_code(e->left->symbol)); register_free(e->left->reg); break; case EXPR_POSTFIX_MINUS: expr_codegen(e->left, file); fprintf(file, "\n\t#Increment\n"); e->reg = register_alloc(); fprintf(file, "\tMOV %s, %s\n", register_name(e->left->reg), register_name(e->reg)); fprintf(file, "\tSUB $1, %s\n", register_name(e->left->reg)); fprintf(file, "\tMOV %s, %s\n", register_name(e->left->reg), symbol_code(e->left->symbol)); register_free(e->left->reg); break; case EXPR_IDENT: fprintf(file, "\n\t#Identifier %d %s\n", e->symbol->which, e->symbol->name); e->reg = register_alloc(); if(e->symbol->type->kind == TYPE_STRING && e->symbol->kind == SCOPE_GLOBAL){ fprintf(file, "\tLEA %s, %s\n", symbol_code(e->symbol), register_name(e->reg)); } else { fprintf(file, "\tMOV %s, %s\n", symbol_code(e->symbol), register_name(e->reg)); } break; case EXPR_INTEGER_LITERAL: //comment label fprintf(file, "\n\t#Integer literal %d\n", e->literal_value); e->reg = register_alloc(); fprintf(file, "\tMOV $%d, %s\n", e->literal_value, register_name(e->reg)); break; case EXPR_STRING_LITERAL: //comment label fprintf(file, "\n\t#String literal %s\n", e->string_literal); e->reg = register_alloc(); fprintf(file, ".data\nSTR%d: \n.string \"%s\"\n.text\n", string_number, e->string_literal); fprintf(file, "\tLEA STR%d, %s\n", string_number++, register_name(e->reg)); break; case EXPR_CHAR_LITERAL: fprintf(file, "\n\t#Char literal %c\n", e->literal_value); e->reg = register_alloc(); fprintf(file, "\tMOV $%d, %s\n", e->literal_value, register_name(e->reg)); break; case EXPR_TRUE: fprintf(file, "\n\t#True\n"); e->reg = register_alloc(); fprintf(file, "\tMOV $%d, %s\n", e->literal_value, register_name(e->reg)); break; case EXPR_FALSE: fprintf(file, "\n\t#False\n"); e->reg = register_alloc(); fprintf(file, "\tMOV $%d, %s\n", e->literal_value, register_name(e->reg)); register_free(e->reg); break; case EXPR_FCALL: if(function_params(e) >= 6) fcall_error(); e->reg = register_alloc(); fprintf(file, "\n\t#Calling function %s\n", e->left->name); if(!e->right){ /* do nothing for no params */ } else if(e->right->kind != EXPR_COMMA){ //this means single argument expr_codegen(e->right, file); fprintf(file, "\n\t#Move Only Argument\n"); fprintf(file, "\tMOV %s, %%rdi\n", register_name(e->right->reg)); register_free(e->right->reg); } else { //multiple parameters struct expr *param = e->right; int param_number = 0; while(param->kind == EXPR_COMMA){ expr_codegen(param->left, file); fprintf(file, "\n\t#Move Argument %d\n", param_number); fprintf(file, "\tMOV %s, ", register_name(param->left->reg)); register_free(param->left->reg); switch(param_number++){ case 0: fprintf(file, "%%rdi"); break; case 1: fprintf(file, "%%rsi"); break; case 2: fprintf(file, "%%rdx"); break; case 3: fprintf(file, "%%rcx"); break; case 4: fprintf(file, "%%r8"); break; case 5: fprintf(file, "%%r9"); break; } fprintf(file, "\n"); param = param->right; } expr_codegen(param, file); fprintf(file, "\n\t#Move Argument %d\n", param_number); fprintf(file, "\tMOV %s, ", register_name(param->reg)); switch(param_number++){ case 0: fprintf(file, "%%rdi"); break; case 1: fprintf(file, "%%rsi"); break; case 2: fprintf(file, "%%rdx"); break; case 3: fprintf(file, "%%rcx"); break; case 4: fprintf(file, "%%r8"); break; case 5: fprintf(file, "%%r9"); break; } fprintf(file, "\n"); register_free(param->reg); } fprintf(file, "\tPUSH %%r10\n"); fprintf(file, "\tPUSH %%r11\n"); fprintf(file, "\n\tCALL %s\n\n", e->left->name); fprintf(file, "\tPOP %%r11\n"); fprintf(file, "\tPOP %%r10\n"); fprintf(file, "\tMOV %%rax, %s\n", register_name(e->reg)); break; case EXPR_PARENS: expr_codegen(e->right, file); e->reg = e->right->reg; break; case EXPR_ARRCALL: //These 4 have to do with arrays case EXPR_ARRINDEX: //We are not implementing arrays for codegen case EXPR_BLOCK: case EXPR_BLOCK_COMMA: array_error(); break; } }