Newer
Older

Clemens Paumgarten
committed
#include <stdlib.h>
#include "mcc/symbol_table_validate.h"
#include "mcc/symbol_table_print.h"
#include "mcc/utils.h"
/*
* Source for multiple parts:
* https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/lectures/13/Slides13.pdf
*/
// -------------------------------- parse expression
void mcc_tac_parse_expression(struct mcc_ast_expression *expression, struct mcc_tac *tac) {
assert(expression);
assert(tac);
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);
mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac);

Clemens Paumgarten
committed
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);
mcc_tac_create_and_add_new_entry_temp(op, literal -> b_value ? "true" : "false", NULL, tac);
case MCC_TAC_INT : {
// + 2 for \0 and in case result is 0
char arg1[mcc_get_number_of_digits(literal -> i_value) + 2];
sprintf(arg1, "%d", literal -> i_value);
mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac);
} break;
case MCC_TAC_FLOAT : {
// just for conversion - when storing the value in tac_new_entry it will take actual string length
char arg1[1000];
gcvt(literal->f_value, 6, arg1);
mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac);
} break;
mcc_tac_create_and_add_new_entry_temp(op, literal -> s_value, NULL, tac);
case MCC_AST_EXPRESSION_TYPE_CALL_EXPRESSION : {
// check if call expression has arguments and push/pop parameters
int arg_size = 0;
if(expression->argument != NULL) {
struct mcc_ast_argument *argument = expression -> argument;
arg_size = argument -> expressions -> size;
// push args
for(int i = arg_size - 1; i >= 0; --i) {
struct mcc_ast_expression *parameter = argument->expressions->arr[i];
bool is_array = parameter -> bracket_expression != NULL;
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_push(type, is_array);
mcc_tac_parse_expression(parameter, tac);
char *arg1 = tac->last_temporary;
mcc_tac_create_and_add_new_entry(op, arg1, NULL, NULL, tac);
{
char *result = expression->function_name->i_value;
mcc_tac_create_and_add_new_entry(MCC_TAC_CALL, NULL, 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);
char *arg1 = mcc_tac_new_return_function_name(result);
mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac);
}
}
// POP params
if(expression->argument != NULL) {
struct mcc_ast_argument *argument = expression -> argument;
arg_size = argument -> expressions -> size;
for(int i = arg_size - 1; i >= 0; --i) {
struct mcc_ast_expression *parameter = argument->expressions->arr[i];
bool is_array = parameter -> bracket_expression != NULL;
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_pop(type, true);
// get array size from symbol table
long array_size = 0;
if (is_array) {
struct mcc_symbol *s = mcc_symbol_table_get_symbol(tac -> current_symbol_table,
parameter -> bracket_identifier ->i_value, is_array);
if (s != NULL) {
array_size = s ->array_size;
}
char arg1[mcc_get_number_of_digits((int) array_size) + 2];
mcc_tac_create_and_add_new_entry(op, arg1, NULL, NULL, tac);
} else {
// printf("%d\n", op);
mcc_tac_create_and_add_new_entry(op, NULL, NULL, 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);
mcc_tac_create_and_add_new_entry_temp(op, arg1, NULL, tac);
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);
mcc_tac_parse_expression(expression->rhs, tac);
mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac);
case MCC_AST_EXPRESSION_TYPE_PARENTH :
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);
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);
mcc_tac_create_and_add_new_entry_temp(op, arg1, arg2, tac);
void mcc_tac_parse_statement_list(struct mcc_ast_statement_list *stl, struct mcc_tac *tac) {
assert(tac);
while(stl != NULL) {
mcc_tac_parse_statement(stl->statement, tac);
stl = stl->next;
void mcc_tac_parse_statement(struct mcc_ast_statement *statement, struct mcc_tac *tac) {
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->if_condition, tac);
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;

Clemens Paumgarten
committed
mcc_tac_enter_next_deeper_scope(tac);

Clemens Paumgarten
committed
mcc_tac_parse_statement(statement->if_stmt, tac);
// go back to previous scope
mcc_tac_exit_to_outer_scope(tac, current_scope_index);

Clemens Paumgarten
committed

Clemens Paumgarten
committed
char *else_label = mcc_tac_new_label_string(tac);
mcc_tac_create_and_add_new_entry(MCC_TAC_JMP, NULL, NULL, else_label, tac);
// end if code with if_label
mcc_tac_create_and_add_new_entry(MCC_TAC_LABEL, NULL, NULL, if_label, tac);
if(statement->else_stmt != NULL) {
current_scope_index = tac->current_symbol_index;

Clemens Paumgarten
committed
mcc_tac_enter_next_deeper_scope(tac);
mcc_tac_parse_statement(statement->else_stmt, tac);

Clemens Paumgarten
committed
//go back to previous scope
mcc_tac_exit_to_outer_scope(tac, current_scope_index);

Clemens Paumgarten
committed
// set else label anyway
mcc_tac_create_and_add_new_entry(MCC_TAC_LABEL, NULL, NULL, else_label, tac);
case MCC_AST_STATEMENT_TYPE_EXPRESSION:
mcc_tac_parse_expression(statement->expression, tac);
break;
case MCC_AST_STATEMENT_TYPE_WHILE: {
char *before_while_label = mcc_tac_new_label_string(tac);
char *after_while_label = mcc_tac_new_label_string(tac);
mcc_tac_create_and_add_new_entry(MCC_TAC_LABEL, NULL, NULL, before_while_label, tac);
mcc_tac_parse_expression(statement->while_condition, tac);

Clemens Paumgarten
committed

Clemens Paumgarten
committed
mcc_tac_create_and_add_new_entry(MCC_TAC_JMP_FALSE, last_temp, NULL, after_while_label, tac);

Clemens Paumgarten
committed
int current_scope_index = tac->current_symbol_index;
mcc_tac_enter_next_deeper_scope(tac);

Clemens Paumgarten
committed
mcc_tac_parse_statement(statement->while_stmt, tac);

Clemens Paumgarten
committed
//go back to previous scope
mcc_tac_exit_to_outer_scope(tac, current_scope_index);
// jump back up
mcc_tac_create_and_add_new_entry(MCC_TAC_JMP, NULL, NULL, before_while_label, tac);
// add end while label
mcc_tac_create_and_add_new_entry(MCC_TAC_LABEL, NULL, NULL, after_while_label, tac);
case MCC_AST_STATEMENT_TYPE_DECL: {
struct mcc_ast_declaration *declaration = statement -> declaration;
struct mcc_ast_literal *arr_literal = declaration->arr_literal;
// Add entry for array size
if(arr_literal != NULL) {
// save array size in first argument
char arg1[mcc_get_number_of_digits(arr_literal->i_value) + 2];
sprintf(arg1, "%d", arr_literal->i_value);
mcc_tac_create_and_add_new_entry(
MCC_TAC_ARR_DECL,
mcc_ast_type_to_string_size(declaration ->type),
NULL,
arg1,
tac
);
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;

Clemens Paumgarten
committed
enum mcc_ast_data_type assignment_type = mcc_symbol_table_get_symbol(
tac->current_symbol_table,
result,

Clemens Paumgarten
committed
enum mcc_tac_operation tac_op = mcc_convert_ast_type_to_tac_assignment(assignment_type);
if(a->type == MCC_AST_ASSIGNMENT_TYPE_ARRAY) {
mcc_tac_parse_expression(a->array_ass.index, tac);

Clemens Paumgarten
committed

Clemens Paumgarten
committed
mcc_tac_parse_expression(a->array_ass.rhs, tac);
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);

Clemens Paumgarten
committed
mcc_tac_create_and_add_new_entry(tac_op, arg1, NULL, result, tac);
}
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);
}
// -------------------------------- parse function
// TODO: check if not used when assembly code is generated (probably not) -> then kick this out
//void parse_params(struct mcc_ast_parameter *parameter, struct mcc_tac *tac) {
// // parse params from right to left
// for(int i = 0; i < parameter->parameters->size; i++) {
// struct mcc_ast_declaration *param_decl = (struct mcc_ast_declaration *) parameter->parameters->arr[i];
// bool is_array = param_decl->arr_literal != NULL;
// enum mcc_tac_operation tac_op = mcc_convert_ast_type_to_tac_param(param_decl->type, is_array);
//
// // save array size in first argument
// int number_of_digits = mcc_get_number_of_digits(param_decl->arr_literal->i_value);
// char *arg1 = NULL;
//
// if(is_array) {
// snprintf(arg1, sizeof(char) * number_of_digits, "%d", param_decl->arr_literal->i_value);
// }
//
// mcc_tac_create_and_add_new_entry(tac_op, arg1, NULL, param_decl->ident->i_value, tac);
// }
//}
void mcc_tac_parse_function(struct mcc_ast_function *f, struct mcc_tac *tac) {
struct mcc_symbol_table *t = mcc_symbol_table_get_inner_table_by_name(tac->root_table, f->identifier->i_value);
tac->current_symbol_table = t;
tac->current_symbol_index = 0;
char arg1[mcc_get_number_of_digits(tac->funcion_counter) + 2];
sprintf(arg1, "%d", tac -> funcion_counter);
mcc_tac_create_and_add_new_entry(MCC_TAC_FUNCTION_START, arg1, f -> identifier -> i_value, NULL, tac);
if(f->statement != NULL) {
mcc_tac_parse_statement(f->statement, tac);
Dynamic_Array *tac_entries = tac -> tac_entries;
struct mcc_tac_entry *last_tac_entry = (struct mcc_tac_entry *) tac_entries -> arr[tac_entries -> size - 1];
// add function-end operation if last operation is not return
if (last_tac_entry -> tac_op != MCC_TAC_RETURN) {
mcc_tac_create_and_add_new_entry(MCC_TAC_FUNCTION_END, NULL, NULL, NULL, tac);
}
tac -> funcion_counter += 1;
// start parsing program
struct mcc_tac *mcc_tac_build(struct mcc_ast_program *program, struct mcc_symbol_table *st) {
for(int i = 0; i < program->function_def->size; i++) {
f = program->function_def->arr[i];
// parse all functions one after another
mcc_tac_parse_function(f, tac);
// mcc_tac_create_and_add_new_entry(MCC_TAC_EOF,NULL,NULL,NULL,tac);