|
@@ -0,0 +1,129 @@
|
|
|
|
|
+#include "Parser.hpp"
|
|
|
|
|
+
|
|
|
|
|
+Parser::Parser(Lexer lexer) : lexer(lexer), curToken(Token()), peekToken(Token())
|
|
|
|
|
+{
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+}
|
|
|
|
|
+bool Parser::checkToken(TokenType kind)
|
|
|
|
|
+{
|
|
|
|
|
+ return kind = (this->curToken).get_kind();
|
|
|
|
|
+}
|
|
|
|
|
+bool Parser::checkPeek(TokenType kind)
|
|
|
|
|
+{
|
|
|
|
|
+ return kind = (this->peekToken).get_kind();
|
|
|
|
|
+}
|
|
|
|
|
+void Parser::match(TokenType kind)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!checkToken(kind))
|
|
|
|
|
+ {
|
|
|
|
|
+ abort("Expected " + token_name(kind) + ", got " + token_name((this->curToken).get_kind()));
|
|
|
|
|
+ }
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Token Parser::nextToken()
|
|
|
|
|
+{
|
|
|
|
|
+ this->curToken = this->peekToken;
|
|
|
|
|
+ this->peekToken = (this->lexer).getToken();
|
|
|
|
|
+}
|
|
|
|
|
+void Parser::abort(std::string message)
|
|
|
|
|
+{
|
|
|
|
|
+ std::cout << "Error: " << message << std::endl;
|
|
|
|
|
+ exit(1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Parser::program()
|
|
|
|
|
+{
|
|
|
|
|
+ while (checkToken(TokenType::NEWLINE)){
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ }
|
|
|
|
|
+ while (!checkToken(TokenType::END_OF_FILE))
|
|
|
|
|
+ {
|
|
|
|
|
+ statement();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Parser::statement()
|
|
|
|
|
+{
|
|
|
|
|
+ // "PRINT" (expression | string)
|
|
|
|
|
+ if (checkToken(TokenType::PRINT))
|
|
|
|
|
+ {
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+
|
|
|
|
|
+ if (checkToken(TokenType::STRING))
|
|
|
|
|
+ {
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ expression();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // "IF" comparison "THEN" nl {statement} "ENDIF"
|
|
|
|
|
+ else if (checkToken(TokenType::IF))
|
|
|
|
|
+ {
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ comparison();
|
|
|
|
|
+ match(TokenType::THEN);
|
|
|
|
|
+ nl();
|
|
|
|
|
+ while (!checkToken(TokenType::ENDIF))
|
|
|
|
|
+ {
|
|
|
|
|
+ statement();
|
|
|
|
|
+ }
|
|
|
|
|
+ match(TokenType::ENDIF);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // "WHILE" comparison "REPEAT" nl {statement nl} "ENDWHILE"
|
|
|
|
|
+ else if (checkToken(TokenType::WHILE))
|
|
|
|
|
+ {
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ comparison();
|
|
|
|
|
+ match(TokenType::REPEAT);
|
|
|
|
|
+ nl();
|
|
|
|
|
+ while (!checkToken(TokenType::ENDWHILE))
|
|
|
|
|
+ {
|
|
|
|
|
+ statement();
|
|
|
|
|
+ }
|
|
|
|
|
+ match(TokenType::ENDWHILE);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // "LABEL" ident
|
|
|
|
|
+ else if (checkToken(TokenType::LABEL)){
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ ident();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // "GOTO" ident
|
|
|
|
|
+ else if (checkToken(TokenType::GOTO)){
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ ident();
|
|
|
|
|
+ }
|
|
|
|
|
+ // "LET" ident "=" expression
|
|
|
|
|
+ else if (checkToken(TokenType::LET)){
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ ident();
|
|
|
|
|
+ match(TokenType::EQ);
|
|
|
|
|
+ expression();
|
|
|
|
|
+ }
|
|
|
|
|
+ // "INPUT" ident
|
|
|
|
|
+ if (checkToken(TokenType::INPUT)){
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ ident();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ else{
|
|
|
|
|
+ abort("Invalid statement at "+ (this->curToken).get_text() + "(" + token_name((this->curToken).get_kind()) + ")");
|
|
|
|
|
+ }
|
|
|
|
|
+ nl();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Parser::nl()
|
|
|
|
|
+{
|
|
|
|
|
+ match(TokenType::NEWLINE);
|
|
|
|
|
+ while (checkToken(TokenType::NEWLINE))
|
|
|
|
|
+ {
|
|
|
|
|
+ nextToken();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|