Improved loop parsing

This commit is contained in:
Rafał Grodziński
2025-07-01 13:45:40 +09:00
parent 993c204596
commit 505eb7eca7
3 changed files with 55 additions and 47 deletions

View File

@@ -9,19 +9,11 @@ This documents specifies what is the allowed syntax for statements and expressio
`+` 1 or more instances
`<TER>` Terminal token, usually new line <NL>, but it can also sometimes be `,`, `else`, or `;`
`<NL>` New line
`<ID>` Identifier
`<EXPR_BLOCK>` Expression block
`<STMT_BLOCK>` Statements block
`<EXPR>` Expression
`<STMT>` Statement
`<TYPE>` Type
### Overall structure
```
@@ -36,7 +28,7 @@ This documents specifies what is the allowed syntax for statements and expressio
+ <Statemnet Variable>
+ <Statement Assignment>
+ <Statement Return>
+ <Statement Loop>
+ <Statement Repeat>
|
+ <Statement Block>...
+ <Statement Expression>
@@ -77,47 +69,52 @@ sint32
```
### Statement Assignment
`<ID> <- <EXPR> <TER>`
`<ID> <- <Expression>`
```
num1 <- 5
```
### Statement Block
(<Statement> <NL>)*
`(<Statement> <NL>)*`
### Statement Repeat
`rep [<StatementVariable> | <StatementAssignment>]? : <Statement Block>`
### Statement Expression
<Expression> <NL>
`rep [<StatementVariable> | <StatementAssignment>]? : <NL> <Statement Block> ;`
### StatementLoop
`loop [<StatementVariable> | <StatementAssignment>] (, <NL>? <Expression> (, <NL>? <Expression>)?)? <NL> <StatementBlock> ;`
`rep [<StatementVariable> | <StatementAssignment>] (, <NL>? <Expression> (, <NL>? <Expression>)? )? : <StatementBlock>`
`rep [<StatementVariable> | <StatementAssignment>] (, <NL>? <Expression> (, <NL>? <Expression>)? )? : <NL> <StatementBlock> ;`
`rep (<Expression> (, <NL>? <Expression>)? )? : <StatementBlock>`
`rep (<Expression> (, <NL>? <Expression>)? )? : <NL> <StatementBlock> ;`
```
loop i sint32 <- 0, true, i < 10
rep i sint32 <- 0, true, i < 10:
doStuff(i)
;
loop i sint32 <- 0,
true, i < 10
rep i sint32 <- 0,
true, i < 10:
doStuff(i)
;
loop i sint32 <- 0,
rep i sint32 <- 0,
true,
i < 10
i < 10:
doStuff(i)
;
```
`loop (<ExpressionLogical> (, <NL>? <ExpressionLogical>)?)? <NL> <StatementBlock> ;`
rep: infiniteCall()
```
### Statement Return
`ret <Expression>? <NL>`
`ret <Expression>?`
### ExpressionVariable:
`<IDENT>`
### Expression Variable
`<ID>`
### Expression If Else:
### Expression If-Else:
`if <Expression> : <ExpressionBlock>`
```
if num1 > 10: putchar('T')
@@ -158,4 +155,4 @@ if num1 > 10: putchar('T') else
```
### Expression Block
`(<Statement> <NL>)* (<StatementExpression> <NL>?)? <TER>!`
`<Statement> <NL>)* <Statement Expression>?`

View File

@@ -274,48 +274,59 @@ shared_ptr<Statement> Parser::matchStatementLoop() {
shared_ptr<Statement> initStatement;
shared_ptr<Expression> preConditionExpression;
shared_ptr<Expression> postConditionExpression;
shared_ptr<Statement> bodyBlockStatement;
bool isMultiLine;
// initial
initStatement = matchStatementVariable();
initStatement = matchStatementVariable() ?: matchStatementAssignment();
if (initStatement != nullptr && !initStatement->isValid())
initStatement = nullptr;
if (tokens.at(currentIndex-1)->getKind() != TokenKind::NEW_LINE) {
if (!tryMatchingTokenKinds({TokenKind::COLON}, false, true)) {
// got initial, expect comma
if (initStatement != nullptr && !tryMatchingTokenKinds({TokenKind::COMMA}, true, true))
return matchStatementInvalid("Expected comma after initial statement");
// optional new line
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
// pre condition
preConditionExpression = nextExpression();
if (preConditionExpression != nullptr && !preConditionExpression->isValid())
return matchStatementInvalid("Expected pre-condition expression");
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) {
if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true)) {
// got pre-condition, expect comma
if (!tryMatchingTokenKinds({TokenKind::COMMA}, true, true))
return matchStatementInvalid("Expected comma after pre-condition statement");
// optional new line
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
// post condition
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");
// expect colon
if (!tryMatchingTokenKinds({TokenKind::COLON}, true, true))
return matchStatementInvalid("Expected \":\"");
}
}
isMultiLine = tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
// body
shared_ptr<Statement> bodyBlockStatement = matchStatementBlock({TokenKind::SEMICOLON});
if (bodyBlockStatement == nullptr)
return matchStatementInvalid("Expected block statement");
else if (!bodyBlockStatement->isValid())
return bodyBlockStatement;
if (isMultiLine)
bodyBlockStatement = matchStatementBlock({TokenKind::SEMICOLON});
else
bodyBlockStatement = matchStatementBlock({TokenKind::NEW_LINE});
if (bodyBlockStatement == nullptr || !bodyBlockStatement->isValid())
return bodyBlockStatement ?: matchStatementInvalid("Expected block statement");
// epxect new line
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true))
return matchStatementInvalid("Expected new line");
tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true);
return make_shared<StatementLoop>(initStatement, preConditionExpression, postConditionExpression, dynamic_pointer_cast<StatementBlock>(bodyBlockStatement));
}
@@ -563,7 +574,7 @@ shared_ptr<Expression> Parser::matchExpressionBlock(vector<TokenKind> terminalTo
vector<shared_ptr<Statement>> statements;
while (!tryMatchingTokenKinds(terminalTokenKinds, false, false)) {
shared_ptr<Statement> statement = nextStatement();
shared_ptr<Statement> statement = nextInBlockStatement();
if (statement == nullptr || !statement->isValid())
return matchExpressionInvalid("Expected statement");
statements.push_back(statement);

View File

@@ -1,6 +1,6 @@
dummy sint32 <- 55
stuff fun: num1 sint32, num2 sint32 -> sint32
num1 sint32 <- 42
num1 <- 5 * num1
ret num1
rep:
i <- i + 1
;
;