/* Build necessary code for a while statement */ void build_while_stmt(environment *env, NODE *node, int while_count, int if_count, int flag, int return_type) { char *s_tmp, *val1, *val2, *temporary; tac_quad *loop_jmp; if (node==NULL || type_of(node)!=WHILE) return; /* Generate label for start of while loop */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__while%d", while_count); append_code(make_label(s_tmp)); /* Generate loop jump */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__while%d", while_count); loop_jmp = make_goto(s_tmp); /* End while loop stmt */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__while%dend", while_count); /* Build IF stmt for condition */ build_if_stmt(env, node, if_count, make_goto(s_tmp), loop_jmp, flag, return_type); append_code(make_label(s_tmp)); }
/* Register params in environment */ void register_params(environment *env, value *param_list) { value *current_param; if (!param_list) return; current_param = param_list; while (current_param!=NULL) { value *param = NULL; value *param_name; param_name = string_value(current_param->identifier); switch(current_param->value_type) { case VT_INTEGR: param = assign(env, param_name, int_value(0), 1); break; case VT_VOID: param = assign(env, param_name, void_value(), 1); break; case VT_FUNCTN: param = assign(env, param_name, null_fn, 1); break; default: fatal("Could not determine parameter type!"); } append_code(make_quad_value("", param, NULL, NULL, TT_POP_PARAM, 0)); current_param = current_param->next; } }
void write_code(FILE *handle,int no_bits,int code) { code_in_progress = code_in_progress + (code << stat_bits); // * powers2[stat_bits+1] stat_bits=stat_bits+no_bits; while (stat_bits>7) { append_code(handle,code_in_progress&255); code_in_progress >>= 8; stat_bits -= 8; } }
/* Push params on param stack in reverse order (recursively) */ tac_quad *push_params(environment *env, value *params_head) { if (!params_head) return NULL; if (params_head->next) { append_code(push_params(env, params_head->next)); } if (params_head->value_type == VT_STRING) { value *tmp = get(env, correct_string_rep(params_head)); return make_quad_value("", tmp, NULL, NULL, TT_PUSH_PARAM, 0); } return make_quad_value("", params_head, NULL, NULL, TT_PUSH_PARAM, 0); }
/* Build necessary code for an if statement */ void build_if_stmt(environment *env, NODE *node, int if_count, tac_quad *false_jump, tac_quad *loop_jump, int flag, int return_type) { char *s_tmp; value *val1, *val2, *temporary; if (node==NULL || (type_of(node)!=IF && type_of(node)!=WHILE)) return; /* LHS is condition */ val1 = make_simple(env, node->left, flag, return_type); /* Generate if statement */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__if%dtrue", if_count); append_code(make_if(val1, s_tmp)); /* Output false branch (i.e. else part) */ if (type_of(node->right)==ELSE) { /* Build code for false part */ build_else_part(env, node->right, 0, flag, return_type); } /* Generate goto end of if statement */ if (false_jump != NULL) { append_code(false_jump); } else { s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__if%dend", if_count); append_code(make_goto(s_tmp)); } /* Generate label for start of true branch */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__if%dtrue", if_count); append_code(make_label(s_tmp)); /* Output true branch */ if (type_of(node->right)==ELSE) { /* Build code for true part */ build_else_part(env, node->right, 1, flag, return_type); } else { /* True part is whole right branch */ make_simple(env, node->right, flag, return_type); } /* Check if extra loop jump has been specified (for WHILE loops etc) */ if (loop_jump) { append_code(loop_jump); } /* Generate end of IF stmt label */ s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__if%dend", if_count); append_code(make_label(s_tmp)); }
/* * Make the given NODE simple - i.e. return a temporary for complex subtrees * The appropriate code is also generated and pushed onto the code stack */ value *make_simple(environment *env, NODE *node, int flag, int return_type) { int i_value = 0; char *s_tmp = NULL; value *val1 = NULL, *val2 = NULL, *temporary = NULL, *temp = NULL; static int if_count = 0; static int while_count = 0; tac_quad *temp_quad = NULL; environment *new_env = NULL; if (node==NULL) return NULL; switch(type_of(node)) { case LEAF: return make_simple(env, node->left, flag, return_type); case CONSTANT: i_value = cast_from_node(node)->value; s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "%d", i_value); return int_value(i_value); case IDENTIFIER: return string_value(cast_from_node(node)->lexeme); case IF: build_if_stmt(env, node, ++if_count, NULL, NULL, flag, return_type); return NULL; case BREAK: s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__while%dend", while_count); append_code(make_goto(s_tmp)); return NULL; case CONTINUE: s_tmp = malloc(sizeof(char) * 25); sprintf(s_tmp, "__while%d", while_count); append_code(make_goto(s_tmp)); return NULL; case WHILE: build_while_stmt(env, node, ++while_count, ++if_count, flag, return_type); return NULL; case '=': if (flag == INTERPRET_FN_SCAN) return NULL; val1 = make_simple(env, node->left, flag, return_type); val2 = make_simple(env, node->right, flag, return_type); if (val2 && val2->value_type!=VT_INTEGR && val2->value_type!=VT_FUNCTN) { if (val2->value_type == VT_STRING) { val2 = get(env, val2->data.string_value); } else { val2 = get(env, val2->identifier); } if (!val2) fatal("Undeclared identifier"); } /* Check the LHS variable has already been defined */ temp = get(env, to_string(val1)); assert(temp!=NULL, "Variable not defined"); /* Type check the assignment */ type_check_assignment(val1, val2, vt_type_convert(temp->value_type)); temporary = assign(env, val1, val2, 0); if (flag != INTERPRET_FN_SCAN) append_code(make_quad_value("=", val2, NULL, temporary, TT_ASSIGN, 0)); return NULL; case '*': case '/': case '>': case '<': case '%': case '-': case '+': case NE_OP: case LE_OP: case GE_OP: case EQ_OP: temporary = generate_temporary(env, int_value(0)); val1 = make_simple(env, node->left, flag, return_type); val2 = make_simple(env, node->right, flag, return_type); if (val1->value_type==VT_STRING) val1 = get(env, correct_string_rep(val1)); if (val2->value_type==VT_STRING) val2 = get(env, correct_string_rep(val2)); assert(val1 != NULL, "Operand value 1 must not be null"); assert(val2 != NULL, "Operand value 2 must not be null"); if (flag != INTERPRET_FN_SCAN) append_code(make_quad_value(type_to_string(type_of(node)), val1, val2, temporary, TT_OP, type_of(node))); return temporary; case '~': if (flag != INTERPRET_PARAMS && flag!=INTERPRET_FN_SCAN) { /* Params should not be registered, because at this point we're not in the correct environment */ register_variable_subtree_tac(env, node, VT_ANY); } val1 = make_simple(env, node->left, flag, return_type); val2 = make_simple(env, node->right, flag, return_type); if (flag == INTERPRET_PARAMS) { return int_param(to_string(val2), to_int(env, val1)); } return NULL; case 'D': /* val1 is FN definition */ /* val1 is executed in current environment */ val1 = make_simple(env, node->left, flag, return_type); /* New FN body environment */ new_env = create_environment(env); if (val1!=NULL) { /* Point function to the correct fn body */ val1->data.func->node_value = node->right; /* Store function definition in environment */ val2 = store_function(env, val1, new_env); } if (flag != INTERPRET_FN_SCAN) { /* Write out FN Name label */ append_code(make_begin_fn(val2)); append_code(make_fn_def(val2)); /* Make init frame */ temp_quad = make_init_frame(); append_code(temp_quad); /* Define parameters with default empty values */ register_params(new_env, val2->data.func->params); append_code(make_fn_body(val2)); /* Look inside fn body */ val2 = make_simple(new_env, node->right, EMBEDDED_FNS, val1->data.func->return_type); /* Update prepare frame with environment size */ temp_quad->operand1 = int_value(env_size(new_env)); /* Write end of function marker */ append_code(make_end_fn(val2)); } return NULL; case 'd': /* val1 is the type */ val1 = make_simple(env, node->left, flag, return_type); /* val2 is fn name & params */ val2 = make_simple(env, node->right, flag, return_type); /* Store return type */ val2->data.func->return_type = to_int(env, val1); return val2; case 'F': /* FN name in val1 */ val1 = make_simple(env, node->left, flag, return_type); /* Pull our parameters */ val2 = make_simple(env, node->right, INTERPRET_PARAMS, return_type); return build_function(env, val1, val2); case RETURN: val1 = make_simple(env, node->left, flag, return_type); /* Provide lookup for non-constants */ if (val1 && val1->value_type!=VT_INTEGR) { if (val1->value_type == VT_STRING) { val1 = get(env, val1->data.string_value); } else { val1 = get(env, val1->identifier); } if (!val1) fatal("Undeclared identifier"); } type_check_return(val1, return_type); append_code(make_return(val1)); return NULL; case ',': val1 = make_simple(env, node->left, flag, return_type); val2 = make_simple(env, node->right, flag, return_type); if (val1 && val2) { return join(val1, val2); } return NULL; case APPLY: /* FN Name */ val1 = make_simple(env, node->left, flag, return_type); /* Params */ val2 = make_simple(env, node->right, flag, return_type); /* Lookup function */ temp = search(env, to_string(val1), VT_FUNCTN, VT_ANY, 1); if (temp) { int fn_return_type; append_code(prepare_fn(val2)); append_code(push_params(env, val2)); /* If we can't typecheck, set a special UNDEFINED flag to say we can't */ /* typecheck. This can happen with function variables, we do not EASILY know the */ /* return type of the functions they are bound to until runtime. */ fn_return_type = UNDEFINED; if (temp->data.func) { fn_return_type = temp->data.func->return_type; } /* Temporary for result (if any) */ switch(fn_return_type) { case INT: temporary = generate_temporary(env, int_value(0)); break; case VOID: temporary = generate_temporary(env, NULL); break; case FUNCTION: temporary = generate_temporary(env, null_fn); break; default: temporary = generate_untypechecked_temporary(env); break; } append_code(make_fn_call(temporary, temp)); return temporary; } else { fatal("Cannot find function '%s'", to_string(val1)); } return NULL; case FUNCTION: case INT: case VOID: return int_value(type_of(node)); case ';': make_simple(env, node->left, flag, return_type); make_simple(env, node->right, flag, return_type); return NULL; default: fatal("Unrecognised node type"); return NULL; } }