From 0c310721157d8586be8022ba25a9be5312bc4851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Tue, 24 Jun 2025 18:40:50 +0900 Subject: [PATCH] Loop parsing --- src/Lexer/Lexer.cpp | 4 ++ src/Lexer/Token.cpp | 2 + src/Lexer/Token.h | 1 + src/Parser/Expression/ExpressionBinary.cpp | 20 ++++---- src/Parser/Expression/ExpressionBinary.h | 3 +- src/Parser/Parser.cpp | 53 +++++++++++++++++++++- src/Parser/Parser.h | 1 + src/Parser/Statement/Statement.h | 1 + src/Parser/Statement/StatementLoop.cpp | 39 ++++++++++++++++ src/Parser/Statement/StatementLoop.h | 20 ++++++++ 10 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 src/Parser/Statement/StatementLoop.cpp create mode 100644 src/Parser/Statement/StatementLoop.h diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp index b53893f..ddd9aa9 100644 --- a/src/Lexer/Lexer.cpp +++ b/src/Lexer/Lexer.cpp @@ -194,6 +194,10 @@ shared_ptr Lexer::nextToken() { token = match(TokenKind::RETURN, "ret", true); if (token != nullptr) return token; + + token = match(TokenKind::REPEAT, "rep", true); + if (token != nullptr) + return token; // literal token = match(TokenKind::BOOL, "true", true); diff --git a/src/Lexer/Token.cpp b/src/Lexer/Token.cpp index a4fed2d..b912fb3 100644 --- a/src/Lexer/Token.cpp +++ b/src/Lexer/Token.cpp @@ -140,6 +140,8 @@ string Token::toString() { return "FUNCTION"; case TokenKind::RETURN: return "RETURN"; + case TokenKind::REPEAT: + return "REPEAT"; case TokenKind::M_EXTERN: return "@EXTERN"; diff --git a/src/Lexer/Token.h b/src/Lexer/Token.h index ac0ac5e..dd2cb9d 100644 --- a/src/Lexer/Token.h +++ b/src/Lexer/Token.h @@ -33,6 +33,7 @@ enum class TokenKind { FUNCTION, RETURN, + REPEAT, BOOL, INTEGER_DEC, diff --git a/src/Parser/Expression/ExpressionBinary.cpp b/src/Parser/Expression/ExpressionBinary.cpp index 90ead9d..bd062b9 100644 --- a/src/Parser/Expression/ExpressionBinary.cpp +++ b/src/Parser/Expression/ExpressionBinary.cpp @@ -1,15 +1,7 @@ #include "ExpressionBinary.h" ExpressionBinary::ExpressionBinary(shared_ptr token, shared_ptr left, shared_ptr right): -Expression(ExpressionKind::BINARY, ValueType::NONE), left(left), right(right) { - // Types must match - if (left->getValueType() != right->getValueType()) - exit(1); - - // Booleans can only do = or != - if (valueType == ValueType::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) - exit(1); - +Expression(ExpressionKind::BINARY, ValueType::NONE), operation(ExpressionBinaryOperation::INVALID), left(left), right(right) { switch (token->getKind()) { case TokenKind::EQUAL: operation = ExpressionBinaryOperation::EQUAL; @@ -56,8 +48,16 @@ Expression(ExpressionKind::BINARY, ValueType::NONE), left(left), right(right) { valueType = left->getValueType(); break; default: - exit(1); + break; } + + // Types must match + if (left->getValueType() != right->getValueType()) + valueType = ValueType::NONE; + + // Booleans can only do = or != + if (valueType == ValueType::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) + valueType = ValueType::NONE; } ExpressionBinaryOperation ExpressionBinary::getOperation() { diff --git a/src/Parser/Expression/ExpressionBinary.h b/src/Parser/Expression/ExpressionBinary.h index 582aeb7..5fbc44c 100644 --- a/src/Parser/Expression/ExpressionBinary.h +++ b/src/Parser/Expression/ExpressionBinary.h @@ -11,7 +11,8 @@ enum class ExpressionBinaryOperation { SUB, MUL, DIV, - MOD + MOD, + INVALID }; class ExpressionBinary: public Expression { diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 6af6ba7..203a328 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -15,6 +15,7 @@ #include "Parser/Statement/StatementExpression.h" #include "Parser/Statement/StatementMetaExternFunction.h" #include "Parser/Statement/StatementBlock.h" +#include "Parser/Statement/StatementLoop.h" #include "Parser/Statement/StatementInvalid.h" Parser::Parser(vector> tokens): tokens(tokens) { @@ -53,6 +54,10 @@ shared_ptr Parser::nextStatement() { statement = matchStatementReturn(); if (statement != nullptr) return statement; + + statement = matchStatementLoop(); + if (statement != nullptr) + return statement; statement = matchStatementExpression(); if (statement != nullptr) @@ -151,8 +156,8 @@ shared_ptr Parser::matchStatementVariable() { if (expression == nullptr || !expression->isValid()) return matchStatementInvalid(); - // Expect new line - if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true)) + // Expect comma or new line + if (!tryMatchingTokenKinds({TokenKind::COMMA}, true, false) && !tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true)) return matchStatementInvalid("Expected a new line after variable declaration"); return make_shared(identifierToken->getLexme(), valueType, expression); @@ -174,6 +179,50 @@ shared_ptr Parser::matchStatementReturn() { return make_shared(expression); } +shared_ptr Parser::matchStatementLoop() { + if (!tryMatchingTokenKinds({TokenKind::REPEAT}, true, true)) + return nullptr; + + // initial + shared_ptr initStatement = matchStatementVariable(); + if (initStatement != nullptr && !initStatement->isValid()) + initStatement = nullptr; + + // got initial, expect comma + if (initStatement != nullptr && !tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) + return matchStatementInvalid("Expected comma after initial statement"); + + // pre condition + shared_ptr preConditionExpression = nextExpression(); + if (preConditionExpression == nullptr || !preConditionExpression->isValid()) + return matchStatementInvalid("Expected pre-condition expression"); + + // post condition + shared_ptr postConditionExpression; + if (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)) { + postConditionExpression = nextExpression(); + if (postConditionExpression == nullptr || !postConditionExpression->isValid()) + return matchStatementInvalid("Expected post-condition expression"); + } + + // epxect new line + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) + return matchStatementInvalid("Expected new line"); + + // body + shared_ptr bodyBlockStatement = matchStatementBlock({TokenKind::SEMICOLON}, true); + if (bodyBlockStatement == nullptr) + return matchStatementInvalid("Expected block statement"); + else if (!bodyBlockStatement->isValid()) + return bodyBlockStatement; + + // epxect new line + if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) + return matchStatementInvalid("Expected new line"); + + return make_shared(initStatement, preConditionExpression, postConditionExpression, dynamic_pointer_cast(bodyBlockStatement)); +} + shared_ptr Parser::matchStatementExpression() { shared_ptr expression = nextExpression(); diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 9243914..9a627f5 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -22,6 +22,7 @@ private: shared_ptr matchStatementFunction(); shared_ptr matchStatementVariable(); shared_ptr matchStatementReturn(); + shared_ptr matchStatementLoop(); shared_ptr matchStatementExpression(); shared_ptr matchStatementMetaExternFunction(); shared_ptr matchStatementBlock(vector terminalTokenKinds, bool shouldConsumeTerminal); diff --git a/src/Parser/Statement/Statement.h b/src/Parser/Statement/Statement.h index 83bbf91..bee843b 100644 --- a/src/Parser/Statement/Statement.h +++ b/src/Parser/Statement/Statement.h @@ -13,6 +13,7 @@ enum class StatementKind { RETURN, FUNCTION, VARIABLE, + LOOP, META_EXTERN_FUNCTION, INVALID }; diff --git a/src/Parser/Statement/StatementLoop.cpp b/src/Parser/Statement/StatementLoop.cpp new file mode 100644 index 0000000..e29eca2 --- /dev/null +++ b/src/Parser/Statement/StatementLoop.cpp @@ -0,0 +1,39 @@ +#include "StatementLoop.h" + +#include "Parser/Expression/Expression.h" +#include "Parser/Statement/StatementBlock.h" + +StatementLoop::StatementLoop(shared_ptr initStatement, shared_ptr preConditionExpression, shared_ptr postConditionExpression, shared_ptr bodyBlockStatement): +Statement(StatementKind::LOOP), initStatement(initStatement), preConditionExpression(preConditionExpression), postConditionExpression(postConditionExpression), bodyBlockStatement(bodyBlockStatement) { } + +shared_ptr StatementLoop::getInitStatement() { + return initStatement; +} + +shared_ptr StatementLoop::getPreConditionExpression() { + return preConditionExpression; +} + +shared_ptr StatementLoop::getPostConditionExpression() { + return postConditionExpression; +} + +shared_ptr StatementLoop::getBodyBlockStatement() { + return bodyBlockStatement; +} + +string StatementLoop::toString(int indent) { + string value; + for (int ind=0; indtoString(0), ", "; + if (preConditionExpression != nullptr) + value += preConditionExpression->toString(0) + ", "; + if (postConditionExpression != nullptr) + value += postConditionExpression->toString(0); + value += "):\n"; + value += bodyBlockStatement->toString(indent+1); + return value; +} \ No newline at end of file diff --git a/src/Parser/Statement/StatementLoop.h b/src/Parser/Statement/StatementLoop.h new file mode 100644 index 0000000..00cd47d --- /dev/null +++ b/src/Parser/Statement/StatementLoop.h @@ -0,0 +1,20 @@ +#include "Statement.h" + +class Expression; +class StatementBlock; + +class StatementLoop: public Statement { +private: + shared_ptr initStatement; + shared_ptr preConditionExpression; + shared_ptr postConditionExpression; + shared_ptr bodyBlockStatement; + +public: + StatementLoop(shared_ptr initStatement, shared_ptr preConditionExpression, shared_ptr postConditionExpression, shared_ptr bodyBlockStatement); + shared_ptr getInitStatement(); + shared_ptr getPreConditionExpression(); + shared_ptr getPostConditionExpression(); + shared_ptr getBodyBlockStatement(); + string toString(int indent) override; +}; \ No newline at end of file