From df4604f27bbd8ed42ea2c7026c7e4845aafd1a8b Mon Sep 17 00:00:00 2001 From: A404M Date: Tue, 18 Feb 2025 23:42:10 +0330 Subject: add while fix some memory leaks --- src/compiler/ast-tree.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/compiler/ast-tree.h | 9 ++++++ src/compiler/lexer.c | 10 ++++--- src/compiler/lexer.h | 1 + src/compiler/parser.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- src/compiler/parser.h | 7 +++++ 6 files changed, 166 insertions(+), 6 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c index 66a5f6b..3d7c675 100644 --- a/src/compiler/ast-tree.c +++ b/src/compiler/ast-tree.c @@ -110,6 +110,7 @@ const char *AST_TREE_TOKEN_STRINGS[] = { "AST_TREE_TOKEN_KEYWORD_PRINT_U64", "AST_TREE_TOKEN_KEYWORD_RETURN", "AST_TREE_TOKEN_KEYWORD_IF", + "AST_TREE_TOKEN_KEYWORD_WHILE", "AST_TREE_TOKEN_TYPE_FUNCTION", "AST_TREE_TOKEN_TYPE_TYPE", @@ -337,6 +338,23 @@ void astTreePrint(const AstTree *tree, int indent) { printf(" "); } goto RETURN_SUCCESS; + case AST_TREE_TOKEN_KEYWORD_WHILE: { + AstTreeWhile *metadata = tree->metadata; + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("condition=\n"); + astTreePrint(metadata->condition, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("body=\n"); + astTreePrint(metadata->body, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + } + goto RETURN_SUCCESS; case AST_TREE_TOKEN_SCOPE: { AstTreeScope *metadata = tree->metadata; printf(",\n"); @@ -487,6 +505,13 @@ void astTreeDestroy(AstTree tree) { free(metadata); } return; + case AST_TREE_TOKEN_KEYWORD_WHILE: { + AstTreeWhile *metadata = tree.metadata; + astTreeDelete(metadata->condition); + astTreeDelete(metadata->body); + free(metadata); + } + return; case AST_TREE_TOKEN_SCOPE: { AstTreeScope *metadata = tree.metadata; for (size_t i = 0; i < metadata->expressions_size; ++i) { @@ -676,6 +701,7 @@ AstTree *copyAstTree(AstTree *tree) { tree->str_begin, tree->str_end); } case AST_TREE_TOKEN_KEYWORD_IF: + case AST_TREE_TOKEN_KEYWORD_WHILE: case AST_TREE_TOKEN_SCOPE: case AST_TREE_TOKEN_NONE: } @@ -802,6 +828,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) { case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: case PARSER_TOKEN_SYMBOL_PARENTHESIS: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: goto AFTER_SWITCH; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_TYPE_TYPE: @@ -1036,6 +1063,8 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) { return astTreeParseVariable(parserNode, helper); case PARSER_TOKEN_KEYWORD_IF: return astTreeParseIf(parserNode, helper); + case PARSER_TOKEN_KEYWORD_WHILE: + return astTreeParseWhile(parserNode, helper); case PARSER_TOKEN_SYMBOL_EOL: return astTreeParse((ParserNodeSingleChildMetadata *)parserNode->metadata, helper); @@ -1130,6 +1159,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *p_helper) { node = (ParserNodeSingleChildMetadata *)node->metadata; goto OK_NODE; case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: goto OK_NODE; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_IDENTIFIER: @@ -1512,6 +1542,27 @@ AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper) { parserNode->str_begin, parserNode->str_end); } +AstTree *astTreeParseWhile(ParserNode *parserNode, AstTreeHelper *helper) { + ParserNodeWhileMetadata *node_metadata = parserNode->metadata; + + AstTree *condition = astTreeParse(node_metadata->condition, helper); + if (condition == NULL) { + return NULL; + } + + AstTree *body = astTreeParse(node_metadata->body, helper); + if (body == NULL) { + return NULL; + } + + AstTreeWhile *metadata = a404m_malloc(sizeof(*metadata)); + metadata->condition = condition; + metadata->body = body; + + return newAstTree(AST_TREE_TOKEN_KEYWORD_WHILE, metadata, NULL, + parserNode->str_begin, parserNode->str_end); +} + AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *p_helper) { ParserNodeArray *body = parserNode->metadata; @@ -2054,6 +2105,8 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper, return setTypesVariableDefine(tree, helper); case AST_TREE_TOKEN_KEYWORD_IF: return setTypesIf(tree, helper, function); + case AST_TREE_TOKEN_KEYWORD_WHILE: + return setTypesWhile(tree, helper, function); case AST_TREE_TOKEN_SCOPE: return setTypesScope(tree, helper, function); case AST_TREE_TOKEN_NONE: @@ -2448,6 +2501,25 @@ bool setTypesIf(AstTree *tree, AstTreeSetTypesHelper helper, return true; } +bool setTypesWhile(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunction *function) { + AstTreeWhile *metadata = tree->metadata; + + if (!setAllTypes(metadata->condition, helper, function) || + !setAllTypes(metadata->body, helper, function)) { + return false; + } + + if (!typeIsEqual(metadata->condition->type, &AST_TREE_BOOL_TYPE)) { + printError(metadata->condition->str_begin, metadata->condition->str_end, + "If condition must be boolean"); + return false; + } + + tree->type = &AST_TREE_VOID_TYPE; + return true; +} + bool setTypesScope(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function) { AstTreeScope *metadata = tree->metadata; @@ -2497,6 +2569,7 @@ bool astTreeClean(AstTree *tree) { case AST_TREE_TOKEN_KEYWORD_PRINT_U64: case AST_TREE_TOKEN_KEYWORD_RETURN: case AST_TREE_TOKEN_KEYWORD_IF: + case AST_TREE_TOKEN_KEYWORD_WHILE: case AST_TREE_TOKEN_TYPE_TYPE: case AST_TREE_TOKEN_TYPE_FUNCTION: case AST_TREE_TOKEN_TYPE_VOID: diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h index eaf8b07..b58d413 100644 --- a/src/compiler/ast-tree.h +++ b/src/compiler/ast-tree.h @@ -10,6 +10,7 @@ typedef enum AstTreeToken { AST_TREE_TOKEN_KEYWORD_PRINT_U64, AST_TREE_TOKEN_KEYWORD_RETURN, AST_TREE_TOKEN_KEYWORD_IF, + AST_TREE_TOKEN_KEYWORD_WHILE, AST_TREE_TOKEN_TYPE_FUNCTION, AST_TREE_TOKEN_TYPE_TYPE, @@ -149,6 +150,11 @@ typedef struct AstTreeIf { AstTree *elseBody; } AstTreeIf; +typedef struct AstTreeWhile { + AstTree *condition; + AstTree *body; +} AstTreeWhile; + typedef struct AstTreeHelper { AstTreeVariables **variables; size_t variables_size; @@ -198,6 +204,7 @@ AstTree *astTreeParseUnaryOperator(ParserNode *parserNode, bool astTreeParseConstant(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseVariable(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper); +AstTree *astTreeParseWhile(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseParenthesis(ParserNode *parserNode, AstTreeHelper *helper); @@ -230,6 +237,8 @@ bool setTypesOperatorUnary(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesVariableDefine(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesIf(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function); +bool setTypesWhile(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunction *function); bool setTypesScope(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function); diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 7fef9be..6263854 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -33,6 +33,7 @@ const char *LEXER_TOKEN_STRINGS[] = { "LEXER_TOKEN_KEYWORD_FALSE", "LEXER_TOKEN_KEYWORD_IF", "LEXER_TOKEN_KEYWORD_ELSE", + "LEXER_TOKEN_KEYWORD_WHILE", "LEXER_TOKEN_NUMBER", @@ -93,9 +94,9 @@ const size_t LEXER_SYMBOL_SIZE = sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS); const char *LEXER_KEYWORD_STRINGS[] = { - "type", "void", "i8", "u8", "i16", "u16", "i32", - "u32", "i64", "u64", "f16", "f32", "f64", "f128", - "bool", "print_u64", "return", "true", "false", "if", "else", + "type", "void", "i8", "u8", "i16", "u16", "i32", "u32", + "i64", "u64", "f16", "f32", "f64", "f128", "bool", "print_u64", + "return", "true", "false", "if", "else", "while", }; const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_TYPE, LEXER_TOKEN_KEYWORD_VOID, @@ -108,7 +109,7 @@ const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_BOOL, LEXER_TOKEN_KEYWORD_PRINT_U64, LEXER_TOKEN_KEYWORD_RETURN, LEXER_TOKEN_KEYWORD_TRUE, LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_IF, - LEXER_TOKEN_KEYWORD_ELSE, + LEXER_TOKEN_KEYWORD_ELSE, LEXER_TOKEN_KEYWORD_WHILE, }; const size_t LEXER_KEYWORD_SIZE = sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS); @@ -255,6 +256,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter, case LEXER_TOKEN_KEYWORD_FALSE: case LEXER_TOKEN_KEYWORD_IF: case LEXER_TOKEN_KEYWORD_ELSE: + case LEXER_TOKEN_KEYWORD_WHILE: case LEXER_TOKEN_NUMBER: case LEXER_TOKEN_SYMBOL_EOL: case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS: diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h index 0a6da3a..92d943e 100644 --- a/src/compiler/lexer.h +++ b/src/compiler/lexer.h @@ -26,6 +26,7 @@ typedef enum LexerToken { LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_IF, LEXER_TOKEN_KEYWORD_ELSE, + LEXER_TOKEN_KEYWORD_WHILE, LEXER_TOKEN_NUMBER, diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 84dca1c..9f6b060 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -38,6 +38,7 @@ const char *PARSER_TOKEN_STRINGS[] = { "PARSER_TOKEN_KEYWORD_PRINT_U64", "PARSER_TOKEN_KEYWORD_RETURN", "PARSER_TOKEN_KEYWORD_IF", + "PARSER_TOKEN_KEYWORD_WHILE", "PARSER_TOKEN_CONSTANT", "PARSER_TOKEN_VARIABLE", @@ -129,7 +130,7 @@ static constexpr ParserOrder PARSER_ORDER[] = { }, { .ltr = true, - ORDER_ARRAY(LEXER_TOKEN_KEYWORD_IF, ), + ORDER_ARRAY(LEXER_TOKEN_KEYWORD_IF, LEXER_TOKEN_KEYWORD_WHILE, ), }, }; @@ -354,7 +355,27 @@ void parserNodePrint(const ParserNode *node, int indent) { printf("\n"); for (int i = 0; i < indent; ++i) printf(" "); - free(metadata); + } + case PARSER_TOKEN_KEYWORD_WHILE: { + ParserNodeIfMetadata *metadata = node->metadata; + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("condition=\n"); + parserNodePrint(metadata->condition, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("ifBody=\n"); + parserNodePrint(metadata->ifBody, indent + 1); + printf("\n,"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("elseBody=\n"); + parserNodePrint(metadata->elseBody, indent + 1); + printf("\n"); + for (int i = 0; i < indent; ++i) + printf(" "); } goto RETURN_SUCCESS; case PARSER_TOKEN_NONE: @@ -483,6 +504,13 @@ void parserNodeDelete(ParserNode *node) { free(metadata); } goto RETURN_SUCCESS; + case PARSER_TOKEN_KEYWORD_WHILE: { + ParserNodeWhileMetadata *metadata = node->metadata; + parserNodeDelete(metadata->condition); + parserNodeDelete(metadata->body); + free(metadata); + } + goto RETURN_SUCCESS; case PARSER_TOKEN_NONE: } UNREACHABLE; @@ -692,6 +720,8 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end, } case LEXER_TOKEN_KEYWORD_IF: return parserIf(node, end, parent); + case LEXER_TOKEN_KEYWORD_WHILE: + return parserWhile(node, end, parent); case LEXER_TOKEN_KEYWORD_ELSE: case LEXER_TOKEN_SYMBOL: case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS: @@ -1058,6 +1088,7 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end, switch (bodyArray->data[i]->token) { case PARSER_TOKEN_SYMBOL_EOL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: continue; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_IDENTIFIER: @@ -1364,6 +1395,40 @@ ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) { elseBody->str_end, metadata, parent); } +ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent) { + LexerNode *conditionNode = node + 1; + if (conditionNode >= end) { + printError(node->str_begin, node->str_end, "While has no condition"); + return NULL; + } + + ParserNode *condition = + getUntilCommonParent(conditionNode->parserNode, parent); + + if (condition == NULL) { + printError(conditionNode->str_begin, conditionNode->str_end, + "While has bad condition"); + return NULL; + } + + LexerNode *bodyNode = + getNextLexerNodeUsingCommonParent(conditionNode, end, parent); + ParserNode *body = getUntilCommonParent(bodyNode->parserNode, parent); + + if (body == NULL) { + printError(node->str_begin, node->str_end, "While has bad body"); + return NULL; + } + + ParserNodeWhileMetadata *metadata = a404m_malloc(sizeof(*metadata)); + metadata->condition = condition; + metadata->body = body; + + return condition->parent = body->parent = node->parserNode = + newParserNode(PARSER_TOKEN_KEYWORD_WHILE, node->str_begin, + body->str_end, metadata, parent); +} + bool isAllArguments(const ParserNodeArray *nodes) { for (size_t i = 0; i < nodes->size; ++i) { const ParserNode *node = nodes->data[i]; @@ -1402,6 +1467,7 @@ bool isExpression(ParserNode *node) { case PARSER_TOKEN_VALUE_FLOAT: case PARSER_TOKEN_VALUE_BOOL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: return true; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_TYPE_TYPE: @@ -1478,6 +1544,7 @@ bool isType(ParserNode *node) { case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL: case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: return false; case PARSER_TOKEN_NONE: } @@ -1533,6 +1600,7 @@ bool isValue(ParserNode *node) { case PARSER_TOKEN_SYMBOL_COMMA: case PARSER_TOKEN_KEYWORD_PRINT_U64: case PARSER_TOKEN_KEYWORD_RETURN: + case PARSER_TOKEN_KEYWORD_WHILE: return false; case PARSER_TOKEN_NONE: } diff --git a/src/compiler/parser.h b/src/compiler/parser.h index 3af47e7..6fe6d6f 100644 --- a/src/compiler/parser.h +++ b/src/compiler/parser.h @@ -34,6 +34,7 @@ typedef enum ParserToken { PARSER_TOKEN_KEYWORD_PRINT_U64, PARSER_TOKEN_KEYWORD_RETURN, PARSER_TOKEN_KEYWORD_IF, + PARSER_TOKEN_KEYWORD_WHILE, PARSER_TOKEN_CONSTANT, PARSER_TOKEN_VARIABLE, @@ -131,6 +132,11 @@ typedef struct ParserNodeIfMetadata { ParserNode *elseBody; } ParserNodeIfMetadata; +typedef struct ParserNodeWhileMetadata { + ParserNode *condition; + ParserNode *body; +} ParserNodeWhileMetadata; + void parserNodePrint(const ParserNode *node, int indent); void parserNodeDelete(ParserNode *node); @@ -175,6 +181,7 @@ ParserNode *parserBinaryOrLeftOperator(LexerNode *node, LexerNode *begin, ParserToken token, LexerToken laterToken); ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent); +ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent); bool isAllArguments(const ParserNodeArray *nodes); -- cgit v1.2.3