Better parsing of if then else

This commit is contained in:
Rafał Grodziński
2025-06-13 11:13:13 +09:00
parent 37bcb5c2c7
commit 6b67154260
4 changed files with 32 additions and 33 deletions

View File

@@ -20,6 +20,10 @@ vector<shared_ptr<Token>> Lexer::getTokens() {
exit(1); exit(1);
} }
// Insert an additional new line just before end
if (token->getKind() == TokenKind::END && tokens.back()->getKind() != TokenKind::NEW_LINE)
tokens.push_back(make_shared<Token>(TokenKind::NEW_LINE, "\n", token->getLine(), token->getColumn()));
// filter out multiple new lines // filter out multiple new lines
if (tokens.empty() || token->getKind() != TokenKind::NEW_LINE || tokens.back()->getKind() != token->getKind()) if (tokens.empty() || token->getKind() != TokenKind::NEW_LINE || tokens.back()->getKind() != token->getKind())
tokens.push_back(token); tokens.push_back(token);

View File

@@ -45,7 +45,6 @@ shared_ptr<Statement> Parser::nextStatement() {
} }
shared_ptr<Statement> Parser::matchStatementFunctionDeclaration() { shared_ptr<Statement> Parser::matchStatementFunctionDeclaration() {
//if (!matchesTokenKinds({TokenKind::IDENTIFIER, TokenKind::COLON, TokenKind::FUNCTION}))
if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::COLON, TokenKind::FUNCTION}, true, false)) if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::COLON, TokenKind::FUNCTION}, true, false))
return nullptr; return nullptr;
@@ -59,12 +58,15 @@ shared_ptr<Statement> Parser::matchStatementFunctionDeclaration() {
currentIndex++; currentIndex++;
currentIndex++; // new line currentIndex++; // new line
shared_ptr<Statement> statementBlock = matchStatementBlock(); shared_ptr<Statement> statementBlock = matchStatementBlock({TokenKind::SEMICOLON}, true);
if (statementBlock == nullptr) if (statementBlock == nullptr)
return matchStatementInvalid(); return matchStatementInvalid();
else if (!statementBlock->isValid()) else if (!statementBlock->isValid())
return statementBlock; return statementBlock;
else
if(!tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true))
return matchStatementInvalid("Expected a new line after a function declaration");
return make_shared<StatementFunctionDeclaration>(identifierToken->getLexme(), ValueType::SINT32, dynamic_pointer_cast<StatementBlock>(statementBlock)); return make_shared<StatementFunctionDeclaration>(identifierToken->getLexme(), ValueType::SINT32, dynamic_pointer_cast<StatementBlock>(statementBlock));
} }
@@ -99,16 +101,17 @@ shared_ptr<Statement> Parser::matchStatementVarDeclaration() {
return matchStatementInvalid(); return matchStatementInvalid();
// Expect new line // Expect new line
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true))
return matchStatementInvalid("Expected a new line"); return matchStatementInvalid("Expected a new line after variable declaration");
return make_shared<StatementVarDeclaration>(identifierToken->getLexme(), valueType, expression); return make_shared<StatementVarDeclaration>(identifierToken->getLexme(), valueType, expression);
} }
shared_ptr<Statement> Parser::matchStatementBlock() { shared_ptr<Statement> Parser::matchStatementBlock(vector<TokenKind> terminalTokenKinds, bool shouldConsumeTerminal) {
vector<shared_ptr<Statement>> statements; vector<shared_ptr<Statement>> statements;
while (!tryMatchingTokenKinds({TokenKind::SEMICOLON, TokenKind::COLON}, false, false)) { bool hasNewLineTerminal = find(terminalTokenKinds.begin(), terminalTokenKinds.end(), TokenKind::NEW_LINE) != terminalTokenKinds.end();
while (!tryMatchingTokenKinds(terminalTokenKinds, false, shouldConsumeTerminal)) {
shared_ptr<Statement> statement = nextStatement(); shared_ptr<Statement> statement = nextStatement();
if (statement == nullptr) if (statement == nullptr)
return matchStatementInvalid(); return matchStatementInvalid();
@@ -116,15 +119,12 @@ shared_ptr<Statement> Parser::matchStatementBlock() {
return statement; return statement;
else else
statements.push_back(statement); statements.push_back(statement);
}
// consune ';' only
if (tryMatchingTokenKinds({TokenKind::SEMICOLON}, true, true)) {
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE, TokenKind::END}, false, false))
return matchStatementInvalid();
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); if (hasNewLineTerminal && tokens.at(currentIndex-1)->getKind() == TokenKind::NEW_LINE)
currentIndex--;
} }
return make_shared<StatementBlock>(statements); return make_shared<StatementBlock>(statements);
} }
@@ -302,7 +302,6 @@ shared_ptr<Expression> Parser::matchExpressionIfElse() {
// Try maching '?' // Try maching '?'
shared_ptr<Token> token = tokens.at(currentIndex); shared_ptr<Token> token = tokens.at(currentIndex);
//if (!tryAdvancingForOneOfTokenKinds({TokenKind::QUESTION}))
if (!tryMatchingTokenKinds({TokenKind::QUESTION}, true, true)) if (!tryMatchingTokenKinds({TokenKind::QUESTION}, true, true))
return nullptr; return nullptr;
@@ -313,37 +312,33 @@ shared_ptr<Expression> Parser::matchExpressionIfElse() {
else if (!condition->isValid()) else if (!condition->isValid())
return condition; return condition;
// Match ':', '\n', or ':\n' // Consume optional ':'
if (tryMatchingTokenKinds({TokenKind::COLON, TokenKind::NEW_LINE}, true, false)) tryMatchingTokenKinds({TokenKind::COLON}, true, true);
currentIndex += 2; // Consume optional new line
else if (tryMatchingTokenKinds({TokenKind::COLON, TokenKind::NEW_LINE}, false, false)) tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
currentIndex++;
else
return matchExpressionInvalid();
// Match then block // Match then block
shared_ptr<Statement> thenBlock = matchStatementBlock(); shared_ptr<Statement> thenBlock = matchStatementBlock({TokenKind::COLON, TokenKind::SEMICOLON}, false);
if (thenBlock == nullptr) if (thenBlock == nullptr)
return matchExpressionInvalid(); return matchExpressionInvalid();
else if (!thenBlock->isValid()) else if (!thenBlock->isValid())
return matchExpressionInvalid(); // FIXME return matchExpressionInvalid(); // FIXME
// Match else block // Match else block. Then and else block are separated by ':'
shared_ptr<Statement> elseBlock; shared_ptr<Statement> elseBlock;
if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) {
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); bool isSingleLine = !tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
vector<TokenKind> terminalTokens = {TokenKind::SEMICOLON};
if (isSingleLine)
terminalTokens.push_back(TokenKind::NEW_LINE);
elseBlock = matchStatementBlock(); elseBlock = matchStatementBlock(terminalTokens, false);
if (elseBlock == nullptr) if (elseBlock == nullptr)
return matchExpressionInvalid(); return matchExpressionInvalid();
else if (!elseBlock->isValid()) else if (!elseBlock->isValid())
return matchExpressionInvalid(); // FIXME return matchExpressionInvalid(); // FIXME
// hack to treat statement as an expression
if (tokens.at(currentIndex-1)->getKind() == TokenKind::NEW_LINE)
currentIndex--;
} }
tryMatchingTokenKinds({TokenKind::SEMICOLON}, true, true);
return make_shared<ExpressionIfElse>(condition, dynamic_pointer_cast<StatementBlock>(thenBlock), dynamic_pointer_cast<StatementBlock>(elseBlock)); return make_shared<ExpressionIfElse>(condition, dynamic_pointer_cast<StatementBlock>(thenBlock), dynamic_pointer_cast<StatementBlock>(elseBlock));
} }

