Skip to content
Snippets Groups Projects
tac_build.c 12.1 KiB
Newer Older
Clemens Paumgarten's avatar
Clemens Paumgarten committed
#include <stdio.h>
Clemens Paumgarten's avatar
Clemens Paumgarten committed
#include <string.h>
#include <assert.h>
FlorianKrull's avatar
FlorianKrull committed

Clemens Paumgarten's avatar
Clemens Paumgarten committed
#include "tac_build.h"
#include "symbol_table.h"
FlorianKrull's avatar
FlorianKrull committed
#include "utils.h"
FlorianKrull's avatar
FlorianKrull committed

Clemens Paumgarten's avatar
Clemens Paumgarten committed
// -------------------------------- 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: {
FlorianKrull's avatar
FlorianKrull committed
            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 = convert_ast_type_to_tac_ident(type);

            char *arg1 = identifier->i_value;
            mcc_tac_create_and_add_new_entry_temp(op,arg1,NULL,tac);
        case MCC_AST_EXPRESSION_TYPE_LITERAL : {
FlorianKrull's avatar
FlorianKrull committed
            struct mcc_ast_literal *literal = expression->literal;            
            enum mcc_tac_operation op = convert_ast_type_to_tac_literal(literal->type);
            char *arg1;
            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 : {
FlorianKrull's avatar
FlorianKrull committed
            //TODO check for array
            int arg_size;
            if(expression->argument) {
FlorianKrull's avatar
FlorianKrull committed
                arg_size = expression->argument->expressions->size;
                for(int i = 0; i < arg_size; i++) {
FlorianKrull's avatar
FlorianKrull committed

                    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);
FlorianKrull's avatar
FlorianKrull committed
                    enum mcc_tac_operation op = convert_ast_type_to_tac_param(type);

                    mcc_tac_parse_expression(parameter, tac);
FlorianKrull's avatar
FlorianKrull committed
                    char *arg1 = tac->last_label;
                    mcc_tac_create_and_add_new_entry(op, arg1, NULL, NULL, tac);
            char *arg1 = malloc(mcc_get_number_of_digits(tac->temporary_count) + 2);
FlorianKrull's avatar
FlorianKrull committed
            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);
FlorianKrull's avatar
FlorianKrull committed
            enum mcc_tac_operation op = 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);
FlorianKrull's avatar
FlorianKrull committed
            enum mcc_tac_operation op = convert_ast_type_to_tac_unary(type);

            mcc_tac_parse_expression(expression->unary_expression, tac);
FlorianKrull's avatar
FlorianKrull committed
            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);
FlorianKrull's avatar
FlorianKrull committed
            enum mcc_tac_operation op = convert_ast_type_to_tac_binary(expression->op, type);

            mcc_tac_parse_expression(expression->lhs, tac);
FlorianKrull's avatar
FlorianKrull committed
            char *arg1 = tac->last_temporary;

            mcc_tac_parse_expression(expression->rhs, tac);
FlorianKrull's avatar
FlorianKrull committed
            char *arg2 = tac->last_temporary;

            mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac);
        case MCC_AST_EXPRESSION_TYPE_PARENTH :
FlorianKrull's avatar
FlorianKrull committed
            mcc_tac_parse_expression(expression->expression,tac);
        case MCC_AST_EXPRESSION_TYPE_BRACKET : {
            enum mcc_ast_data_type type = mcc_symbol_table_get_expression_return_type(expression,
                                                                                      tac->current_symbol_table);
FlorianKrull's avatar
FlorianKrull committed
            enum mcc_tac_operation op = 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);
FlorianKrull's avatar
FlorianKrull committed

            char *arg2 = tac->last_temporary;

            mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac);
        } break;
Clemens Paumgarten's avatar
Clemens Paumgarten committed
        default:
            return;
Clemens Paumgarten's avatar
Clemens Paumgarten committed
}
Clemens Paumgarten's avatar
Clemens Paumgarten committed
// -------------------------------- parse statement
FlorianKrull's avatar
FlorianKrull committed

Clemens Paumgarten's avatar
Clemens Paumgarten committed
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) {
        switch (statement -> type) {
            case MCC_AST_STATEMENT_TYPE_COMPOUND:
                mcc_tac_parse_statement_list(statement -> statement_list, tac);
                break;
            case MCC_AST_STATEMENT_TYPE_IF: {

                // 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_scoper(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_scoper(tac, current_scope_index);
                    tac -> current_symbol_index++;
                }

            } break;
            case MCC_AST_STATEMENT_TYPE_EXPRESSION:
                mcc_tac_parse_expression(statement -> expression, tac);
                break;
            case MCC_AST_STATEMENT_TYPE_WHILE: {
                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_scoper(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: {
                // 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 = convert_ast_type_to_tac_operation(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: {
                // 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 = convert_ast_type_to_tac_operation(return_type);

                mcc_tac_parse_expression(statement -> expression, tac);
                char *arg1 = tac -> last_temporary;

FlorianKrull's avatar
FlorianKrull committed
                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;
Clemens Paumgarten's avatar
Clemens Paumgarten committed
}

// -------------------------------- 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);
Clemens Paumgarten's avatar
Clemens Paumgarten committed

Clemens Paumgarten's avatar
Clemens Paumgarten committed
// 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);
Clemens Paumgarten's avatar
Clemens Paumgarten committed

    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");

            if (t != NULL) {
Clemens Paumgarten's avatar
Clemens Paumgarten committed
    }

    return tac;
}