/*
* 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;
StatementList* statlistval;
Assert* assertval;
FunctionCall* callval;
Print* printval;
Input* inputval;
Abort* abortval;
Branch* branchval;
Branch::Body* branchbodyval;
VarDeclaration* declval;
Assignment* assignval;
Loop* loopval;
BranchCase *caseval;
BranchCaseList *caselistval;
Return* returnval;
Expression* expressionval;
ExpressionList* exprlistval;
SemiExpression *semiexpval;
Id* idval;
Number* numericval;
Function* funval;
FunArg *argval;
FunArgList *arglistval;
Main* mainval;
}
%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
%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 var_init
%type call_arglist call_args
%type semi_expression
%type variable
%type numeric
%type main
%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_DECL fun_return ID args FUN_END statements {
$$ = new Function(new Id($3), $2, $4, $6);
}
;
fun_return:
/* epsilon */ { $$ = Type::VOID; } | TYPENAME { $$ = $1; }
;
args:
/* epsilon */ { $$ = new FunArgList(); }| PARAMS args_decl { $$ = $2; }
;
args_decl:
arg_decl {
$$ = new FunArgList();
$$->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 {
$$ = new Main($2);
}
;
statements:
/* epsilon */ {
$$ = new StatementList();
}
| statements statement {
if ($2 != nullptr) {
$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 {
$$ = 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 BranchCaseList();
$$->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 ExpressionList();
}
| PARAMS call_arglist {
$$ = $2;
}
;
call_arglist:
expression {
$$ = new ExpressionList();
$$->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:
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:
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);
}