#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <mcc/ast.h> #include "mcc/tac_build.h" #include "mcc/tac_string_builder.h" #include "mcc/symbol_table.h" #include "mcc/symbol_table_validate.h" #include "mcc/symbol_table_print.h" #include "mcc/utils.h" // -------------------------------- parse expression void mcc_tac_parse_expression(struct mcc_ast_expression *expression, struct mcc_tac *tac) { assert(expression); assert(tac); switch (expression -> type) { case MCC_AST_EXPRESSION_TYPE_IDENTIFIER: { struct mcc_ast_identifier *identifier = expression->identifier; enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression,tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_ident(type); char *arg1 = identifier->i_value; mcc_tac_create_and_add_new_entry_temp(op,arg1,NULL,tac); } break; case MCC_AST_EXPRESSION_TYPE_LITERAL : { struct mcc_ast_literal *literal = expression->literal; enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_literal(literal->type); char *arg1 = malloc((size_t ) mcc_get_number_of_digits(tac->temporary_count) + 2); switch (op) { case MCC_TAC_BOOL : arg1 = literal->b_value ? "true" : "false"; break; case MCC_TAC_INT : sprintf(arg1, "%d", literal->i_value); break; case MCC_TAC_FLOAT : sprintf(arg1, "%f", literal->f_value); break; case MCC_TAC_STRING : arg1= literal->s_value; break; default: break; } mcc_tac_create_and_add_new_entry_temp(op,arg1,NULL,tac); } break; case MCC_AST_EXPRESSION_TYPE_CALL_EXPRESSION : { //TODO check for array int arg_size; if(expression->argument) { arg_size = expression->argument->expressions->size; for(int i = 0; i < arg_size; i++) { struct mcc_ast_expression *parameter = expression->argument->expressions->arr[i]; enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(parameter, tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_param(type); mcc_tac_parse_expression(parameter, tac); char *arg1 = tac->last_label; mcc_tac_create_and_add_new_entry(op, arg1, NULL, NULL, tac); } } char *arg1 = malloc((size_t ) mcc_get_number_of_digits(tac->temporary_count) + 2); sprintf(arg1, "$%d", arg_size); char *result = expression->function_name->i_value; mcc_tac_create_and_add_new_entry(MCC_TAC_CALL, arg1, NULL, result, tac); enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression, tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_ident(type); if(type != MCC_TAC_UNKNOWN) { char *arg1 = mcc_tac_new_return_function_name(result); mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac); } } break; case MCC_AST_EXPRESSION_TYPE_UNARY_OP : { enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression, tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_unary(type); mcc_tac_parse_expression(expression->unary_expression, tac); char *arg1 = tac->last_temporary; mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac); } break; case MCC_AST_EXPRESSION_TYPE_BINARY_OP : { enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression, tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_binary(expression->op, type); mcc_tac_parse_expression(expression->lhs, tac); char *arg1 = tac->last_temporary; mcc_tac_parse_expression(expression->rhs, tac); char *arg2 = tac->last_temporary; mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac); } break; case MCC_AST_EXPRESSION_TYPE_PARENTH : mcc_tac_parse_expression(expression->expression,tac); break; case MCC_AST_EXPRESSION_TYPE_BRACKET : { enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression, tac->current_symbol_table); enum mcc_tac_operation op = mcc_convert_ast_type_to_tac_load(type); struct mcc_ast_identifier *ident = expression->bracket_identifier; char *arg1 = ident->i_value; mcc_tac_parse_expression(expression->bracket_expression, tac); char *arg2 = tac->last_temporary; mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac); } break; default: return; } } // -------------------------------- parse statement void mcc_tac_parse_statement_list(struct mcc_ast_statement_list *stl, struct mcc_tac *tac) { assert(stl); assert(tac); while (stl != NULL) { mcc_tac_parse_statement(stl -> statement, tac); stl = stl -> next; } } struct mcc_tac *mcc_tac_parse_statement(struct mcc_ast_statement *statement, struct mcc_tac *tac) { printf("Parse statement \n"); switch (statement -> type) { case MCC_AST_STATEMENT_TYPE_COMPOUND: printf("\t Compound \n"); mcc_tac_parse_statement_list(statement -> statement_list, tac); break; case MCC_AST_STATEMENT_TYPE_IF: { printf("\t If \n"); // evaluate if expression mcc_tac_parse_expression(statement -> while_condition, tac); char *last_temp = tac -> last_temporary; // now do that jump / jumpfalse stuff here char *if_label = mcc_tac_new_label_string(tac); mcc_tac_create_and_add_new_entry(MCC_TAC_JMP_FALSE, last_temp, NULL, if_label, tac); // scope go to deeper scope and save current index int current_scope_index = tac -> current_symbol_index; mcc_tac_enter_next_deeper_scope(tac); mcc_tac_parse_statement(statement -> if_stmt, tac); // go back to previous scope mcc_tac_exit_to_outer_scope(tac, current_scope_index); tac -> current_symbol_index++; char *else_label= mcc_tac_new_label_string(tac); mcc_tac_create_and_add_new_entry(MCC_TAC_JMP, NULL, NULL, else_label, tac); if (statement -> else_stmt != NULL) { // jump last label current_scope_index = tac -> current_symbol_index; mcc_tac_enter_next_deeper_scope(tac); mcc_tac_parse_statement(statement -> else_stmt, tac); //go back to previous scope mcc_tac_exit_to_outer_scope(tac, current_scope_index); tac -> current_symbol_index++; } } break; case MCC_AST_STATEMENT_TYPE_EXPRESSION: printf("\t Expression \n"); mcc_tac_parse_expression(statement -> expression, tac); break; case MCC_AST_STATEMENT_TYPE_WHILE: { printf("\t While \n"); mcc_tac_parse_expression(statement -> while_condition, tac); char *last_temp = tac -> last_temporary; char *while_label = mcc_tac_new_label_string(tac); mcc_tac_create_and_add_new_entry(MCC_TAC_JMP_FALSE, last_temp, NULL, while_label, tac); int current_scope_index = tac -> current_symbol_index; mcc_tac_enter_next_deeper_scope(tac); mcc_tac_parse_statement(statement -> if_stmt, tac); //go back to previous scope mcc_tac_exit_to_outer_scope(tac, current_scope_index); tac -> current_symbol_index++; } break; case MCC_AST_STATEMENT_TYPE_DECL: { // Check nicht ganz um was es da geht // struct mCc_ast_literal *array_size = statement->declaration->array_size; // if (array_size) { // builder->current_variable_count += atoi(array_size->value); // create_and_add_line(builder, MCC_TAC_OPERATION_ARRAY_DECLARATION, // array_size->value, NULL, // statement->declaration->identifier->name); // } // break; // } } break; case MCC_AST_STATEMENT_TYPE_ASSGN_ARR: case MCC_AST_STATEMENT_TYPE_ASSGN: { printf("\t Assignment \n"); // get type struct mcc_ast_assignment *a = statement -> assignment; char *result = statement -> assignment -> identifier ->i_value; enum mcc_ast_data_type assignment_type = mcc_symbol_table_get_symbol( tac->current_symbol_table, result, true) -> data_type; enum mcc_tac_operation tac_op = mcc_convert_ast_type_to_tac_literal(assignment_type); if (a -> type == MCC_AST_ASSIGNMENT_TYPE_ARRAY) { mcc_tac_parse_expression(a -> array_ass.index, tac); char *arg2 = tac -> last_temporary; mcc_tac_parse_expression(a -> array_ass.rhs, tac); char *arg1 = tac -> last_temporary; mcc_tac_create_and_add_new_entry(tac_op, arg1, arg2, result, tac); } else { // evaluate expression mcc_tac_parse_expression(a -> normal_ass.rhs, tac); char *arg1 = tac -> last_temporary; mcc_tac_create_and_add_new_entry(tac_op, arg1, NULL, result, tac); } } break; case MCC_AST_STATEMENT_TYPE_RETURN: { printf("\t Return \n"); // TODO: get symbol table name from a seperate variable (tac -> root_table) // get expression type enum mcc_ast_data_type return_type = mcc_symbol_table_get_expression_return_type( statement -> expression, tac -> current_symbol_table ); enum mcc_tac_operation tac_op = mcc_convert_ast_type_to_tac_literal(return_type); mcc_tac_parse_expression(statement -> expression, tac); char *arg1 = tac -> last_temporary; char *result = mcc_tac_new_return_function_name(tac -> current_symbol_table -> sym_table_name); mcc_tac_create_and_add_new_entry(MCC_TAC_RETURN, arg1, NULL, result, tac); } break; } } // -------------------------------- parse function int mcc_tac_parse_function(struct mcc_ast_function *f, struct mcc_tac *tac) { assert(f); assert(tac); // TODO: do something with params if (f->statement != NULL) { mcc_tac_parse_statement(f -> statement, tac); } } // start parsing program struct mcc_tac *mcc_tac_build(struct mcc_ast_program *program, struct mcc_symbol_table *st) { struct mcc_tac *tac = mcc_tac_new(NULL, st); struct mcc_ast_function *f = NULL; // look for main an start parsing program for (int i = 0; i < program -> function_def -> size; i++) { f = program -> function_def -> arr[i]; if (strcmp(f -> identifier -> i_value, "main") == 0) { struct mcc_symbol_table *t = mcc_symbol_table_get_inner_table_by_name(st, "main"); tac -> current_symbol_table = t; tac -> current_symbol_index = 0; mcc_symbol_table_print(tac -> current_symbol_table, stdout); if (t != NULL) { mcc_tac_parse_function(f, tac); } } } printf("Build tac over \n"); return tac; }