From 560d7b5e56d91db80d93de810016c714e4bedc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 17:20:29 +0100 Subject: [PATCH 01/25] Update EXPR_TOKEN_BOOLEAN_LITERAL --- src/parser_expr_internal.c | 22 +++++++++------------- src/parser_expr_internal.h | 1 + src/parser_expr_rules.c | 2 +- src/parser_expr_rules.h | 5 +---- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/parser_expr_internal.c b/src/parser_expr_internal.c index 64cee70..8b5e8ea 100644 --- a/src/parser_expr_internal.c +++ b/src/parser_expr_internal.c @@ -128,6 +128,14 @@ ExprToken* load_expr_token(Lexer* lexer, Token* last_token) { expr_t->data.s = c_string_copy(last_token->data); break; // Literals + case TOKEN_TRUE: + expr_t->type = EXPR_TOKEN_BOOLEAN_LITERAL; + expr_t->data.b = true; + break; + case TOKEN_FALSE: + expr_t->type = EXPR_TOKEN_BOOLEAN_LITERAL; + expr_t->data.b = false; + break; case TOKEN_DOUBLE_LITERAL: expr_t->type = EXPR_TOKEN_DOUBLE_LITERAL; expr_t->data.s = c_string_copy(last_token->data); @@ -164,7 +172,6 @@ ExprToken* load_expr_token(Lexer* lexer, Token* last_token) { void expr_token_free(ExprToken* t) { if(t != NULL) { if((t->type == EXPR_TOKEN_IDENTIFIER || - t->type == EXPR_TOKEN_BOOLEAN_LITERAL || t->type == EXPR_TOKEN_INTEGER_LITERAL || t->type == EXPR_TOKEN_DOUBLE_LITERAL || t->type == EXPR_TOKEN_STRING_LITERAL @@ -187,18 +194,7 @@ int expr_llist_type_cmp(LListBaseItem* a, LListBaseItem* b) { void expr_llist_free(LListBaseItem* item) { ASSERT(item != NULL); - ExprToken* t = (ExprToken*) item; - - if(t != NULL) { - if((t->type == EXPR_TOKEN_IDENTIFIER || - t->type == EXPR_TOKEN_BOOLEAN_LITERAL || - t->type == EXPR_TOKEN_INTEGER_LITERAL || - t->type == EXPR_TOKEN_DOUBLE_LITERAL || - t->type == EXPR_TOKEN_STRING_LITERAL - ) && t->data.s != NULL) { - memory_free(t->data.s); - } - } + expr_token_free(item); } ExprToken* create_expr_token(ExprTokenType type) { diff --git a/src/parser_expr_internal.h b/src/parser_expr_internal.h index 0eaec93..8ed2dc5 100644 --- a/src/parser_expr_internal.h +++ b/src/parser_expr_internal.h @@ -64,6 +64,7 @@ typedef unsigned ExprIdx; typedef union expr_data_u { ExprIdx idx; char* s; + bool b; } ExprData; typedef struct expr_token_t { diff --git a/src/parser_expr_rules.c b/src/parser_expr_rules.c index bc1ac55..f5cd2b3 100644 --- a/src/parser_expr_rules.c +++ b/src/parser_expr_rules.c @@ -125,7 +125,7 @@ bool expression_rule_id(Parser* parser, LList* expr_token_buffer, ExprIdx* expre i->data_type = DATA_TYPE_BOOLEAN; CodeConstructor* constructor = parser->code_constructor; - GENERATE_CODE(I_PUSH_STACK, code_instruction_operand_init_boolean(0 == strcmp(i->data.s, "true"))); + GENERATE_CODE(I_PUSH_STACK, code_instruction_operand_init_boolean(i->data.b)); } else if(i->type == EXPR_TOKEN_IDENTIFIER) { SymbolVariable* variable = symbol_register_find_variable_recursive( diff --git a/src/parser_expr_rules.h b/src/parser_expr_rules.h index dd8c533..4ff08bd 100644 --- a/src/parser_expr_rules.h +++ b/src/parser_expr_rules.h @@ -109,15 +109,12 @@ bool expression_rule_div_int(Parser* parser, LList* expr_token_buffer, ExprIdx* bool expression_rule_unary_minus(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); -// Boolshit +// Comparison bool expression_rule_greater(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); bool expression_rule_greater_or_equal(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); bool expression_rule_equal(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); - bool expression_rule_not_equal(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); - bool expression_rule_lesser_or_equal(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); - bool expression_rule_lesser(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); #endif //_PARSER_EXPR_RULES_H From 14f7b9dabeb378a0b2ad11f8e505b9f17bbbab0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 17:43:26 +0100 Subject: [PATCH 02/25] Fix implicit conversion warning --- src/parser_expr_internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser_expr_internal.c b/src/parser_expr_internal.c index 8b5e8ea..6f6504d 100644 --- a/src/parser_expr_internal.c +++ b/src/parser_expr_internal.c @@ -194,7 +194,7 @@ int expr_llist_type_cmp(LListBaseItem* a, LListBaseItem* b) { void expr_llist_free(LListBaseItem* item) { ASSERT(item != NULL); - expr_token_free(item); + expr_token_free((ExprToken*)item); } ExprToken* create_expr_token(ExprTokenType type) { From d6099a6f748b4e099b4319d38c48b66785e6adf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 17:50:10 +0100 Subject: [PATCH 03/25] Try to add boolean comparison semantic --- src/parser_semantic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/parser_semantic.c b/src/parser_semantic.c index 773dbe3..aca6d69 100644 --- a/src/parser_semantic.c +++ b/src/parser_semantic.c @@ -92,6 +92,12 @@ ParserSemantic* parser_semantic_init() { DATA_TYPE_STRING, DATA_TYPE_STRING, DATA_TYPE_STRING, DATA_TYPE_BOOLEAN); } + parser_semantic_add_operation_signature(parser_semantic, OPERATION_EQUAL, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); + parser_semantic_add_operation_signature(parser_semantic, OPERATION_NOT_EQUAL, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); // implicit conversions parser_semantic_add_operation_signature(parser_semantic, OPERATION_IMPLICIT_CONVERSION, From a0075c5e8aa073e3b924bc80e040de4b4ad84b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 17:52:22 +0100 Subject: [PATCH 04/25] Remove outdated 'TODO' --- src/parser_semantic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser_semantic.c b/src/parser_semantic.c index aca6d69..66812b3 100644 --- a/src/parser_semantic.c +++ b/src/parser_semantic.c @@ -68,7 +68,6 @@ ParserSemantic* parser_semantic_init() { DATA_TYPE_DOUBLE, DATA_TYPE_INTEGER); - // TODO add boolean, string, double in greater operation const TypeExpressionOperation compare_operations[] = { OPERATION_GREATER, OPERATION_GREATER_OR_EQUAL, From 592f6732a043cb20e1afd0be3dd6ceb3882f10a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 18:46:15 +0100 Subject: [PATCH 05/25] Add not, and, or expression_rule prototype --- src/parser_expr_rules.c | 89 +++++++++++++++++++++++++++++++++++++++++ src/parser_expr_rules.h | 7 +++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/parser_expr_rules.c b/src/parser_expr_rules.c index f5cd2b3..0fffcb8 100644 --- a/src/parser_expr_rules.c +++ b/src/parser_expr_rules.c @@ -15,6 +15,9 @@ const expression_rule_function expr_rule_table[EXPR_RULE_TABLE_SIZE] = { expression_rule_div, expression_rule_div_int, expression_rule_unary_minus, + expression_rule_not, + expression_rule_and, + expression_rule_or, expression_rule_greater, expression_rule_greater_or_equal, expression_rule_equal, @@ -851,4 +854,90 @@ bool expression_rule_fn_chr(Parser* parser, LList* expr_token_buffer, ExprIdx* e EXPR_RULE_REPLACE(e); return true; +} + +bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx) +{ + /* + * RULE + * E -> NOT E + */ + + CodeConstructor* constructor = parser->code_constructor; + UNUSED(parser); + + // NOTE: we are processing rule backwards! + EXPR_RULE_CHECK_START(); + EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); + EXPR_RULE_CHECK_TYPE(EXPR_TOKEN_NOT); + EXPR_RULE_CHECK_FINISH(); + EXPR_CHECK_UNARY_OPERATION_IMPLICIT_CONVERSION(OPERATION_UNARY_MINUS); + + // NOTE: now we are processing rule regular way - from the left to the right + + CodeInstructionOperand* inverse_operand = NULL; + if(EXPR_HIGHER_OPERAND->data_type != DATA_TYPE_BOOLEAN) { + SEMANTIC_ANALYSIS( + { + parser->parser_semantic->error_report.error_code = ERROR_SEMANTIC_TYPE; + return false; + } + ); + } + CODE_GENERATION( + { + CodeConstructor* constructor = parser->code_constructor; + GENERATE_CODE(I_NOT_STACK); + } + ); + + ExprToken* e = create_expression((*expression_idx)++); + e->data_type = DATA_TYPE_BOOLEAN; + EXPR_RULE_REPLACE(e); + return true; +} + +bool expression_rule_and(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx) { + /* + * RULE + * E -> E AND E + */ + // backward + EXPR_RULE_CHECK_START(); + EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); + EXPR_RULE_CHECK_TYPE(EXPR_TOKEN_AND); + EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); + EXPR_RULE_CHECK_FINISH(); + EXPR_CHECK_BINARY_OPERATION_IMPLICIT_CONVERSION(OPERATION_AND); + + CREATE_EXPR_RESULT_OF_BINARY_OPERATION(OPERATION_AND); + + CodeConstructor* constructor = parser->code_constructor; + GENERATE_IMPLICIT_CONVERSIONS_FOR_BINARY_OPERATION_SIGNATURE(); + GENERATE_CODE(I_AND_STACK); + + EXPR_RULE_REPLACE(e); + return true; +} +bool expression_rule_or(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx) { + /* + * RULE + * E -> E OR E + */ + // backward + EXPR_RULE_CHECK_START(); + EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); + EXPR_RULE_CHECK_TYPE(EXPR_TOKEN_OR); + EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); + EXPR_RULE_CHECK_FINISH(); + EXPR_CHECK_BINARY_OPERATION_IMPLICIT_CONVERSION(OPERATION_OR); + + CREATE_EXPR_RESULT_OF_BINARY_OPERATION(OPERATION_OR); + + CodeConstructor* constructor = parser->code_constructor; + GENERATE_IMPLICIT_CONVERSIONS_FOR_BINARY_OPERATION_SIGNATURE(); + GENERATE_CODE(I_OR_STACK); + + EXPR_RULE_REPLACE(e); + return true; } \ No newline at end of file diff --git a/src/parser_expr_rules.h b/src/parser_expr_rules.h index 4ff08bd..0591f80 100644 --- a/src/parser_expr_rules.h +++ b/src/parser_expr_rules.h @@ -79,7 +79,7 @@ // -------------------------- -#define EXPR_RULE_TABLE_SIZE 19 +#define EXPR_RULE_TABLE_SIZE 22 typedef bool(*expression_rule_function)(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); extern const expression_rule_function expr_rule_table[EXPR_RULE_TABLE_SIZE]; @@ -109,6 +109,11 @@ bool expression_rule_div_int(Parser* parser, LList* expr_token_buffer, ExprIdx* bool expression_rule_unary_minus(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); +// Boolean +bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expression_idx); +bool expression_rule_and(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); +bool expression_rule_or(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); + // Comparison bool expression_rule_greater(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); bool expression_rule_greater_or_equal(Parser* parser, LList *expr_token_buffer, ExprIdx* expression_idx); From cc95837050a7ec0a1b9a8799d1310a7093edd3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 18:53:03 +0100 Subject: [PATCH 06/25] Add or, and semantic checking --- src/parser_semantic.c | 8 ++++++++ src/parser_semantic.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/parser_semantic.c b/src/parser_semantic.c index 66812b3..ca7912d 100644 --- a/src/parser_semantic.c +++ b/src/parser_semantic.c @@ -67,6 +67,14 @@ ParserSemantic* parser_semantic_init() { DATA_TYPE_INTEGER, DATA_TYPE_INTEGER, DATA_TYPE_DOUBLE, DATA_TYPE_INTEGER); + parser_semantic_add_operation_signature(parser_semantic, OPERATION_AND, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); + + parser_semantic_add_operation_signature(parser_semantic, OPERATION_OR, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); + const TypeExpressionOperation compare_operations[] = { OPERATION_GREATER, diff --git a/src/parser_semantic.h b/src/parser_semantic.h index 99d2c6d..533bbb9 100644 --- a/src/parser_semantic.h +++ b/src/parser_semantic.h @@ -22,6 +22,9 @@ typedef enum { // Bool operations + OPERATION_AND, + OPERATION_OR, + OPERATION_GREATER, OPERATION_GREATER_OR_EQUAL, OPERATION_LESSER, From 5214d73c5ef512f0cbe0398c02a5f1de23766a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 18:56:47 +0100 Subject: [PATCH 07/25] Fix unused variables --- src/parser_expr_rules.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/parser_expr_rules.c b/src/parser_expr_rules.c index 0fffcb8..4c9423b 100644 --- a/src/parser_expr_rules.c +++ b/src/parser_expr_rules.c @@ -863,9 +863,6 @@ bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expr * E -> NOT E */ - CodeConstructor* constructor = parser->code_constructor; - UNUSED(parser); - // NOTE: we are processing rule backwards! EXPR_RULE_CHECK_START(); EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); @@ -875,7 +872,6 @@ bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expr // NOTE: now we are processing rule regular way - from the left to the right - CodeInstructionOperand* inverse_operand = NULL; if(EXPR_HIGHER_OPERAND->data_type != DATA_TYPE_BOOLEAN) { SEMANTIC_ANALYSIS( { From 8b1893653556e2e75322f9e55052aa198f06fa73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pazdiora?= Date: Sun, 5 Nov 2017 19:05:21 +0100 Subject: [PATCH 08/25] Add operation NOT declaration --- src/parser_expr_rules.c | 2 +- src/parser_semantic.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parser_expr_rules.c b/src/parser_expr_rules.c index 4c9423b..abadbe5 100644 --- a/src/parser_expr_rules.c +++ b/src/parser_expr_rules.c @@ -868,7 +868,7 @@ bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expr EXPR_RULE_CHECK_TYPE(EXPR_EXPRESSION); EXPR_RULE_CHECK_TYPE(EXPR_TOKEN_NOT); EXPR_RULE_CHECK_FINISH(); - EXPR_CHECK_UNARY_OPERATION_IMPLICIT_CONVERSION(OPERATION_UNARY_MINUS); + EXPR_CHECK_UNARY_OPERATION_IMPLICIT_CONVERSION(OPERATION_NOT); // NOTE: now we are processing rule regular way - from the left to the right diff --git a/src/parser_semantic.h b/src/parser_semantic.h index 533bbb9..b08e813 100644 --- a/src/parser_semantic.h +++ b/src/parser_semantic.h @@ -22,6 +22,7 @@ typedef enum { // Bool operations + OPERATION_NOT, OPERATION_AND, OPERATION_OR, From 70db3d477910e41c4246cffd01304b4402ac828e Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Wed, 8 Nov 2017 16:20:52 +0100 Subject: [PATCH 09/25] Ad algorithm for octa -> dec, hexa -> dec --- src/common.c | 11 +++++ src/common.h | 8 +++ src/lexer.c | 44 +++++++++++++---- test/lexer.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 10 deletions(-) diff --git a/src/common.c b/src/common.c index 712ba9c..d6417fa 100644 --- a/src/common.c +++ b/src/common.c @@ -12,4 +12,15 @@ char* c_string_copy(const char* string) { } return copied; +} + +int radix_to_int(char char_value) { + + if((int) char_value >= '0' && (int) char_value <= '9') + return (int) char_value - '0'; + if((int) char_value >= 'a' && (int) char_value <= 'e') + return (int) char_value - 'a' + 10; + + return 0; + } \ No newline at end of file diff --git a/src/common.h b/src/common.h index c343ae5..74b1e5d 100644 --- a/src/common.h +++ b/src/common.h @@ -11,4 +11,12 @@ char* c_string_copy(const char* string); +/** + * @brief Transform char to integer + * + * @param char_value + * @return integer value + */ +int radix_to_int(char char_value); + #endif // _COMMON_H diff --git a/src/lexer.c b/src/lexer.c index babc19f..9da87f0 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -3,6 +3,7 @@ #include "memory.h" #include "debug.h" #include "lexer_fsm.h" +#include "common.h" Lexer* lexer_init(lexer_input_stream_f input_stream) { @@ -40,10 +41,9 @@ void lexer_rewind_token(Lexer* lexer, Token token) { void lexer_transform_integer_value(char* integer_value) { - char* integer_value_copy = memory_alloc(sizeof(integer_value)); - strcpy(integer_value_copy, integer_value); + char* integer_value_copy = c_string_copy(integer_value); int sum = 0; - int multiplier = 0; + int multiplier = strlen(integer_value) - 2; // First char is type of integer. [0-9] -> decimal, 'b' -> binary, 'o' -> octa, 'h' -> hexa switch(integer_value[0]) { @@ -52,28 +52,41 @@ void lexer_transform_integer_value(char* integer_value) { case 'b': // From binary to Decimal for(int i = 1; i < strlen(integer_value); i++) { - if(integer_value[i] == '1') - sum = sum + (1 * pow(2, multiplier)); - multiplier = multiplier + 1; + sum += radix_to_int(integer_value[i]) * pow(2, multiplier); + multiplier--; } - sprintf(integer_value, "%d", sum); - break; case 'o': // From octa to Decimal - // TODO: Input: something like o12321103221032, tranform it into decimal into input pointer + for(int i = 1; i < strlen(integer_value); i++) { + sum += radix_to_int(integer_value[i]) * pow(8, multiplier); + multiplier--; + } + break; case 'h': // From hexa to Decimal - // TODO: Input: something like h12b2a103221032, tranform it into decimal into input pointer + for(int i = 1; i < strlen(integer_value); i++) { + sum += radix_to_int(integer_value[i]) * pow(16, multiplier); + multiplier--; + } + + break; + + default: + sum = atoi(integer_value); break; } + int length = strlen(integer_value); + + snprintf(integer_value, length * 2, "%d", sum); + memory_free(integer_value_copy); } @@ -115,7 +128,18 @@ Token lexer_next_token(Lexer* lexer) { // Transform integer value to decimal system if(token.type == TOKEN_INTEGER_LITERAL) { + + // Transform size of memory + char* copy = c_string_copy(token.data); + memory_free(token.data); + token.data = memory_alloc(sizeof(char) * strlen(copy) * 2); + + // Copy data, I need memory after string + strcpy(token.data, copy); + + // Transorm integer format lexer_transform_integer_value(token.data); + memory_free(copy); } return token; diff --git a/test/lexer.cpp b/test/lexer.cpp index d0ca40b..393ce74 100644 --- a/test/lexer.cpp +++ b/test/lexer.cpp @@ -31,6 +31,133 @@ class LexerTokenizerTestFixture : public ::testing::Test { } }; + +TEST_F(LexerTokenizerTestFixture, StringToInteger) { + + char* integer_value = (char*) memory_alloc(sizeof(char) * 1000); + + strcpy(integer_value, "b101"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "5" + ); + + strcpy(integer_value, "b0"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "0" + ); + + strcpy(integer_value, "b00000000000000000000000000000000000000000000000000000000000"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "0" + ); + + strcpy(integer_value, "b111"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "7" + ); + + strcpy(integer_value, "b000000111"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "7" + ); + + strcpy(integer_value, "b000010111"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "23" + ); + + strcpy(integer_value, "b000000110"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "6" + ); + + strcpy(integer_value, "o1"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "1" + ); + + strcpy(integer_value, "o1065"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "565" + ); + + strcpy(integer_value, "h6776"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "26486" + ); + + strcpy(integer_value, "hd25"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "3365" + ); + + strcpy(integer_value, "hd2a5"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "53925" + ); + + strcpy(integer_value, "hd245456"); + + lexer_transform_integer_value(integer_value); + + EXPECT_STREQ( + integer_value, + "220484694" + ); + + + memory_free(integer_value); + +} + TEST_F(LexerTokenizerTestFixture, Keywords) { provider->setString("AS + sCOpE"); char_stack_empty(lexer->lexer_fsm->stack); @@ -49,6 +176,8 @@ TEST_F(LexerTokenizerTestFixture, Keywords) { this->getNextTokenType(), TOKEN_SCOPE ) << "Error SCOPE token"; + + } TEST_F(LexerTokenizerTestFixture, MathTokens) { From 21f3b404f80cfa6944e34341fb5106b95e80c545 Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Wed, 8 Nov 2017 16:44:50 +0100 Subject: [PATCH 10/25] Add tests for --- src/parser.c | 1 + test/parser.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/parser.c b/src/parser.c index f35101c..3d8dd6f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -958,6 +958,7 @@ bool parser_parse_assignment(Parser* parser) { /* * RULE * -> = + * -> */ DataType expression_data_type; diff --git a/test/parser.cpp b/test/parser.cpp index c64855a..5d60dd5 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -433,6 +433,48 @@ TEST_F(ParserTestFixture, DeclarationAssigment2) { } +TEST_F(ParserTestFixture, ModifyAssigment) { + provider->setString("+= 31"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("-= 31"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("*= 31"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("/= 31"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("+= foo()"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("-= a+b+c+d"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("*= foo()*foo(foo())"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); + + provider->setString("/= 12+15"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ); +} + TEST_F(ParserTestFixture, DoWhile) { provider->setString(R"(DO WHILE 42 input id From dfc16fb629c6c55ce35de341790f6a7b4496c611 Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Wed, 8 Nov 2017 16:48:16 +0100 Subject: [PATCH 11/25] Add todo --- src/parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser.c b/src/parser.c index 3d8dd6f..824d458 100644 --- a/src/parser.c +++ b/src/parser.c @@ -964,6 +964,7 @@ bool parser_parse_assignment(Parser* parser) { DataType expression_data_type; SymbolVariable* actual_variable = parser->parser_semantic->actual_variable; RULES( + // Todo: for tokens +=, -=, /= .... call rule modify_assignment and return value CHECK_TOKEN(TOKEN_EQUAL); CALL_EXPRESSION_RULE(expression_data_type); ); From 5995b218e7a67a8d716e086d3b0be321777aa3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Wed, 8 Nov 2017 16:58:08 +0100 Subject: [PATCH 12/25] Fix implementation for BASE extension --- src/common.c | 12 +++--- src/common.h | 4 +- src/lexer.c | 78 ++++++++++++++--------------------- src/lexer.h | 2 +- test/lexer.cpp | 109 +++++++++++++++++++++++++------------------------ 5 files changed, 95 insertions(+), 110 deletions(-) diff --git a/src/common.c b/src/common.c index d6417fa..a93f29d 100644 --- a/src/common.c +++ b/src/common.c @@ -14,13 +14,13 @@ char* c_string_copy(const char* string) { return copied; } -int radix_to_int(char char_value) { - - if((int) char_value >= '0' && (int) char_value <= '9') - return (int) char_value - '0'; - if((int) char_value >= 'a' && (int) char_value <= 'e') - return (int) char_value - 'a' + 10; +int hex_to_int(char char_) { + if((int) char_ >= '0' && (int) char_ <= '9') + return (int) char_ - '0'; + if((int) char_ >= 'a' && (int) char_ <= 'e') + return (int) char_ - 'a' + 10; + LOG_WARNING("Invalid char %c to convert.", char_); return 0; } \ No newline at end of file diff --git a/src/common.h b/src/common.h index 74b1e5d..98d0832 100644 --- a/src/common.h +++ b/src/common.h @@ -14,9 +14,9 @@ char* c_string_copy(const char* string); /** * @brief Transform char to integer * - * @param char_value + * @param char_ * @return integer value */ -int radix_to_int(char char_value); +int hex_to_int(char char_); #endif // _COMMON_H diff --git a/src/lexer.c b/src/lexer.c index 9da87f0..f1bb362 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -24,7 +24,7 @@ void lexer_free(Lexer** lexer) { NULL_POINTER_CHECK(*lexer,); lexer_fsm_free(&((*lexer)->lexer_fsm)); - if ((*lexer)->is_token_rewind) { + if((*lexer)->is_token_rewind) { token_free(&(*lexer)->rewind_token); } memory_free(*lexer); @@ -39,55 +39,44 @@ void lexer_rewind_token(Lexer* lexer, Token token) { lexer->rewind_token = token_copy(token); } -void lexer_transform_integer_value(char* integer_value) { +void lexer_transform_integer_value(char** integer_value) { + NULL_POINTER_CHECK(integer_value,); + NULL_POINTER_CHECK(*integer_value,); - char* integer_value_copy = c_string_copy(integer_value); - int sum = 0; - int multiplier = strlen(integer_value) - 2; - - // First char is type of integer. [0-9] -> decimal, 'b' -> binary, 'o' -> octa, 'h' -> hexa - switch(integer_value[0]) { + size_t target_length = (1 + strlen(*integer_value)) * 2; + char* integer_value_copy = memory_alloc(target_length * sizeof(char)); + int result = 0; + size_t multiplier = 0; + size_t base; + // First char is type of integer. [0-9] -> decimal, 'b' -> binary, 'o' -> octa, 'h' -> hexa + switch(**integer_value) { case 'b': - // From binary to Decimal - for(int i = 1; i < strlen(integer_value); i++) { - sum += radix_to_int(integer_value[i]) * pow(2, multiplier); - multiplier--; - } - + base = 2; break; - case 'o': - // From octa to Decimal - for(int i = 1; i < strlen(integer_value); i++) { - sum += radix_to_int(integer_value[i]) * pow(8, multiplier); - multiplier--; - } - + base = 8; break; - case 'h': - // From hexa to Decimal - for(int i = 1; i < strlen(integer_value); i++) { - sum += radix_to_int(integer_value[i]) * pow(16, multiplier); - multiplier--; - } - + base = 16; break; default: - sum = atoi(integer_value); + base = 10; break; - } - int length = strlen(integer_value); + for(size_t i = strlen(*integer_value) - 1; i >= 1; i--) { + result += hex_to_int((*integer_value)[i]) * pow(base, multiplier); + multiplier++; + } - snprintf(integer_value, length * 2, "%d", sum); + snprintf(integer_value_copy, target_length, "%d", result); - memory_free(integer_value_copy); + memory_free(*integer_value); + *integer_value = integer_value_copy; } @@ -102,7 +91,7 @@ Token lexer_next_token(Lexer* lexer) { if(lexer->is_token_rewind) { lexer->is_token_rewind = false; - Token tmp = { .data = lexer->rewind_token.data,.type = lexer->rewind_token.type }; + Token tmp = {.data = lexer->rewind_token.data, .type = lexer->rewind_token.type}; lexer->rewind_token.data = NULL; lexer->rewind_token.type = TOKEN_UNKNOWN; @@ -128,7 +117,6 @@ Token lexer_next_token(Lexer* lexer) { // Transform integer value to decimal system if(token.type == TOKEN_INTEGER_LITERAL) { - // Transform size of memory char* copy = c_string_copy(token.data); memory_free(token.data); @@ -137,8 +125,8 @@ Token lexer_next_token(Lexer* lexer) { // Copy data, I need memory after string strcpy(token.data, copy); - // Transorm integer format - lexer_transform_integer_value(token.data); + // transform to integer format + lexer_transform_integer_value(&token.data); memory_free(copy); } @@ -148,19 +136,15 @@ Token lexer_next_token(Lexer* lexer) { char* lexer_store_token_data(const Lexer* lexer, Token token) { NULL_POINTER_CHECK(lexer, NULL); - size_t data_length = string_length(lexer->lexer_fsm->stream_buffer); - if(token.type == TOKEN_IDENTIFIER || + if( + token.type == TOKEN_IDENTIFIER || token.type == TOKEN_STRING_VALUE || token.type == TOKEN_INTEGER_LITERAL || token.type == TOKEN_DOUBLE_LITERAL ) { - char* data = memory_alloc(sizeof(char) * (data_length + 1)); - - if (NULL == strcpy(data, string_content(lexer->lexer_fsm->stream_buffer))) { - exit_with_code(ERROR_INTERNAL); - } - return data; - } else { - return NULL; + + return c_string_copy(string_content(lexer->lexer_fsm->stream_buffer)); } + + return NULL; } diff --git a/src/lexer.h b/src/lexer.h index a992c7f..5c98e6c 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -59,6 +59,6 @@ void lexer_rewind_token(Lexer* lexer, Token token); * * @param char* integer_value */ -void lexer_transform_integer_value(char* integer_value); +void lexer_transform_integer_value(char** integer_value); #endif //_LEXER_H diff --git a/test/lexer.cpp b/test/lexer.cpp index 393ce74..c3dd55b 100644 --- a/test/lexer.cpp +++ b/test/lexer.cpp @@ -33,129 +33,130 @@ class LexerTokenizerTestFixture : public ::testing::Test { TEST_F(LexerTokenizerTestFixture, StringToInteger) { + char* integer_value; - char* integer_value = (char*) memory_alloc(sizeof(char) * 1000); - - strcpy(integer_value, "b101"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b101"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "5" ); + memory_free(integer_value); - strcpy(integer_value, "b0"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b0"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "0" ); + memory_free(integer_value); - strcpy(integer_value, "b00000000000000000000000000000000000000000000000000000000000"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b00000000000000000000000000000000000000000000000000000000000"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "0" ); + memory_free(integer_value); - strcpy(integer_value, "b111"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b111"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "7" ); + memory_free(integer_value); - strcpy(integer_value, "b000000111"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b000000111"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "7" ); + memory_free(integer_value); - strcpy(integer_value, "b000010111"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b000010111"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "23" ); + memory_free(integer_value); - strcpy(integer_value, "b000000110"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("b000000110"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "6" ); + memory_free(integer_value); - strcpy(integer_value, "o1"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("o1"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "1" ); + memory_free(integer_value); - strcpy(integer_value, "o1065"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("o1065"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "565" ); + memory_free(integer_value); - strcpy(integer_value, "h6776"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("h6776"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "26486" ); + memory_free(integer_value); - strcpy(integer_value, "hd25"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("hd25"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "3365" ); + memory_free(integer_value); - strcpy(integer_value, "hd2a5"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("hd2a5"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "53925" ); + memory_free(integer_value); - strcpy(integer_value, "hd245456"); - - lexer_transform_integer_value(integer_value); - + integer_value = c_string_copy("hd245456"); + lexer_transform_integer_value(&integer_value); EXPECT_STREQ( integer_value, "220484694" ); + memory_free(integer_value); + + integer_value = c_string_copy("h0000001"); + lexer_transform_integer_value(&integer_value); + EXPECT_STREQ( + integer_value, + "1" + ); memory_free(integer_value); + integer_value = c_string_copy("h0000000"); + lexer_transform_integer_value(&integer_value); + EXPECT_STREQ( + integer_value, + "0" + ); + + memory_free(integer_value); } TEST_F(LexerTokenizerTestFixture, Keywords) { From 2669563eb83bea09b18723896b180a6fbb5101b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Wed, 8 Nov 2017 17:00:54 +0100 Subject: [PATCH 13/25] Fixed segfault from augmented operators --- src/parser.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/parser.c b/src/parser.c index 824d458..4ca4a30 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1043,11 +1043,14 @@ bool parser_parse_modify_assignment(Parser* parser) { } ); - // TODO implicit conversion - OperationSignature* operation_signature = parser_semantic_get_operation_signature(parser->parser_semantic, operation_type, actual_variable->data_type, expression_data_type, DATA_TYPE_ANY); - CODE_GENERATION( { + OperationSignature* operation_signature = parser_semantic_get_operation_signature(parser->parser_semantic, + operation_type, + actual_variable->data_type, + expression_data_type, + DATA_TYPE_ANY); + CodeConstructor* constructor = parser->code_constructor; if(operation_type == OPERATION_ADD && expression_data_type == DATA_TYPE_STRING && actual_variable->data_type == DATA_TYPE_STRING) { From c2c762908fc5fd9d861c9cdc2960c2ff728d2358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Wed, 8 Nov 2017 17:05:11 +0100 Subject: [PATCH 14/25] Reformat code --- src/parser.c | 93 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/src/parser.c b/src/parser.c index 4ca4a30..a94a6be 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1006,7 +1006,7 @@ bool parser_parse_modify_assignment(Parser* parser) { */ const unsigned int shorten_operators_count = 5; - const int map_diff = (int)TOKEN_AUGMENTED_ASSIGN_OPERATORS + 1; + const int map_diff = (int) TOKEN_AUGMENTED_ASSIGN_OPERATORS + 1; TypeExpressionOperation token_type_mapped_to_operation[shorten_operators_count]; TypeInstruction token_type_mapped_to_instruction[shorten_operators_count]; @@ -1037,45 +1037,74 @@ bool parser_parse_modify_assignment(Parser* parser) { SEMANTIC_ANALYSIS( { - if(actual_variable == NULL) - return false; - CHECK_BINARY_OPERATION_IMPLICIT_CONVERSION(operation_type, actual_variable->data_type, expression_data_type); + if(actual_variable == NULL) + return false; + CHECK_BINARY_OPERATION_IMPLICIT_CONVERSION( + operation_type, + actual_variable->data_type, + expression_data_type + ); } ); CODE_GENERATION( - { - OperationSignature* operation_signature = parser_semantic_get_operation_signature(parser->parser_semantic, - operation_type, - actual_variable->data_type, - expression_data_type, - DATA_TYPE_ANY); - - CodeConstructor* constructor = parser->code_constructor; - if(operation_type == OPERATION_ADD && expression_data_type == DATA_TYPE_STRING && - actual_variable->data_type == DATA_TYPE_STRING) { - GENERATE_CODE(I_POP_STACK, code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1)); - GENERATE_CODE( - I_CONCAT_STRING, - code_instruction_operand_init_variable(actual_variable), - code_instruction_operand_init_variable(actual_variable), - code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1) - ); - } + { + OperationSignature* operation_signature = parser_semantic_get_operation_signature( + parser->parser_semantic, + operation_type, + actual_variable->data_type, + expression_data_type, + DATA_TYPE_ANY + ); - else { - GENERATE_STACK_DATA_TYPE_CONVERSION_CODE(expression_data_type, operation_signature->conversion_target_type); - GENERATE_CODE(I_POP_STACK, code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1)); + CodeConstructor* constructor = parser->code_constructor; + if( + operation_type == OPERATION_ADD && + expression_data_type == DATA_TYPE_STRING && + actual_variable->data_type == DATA_TYPE_STRING + ) { + // special case for string concat + GENERATE_CODE( + I_POP_STACK, + code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1) + ); + GENERATE_CODE( + I_CONCAT_STRING, + code_instruction_operand_init_variable(actual_variable), + code_instruction_operand_init_variable(actual_variable), + code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1) + ); + } else { + GENERATE_STACK_DATA_TYPE_CONVERSION_CODE( + expression_data_type, + operation_signature->conversion_target_type + ); + GENERATE_CODE( + I_POP_STACK, + code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1) + ); - GENERATE_CODE(I_PUSH_STACK, code_instruction_operand_init_variable(actual_variable)); - GENERATE_STACK_DATA_TYPE_CONVERSION_CODE(actual_variable->data_type, operation_signature->conversion_target_type); - GENERATE_CODE(I_PUSH_STACK, code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1)); + GENERATE_CODE( + I_PUSH_STACK, + code_instruction_operand_init_variable(actual_variable) + ); + GENERATE_STACK_DATA_TYPE_CONVERSION_CODE( + actual_variable->data_type, + operation_signature->conversion_target_type + ); + GENERATE_CODE( + I_PUSH_STACK, + code_instruction_operand_init_variable(parser->parser_semantic->temp_variable1) + ); - GENERATE_CODE(corresponding_instruction); - GENERATE_STACK_DATA_TYPE_CONVERSION_CODE(operation_signature->result_type, actual_variable->data_type); - GENERATE_CODE(I_POP_STACK, code_instruction_operand_init_variable(actual_variable)); + GENERATE_CODE(corresponding_instruction); + GENERATE_STACK_DATA_TYPE_CONVERSION_CODE( + operation_signature->result_type, + actual_variable->data_type + ); + GENERATE_CODE(I_POP_STACK, code_instruction_operand_init_variable(actual_variable)); + } } - } ); parser->parser_semantic->actual_variable = NULL; From 976a66878fd50e52dd3fff77cccafbceda1fe409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Wed, 8 Nov 2017 23:31:20 +0100 Subject: [PATCH 15/25] Fix integer transform for integer values --- src/lexer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lexer.c b/src/lexer.c index f1bb362..f4893b2 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -49,6 +49,7 @@ void lexer_transform_integer_value(char** integer_value) { int result = 0; size_t multiplier = 0; + int offset = 1; size_t base; // First char is type of integer. [0-9] -> decimal, 'b' -> binary, 'o' -> octa, 'h' -> hexa switch(**integer_value) { @@ -64,11 +65,12 @@ void lexer_transform_integer_value(char** integer_value) { break; default: + offset = 0; base = 10; break; } - for(size_t i = strlen(*integer_value) - 1; i >= 1; i--) { + for(int i = (int) (strlen(*integer_value) - 1); i >= offset; i--) { result += hex_to_int((*integer_value)[i]) * pow(base, multiplier); multiplier++; } From b7861ae7f38dbbda04d92c6e3760ed09e0e63e7c Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Thu, 9 Nov 2017 00:13:10 +0100 Subject: [PATCH 16/25] Fix error in hexa -> dec --- rozsireni | 1 + src/common.c | 3 ++- test/lexer.cpp | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rozsireni b/rozsireni index 008b9d5..c7c5ef2 100644 --- a/rozsireni +++ b/rozsireni @@ -1,4 +1,5 @@ FUNEXP IFTHEN SCOPE +BASE UNARY diff --git a/src/common.c b/src/common.c index a93f29d..4a062fb 100644 --- a/src/common.c +++ b/src/common.c @@ -15,9 +15,10 @@ char* c_string_copy(const char* string) { } int hex_to_int(char char_) { + if((int) char_ >= '0' && (int) char_ <= '9') return (int) char_ - '0'; - if((int) char_ >= 'a' && (int) char_ <= 'e') + if((int) char_ >= 'a' && (int) char_ <= 'f') return (int) char_ - 'a' + 10; LOG_WARNING("Invalid char %c to convert.", char_); diff --git a/test/lexer.cpp b/test/lexer.cpp index c3dd55b..25bc961 100644 --- a/test/lexer.cpp +++ b/test/lexer.cpp @@ -157,6 +157,15 @@ TEST_F(LexerTokenizerTestFixture, StringToInteger) { ); memory_free(integer_value); + + integer_value = c_string_copy("h1f1a1"); + lexer_transform_integer_value(&integer_value); + EXPECT_STREQ( + integer_value, + "127393" + ); + + memory_free(integer_value); } TEST_F(LexerTokenizerTestFixture, Keywords) { From 3d79e912b5ac3d420816629a0481501229ea19ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Thu, 9 Nov 2017 01:07:36 +0100 Subject: [PATCH 17/25] Fix variable declaration in nested scopes for extension SCOPE --- src/code_constructor.c | 25 +++++++++++++------------ src/code_constructor.h | 3 ++- src/parser.c | 3 ++- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/code_constructor.c b/src/code_constructor.c index 9a7ce64..4a354c3 100644 --- a/src/code_constructor.c +++ b/src/code_constructor.c @@ -12,7 +12,8 @@ CodeConstructor* code_constructor_init() { constructor->code_label_stack = stack_code_label_init(); constructor->conditions_label_stack = stack_code_label_init(); constructor->loops_label_stack = stack_code_label_init(); - constructor->loops_initial_instruction_stack = stack_code_instruction_init(); + constructor->loops_depth = 0; + constructor->loops_initial_instruction = NULL; llist_init(&constructor->conversion_instructions, sizeof(TypeConversionInstruction), NULL, NULL, NULL); code_constructor_add_conversion_instruction(constructor, I_INT_TO_FLOAT, DATA_TYPE_INTEGER, DATA_TYPE_DOUBLE, @@ -37,7 +38,6 @@ void code_constructor_free(CodeConstructor** constructor) { stack_free(&(*constructor)->code_label_stack); stack_free(&(*constructor)->conditions_label_stack); stack_free(&(*constructor)->loops_label_stack); - stack_free(&(*constructor)->loops_initial_instruction_stack); llist_free(&(*constructor)->conversion_instructions); code_generator_free(&((*constructor)->generator)); memory_free(*constructor); @@ -73,9 +73,7 @@ void code_constructor_variable_declaration(CodeConstructor* constructor, SymbolV NULL_POINTER_CHECK(constructor,); NULL_POINTER_CHECK(symbol_variable,); - // TODO: Add generating symbol with corresponding frame - CodeInstruction* loop_start_instruction = stack_code_instruction_head(constructor->loops_initial_instruction_stack); - if(loop_start_instruction == NULL) { + if(constructor->loops_initial_instruction == NULL) { // not in scope, directly declare variable GENERATE_CODE( I_DEF_VAR, @@ -93,7 +91,7 @@ void code_constructor_variable_declaration(CodeConstructor* constructor, SymbolV code_generator_insert_instruction_before( constructor->generator, declaration, - loop_start_instruction + constructor->loops_initial_instruction ); } @@ -276,11 +274,11 @@ void code_constructor_while_before_condition(CodeConstructor* constructor) { I_LABEL, code_instruction_operand_init_label(label) ); + // push label instruction to declare variables before while loop - stack_code_instruction_push( - constructor->loops_initial_instruction_stack, - loop_start_instruction - ); + if(constructor->loops_depth++ == 0) { + constructor->loops_initial_instruction = loop_start_instruction; + } } @@ -323,7 +321,9 @@ void code_constructor_while_end(CodeConstructor* constructor) { code_label_free(&end_label); // starting label instruction is now more needed - stack_code_instruction_pop(constructor->loops_initial_instruction_stack); + if(--constructor->loops_depth == 0) { + constructor->loops_initial_instruction = NULL; + } } void code_constructor_variable_expression_assignment(CodeConstructor* constructor, SymbolVariable* variable) { @@ -548,7 +548,8 @@ void code_constructor_fn_asc( } void code_constructor_fn_substr(CodeConstructor* constructor, SymbolVariable* tmp1, SymbolVariable* tmp2, - SymbolVariable* tmp3, SymbolVariable* tmp4, SymbolVariable* tmp5, DataType param_1_type, DataType param_2_type, DataType param_3_type) { + SymbolVariable* tmp3, SymbolVariable* tmp4, SymbolVariable* tmp5, DataType param_1_type, + DataType param_2_type, DataType param_3_type) { char* continue_label = code_constructor_generate_label(constructor, "substr_continue"); diff --git a/src/code_constructor.h b/src/code_constructor.h index 6010579..ba47634 100644 --- a/src/code_constructor.h +++ b/src/code_constructor.h @@ -51,7 +51,8 @@ typedef struct code_constructor_t { Stack* loops_label_stack; size_t scope_depth; // for registering label loops to prepend variable declaration before cycle - Stack* loops_initial_instruction_stack; + CodeInstruction* loops_initial_instruction; + size_t loops_depth; // for generating labels in nested control statements size_t control_statement_depth; diff --git a/src/parser.c b/src/parser.c index a94a6be..0ff828a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -51,10 +51,11 @@ bool parser_parse(Parser* parser) { return false; } ASSERT(parser->code_constructor->code_label_stack->head == NULL); - ASSERT(parser->code_constructor->loops_initial_instruction_stack->head == NULL); + ASSERT(parser->code_constructor->loops_initial_instruction == NULL); ASSERT(parser->code_constructor->conditions_label_stack->head == NULL); ASSERT(parser->code_constructor->loops_label_stack->head == NULL); ASSERT(parser->code_constructor->control_statement_depth == 0); + ASSERT(parser->code_constructor->loops_depth == 0); ASSERT(parser->code_constructor->scope_depth == 0); return true; } From 2293c2a98f7cc2571873983cd3592076a33a0b7f Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Thu, 9 Nov 2017 20:56:08 +0100 Subject: [PATCH 18/25] Repair unit tests --- test/lexer.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/parser.cpp | 23 +++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/test/lexer.cpp b/test/lexer.cpp index 25bc961..3bbafc5 100644 --- a/test/lexer.cpp +++ b/test/lexer.cpp @@ -383,6 +383,50 @@ TEST_F(LexerTokenizerTestFixture, EOFToken) { ) << "Error EOF token"; } +TEST_F(LexerTokenizerTestFixture, AssignmentTokens) { + provider->setString("+= 31"); + char_stack_empty(lexer->lexer_fsm->stack); + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_ASSIGN_ADD + ) << "Error ASSIGN_ADD token"; + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_INTEGER_LITERAL + ) << "Error ADD token"; + + +} + +TEST_F(LexerTokenizerTestFixture, AssignmentTokens1) { + provider->setString("-= 31 + b"); + char_stack_empty(lexer->lexer_fsm->stack); + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_ASSIGN_SUB + ) << "Error ASSIGN_ADD token"; + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_INTEGER_LITERAL + ) << "Error INTEGER_LITERAL token"; + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_ADD + ) << "Error INTEGER_LITERAL token"; + + EXPECT_EQ( + this->getNextTokenType(), + TOKEN_IDENTIFIER + ) << "Error IDENTIFIER token"; + + +} + TEST_F(LexerTokenizerTestFixture, RelationOperators) { provider->setString("< > <= >= <>"); char_stack_empty(lexer->lexer_fsm->stack); diff --git a/test/parser.cpp b/test/parser.cpp index 5d60dd5..f3ed2e9 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -438,36 +438,52 @@ TEST_F(ParserTestFixture, ModifyAssigment) { EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} +TEST_F(ParserTestFixture, ModifyAssigment1) { provider->setString("-= 31"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} +TEST_F(ParserTestFixture, ModifyAssigment2) { provider->setString("*= 31"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} +TEST_F(ParserTestFixture, ModifyAssigment3) { provider->setString("/= 31"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} + +TEST_F(ParserTestFixture, ModifyAssigment4) { provider->setString("+= foo()"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} +TEST_F(ParserTestFixture, ModifyAssigment5) { provider->setString("-= a+b+c+d"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} +TEST_F(ParserTestFixture, ModifyAssigment6) { provider->setString("*= foo()*foo(foo())"); EXPECT_TRUE( parser_parse_modify_assignment(parser) ); +} + +TEST_F(ParserTestFixture, ModifyAssigment7) { provider->setString("/= 12+15"); EXPECT_TRUE( @@ -499,6 +515,13 @@ TEST_F(ParserTestFixture, ReturnRule) { ) << "Error parsing rule"; } +TEST_F(ParserTestFixture, ModifyAssignment) { + provider->setString("+= 31"); + EXPECT_TRUE( + parser_parse_modify_assignment(parser) + ) << "Error parsing rule"; +} + TEST_F(ParserTestFixture, ComplexTest) { provider->setString(R"( SCOPE From 4022f9db42face15f90a460487dba50c8e48ae38 Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Thu, 9 Nov 2017 21:20:27 +0100 Subject: [PATCH 19/25] Add some comments --- src/code_instruction.h | 1 - src/common.h | 6 ++++++ src/lexer_fsm.h | 1 + src/parser.c | 2 ++ src/stack.h | 18 ++++++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/code_instruction.h b/src/code_instruction.h index a9f7688..1bf256c 100644 --- a/src/code_instruction.h +++ b/src/code_instruction.h @@ -132,7 +132,6 @@ CodeInstruction* code_instruction_init( void code_instruction_free(CodeInstruction** instruction); - char* code_instruction_render(CodeInstruction* instruction); #endif //_INSTRUCTION_H diff --git a/src/common.h b/src/common.h index 98d0832..94f9e37 100644 --- a/src/common.h +++ b/src/common.h @@ -9,6 +9,12 @@ #define GET_OVERLOADED_MACRO1234(_1, _2, _3, _4, ...) MSVC_EXPAND(GET_FIRST_ARG(__VA_ARGS__, 0)) #define GET_OVERLOADED_MACRO12345(_1, _2, _3, _4, _5, ...) MSVC_EXPAND(GET_FIRST_ARG(__VA_ARGS__, 0)) +/** + * @brief Copy string (native c) and get pointer for it + * + * @param char* input string + * @return char* copy of the string + */ char* c_string_copy(const char* string); /** diff --git a/src/lexer_fsm.h b/src/lexer_fsm.h index 7b10698..5d18fd8 100644 --- a/src/lexer_fsm.h +++ b/src/lexer_fsm.h @@ -5,6 +5,7 @@ #include "char_stack.h" #include "dynamic_string.h" +// Lenght of lexer buffer #define LEXER_FSM_STREAM_BUFFER_DEFAULT_LENGTH 2 /** diff --git a/src/parser.c b/src/parser.c index 0ff828a..e4cde12 100644 --- a/src/parser.c +++ b/src/parser.c @@ -766,6 +766,8 @@ bool parser_parse_input(Parser* parser) { } bool parser_parse_condition(Parser* parser) { + + DataType expression_data_type; RULES( diff --git a/src/stack.h b/src/stack.h index cfba082..cad314d 100644 --- a/src/stack.h +++ b/src/stack.h @@ -16,12 +16,30 @@ typedef struct stack__t { StackBaseItem* head; } Stack; +/** + * @brief Constructor for stack + * + * @param stack_item_free_callback + * @return + */ Stack* stack_init(stack_item_free_callback_f stack_item_free_callback); void stack_free(Stack** stack); +/** + * @brief Push pointer into stack + * + * @param Stack* stack Pointer to stack + * @param StackBaseItem* item Item which will be pushed + */ void stack_push(Stack* stack, StackBaseItem* item); +/** + * @brief Pop item from stack and return pointer on value + * + * @param Stack* stack Pointer to stack + * @return StackBaseItem* Popped item + */ StackBaseItem* stack_pop(Stack* stack); StackBaseItem* stack_get_by_index(Stack* stack, size_t index); From 4a724a02580254618ce4414ffbd0e6ef72fe0995 Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Thu, 9 Nov 2017 23:41:45 +0100 Subject: [PATCH 20/25] Add modify assignment into assignment --- src/parser.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/parser.c b/src/parser.c index e4cde12..796cbd3 100644 --- a/src/parser.c +++ b/src/parser.c @@ -967,7 +967,25 @@ bool parser_parse_assignment(Parser* parser) { DataType expression_data_type; SymbolVariable* actual_variable = parser->parser_semantic->actual_variable; RULES( - // Todo: for tokens +=, -=, /= .... call rule modify_assignment and return value + + CONDITIONAL_RULES( + lexer_rewind_token(parser->lexer, token); + + CHECK_RULE( + token_type == TOKEN_ASSIGN_SUB || token_type == TOKEN_ASSIGN_ADD || + token_type == TOKEN_ASSIGN_DIVIDE || token_type == TOKEN_ASSIGN_MULTIPLY || + token_type == TOKEN_ASSIGN_INT_DIVIDE, + modify_assignment, + BEFORE({}), + AFTER( + { + token_free(&token); + return true; + } + ) + ); + ); + CHECK_TOKEN(TOKEN_EQUAL); CALL_EXPRESSION_RULE(expression_data_type); ); From 3fe24b7bdf0f458e5ec30ed09fce420ab782df70 Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Sat, 11 Nov 2017 19:42:35 +0100 Subject: [PATCH 21/25] Add tests for grammar --- test/parser.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/parser.cpp b/test/parser.cpp index f3ed2e9..a5ed7f7 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -926,6 +926,85 @@ scope print len; end scope +)"); + EXPECT_TRUE( + parser_parse_program(parser) + ); +} + +TEST_F(ParserTestFixture, ModifyAssignmentProgram) { + provider->setString(R"( +scope +dim a as integer +a = 10 +a += 10 +a *= 10 +a -= 10 +a /= 10 +a \= 10 +end scope +)"); + EXPECT_TRUE( + parser_parse_program(parser) + ); +} + +TEST_F(ParserTestFixture, ModifyAssignmentInFunction) { + provider->setString(R"( +function dghsh() as integer +dim a as integer +a = 10 +a += 10 +a *= 10 +a -= 10 +a /= 10 +a \= 10 +end function + +scope +end scope + +)"); + EXPECT_TRUE( + parser_parse_program(parser) + ); +} + + +TEST_F(ParserTestFixture, ModifyAssignmentEverywhere) { + provider->setString(R"( +function dghsh() as integer +dim a as integer +a = 10 +a += 10 +a *= 10 +a -= 10 +a /= 10 +a \= 10 +end function + +scope + +dim a as integer +a = 10 +a += 10 +a *= 10 +a -= 10 +a /= 10 +a \= 10 + +if a < 10 then +dim a as integer +a = 10 +a += 10 +a *= 10 +a -= 10 +a /= 10 +a \= 10 +end if + +end scope + )"); EXPECT_TRUE( parser_parse_program(parser) From a918fd2e899e72a5ab9efa2ebc0bd6a6122ea738 Mon Sep 17 00:00:00 2001 From: Son Hai Nguyen Date: Sat, 11 Nov 2017 22:30:47 +0100 Subject: [PATCH 22/25] Fix not rule --- src/parser_expr_rules.c | 10 +--------- src/parser_semantic.c | 5 ++++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/parser_expr_rules.c b/src/parser_expr_rules.c index abadbe5..9997e35 100644 --- a/src/parser_expr_rules.c +++ b/src/parser_expr_rules.c @@ -872,14 +872,6 @@ bool expression_rule_not(Parser* parser, LList* expr_token_buffer, ExprIdx* expr // NOTE: now we are processing rule regular way - from the left to the right - if(EXPR_HIGHER_OPERAND->data_type != DATA_TYPE_BOOLEAN) { - SEMANTIC_ANALYSIS( - { - parser->parser_semantic->error_report.error_code = ERROR_SEMANTIC_TYPE; - return false; - } - ); - } CODE_GENERATION( { CodeConstructor* constructor = parser->code_constructor; @@ -936,4 +928,4 @@ bool expression_rule_or(Parser* parser, LList *expr_token_buffer, ExprIdx* expre EXPR_RULE_REPLACE(e); return true; -} \ No newline at end of file +} diff --git a/src/parser_semantic.c b/src/parser_semantic.c index ca7912d..881af44 100644 --- a/src/parser_semantic.c +++ b/src/parser_semantic.c @@ -74,6 +74,9 @@ ParserSemantic* parser_semantic_init() { parser_semantic_add_operation_signature(parser_semantic, OPERATION_OR, DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); + parser_semantic_add_operation_signature(parser_semantic, OPERATION_NOT, + DATA_TYPE_BOOLEAN, DATA_TYPE_NONE, + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); const TypeExpressionOperation compare_operations[] = { @@ -104,7 +107,7 @@ ParserSemantic* parser_semantic_init() { DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); parser_semantic_add_operation_signature(parser_semantic, OPERATION_NOT_EQUAL, DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN, - DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); + DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN); // implicit conversions parser_semantic_add_operation_signature(parser_semantic, OPERATION_IMPLICIT_CONVERSION, From 2ebba6731a0db6625ff98aa967e14c088193272e Mon Sep 17 00:00:00 2001 From: Martin Kobelka Date: Sat, 11 Nov 2017 23:51:21 +0100 Subject: [PATCH 23/25] Add new ll.txt grammar description --- doc/ll.txt | 146 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 59 deletions(-) diff --git a/doc/ll.txt b/doc/ll.txt index 459205d..cc18f31 100644 --- a/doc/ll.txt +++ b/doc/ll.txt @@ -1,84 +1,112 @@ -// Celý program -> EOF - -> + -> + -> SCOPE EOL END SCOPE -// Definiční část - -> EOL + -> -> E -> -> + -> -// Deklarace a definice funcí + -> EOL END FUNCTION -> DECLARE EOL - -> EOL END FUNCTION - -> FUNCTION IDENTIFIER () AS TYPE + -> FUNCTION IDENTIFIER () AS + -> E -> + -> E - -> , - -> AS + -> -// Příkazy ve funkcí - -> E - -> EOL + -> IDENTIFIER AS TYPE -// Příkazy ve scope -> E - -> EOL - -// Použitelné v těle funkce - -> - -> - -> - -> - -> - -// Použitelné ve scope - -> - -> - -> - -> - -> - - -> EQUAL // přiřazení - -> INPUT IDENTIFIER // načtení ze vstupu - -> PRINT // tisk na výstup, alespoň jeden příkaz, každý se středníkem - -> RETURN - -> // TODO nevíme, spekulativní - -> SCOPE EOL END SCOPE - -// Tisk řetězce - -> SEMICOLON - -> E - -> - -// Deklarace proměnné - -> DIM AS + -> EOL + -> E + -> EOL + + -> E + -> EOL + + -> + -> + -> + -> + -> + -> + -> + -> + -> + + -> + -> + -> + -> + -> + -> + -> + -> + + -> + -> + -> + -> + -> + -> + -> + -> + -> + -> + + -> DIM IDENTIFIER AS -> E -> + -> INTEGER + -> BOOLEAN + -> STRING + -> DOUBLE + + -> IDENTIF -> = + -> + + -> E + -> + -> DIM SHARED IDENTIFIER AS + + -> STATIC IDENTIFIER AS + + -> RETURN + + -> + -> += + -> -= + -> *= + -> /= + -> \= + + -> PRINT + -> E + -> + -> SEMICOLON + + -> DO WHILE EOL LOOP + + -> INPUT IDENTIFIER -// podmínky - -> IF THEN EOL END IF - -> E - -> ELSE EOL - -> DO WHILE EOL LOOP + -> IF THEN EOL + END IF + -> E + -> ELSEIF THEN EOL -// volání funkce (pravidlo volané z expression kvůli rekurzi) - = IDENTIFIER () - -> E - -> - -> E - -> , - -> + -> E + -> ELSE EOL -// Todo: Bonusové zadání, for - -> FOR EQUAL TO .....? + -> FOR IDENTIFIER EOL NEXT - -> -> E - -> EOL + -> EOL \ No newline at end of file From 13733f2c54db5453a0934264b865484924a81529 Mon Sep 17 00:00:00 2001 From: Son Hai Nguyen Date: Sun, 12 Nov 2017 15:25:01 +0100 Subject: [PATCH 24/25] Fix invalid free in expression modul --- src/parser_expr_internal.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/parser_expr_internal.c b/src/parser_expr_internal.c index 6f6504d..712c8d6 100644 --- a/src/parser_expr_internal.c +++ b/src/parser_expr_internal.c @@ -194,7 +194,16 @@ int expr_llist_type_cmp(LListBaseItem* a, LListBaseItem* b) { void expr_llist_free(LListBaseItem* item) { ASSERT(item != NULL); - expr_token_free((ExprToken*)item); + ExprToken* t = (ExprToken*)item; + if(t != NULL) { + if((t->type == EXPR_TOKEN_IDENTIFIER || + t->type == EXPR_TOKEN_INTEGER_LITERAL || + t->type == EXPR_TOKEN_DOUBLE_LITERAL || + t->type == EXPR_TOKEN_STRING_LITERAL + ) && t->data.s != NULL) { + memory_free(t->data.s); + } + } } ExprToken* create_expr_token(ExprTokenType type) { From bf7574ecc169823f440c6c60fdccabd72e20005e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Kol=C3=A1=C5=99?= Date: Sun, 12 Nov 2017 22:01:56 +0100 Subject: [PATCH 25/25] Add boolop between extensions --- rozsireni | 1 + 1 file changed, 1 insertion(+) diff --git a/rozsireni b/rozsireni index 0998ca5..5c9f6f8 100644 --- a/rozsireni +++ b/rozsireni @@ -1,3 +1,4 @@ FUNEXP IFTHEN SCOPE +BOOLOP