#include <stdio.h> #include <stdlib.h> #include <assert.h> #include "mcc/ast.h" #include "mcc/symbol_table_parse.h" #include "utils/unused.h" // ------------------------------------------------------------ Variable int mcc_symbol_table_add_variable_declaration( struct mcc_ast_declaration *declaration, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec) { assert(declaration); assert(symbol_table); assert(ec); struct mcc_symbol *vs = mcc_symbol_new_symbol_variable(declaration->ident->i_value, declaration->type); // check if already declared if(mcc_symbol_table_get_symbol(symbol_table, vs->variable_name) == NULL) { mcc_symbol_table_insert_symbol(symbol_table, vs); return 0; } else { mcc_symbol_table_add_error(ec, mcc_symbol_table_new_error(&(declaration->node.sloc), MCC_SEMANTIC_ERROR_VARIABLE_ALREADY_DECLARED)); return 1; } } // ------------------------------------------------------------ Array // returns 1 if error int mcc_symbol_table_check_array_declaration_size( struct mcc_ast_declaration *declaration, struct mcc_symbol_table_error_collector *ec) { if(declaration->arr_literal != NULL) { // check if size is int if(declaration->arr_literal->type != MCC_AST_DATA_TYPE_INT) { mcc_symbol_table_add_error( ec, mcc_symbol_table_new_error(&(declaration->node.sloc), MCC_SEMANTIC_ERROR_ARRAY_SIZE_DEFINITION)); return 1; } } return 0; } int mcc_symbol_table_add_array_declaration( struct mcc_ast_declaration *declaration, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec) { assert(declaration); assert(symbol_table); assert(ec); if(mcc_symbol_table_check_array_declaration_size(declaration, ec) == 1) { return 1; } struct mcc_symbol *vs = mcc_symbol_new_symbol_array( declaration->ident->i_value, declaration->type, declaration->arr_literal->i_value); vs->symbol_type = MCC_SYMBOL_TYPE_ARRAY; // check if already declared if(mcc_symbol_table_get_symbol(symbol_table, vs->variable_name) == NULL) { // add array declaration to symbol table mcc_symbol_table_insert_symbol(symbol_table, vs); return 0; } else { mcc_symbol_table_add_error(ec, mcc_symbol_table_new_error(&(declaration->node.sloc), MCC_SEMANTIC_ERROR_ARRAY_ALREADY_DECLARED)); return 1; } } // ---------------------------------------------------------- Statement int mcc_symbol_table_parse_compound_statement( struct mcc_ast_statement *statement, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec ) { assert(statement); assert(statement->type == MCC_AST_STATEMENT_TYPE_COMPOUND); assert(symbol_table); assert(ec); struct mcc_ast_statement_list *stl = statement->statement_list; if(stl == NULL){ return 0; } while(stl->statement != NULL ) { int create_new = 0; if (stl -> statement -> type == MCC_AST_STATEMENT_TYPE_COMPOUND) { create_new = 1; } int statement_result = mcc_symbol_table_parse_statement( stl->statement, symbol_table, ec, create_new ); if(statement_result == 1) { return 1; } if (stl->next == NULL){ break; } else{ stl = stl->next; } } return 0; } int mcc_symbol_table_parse_statement( struct mcc_ast_statement *statement, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec, int create_new) { assert(statement); assert(symbol_table); assert(ec); struct mcc_symbol_table *table = symbol_table; if (create_new) { table = mcc_symbol_table_create_inner_table(symbol_table,symbol_table->parent->sym_table_name); } switch(statement->type) { case MCC_AST_STATEMENT_TYPE_RETURN: case MCC_AST_STATEMENT_TYPE_EXPRESSION: return mcc_symbol_table_validate_expression(statement->expression, symbol_table, ec); case MCC_AST_STATEMENT_TYPE_WHILE: if(mcc_symbol_table_validate_expression( statement->while_condition, symbol_table, ec) == 0) { if (mcc_symbol_table_validate_condition_to_type_bool( statement -> while_condition, symbol_table, ec ) == 0) { return mcc_symbol_table_parse_statement( statement->while_stmt, table, ec, 1); } else { return 1; } } else { return 1; } case MCC_AST_STATEMENT_TYPE_IF:; if(mcc_symbol_table_validate_expression( statement->if_condition, symbol_table, ec) == 0) { if (mcc_symbol_table_validate_condition_to_type_bool( statement -> if_condition, symbol_table, ec ) == 0) { return mcc_symbol_table_parse_statement( statement->if_stmt, symbol_table, ec, 1); } else { return 1; } } else { return 1; } case MCC_AST_STATEMENT_TYPE_DECL: if(mcc_symbol_table_get_symbol(symbol_table, statement->declaration->ident->i_value) != NULL) { mcc_symbol_table_add_error(ec, mcc_symbol_table_new_error(&(statement->node.sloc), MCC_SEMANTIC_ERROR_VARIABLE_ALREADY_DECLARED)); } if (statement->declaration->arr_literal != NULL) { // array declaration return mcc_symbol_table_add_array_declaration(statement->declaration, symbol_table, ec); } else { // variable declaration return mcc_symbol_table_add_variable_declaration(statement->declaration, symbol_table, ec); } case MCC_AST_STATEMENT_TYPE_ASSGN: case MCC_AST_STATEMENT_TYPE_ASSGN_ARR: return mcc_symbol_table_validate_assignment_semantic(statement->assignment, symbol_table, ec); case MCC_AST_STATEMENT_TYPE_COMPOUND: return mcc_symbol_table_parse_compound_statement( statement, symbol_table, ec ); default: return 0; } } // ---------------------------------------------------------- Function int mcc_symbol_table_parse_function( struct mcc_ast_function *func_def, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec ) { assert(func_def); assert(symbol_table); assert(ec); // create new scope and parse function struct mcc_symbol_table *sub_table = mcc_symbol_table_create_inner_table(symbol_table,func_def->identifier->i_value); // add params to sub table if (func_def -> parameter != NULL && func_def -> parameter -> size > 0) { struct mcc_ast_parameter *p = func_def -> parameter; for (int i = 0; i < p -> size; i++) { struct mcc_ast_declaration *declaration = p -> parameters[i]; // at this point symbol table is still empty -> adding won't result in an error if (declaration -> arr_literal != NULL) { // array declaration mcc_symbol_table_add_array_declaration(declaration, sub_table, ec); } else { // variable declaration mcc_symbol_table_add_variable_declaration(declaration, sub_table, ec); } } } int valid_function_body = mcc_symbol_table_parse_statement(func_def -> statement, sub_table, ec, 0); if (valid_function_body == 0) { // valid function body - check if return type of non-void function is correct if (func_def -> return_type != MCC_AST_DATA_TYPE_VOID) { valid_function_body = mcc_symbol_table_validate_statement_return( func_def -> statement, func_def -> return_type, sub_table, ec ); } } return valid_function_body; } int mcc_symbol_table_add_function_declaration( struct mcc_ast_function *func_def, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec) { assert(symbol_table); assert(ec); assert(func_def); struct mcc_symbol *fs = mcc_symbol_new_symbol_function( func_def->identifier->i_value, func_def->return_type, func_def->parameter); // check if already declared if(mcc_symbol_table_get_symbol(symbol_table, fs -> variable_name) == NULL) { mcc_symbol_table_insert_symbol(symbol_table, fs); return 0; } else { // already declared - create already declared error message mcc_symbol_table_add_error(ec, mcc_symbol_table_new_error(&(func_def->node.sloc), MCC_SEMANTIC_ERROR_FUNC_ALREADY_DECLARED)); return 1; } } // ---------------------------------------------------------- Program void mcc_add_builtin_function( struct mcc_symbol_table *symbol_table, char *variable_name, enum mcc_ast_data_type return_type, enum mcc_ast_data_type param_type) { struct mcc_symbol *symbol = malloc(sizeof(*symbol)); symbol -> variable_name = variable_name; symbol -> data_type = return_type; symbol -> symbol_type = MCC_SYMBOL_TYPE_BUILTIN_FUNCTION; symbol -> func_arguments = mcc_create_dynamic_array(5); if (param_type != MCC_AST_DATA_TYPE_VOID) { struct mcc_symbol_function_argument *fp = malloc(sizeof(*fp)); fp -> arg_type = param_type; mcc_add_to_array(symbol -> func_arguments, fp); } symbol_table -> inner_tables -> arr[0] = NULL; mcc_symbol_table_insert_symbol(symbol_table,symbol); } void mcc_symbol_table_add_builtins(struct mcc_symbol_table *symbol_table) { mcc_add_builtin_function(symbol_table,"print_nl",MCC_AST_DATA_TYPE_VOID,MCC_AST_DATA_TYPE_VOID); mcc_add_builtin_function(symbol_table,"print",MCC_AST_DATA_TYPE_VOID,MCC_AST_DATA_TYPE_STRING); mcc_add_builtin_function(symbol_table,"print_int",MCC_AST_DATA_TYPE_VOID,MCC_AST_DATA_TYPE_INT); mcc_add_builtin_function(symbol_table,"print_float",MCC_AST_DATA_TYPE_VOID,MCC_AST_DATA_TYPE_FLOAT); mcc_add_builtin_function(symbol_table,"read_int",MCC_AST_DATA_TYPE_INT,MCC_AST_DATA_TYPE_VOID); mcc_add_builtin_function(symbol_table,"read_float",MCC_AST_DATA_TYPE_FLOAT,MCC_AST_DATA_TYPE_VOID); } int mcc_symbol_table_parse_program( struct mcc_ast_program *program, struct mcc_symbol_table *symbol_table, struct mcc_symbol_table_error_collector *ec) { assert(program); int function_parse = 0; for(int i = 0; i < program->size; i++) { function_parse = mcc_symbol_table_add_function_declaration(program->function_def[i], symbol_table, ec); if (function_parse) break; } // if everything so far ok if (function_parse == 0) { // parse all functions for(int i = 0; i < program->size; i++) { function_parse = mcc_symbol_table_parse_function(program->function_def[i], symbol_table, ec); if (function_parse) break; } } return function_parse; } struct mcc_symbol_table *mcc_symbol_table_build_program(struct mcc_ast_program *program, struct mcc_symbol_table_error_collector *ec) { assert(program); struct mcc_symbol_table *st = mcc_symbol_table_new_table(NULL); mcc_symbol_table_add_builtins(st); if (mcc_symbol_table_parse_program(program, st, ec) == 0) { // check if main exists if (mcc_symbol_table_validate_main(program, st, ec) == 0) { return st; } else { return NULL; } } else { return NULL; } } struct mcc_symbol_table *mcc_symbol_table_build_function(struct mcc_ast_function *function, struct mcc_symbol_table_error_collector *ec) { assert(function); struct mcc_symbol_table *st = mcc_symbol_table_new_table(NULL); mcc_symbol_table_add_builtins(st); int parse_function = mcc_symbol_table_add_function_declaration(function, st, ec); if (parse_function == 0) { if (mcc_symbol_table_parse_function(function, st, ec) == 0) { return st; } else { // handle error collection return NULL; } } else { // handle error collection return NULL; } }