diff --git a/function.cpp b/function.cpp new file mode 100644 index 0000000..d77213c --- /dev/null +++ b/function.cpp @@ -0,0 +1,57 @@ +#include "function.h" +#include +#include + +struct t_parameter { + std::string name; + uint32_t type; +}; + +struct t_function { + std::string name; + uint32_t address; + uint32_t type; + std::vector parameters; +}; + +static std::vector functions; +static int current_function = -1; + +const bool function_register(const std::string name, const uint32_t address) { + for (auto f : functions) if (f.name == name) return false; + functions.push_back({name, address}); + current_function = functions.size()-1; + return true; +} + +void function_set_type(const uint32_t type) { + functions[current_function].type = type; +} + +const int function_get_type() { + return functions[current_function].type; +} + +const bool function_parameter_add(const std::string name, const uint32_t type) { + for (auto p : functions[current_function].parameters) if (p.name == name) return false; + functions[current_function].parameters.push_back({name, type}); + return true; +} + +const bool function_exists(const std::string name) { + for (auto f : functions) if (f.name == name) return true; + return false; +} + +const uint32_t function_get_address(const std::string name) { + for (auto f : functions) if (f.name == name) return f.address; + return 0; +} + +const int function_get_num_parameters() { + return functions[current_function].parameters.size(); +} + +const int function_get_parameter_type(const int index) { + return functions[current_function].parameters[index].type; +} diff --git a/function.h b/function.h index b826441..59935dc 100644 --- a/function.h +++ b/function.h @@ -5,8 +5,17 @@ // Register a new function. Returns false if a function with the same name already exists const bool function_register(const std::string name, const uint32_t address); -// Add a parameter to the last registered function -void function_parameter_add(const std::string name, const int type); +// Set the return type of the last searched function +void function_set_type(const uint32_t type); + +// Get the return type of the last searched function or -1 if none +const int function_get_type(); + +// Add a parameter to the last registered function, returns false if there's a parameter already named like that +const bool function_parameter_add(const std::string name, const uint32_t type); + +// Check if there's a function with that name +const bool function_exists(const std::string name); // Retrieve the address of the specified function, or zero if there's no such function diff --git a/parser.cpp b/parser.cpp index 0f25f7f..4f18547 100644 --- a/parser.cpp +++ b/parser.cpp @@ -2,11 +2,13 @@ #include "tokenizer.h" #include "scope.h" #include "types.h" +#include "function.h" #include "error.h" #include #include #include #include +#include #define MAX_CODE_SIZE 65536 #define MAX_LABELS 256 @@ -417,6 +419,7 @@ static void parse_expression() { static bool identifier_exists(const std::string identifier) { if (scope_variable_exists(identifier)) return true; if (types_exist(identifier) != -1) return true; + if (function_exists(identifier)) return true; return false; } @@ -474,8 +477,7 @@ static void parse_var() { static void parse_struct() { EXPECT(TOKEN_IDENTIFIER, "Expected identifier"); - char struct_name[40]; - strcpy(struct_name, tkn_get_string()); + const std::string struct_name = tkn_get_string(); if (identifier_exists(struct_name)) HALT("Identifier already exists"); const int struct_num = types_add(struct_name); tkn_next(); @@ -485,7 +487,6 @@ static void parse_struct() { char member_name[40]; strcpy(member_name, tkn_get_string()); tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'"); - // TODO [RZC 04/05/2021] Implement support for arrays tkn_next(); if (tkn_get_token() == TOKEN_ARRAY) { tkn_next(); EXPECT(TOKEN_OF, "Expected 'of'"); @@ -495,8 +496,7 @@ static void parse_struct() { tkn_next(); } EXPECT(TOKEN_IDENTIFIER, "Expected type identifier"); - char type_name[40]; - strcpy(type_name, tkn_get_string()); + const std::string type_name = tkn_get_string(); const int type_num = types_exist(type_name); if (type_num == -1) HALT("Unknown type"); types_add_member(struct_num, member_name, type_num, member_length); @@ -505,6 +505,51 @@ static void parse_struct() { tkn_next(); } +static void parse_function() { + EXPECT(TOKEN_IDENTIFIER, "Expected identifier"); + const std::string function_name = tkn_get_string(); + if (identifier_exists(function_name)) HALT("Identifier already exists"); + function_register(function_name, codepos); + tkn_next(); EXPECT(TOKEN_LPAR, "Expected '('"); + tkn_next(); + scope_open_local(); + std::stack addresses; + while (tkn_get_token() != TOKEN_RPAR) { + if (function_get_num_parameters() != 0) { + EXPECT(TOKEN_COMMA, "Expected ',' or ')'"); + tkn_next(); + } + EXPECT(TOKEN_IDENTIFIER, "Expected identifier"); + const std::string param_name = tkn_get_string(); + tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'"); + tkn_next(); EXPECT(TOKEN_IDENTIFIER, "Expected type identifier"); + const std::string type_name = tkn_get_string(); + const int type_num = types_exist(type_name); + if (type_num == -1) HALT("Unknown type"); + if (!function_parameter_add(param_name, type_num)) HALT("Parameter name already used"); + addresses.push(scope_declare_variable(param_name, type_num, 1)); + tkn_next(); + } + while (!addresses.empty()) { + emmit(OP_STL); + emmit_dw(addresses.top()); + addresses.pop(); + } + tkn_next(); + if (tkn_get_token() == TOKEN_AS) { + tkn_next(); EXPECT(TOKEN_IDENTIFIER, "Expected type identifier"); + const std::string type_name = tkn_get_string(); + const int type_num = types_exist(type_name); + if (type_num == -1) HALT("Unknown type"); + function_set_type(type_num); + tkn_next(); + } + parse_statements(); + scope_close_local(); + EXPECT(TOKEN_END, "Expected statement or 'end'"); + tkn_next(); +} + /*static void parse_dim() { EXPECT(TOKEN_IDENTIFIER, "Expected variable"); char varname[40]; @@ -703,12 +748,19 @@ static void parse_gosub() { tkn_next(); }*/ -/* + static void parse_return() { - // TODO [RZC 27/04/2021] Falta afegir paràmetre de retorn + const int return_type = function_get_type(); + if (return_type != -1) { + if (return_type == 0) { + parse_expression(); + } else if (return_type == 1) { + // TODO [RZC 04/05/2021] Falta gestionar tipus string + } + } emmit(OP_RET); } -*/ + // XXX [RZC 27/04/2021] No hi ha labels /*static void parse_label() { @@ -737,21 +789,16 @@ static void parse_call() { } } } - +*/ static void parse_statements() { while (!parser_finished) { current_line = tkn_get_line(); switch (tkn_get_token()) { case TOKEN_CONST: tkn_next(); parse_const(); break; - case TOKEN_DIM: - tkn_next(); parse_dim(); break; - case TOKEN_LET: - tkn_next(); parse_let(); break; - case TOKEN_INC: - tkn_next(); parse_inc(); break; - case TOKEN_DEC: - tkn_next(); parse_dec(); break; + case TOKEN_VAR: + tkn_next(); parse_var(); break; +/* case TOKEN_IF: tkn_next(); parse_if(); break; case TOKEN_FOR: @@ -760,23 +807,25 @@ static void parse_statements() { tkn_next(); parse_break(); break; case TOKEN_CONTINUE: tkn_next(); parse_continue(); break; +*/ case TOKEN_RETURN: tkn_next(); parse_return(); break; case TOKEN_REM: tkn_next(); break; +/* case TOKEN_IDENTIFIER: for (int i = 0; i < num_external_functions; i++) { if (strcmp(external_functions[i].name, tkn_get_string()) == 0) { parse_call(); break; } } parse_let(); break; +*/ default: return; } } } -*/ static void parse_global_statements() { while (!parser_finished) { current_line = tkn_get_line(); @@ -787,8 +836,8 @@ static void parse_global_statements() { tkn_next(); parse_var(); break; case TOKEN_STRUCT: tkn_next(); parse_struct(); break; - /*case TOKEN_FUNCTION: - tkn_next(); parse_function(); break;*/ + case TOKEN_FUNCTION: + tkn_next(); parse_function(); break; case TOKEN_REM: tkn_next(); break; case TOKEN_ENDFILE: diff --git a/scope.cpp b/scope.cpp index 60f0762..c529a13 100644 --- a/scope.cpp +++ b/scope.cpp @@ -30,6 +30,7 @@ const bool scope_is_local() { void scope_open_local() { are_we_inside_local = true; + blocks.push(0); } const int scope_close_local() { @@ -37,6 +38,7 @@ const int scope_close_local() { // Malament, no havem tancat algún block. No se si es detectarà abans per altra part. Per ara anem a deixar este comentari. } const int return_value = local.total_size; + while (!blocks.empty()) blocks.pop(); local.variables.clear(); local.total_size = 0; are_we_inside_local = false; diff --git a/test.vb b/test.vb index 9c98dd5..0d42149 100644 --- a/test.vb +++ b/test.vb @@ -12,3 +12,8 @@ end var peiv as array of 2 triangle const perico as number = 4-peiv[1].a.x * peiv[0].c.y[2] + +function tarari(a as number, b as number) as number + var x as number +end +