/* * Monicelli: an esoteric language compiler * * Copyright (C) 2014 Stefano Sanfilippo * * 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 . */ %code top { #include "Nodes.hpp" using namespace monicelli; } %skeleton "lalr1.cc" %require "3.0" %language "c++" %defines %locations %token-table %define parse.error verbose %define api.namespace {monicelli} %define parser_class_name {Parser} %lex-param {Scanner &scanner} %parse-param {Scanner &scanner} %parse-param {Program &program} %code requires { #include "Nodes.hpp" namespace monicelli { class Scanner; } } %code { static int yylex(Parser::semantic_type*, Parser::location_type*, Scanner&); } %token MAIN ERROR %token RETURN %token ARTICLE TYPENAME STAR %token VARDECL ASSIGN %token PRINT INPUT %token ASSERT BANG %token LOOP_BEGIN LOOP_CONDITION %token BRANCH_CONDITION BRANCH_BEGIN BRANCH_ELSE BRANCH_END CASE_END %token COLON COMMA %token FUN_DECL PARAMS FUN_CALL FUN_END %token ABORT %token ID NUMBER FLOAT %left OP_LT OP_GT OP_LTE OP_GTE %left OP_PLUS OP_MINUS %left OP_TIMES OP_DIV %left OP_SHL OP_SHR %nonassoc LOWER_THAN_ELSE %nonassoc BRANCH_ELSE %union { int intval; double floatval; std::string* strval; bool boolval; Type typeval; Statement* statementval; PointerList* statlistval; Assert* assertval; FunctionCall* callval; Print* printval; Input* inputval; Abort* abortval; Branch* branchval; Branch::Body* branchbodyval; VarDeclaration* declval; Assignment* assignval; Loop* loopval; BranchCase *caseval; PointerList *caselistval; Return* returnval; Expression* expressionval; PointerList* exprlistval; SemiExpression *semiexpval; Id* idval; Number* numericval; Function* funval; FunctionPrototype* protoval; FunArg *argval; PointerList *arglistval; } %type NUMBER %type FLOAT %type ID %type TYPENAME fun_return %type statement %type statements %type branch_body %type assert_stmt %type fun_call %type arg_decl %type args_decl args %type fun_decl main %type fun_proto %type print_stmt %type input_stmt %type abort_stmt %type branch_stmt %type case_stmt %type cases %type var_decl %type assign_stmt %type loop_stmt %type return_stmt %type expression maybe_expression simple_expression expression_inner %type var_init %type call_arglist call_args %type semi_expression semi_expression_inner %type variable %type numeric %type pointer %start program %% program: /* epsilon */ | fun_decls main fun_decls { program.setMain($2); } ; fun_decls: /* epsilon */ | fun_decl { program.addFunction($1); } fun_decls ; fun_decl: fun_proto statements { $$ = new Function($1, $2); } ; fun_proto: FUN_DECL fun_return ID args FUN_END { $$ = new FunctionPrototype(new Id($3), $2, $4); } ; fun_return: /* epsilon */ { $$ = Type::VOID; } | TYPENAME { $$ = $1; } ; args: /* epsilon */ { $$ = new PointerList(); } | PARAMS args_decl { $$ = $2; } ; args_decl: arg_decl { $$ = new PointerList(); $$->push_back($1); } | args_decl COMMA arg_decl { $1->push_back($3); } ; arg_decl: variable pointer TYPENAME { $$ = new FunArg($1, $3, $2); } ; main: MAIN statements { $$ = makeMain($2); } ; statements: /* epsilon */ { $$ = new PointerList(); } | statements statement { if ($2 != nullptr) { $2->setLocation(@2); $1->push_back($2); } $$ = $1; } ; statement: assert_stmt { $$ = $1; } | fun_call { $$ = $1; } | print_stmt { $$ = $1; } | input_stmt { $$ = $1; } | abort_stmt { $$ = $1; } | branch_stmt { $$ = $1; } | var_decl { $$ = $1; } | assign_stmt { $$ = $1; } | loop_stmt { $$ = $1; } | return_stmt { $$ = $1; } | COMMA { $$ = nullptr; } ; var_decl: VARDECL variable COMMA pointer TYPENAME var_init { $$ = new VarDeclaration($2, $5, $4, $6); } ; pointer: /* epsilon */ { $$ = false; } | STAR { $$ = true; } ; var_init: /* epsilon */ { $$ = nullptr; } | ASSIGN expression { $$ = $2; } ; numeric: NUMBER { $$ = new Integer($1); } | FLOAT { $$ = new Float($1); } ; variable: ID { $$ = new Id($1); } | ARTICLE ID { $$ = new Id($2); } ; assign_stmt: variable ASSIGN expression { $$ = new Assignment($1, $3); } ; print_stmt: expression PRINT { $$ = new Print($1); program.addModule(new Module("iostream", Module::SYSTEM)); } ; input_stmt: INPUT variable { $$ = new Input($2); program.addModule(new Module("iostream", Module::SYSTEM)); } ; return_stmt: RETURN maybe_expression BANG { $$ = new Return($2); } ; maybe_expression: expression { $$ = $1; } | /* epsilon */ { $$ = nullptr; } ; loop_stmt: LOOP_BEGIN statements LOOP_CONDITION expression { $$ = new Loop($2, $4); } ; branch_stmt: BRANCH_CONDITION variable BRANCH_BEGIN branch_body BRANCH_END { $2->setLocation(@2); $$ = new Branch($2, $4); } ; branch_body: cases %prec LOWER_THAN_ELSE { $$ = new Branch::Body($1); } | cases BRANCH_ELSE COLON statements { $$ = new Branch::Body($1, $4); } ; cases: case_stmt { $$ = new PointerList(); $$->push_back($1); } | cases CASE_END case_stmt { $1->push_back($3); $$ = $1; } ; case_stmt: semi_expression COLON statements { $$ = new BranchCase($1, $3); } ; fun_call: FUN_CALL ID call_args FUN_END { $$ = new FunctionCall(new Id($2), $3); } ; call_args: /* epsilon */ { $$ = new PointerList(); } | PARAMS call_arglist { $$ = $2; } ; call_arglist: expression { $$ = new PointerList(); $$->push_back($1); } | call_arglist COMMA expression { $$->push_back($3); } ; abort_stmt: ABORT { $$ = new Abort(); program.addModule(new Module("cstdlib", Module::SYSTEM)); } ; assert_stmt: ASSERT expression BANG { $$ = new Assert($2); program.addModule(new Module("cassert", Module::SYSTEM)); } ; expression: expression_inner { $1->setLocation(@1); $$ = $1; } ; expression_inner: simple_expression { $$ = $1; } | expression OP_LT expression { $$ = new ExpLt($1, $3); } | expression OP_GT expression { $$ = new ExpGt($1, $3); } | expression OP_LTE expression { $$ = new ExpLte($1, $3); } | expression OP_GTE expression { $$ = new ExpGte($1, $3); } | expression OP_PLUS expression { $$ = new ExpPlus($1, $3); } | expression OP_MINUS expression { $$ = new ExpMinus($1, $3); } | expression OP_TIMES expression { $$ = new ExpTimes($1, $3); } | expression OP_DIV expression { $$ = new ExpDiv($1, $3); } | expression OP_SHL expression { $$ = new ExpShl($1, $3); } | expression OP_SHR expression { $$ = new ExpShr($1, $3); } ; semi_expression: semi_expression_inner { $1->setLocation(@1); $$ = $1; } ; semi_expression_inner: expression { $$ = new SemiExpEq($1); } | OP_LT expression { $$ = new SemiExpLt($2); } | OP_GT expression { $$ = new SemiExpGt($2); } | OP_LTE expression { $$ = new SemiExpLte($2); } | OP_GTE expression { $$ = new SemiExpGte($2); } | OP_PLUS expression { $$ = new SemiExpPlus($2); } | OP_MINUS expression { $$ = new SemiExpMinus($2); } | OP_TIMES expression { $$ = new SemiExpTimes($2); } | OP_DIV expression { $$ = new SemiExpDiv($2); } | OP_SHL expression { $$ = new SemiExpShl($2); } | OP_SHR expression { $$ = new SemiExpShr($2); } ; simple_expression: fun_call { $$ = $1; } | numeric { $$ = $1; } | variable { $$ = $1; } ; %% #include "Scanner.hpp" void Parser::error(const location_type& loc, const std::string &message) { std::cerr << "line " << loc.begin.line << ", col " << loc.begin.column; std::cerr << ": " << message << std::endl; std::exit(1); } int yylex(Parser::semantic_type *lval, Parser::location_type *loc, Scanner &scanner) { return scanner.yylex(lval, loc); }