View File

@@ -17,7 +17,7 @@ private:
shared_ptr<Statement> nextStatement(); shared_ptr<Statement> nextStatement();
shared_ptr<Statement> matchStatementFunctionDeclaration(); shared_ptr<Statement> matchStatementFunctionDeclaration();
shared_ptr<Statement> matchStatementVarDeclaration(); shared_ptr<Statement> matchStatementVarDeclaration();
shared_ptr<Statement> matchStatementBlock(); shared_ptr<Statement> matchStatementBlock(vector<TokenKind> terminalTokenKinds, bool shouldConsumeTerminal);
shared_ptr<Statement> matchStatementReturn(); shared_ptr<Statement> matchStatementReturn();
shared_ptr<Statement> matchStatementExpression(); shared_ptr<Statement> matchStatementExpression();
shared_ptr<StatementInvalid> matchStatementInvalid(string message = ""); shared_ptr<StatementInvalid> matchStatementInvalid(string message = "");

View File

@@ -177,7 +177,7 @@ Statement(StatementKind::INVALID), token(token), message(message) {
} }
string StatementInvalid::toString(int indent) { string StatementInvalid::toString(int indent) {
return "Error for token " + token->getLexme() + " at " + to_string(token->getLine()) + ":" + to_string(token->getColumn()) + ": " + message + "\n"; return "Error for token " + token->toString() + " at " + to_string(token->getLine()) + ":" + to_string(token->getColumn()) + ": " + message + "\n";
} }
string StatementInvalid::getMessage() { string StatementInvalid::getMessage() {