/* ============================================================================= // // This file is part of the qlow compiler. // // Copyright (C) 2014-2015 Nicolas Winkler // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ===========================================================================*/ %{ #include #include #include #include #include "Ast.h" #include "ErrorReporting.h" using namespace qlow::ast; extern int qlow_parser_lex(); void yy_pop_state(void); int qlow_parser_error(const char* msg) { //throw msg; //printf("error happened: %s\n", msg); // throw msg; } std::unique_ptr>> parsedClasses; const char* qlow_parser_filename = ""; # define YYLLOC_DEFAULT(Cur, Rhs, N) \ do \ if (N) \ { \ (Cur).first_line = YYRHSLOC(Rhs, 1).first_line; \ (Cur).first_column = YYRHSLOC(Rhs, 1).first_column; \ (Cur).last_line = YYRHSLOC(Rhs, N).last_line; \ (Cur).last_column = YYRHSLOC(Rhs, N).last_column; \ (Cur).filename = YYRHSLOC(Rhs, 1).filename; \ } \ else \ { \ (Cur).first_line = (Cur).last_line = \ YYRHSLOC(Rhs, 0).last_line; \ (Cur).first_column = (Cur).last_column = \ YYRHSLOC(Rhs, 0).last_column; \ } \ while (0) %} %define api.prefix {qlow_parser_} %define parse.error verbose // %define parse.lac full %locations %code requires { #include "Ast.h" typedef qlow::CodePosition QLOW_PARSER_LTYPE; #define QLOW_PARSER_LTYPE_IS_DECLARED } %initial-action { @$.filename = qlow_parser_filename; }; //%define api.location.type {qlow::CodePosition} %union { std::vector>* topLevel; qlow::ast::Class* classDefinition; qlow::ast::Type* type; qlow::ast::ClassType* classType; qlow::ast::ArrayType* arrayType; qlow::ast::FeatureDeclaration* featureDeclaration; std::vector>* featureList; std::vector>* argumentList; std::vector>* statements; std::vector>* expressionList; qlow::ast::ArgumentDeclaration* argumentDeclaration; qlow::ast::DoEndBlock* doEndBlock; qlow::ast::IfElseBlock* ifElseBlock; qlow::ast::WhileBlock* whileBlock; qlow::ast::Statement* statement; qlow::ast::Expression* expression; qlow::ast::Operation::Operator op; qlow::ast::FieldDeclaration* fieldDeclaration; qlow::ast::MethodDefinition* methodDefinition; qlow::ast::FeatureCall* featureCall; qlow::ast::AssignmentStatement* assignmentStatement; qlow::ast::ReturnStatement* returnStatement; qlow::ast::LocalVariableStatement* localVariableStatement; qlow::ast::UnaryOperation* unaryOperation; qlow::ast::BinaryOperation* binaryOperation; qlow::ast::NewArrayExpression* newArrayExpression; const char* cString; std::string* string; int token; } %token IDENTIFIER %token INT_LITERAL %token TRUE FALSE %token CLASS DO END IF ELSE WHILE RETURN NEW EXTERN %token NEW_LINE %token SEMICOLON COLON COMMA DOT ASSIGN EQUALS NOT_EQUALS %token ROUND_LEFT ROUND_RIGHT SQUARE_LEFT SQUARE_RIGHT %token UNEXPECTED_SYMBOL %type topLevel %type classDefinition %type type %type featureDeclaration %type fieldDeclaration %type methodDefinition %type externMethodDeclaration %type featureList %type argumentList %type statements %type expressionList %type argumentDeclaration %type doEndBlock %type ifElseBlock %type whileBlock %type statement %type expression operationExpression paranthesesExpression %type operator %type featureCall %type assignmentStatement %type returnStatement %type localVariableStatement %type unaryOperation %type binaryOperation %type newArrayExpression %destructor { } %destructor { } %destructor { } // don't delete everything ;) %destructor { if ($$) delete $$; } <*> %left DOT %left ASTERISK SLASH %left PLUS MINUS %left EQUALS %left NOT %left AND %left OR XOR %start topLevel %% /* list of class definitions */ topLevel: /* empty */ { parsedClasses = std::make_unique>>(); } | topLevel classDefinition { parsedClasses->push_back(std::move(std::unique_ptr($2))); $2 = nullptr; } | topLevel methodDefinition { parsedClasses->push_back(std::move(std::unique_ptr($2))); $2 = nullptr; } | topLevel externMethodDeclaration { parsedClasses->push_back(std::move(std::unique_ptr($2))); $2 = nullptr; } | topLevel error methodDefinition { reportError(qlow::SyntaxError(@2)); yyerrok; parsedClasses->push_back(std::move(std::unique_ptr($3))); $3 = nullptr; } | topLevel error classDefinition { reportError(qlow::SyntaxError(@2)); yyerrok; parsedClasses->push_back(std::move(std::unique_ptr($3))); $3 = nullptr; }; classDefinition: CLASS IDENTIFIER featureList END { $$ = new Class(*$2, *$3, @$); delete $2; delete $3; $2 = 0; $3 = 0; } | CLASS error END { reportError(qlow::SyntaxError(@2)); yyerrok; $$ = nullptr; }; type: IDENTIFIER { $$ = new qlow::ast::ClassType(std::move(*$1), @$); delete $1; $1 = nullptr; } | SQUARE_LEFT type SQUARE_RIGHT { $$ = new qlow::ast::ArrayType(std::unique_ptr($2), @$); } | SQUARE_LEFT error SQUARE_RIGHT { reportError(qlow::SyntaxError("invalid type", @2)); }; featureList: /* empty */ { $$ = new std::vector>(); } | featureList featureDeclaration { $$ = $1; $$->push_back(std::move(std::unique_ptr($2))); $2 = nullptr; } | featureList error featureDeclaration { $$ = $1; yyerrok; reportError(qlow::SyntaxError(@2)); $$->push_back(std::move(std::unique_ptr($3))); $3 = nullptr; }; featureDeclaration: fieldDeclaration { $$ = $1; } | methodDefinition { $$ = $1; }; fieldDeclaration: IDENTIFIER COLON type { $$ = new FieldDeclaration(std::unique_ptr($3), std::move(*$1), @$); delete $1; $1 = nullptr; }; externMethodDeclaration: EXTERN IDENTIFIER COLON type { $$ = new MethodDefinition(std::unique_ptr($4), *$2, @$); delete $2; $2 = nullptr; } | EXTERN IDENTIFIER { $$ = new MethodDefinition(nullptr, *$2, @$); delete $2; $2 = nullptr; } | EXTERN IDENTIFIER ROUND_LEFT argumentList ROUND_RIGHT { $$ = new MethodDefinition(nullptr, *$2, std::move(*$4), @$); delete $2; delete $4; $2 = nullptr; $4 = nullptr; } | EXTERN IDENTIFIER ROUND_LEFT argumentList ROUND_RIGHT COLON type { $$ = new MethodDefinition(std::unique_ptr($7), *$2, std::move(*$4), @$); delete $2; delete $4; $2 = nullptr; $4 = nullptr; }; methodDefinition: IDENTIFIER COLON type doEndBlock { $$ = new MethodDefinition(std::unique_ptr($3), *$1, std::unique_ptr($4), @$); delete $1; $1 = nullptr; } | IDENTIFIER doEndBlock { $$ = new MethodDefinition(nullptr, *$1, std::move(std::unique_ptr($2)), @$); delete $1; $1 = nullptr; } | IDENTIFIER ROUND_LEFT argumentList ROUND_RIGHT COLON type doEndBlock { $$ = new MethodDefinition(std::unique_ptr($6), *$1, std::move(*$3), std::unique_ptr($7), @$); delete $1; delete $3; $1 = nullptr; $3 = nullptr; } | IDENTIFIER ROUND_LEFT argumentList ROUND_RIGHT doEndBlock { $$ = new MethodDefinition(nullptr, *$1, std::move(*$3), std::move(std::unique_ptr($5)), @$); delete $1; delete $3; $1 = nullptr; $3 = nullptr; }; argumentList: argumentDeclaration { $$ = new std::vector>(); $$->push_back(std::unique_ptr($1)); } | argumentList COMMA argumentDeclaration { $$ = $1; $$->push_back(std::unique_ptr($3)); }; argumentDeclaration: IDENTIFIER COLON type { $$ = new ArgumentDeclaration(std::unique_ptr($3), std::move(*$1), @$); delete $1; $1 = nullptr; $3 = nullptr; }; doEndBlock: DO statements END { $$ = new DoEndBlock(std::move(*$2), @$); delete $2; $2 = nullptr; }; ifElseBlock: IF expression doEndBlock { $$ = new IfElseBlock(std::unique_ptr($2), std::unique_ptr($3), std::make_unique(qlow::OwningList{}, @3), @$); $2 = nullptr; $3 = nullptr; } | IF expression DO statements ELSE statements END { $$ = new IfElseBlock(std::unique_ptr($2), std::make_unique(std::move(*$4), @4), std::make_unique(std::move(*$6), @6), @$); $2 = nullptr; delete $4; delete $6; }; whileBlock: WHILE expression doEndBlock { $$ = new WhileBlock(std::unique_ptr($2), std::unique_ptr($3), @$); $2 = nullptr; $3 = nullptr; }; statements: pnl { $$ = new std::vector>(); } | statements statement { $$ = $1; // statements can be null on errors if ($1 != nullptr) $$->push_back(std::unique_ptr($2)); }; /*! * hacky way to allow for multiple empty lines between statements */ pnl: /* empty */ { } | pnl NEW_LINE { } ; statement: featureCall statementEnd { $$ = $1; } | assignmentStatement statementEnd { $$ = $1; } | returnStatement statementEnd { $$ = $1; } | localVariableStatement statementEnd { $$ = $1; } | ifElseBlock statementEnd { $$ = $1; } | whileBlock statementEnd { $$ = $1; } | error statementEnd { $$ = nullptr; //printf("error happened here (%s): %d\n", qlow_parser_filename, @1.first_line); //throw qlow::SyntaxError(@1); reportError(qlow::SyntaxError(@1)); printf("unexpected token: %d\n", $1); } ; statementEnd: SEMICOLON pnl {} | NEW_LINE pnl {} ; featureCall: IDENTIFIER { $$ = new FeatureCall(nullptr, *$1, @$); delete $1; $1 = 0; } | IDENTIFIER ROUND_LEFT expressionList ROUND_RIGHT { $$ = new FeatureCall(nullptr, *$1, std::move(*$3), @$); delete $1; delete $3; $1 = 0; $3 = 0; } | expression DOT IDENTIFIER { $$ = new FeatureCall(std::unique_ptr($1), *$3, @$); delete $3; $3 = 0; } | expression DOT IDENTIFIER ROUND_LEFT expressionList ROUND_RIGHT { $$ = new FeatureCall(std::unique_ptr($1), *$3, std::move(*$5), @$); delete $3; $3 = 0; delete $5; $5 = 0; }; /* list of effective arguments */ expressionList: expression { $$ = new std::vector>(); $$->push_back(std::unique_ptr($1)); } | expressionList COMMA expression { $$ = $1; $$->push_back(std::unique_ptr($3)); }; expression: featureCall { $$ = $1; } | operationExpression { $$ = $1; } | paranthesesExpression { $$ = $1; } | newArrayExpression { $$ = $1; } | INT_LITERAL { $$ = new IntConst(std::move(*$1), @$); delete $1; };/* | error { $$ = nullptr; reportError(qlow::SyntaxError(@1)); //throw qlow::SyntaxError(@1); } ; */ operationExpression: binaryOperation { $$ = $1; } | unaryOperation { $$ = $1; }; binaryOperation: expression operator expression { $$ = new BinaryOperation(std::unique_ptr($1), std::unique_ptr($3), $2, @$); }; unaryOperation: expression operator { $$ = new UnaryOperation(std::unique_ptr($1), UnaryOperation::SUFFIX, $2, @$); } | operator expression { $$ = new UnaryOperation(std::unique_ptr($2), UnaryOperation::PREFIX, $1, @$); }; operator: PLUS { $$ = qlow::ast::Operation::Operator::PLUS; } | MINUS { $$ = qlow::ast::Operation::Operator::MINUS; } | ASTERISK { $$ = qlow::ast::Operation::Operator::ASTERISK; } | SLASH { $$ = qlow::ast::Operation::Operator::SLASH; } | EQUALS { $$ = qlow::ast::Operation::Operator::EQUALS; } | NOT_EQUALS { $$ = qlow::ast::Operation::Operator::NOT_EQUALS; } | AND { $$ = qlow::ast::Operation::Operator::AND; } | OR { $$ = qlow::ast::Operation::Operator::OR; } | XOR { $$ = qlow::ast::Operation::Operator::XOR; }; paranthesesExpression: ROUND_LEFT expression ROUND_RIGHT { $$ = $2; }; newArrayExpression: NEW SQUARE_LEFT type SEMICOLON expression SQUARE_RIGHT { }; assignmentStatement: expression ASSIGN expression { $$ = new AssignmentStatement(std::unique_ptr($1), std::unique_ptr($3), @$); }; returnStatement: RETURN expression { $$ = new ReturnStatement(std::unique_ptr($2), @$); }; localVariableStatement: IDENTIFIER COLON type { $$ = new LocalVariableStatement(std::move(*$1), std::unique_ptr($3), @$); delete $1; $3 = nullptr; $1 = nullptr; }; %%