#include "Parser.h" Parser::Parser(vector> tokens): tokens(tokens) { } vector> Parser::getStatements() { vector> statements; while (!tryMatchingTokenKinds({TokenKind::END}, true, false)) { shared_ptr statement = nextStatement(); // Abort parsing if we got an error if (!statement->isValid()) { cerr << statement->toString(0); exit(1); } statements.push_back(statement); } return statements; } // // Statement // shared_ptr Parser::nextStatement() { shared_ptr statement; statement = matchStatementFunctionDeclaration(); if (statement != nullptr) return statement; statement = matchStatementVarDeclaration(); if (statement != nullptr) return statement; statement = matchStatementReturn(); if (statement != nullptr) return statement; statement = matchStatementExpression(); if (statement != nullptr) return statement; return matchStatementInvalid(); } shared_ptr Parser::matchStatementFunctionDeclaration() { if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::COLON, TokenKind::FUNCTION}, true, false)) return nullptr; shared_ptr identifierToken = tokens.at(currentIndex); currentIndex++; currentIndex++; // skip colon currentIndex++; // skip fun // Return type ValueType returnType = ValueType::VOID; if (tryMatchingTokenKinds({TokenKind::RIGHT_ARROW}, true, true)) { shared_ptr valueTypeToken = tokens.at(currentIndex); if (valueTypeToken->getLexme().compare("bool") == 0) returnType = ValueType::BOOL; else if (valueTypeToken->getLexme().compare("sint32") == 0) returnType = ValueType::SINT32; else if (valueTypeToken->getLexme().compare("real32") == 0) returnType = ValueType::REAL32; else return matchStatementInvalid("Expected return type"); currentIndex++; // type } currentIndex++; // new line shared_ptr statementBlock = matchStatementBlock({TokenKind::SEMICOLON}, true); if (statementBlock == nullptr) return matchStatementInvalid(); else if (!statementBlock->isValid()) return statementBlock; if(!tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true)) return matchStatementInvalid("Expected a new line after a function declaration"); return make_shared(identifierToken->getLexme(), returnType, dynamic_pointer_cast(statementBlock)); } shared_ptr Parser::matchStatementVarDeclaration() { if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::COLON, TokenKind::TYPE}, true, false)) return nullptr; shared_ptr identifierToken = tokens.at(currentIndex); currentIndex++; currentIndex++; // skip colon shared_ptr valueTypeToken = tokens.at(currentIndex); ValueType valueType; if (valueTypeToken->getLexme().compare("bool") == 0) valueType = ValueType::BOOL; else if (valueTypeToken->getLexme().compare("sint32") == 0) valueType = ValueType::SINT32; else if (valueTypeToken->getLexme().compare("real32") == 0) valueType = ValueType::REAL32; else return matchStatementInvalid("Invalid type"); currentIndex++; // type // Expect left arrow if (!tryMatchingTokenKinds({TokenKind::LEFT_ARROW}, true, true)) return matchStatementInvalid("Expected left arrow"); shared_ptr expression = nextExpression(); if (expression == nullptr || !expression->isValid()) return matchStatementInvalid(); // Expect new line if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, false, true)) return matchStatementInvalid("Expected a new line after variable declaration"); return make_shared(identifierToken->getLexme(), valueType, expression); } shared_ptr Parser::matchStatementBlock(vector terminalTokenKinds, bool shouldConsumeTerminal) { vector> statements; bool hasNewLineTerminal = find(terminalTokenKinds.begin(), terminalTokenKinds.end(), TokenKind::NEW_LINE) != terminalTokenKinds.end(); while (!tryMatchingTokenKinds(terminalTokenKinds, false, shouldConsumeTerminal)) { shared_ptr statement = nextStatement(); if (statement == nullptr) return matchStatementInvalid(); else if (!statement->isValid()) return statement; else statements.push_back(statement); if (hasNewLineTerminal && tokens.at(currentIndex-1)->getKind() == TokenKind::NEW_LINE) currentIndex--; } return make_shared(statements); } shared_ptr Parser::matchStatementReturn() { if (!tryMatchingTokenKinds({TokenKind::RETURN}, true, true)) return nullptr; shared_ptr expression = nextExpression(); if (expression != nullptr && !expression->isValid()) return matchStatementInvalid(); if (!tryMatchingTokenKinds({TokenKind::NEW_LINE, TokenKind::SEMICOLON}, false, false)) return matchStatementInvalid(); tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); return make_shared(expression); } shared_ptr Parser::matchStatementExpression() { shared_ptr expression = nextExpression(); if (expression == nullptr) return nullptr; else if (!expression->isValid()) return make_shared(tokens.at(currentIndex), expression->toString(0)); // Consume new line tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); return make_shared(expression); } shared_ptr Parser::matchStatementInvalid(string message) { return make_shared(tokens.at(currentIndex), message); } // // Expression // shared_ptr Parser::nextExpression() { shared_ptr expression; expression = matchEquality(); if (expression != nullptr) return expression; expression = matchExpressionIfElse(); if (expression != nullptr) return expression; expression = matchExpressionVar(); if (expression != nullptr) return expression; return nullptr; } shared_ptr Parser::matchEquality() { shared_ptr expression = matchComparison(); if (expression == nullptr || !expression->isValid()) return expression; while (tryMatchingTokenKinds({Token::tokensEquality}, false, false)) expression = matchExpressionBinary(expression); return expression; } shared_ptr Parser::matchComparison() { shared_ptr expression = matchTerm(); if (expression == nullptr || !expression->isValid()) return expression; while (tryMatchingTokenKinds({Token::tokensComparison}, false, false)) expression = matchExpressionBinary(expression); return expression; } shared_ptr Parser::matchTerm() { shared_ptr expression = matchFactor(); if (expression == nullptr || !expression->isValid()) return expression; while (tryMatchingTokenKinds({Token::tokensTerm}, false, false)) expression = matchExpressionBinary(expression); return expression; } shared_ptr Parser::matchFactor() { shared_ptr expression = matchPrimary(); if (expression == nullptr || !expression->isValid()) return expression; while (tokens.at(currentIndex)->isOfKind(Token::tokensFactor)) expression = matchExpressionBinary(expression); return expression; } shared_ptr Parser::matchPrimary() { shared_ptr expression; expression = matchExpressionLiteral(); if (expression != nullptr) return expression; expression = matchExpressionVar(); if (expression != nullptr) return expression; expression = matchExpressionGrouping(); if (expression != nullptr) return expression; return nullptr; } shared_ptr Parser::matchExpressionLiteral() { shared_ptr token = tokens.at(currentIndex); if (tryMatchingTokenKinds(Token::tokensLiteral, false, true)) return make_shared(token); return nullptr; } shared_ptr Parser::matchExpressionGrouping() { shared_ptr token = tokens.at(currentIndex); if (tryMatchingTokenKinds({TokenKind::LEFT_PAREN}, true, true)) { shared_ptr expression = matchTerm(); // has grouped expression failed? if (expression == nullptr) { return matchExpressionInvalid(); } else if(!expression->isValid()) { return expression; } else if (tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) { return make_shared(expression); } else { return matchExpressionInvalid(); } } return nullptr; } shared_ptr Parser::matchExpressionBinary(shared_ptr left) { shared_ptr token = tokens.at(currentIndex); shared_ptr right; // What level of binary expression are we having? if (tryMatchingTokenKinds(Token::tokensEquality, false, true)) { right = matchComparison(); } else if (tryMatchingTokenKinds(Token::tokensComparison, false, true)) { right = matchTerm(); } else if (tryMatchingTokenKinds(Token::tokensTerm, false, true)) { right = matchFactor(); } else if (tryMatchingTokenKinds(Token::tokensFactor, false, true)) { right = matchPrimary(); } if (right == nullptr) { return matchExpressionInvalid(); } else if (!right->isValid()) { return right; } else { return make_shared(token, left, right); } return nullptr; } shared_ptr Parser::matchExpressionIfElse() { // Try maching '?' shared_ptr token = tokens.at(currentIndex); if (!tryMatchingTokenKinds({TokenKind::QUESTION}, true, true)) return nullptr; // Then get condition shared_ptr condition = nextExpression(); if (condition == nullptr) return matchExpressionInvalid(); else if (!condition->isValid()) return condition; // Consume optional ':' tryMatchingTokenKinds({TokenKind::COLON}, true, true); // Consume optional new line tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // Match then block shared_ptr thenBlock = matchStatementBlock({TokenKind::COLON, TokenKind::SEMICOLON}, false); if (thenBlock == nullptr) return matchExpressionInvalid(); else if (!thenBlock->isValid()) return matchExpressionInvalid(); // FIXME // Match else block. Then and else block are separated by ':' shared_ptr elseBlock; if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) { bool isSingleLine = !tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); vector terminalTokens = {TokenKind::SEMICOLON}; if (isSingleLine) terminalTokens.push_back(TokenKind::NEW_LINE); elseBlock = matchStatementBlock(terminalTokens, false); if (elseBlock == nullptr) return matchExpressionInvalid(); else if (!elseBlock->isValid()) return matchExpressionInvalid(); // FIXME } tryMatchingTokenKinds({TokenKind::SEMICOLON}, true, true); return make_shared(condition, dynamic_pointer_cast(thenBlock), dynamic_pointer_cast(elseBlock)); } shared_ptr Parser::matchExpressionVar() { shared_ptr token = tokens.at(currentIndex); if (tryMatchingTokenKinds({TokenKind::IDENTIFIER}, true, true)) return make_shared(token->getLexme()); return nullptr; } shared_ptr Parser::matchExpressionInvalid() { return make_shared(tokens.at(currentIndex)); } bool Parser::tryMatchingTokenKinds(vector kinds, bool shouldMatchAll, bool shouldAdvance) { int requiredCount = shouldMatchAll ? kinds.size() : 1; if (currentIndex + requiredCount > tokens.size()) return false; if (shouldMatchAll) { for (int i=0; igetKind()) return false; } if (shouldAdvance) currentIndex += kinds.size(); return true; } else { for (int i=0; igetKind()) { if (shouldAdvance) currentIndex++; return true; } } return false; } }