/* Intermediate Code */ /* The Translators - Spring 2025 */ #include "intermediate_code.h" // 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* getResult(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; count->tnc_union = calloc(1, sizeof(*count->tnc_union)); 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 = *(uint_least8_t*)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 + 1; 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 == NULL) { return; } switch (i->opcode) { case E_LABEL: break; // 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->operand1)); 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; } TableNode* getTN(TNodeOrConst* tnc) { if (tnc->d == NODE) { return tnc->tnc_union->node; } return NULL; } //we must fix this int getConst(TNodeOrConst* tnc) { if (tnc->d == INTEGER) { return tnc->tnc_union->integer; } return -1; }