diff --git a/a.out b/a.out deleted file mode 100644 index e69de29..0000000 diff --git a/src/intermediate_code.c b/src/intermediate_code.c index 6b1b32f..e69de29 100644 --- a/src/intermediate_code.c +++ b/src/intermediate_code.c @@ -1,386 +0,0 @@ -#include "intermediate_code.h" - -Instruction * begin; -Instruction * current; -char * temp = NULL; - - -// TODO: this is here to bring your attention to the comment bellow. -// check if start is NULL if it is assign it to the start globle variable -// otherwise make it next of current and set cur to your instruction. -TNodeOrConst * getOperand1(Instruction * i){ - return i->operand1; -} - -TNodeOrConst * getOperand2(Instruction * i){ - return i->operand2; -} - -TableNode * get_result(Instruction * i){ - return i->result; -} - -Op getOp(Instruction * i){ - return i->opcode; -} - -int getLabel(Instruction * i){ - return i->label; -} - -int get_index(Instruction * i){ - return i->index; -} - -void set_label(Instruction * i, int label){ - i->label = label; -} - -bool isConst(TNodeOrConst * tnc) { - return tnc->d != NODE; -} - -TNodeOrConst * tn_or_const(Discriminant d, void * tnc) { - TNodeOrConst * count = calloc(1, sizeof(*count)); - count->d = d; - switch (d) { - case NODE: - count->tnc_union->node = tnc; - break; - case ADDRESS: - count->tnc_union->address = tnc; - break; - case STRING: - count->tnc_union->string = tnc; - break; - case INTEGER: - count->tnc_union->integer = *(int*)tnc; - break; - case CHARACTER: - count->tnc_union->character = *(char*)tnc; - break; - case BOOLEAN: - count->tnc_union->Boolean = *(bool*)tnc; - break; - } - return count; -} - -static void emit_helper(void){ - Instruction * inst = calloc(1, sizeof(*inst)); - if(begin == NULL){ - begin = current = inst; - current->index = 1; - } else { - current->next = inst; - inst->prev = current; - inst->index = current->index++; - current = inst; - } -} - -void emit_binary_op(Op op, TableNode * result, TNodeOrConst * arg1, TNodeOrConst * arg2){ - emit_helper(); - current->opcode = op; - // TODO: create temp and remove result from param list - current->result = result; - current->operand1 = arg1; - current->operand2 = arg2; - } - -void emit_unary_op(Op op, TableNode * result, TNodeOrConst * arg){ - emit_helper(); - current->opcode = op; - current->result = result; - current->operand1 = arg; - } - -void emit_assignment(TableNode * target, TNodeOrConst * source){ - emit_helper(); - current->opcode = E_ASSIGN; - current->result = target; - current->operand1 = source; - } - -char * get_string(TNodeOrConst * tc){ - char * s; - switch (tc->d) { - case NODE: - return getName(tc->tnc_union->node); - case ADDRESS: - return strdup("null"); - case STRING: - return tc->tnc_union->string; - case INTEGER: - s = calloc(10, sizeof(char)); - sprintf(s, "%d", tc->tnc_union->integer); - return s; - case CHARACTER: - s = calloc(2, sizeof(char)); - sprintf(s, "%c", tc->tnc_union->character); - return s; - case BOOLEAN: - if(tc->tnc_union->Boolean){ - return strdup("true"); - } - return strdup("false"); - } -} - -void emit_as_file(FILE * out_file, Instruction * i){ - if(!i){ - return; - } - switch(i->opcode){ - case E_LABEL: - // this is a terrible one to start with - // fprintf(out_file, "%04.d: %d ", i->index, i->label); - case E_ADD: - fprintf(out_file, "%4.d: %s = %s + %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_SUB: - fprintf(out_file, "%4.d: %s = %s - %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_MUL: - fprintf(out_file, "%4.d: %s = %s * %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_DIV: - fprintf(out_file, "%4.d: %s = %s / %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_MOD: - fprintf(out_file, "%4.d: %s = %s %% %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_OR: - fprintf(out_file, "%4.d: %s = %s | %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_AND: - fprintf(out_file, "%4.d: %s = %s & %s\n", - i->index, getName(i->result), - get_string(i->operand1), - get_string(i->operand2)); - break; - case E_NEG: - fprintf(out_file, "%4.d: %s = -%s\n", - i->index, getName(i->result), - get_string(i->operand1)); - break; - case E_NOT: - fprintf(out_file, "%4.d: %s = !%s\n", - i->index, getName(i->result), - get_string(i->operand1)); - break; - case E_ASSIGN: - fprintf(out_file, "%4.d: %s = %s\n", - i->index, getName(i->result), - get_string(i->operand2)); - break; - case E_GOTO: - // are we ever going to use this? - // yes we do look at bounds checking - case E_IF_X_TRUE: - fprintf(out_file, "%4.d: if %s goto %d\n", - i->index, get_string(i->operand1), - i->label); - break; - case E_IF_X_FALSE: - fprintf(out_file, "%4.d: if %s false goto %d\n", - i->index, get_string(i->operand1), - i->label); - break; - case E_LESS_THAN: - fprintf(out_file, "%4.d: if %s < %s goto %d\n", - i->index, get_string(i->operand1), - get_string(i->operand2), i->label); - break; - case E_EQUAL_TO: - fprintf(out_file, "%4.d: if %s = %s goto %d\n", - i->index, get_string(i->operand1), - get_string(i->operand2), i->label); - break; - case E_CALL: - fprintf(out_file, "%4.d: call %s %s\n", - i->index, get_string(i->operand1), - get_string(i->operand2)); - break; - - case E_PARAM: - fprintf(out_file, "%4.d: param %s \n", - i->index, get_string(i->operand1)); - break; - case E_RETURN: - - case E_INDEX_COPY_RIGHT: - case E_INDEX_COPY_LEFT: - - case E_ADDRESS_OF: - - case E_DEREF_RIGHT: - case E_DEREF_LEFT: - } - - emit_as_file(out_file, i->next); -} - -void emit_label(int label){ - emit_helper(); - current->opcode = E_LABEL; - current->label = label; -} - -void emit_jump(int label){ - emit_helper(); - current->opcode = E_GOTO; - current->label = label; -} - -void emit_conditional_jump(Op condition, int label, ...){ - // when this instruction is a conditional jump then the imput looks like (Op, int, TNodeOrConst *). - // when the inst is a cond with a Relational operation then the input looks like (Op, int, TNodeOrConst *, TNodeOrConst *) - emit_helper(); - va_list argptr; - va_start(argptr, label); - current->opcode = condition; - current->label = label; - TNodeOrConst * n1; - TNodeOrConst * n2; - switch (condition) { - case E_IF_X_TRUE: case E_IF_X_FALSE: - n1 = va_arg(argptr, TNodeOrConst *); - current->operand1 = n1; - break; - case E_LESS_THAN: case E_EQUAL_TO: - n1 = va_arg(argptr, TNodeOrConst *); - n2 = va_arg(argptr, TNodeOrConst *); - current->operand1 = n1; - current->operand2 = n2; - break; - } - va_end(argptr); -} - -void emit_function_start(int name){ - emit_helper(); - current->opcode = E_LABEL; // I think this is right TODO: ask - current->label = name; - // this is probabaly a func decleration -} - -void emit_parameter(TNodeOrConst * param){ - emit_helper(); - current->opcode = E_PARAM; - current->operand1 = param; -} - -void emit_function_call(TableNode * result, int param_count, TNodeOrConst * name){ - emit_helper(); - current->opcode = E_CALL; - current->operand1 = tn_or_const(INTEGER, ¶m_count); - current->operand2 = name; - current->result = result; -} - -void emit_return(TNodeOrConst * value){ - emit_helper(); - current->opcode = E_RETURN; - current->operand1 = value; -} - -void emit_reserve(TableNode * result, TNodeOrConst * size){ - emit_parameter(size); - emit_function_call(result, 1, tn_or_const(NODE, look_up(cur, "reserve"))); -} - -void emit_release(TableNode * pointer){ - emit_parameter(tn_or_const(NODE, pointer)); - emit_function_call(pointer, 1, tn_or_const(NODE, look_up(cur, "release"))); -} - -void emit_deref_right(){ - return; -} - -void emit_deref_left(){ - return; -} - -void emit_field_access(char* result, char* record, char* field){ - emit_helper(); -} - -void emit_array_access(Op op, TableNode * result, TNodeOrConst * array, TNodeOrConst * index){ - emit_helper(); - current->opcode; - current->result = result; - current->operand1 = array; - current->operand2 = index; - // TODO: Still don't know what to do with the dimentions -} - -void emit_bounds_check(TNodeOrConst * index, TNodeOrConst * arr){ - /* - {[string: 5] - . - . - s:= reserve s(5); - s(0) := 'H'; - s(1) := 'e'; - . - . - s._0 num of dims Known at compile time - s._1 size Known at run time - s._1 int | 1 byte - +-------+---+---+---+---+---+ - | 5 | H | e | l | l | o | - +-------+---+---+---+---+---+ - size - ^ - | - p - s._0 ok - s._1 ok - s._2 not ok - t_0 is index - t_1 = *(int *)p = s._1 - if t_0 < 0 GOTO ERROR - if t_0 < s._1 GOTO access array - GOTO ERROR - */ - emit_conditional_jump(E_LESS_THAN, ); - emit_conditional_jump(E_LESS_THAN, ); - emit_jump(); - /* We need a label ERROR to jump to - */ -} - -// * Implement temp variable generator function that produces unique names (t1, t2, etc.) -char * temp_var_gen(){ - char * ret = calloc(9, sizeof(*ret)); - sprintf(ret, "$t%d", temp_count); - temp_count++; - return ret; -} - -char * label_gen(){ - char * ret = calloc( 9, sizeof(*ret)); - sprintf(ret, "L_%d", label_count); - label_count++; - return ret; -} \ No newline at end of file diff --git a/src/intermediate_code.h b/src/intermediate_code.h index b6e6fd4..e69de29 100644 --- a/src/intermediate_code.h +++ b/src/intermediate_code.h @@ -1,155 +0,0 @@ -// Track 1: Core Infrastructure & Basic Expressions -// * Add Bison actions for arithmetic expressions: -// - Addition: $$ = new_temp(); emit_binary_op($$, "ADD", $1, $3); -// - Subtraction, multiplication, division, modulo -#pragma once - -#include "symbol_table.h" -#include -#include - -// these are from page 364 -typedef enum { - E_LABEL = 10000, // this is not in the book - E_ADD, // 1 from the list - E_SUB, // 1 - E_MUL, // 1 - E_DIV, // 1 - E_MOD, // 1 - E_OR, // 1 - E_AND, // 1 - E_NEG, // 2 - E_NOT, // 2 - E_ASSIGN, // 3 - E_GOTO, // 4 - E_COND_GOTO, // 5 I don't thik I need this because we could just follow the < or the = and just assume that it's a cond got - E_IF_X_TRUE, // 5 - E_IF_X_FALSE, // 5 - E_LESS_THAN, // 6 rule 1 + 5 - E_EQUAL_TO, // 6 rule 1 + 5 - E_CALL, // 7 - E_PARAM, // 7 - E_RETURN, // 7 - E_INDEX_COPY_RIGHT, // 8 this is x = y[i] - E_INDEX_COPY_LEFT, // 8 x[i] = y - E_ADDRESS_OF, // 9 x = &y - E_DEREF_RIGHT, // 9 x = *y - E_DEREF_LEFT // 9 x* = y -} Op; - -typedef enum { - NODE = 11000, // TableNode - INTEGER, // int - STRING, // char * - CHARACTER, // char - ADDRESS, // void * - BOOLEAN // bool -} Discriminant; - -typedef union { - TableNode * node; - int integer; - char * string; - char character; - void * address; - bool Boolean; -} TNConstUnion; - -typedef struct { - Discriminant d; - TNConstUnion * tnc_union; -} TNodeOrConst; - -typedef struct Instruction Instruction; -typedef struct Instruction { - Op opcode; - TableNode * result; - TNodeOrConst * operand1; - TNodeOrConst * operand2; - int label; - int index; - - Instruction * prev; - Instruction * next; -} Instruction; - - -typedef struct TFList { - Instruction * i; - TFList * next; -} TFList; - -TFList * make_list(Instruction * i); - // - makelist(i) function to create instruction lists -void merge(TFList * l1, TFList * l2); - // - merge(p1,p2) function to concatenate lists -void backpatch(TFList * l, int label); - // - backpatch(p,i) function to fill in jump targets - - -extern Instruction * begin; -extern Instruction * current; -int temp_count = 0; -int label_count = 0; -bool code_gen = true; - - -TNodeOrConst * tn_or_const(Discriminant , void * ); -void emit_binary_op(Op op, TableNode * result, TNodeOrConst * arg1, TNodeOrConst * arg2); -void emit_unary_op(Op op, TableNode * result, TNodeOrConst * arg); -void emit_assignment(TableNode * target, TNodeOrConst * source); -void emit_as_file(FILE * out_file, Instruction * instr_arr); -void emit_label(int label); -void emit_jump(int label); - -void emit_conditional_jump(Op condition, int label, ...); - -void emit_function_start(int name); -void emit_parameter(TNodeOrConst * param); -void emit_function_call(TableNode * result, int param_count, TNodeOrConst * name); -void emit_return(TNodeOrConst * value); -void emit_reserve(TableNode * result, TNodeOrConst * size); -void emit_release(TableNode * pointer); -void emit_field_access(char* result, char* record, char* field); -void emit_array_access(Op op, TableNode * result, TNodeOrConst * array, TNodeOrConst * index); -void emit_bounds_check(TNodeOrConst * index, TNodeOrConst * arr, int error_label); - -// * Implement instruction array storage for backpatching -/* -Track 2: Control Flow & Boolean Expressions -* Implement backpatching infrastructure: -* Create truelist and falselist attributes for Boolean expressions -* Create control flow emission functions: -* Add Bison actions for control structures: - - if-then-else with backpatching - - while loops with backpatching -* Implement short-circuit Boolean operations (&&, ||, !) -* Add marker (M) nonterminal for recording instruction positions -*/ - - -/* - Track 3: Functions & Complex Types -* Implement function-related emission: -* Add Bison actions for the 'as' clause -* Create memory layout calculation functions: - - calculate_record_size(Record_Type* type) → returns bytes needed - - calculate_array_size(Array_Type* type, int dimensions[]) → returns total bytes - - calculate_field_offset(Record_Type* type, char* field_name) → returns offset -* Add Bison actions for arrays and records - */ - -/* - Track 4: Memory Access & Integration -* Implement array and record access code: - - emit_field_access(char* result, char* record, char* field) - - emit_array_access(char* result, char* array, char* index, char* dimension) -* Add array dimension access (a._1, a._2, etc.) -* Implement bounds checking emission: - - emit_bounds_check(char* index, char* size, char* error_label) -* Create the code generation driver function -* Implement common error handling -* Document the complete intermediate instruction set -* Build integration test suite covering all language features -* Implement row-major/column-major array layout calculation - */ \ No newline at end of file