Macro processor: fix the shift/reduce conflict related to ternary colon operator

The idea is to split the expression rule into smaller subrules, hierarchically
organized according to the operator precedence (Bison still does part of the
job of dealing with precedence).
issue#70
Sébastien Villemot 2019-08-13 18:15:49 +02:00
parent 7048a4ff32
commit 5960a9168c
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
1 changed files with 146 additions and 142 deletions

View File

@ -75,7 +75,10 @@ using namespace macro;
%left EQUAL_EQUAL NOT_EQUAL
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
%nonassoc IN
%left COLON
/* The COLON operator cannot be given a precedence, because it has both a
binary and a ternary forms. But technically it belongs here given how the
grammar rules are organized */
%token COLON
%left UNION
%left INTERSECTION
%left PLUS MINUS
@ -89,12 +92,12 @@ using namespace macro;
%type <DirectivePtr> statement
%type <DirectivePtr> directive directive_one_line directive_multiline for if ifdef ifndef text
%type <EvalPtr> eval
%type <ExpressionPtr> expr
%type <ExpressionPtr> primary_expr oper_expr colon_expr expr
%type <FunctionPtr> function
%type <VariablePtr> symbol
%type <vector<VariablePtr>> comma_name
%type <vector<ExpressionPtr>> comma_expr function_args tuple_comma_expr colon_expr
%type <vector<ExpressionPtr>> comma_expr function_args tuple_comma_expr
%%
@ -284,13 +287,7 @@ tuple_comma_expr : %empty
{ $1.emplace_back($3); $$ = $1; }
;
colon_expr : expr COLON expr
{ $$ = vector<ExpressionPtr>{$1, $3}; }
| colon_expr COLON expr
{ $1.emplace_back($3); $$ = $1; }
;
expr : LPAREN expr RPAREN
primary_expr : LPAREN expr RPAREN
{ $$ = $2; }
| symbol
{ $$ = $1; }
@ -304,15 +301,6 @@ expr : LPAREN expr RPAREN
{ $$ = make_shared<Real>($1, driver.env, @$); }
| QUOTED_STRING
{ $$ = make_shared<String>($1, driver.env, @$); }
| colon_expr
{
if ($1.size() == 2)
$$ = make_shared<Array>($1[0], $1[1], driver.env, @$);
else if ($1.size() == 3)
$$ = make_shared<Array>($1[0], $1[1], $1[2], driver.env, @$);
else
error(@$, "The colon operator only works with 2 or 3 arguments");
}
| LBRACKET comma_expr RBRACKET
{ $$ = make_shared<Array>($2, driver.env, @$); }
| symbol LBRACKET comma_expr RBRACKET
@ -325,22 +313,6 @@ expr : LPAREN expr RPAREN
{ $$ = make_shared<Comprehension>($2, $4, $6, driver.env, @$); }
| LBRACKET expr FOR expr IN expr WHEN expr RBRACKET
{ $$ = make_shared<Comprehension>($2, $4, $6, $8, driver.env, @$); }
| LPAREN BOOL RPAREN expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_bool, $4, driver.env, @$); }
| LPAREN REAL RPAREN expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_real, $4, driver.env, @$); }
| LPAREN STRING RPAREN expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_string, $4, driver.env, @$); }
| LPAREN TUPLE RPAREN expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_tuple, $4, driver.env, @$); }
| LPAREN ARRAY RPAREN expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_array, $4, driver.env, @$); }
| NOT expr
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::logical_not, $2, driver.env, @$); }
| MINUS expr %prec UNARY
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::unary_minus, $2, driver.env, @$); }
| PLUS expr %prec UNARY
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::unary_plus, $2, driver.env, @$); }
| LENGTH LPAREN expr RPAREN
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::length, $3, driver.env, @$); }
| ISEMPTY LPAREN expr RPAREN
@ -403,16 +375,62 @@ expr : LPAREN expr RPAREN
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::normpdf, $3, driver.env, @$); }
| NORMCDF LPAREN expr RPAREN
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::normcdf, $3, driver.env, @$); }
| expr PLUS expr
| MAX LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::max, $3, $5, driver.env, @$); }
| MIN LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::min, $3, $5, driver.env, @$); }
| MOD LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::mod, $3, $5, driver.env, @$); }
| NORMPDF LPAREN expr COMMA expr COMMA expr RPAREN
{ $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normpdf, $3, $5, $7, driver.env, @$); }
| NORMCDF LPAREN expr COMMA expr COMMA expr RPAREN
{ $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normcdf, $3, $5, $7, driver.env, @$); }
;
oper_expr : primary_expr
{ $$ = $1; }
| LPAREN BOOL RPAREN oper_expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_bool, $4, driver.env, @$); }
| LPAREN REAL RPAREN oper_expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_real, $4, driver.env, @$); }
| LPAREN STRING RPAREN oper_expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_string, $4, driver.env, @$); }
| LPAREN TUPLE RPAREN oper_expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_tuple, $4, driver.env, @$); }
| LPAREN ARRAY RPAREN oper_expr %prec CAST
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::cast_array, $4, driver.env, @$); }
| NOT oper_expr
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::logical_not, $2, driver.env, @$); }
| MINUS oper_expr %prec UNARY
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::unary_minus, $2, driver.env, @$); }
| PLUS oper_expr %prec UNARY
{ $$ = make_shared<UnaryOp>(codes::UnaryOp::unary_plus, $2, driver.env, @$); }
| oper_expr PLUS oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::plus, $1, $3, driver.env, @$); }
| expr MINUS expr
| oper_expr MINUS oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::minus, $1, $3, driver.env, @$); }
| expr TIMES expr
| oper_expr TIMES oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::times, $1, $3, driver.env, @$); }
| expr DIVIDE expr
| oper_expr DIVIDE oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::divide, $1, $3, driver.env, @$); }
| expr POWER expr
| oper_expr POWER oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::power, $1, $3, driver.env, @$); }
| oper_expr UNION oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::set_union, $1, $3, driver.env, @$); }
| oper_expr INTERSECTION oper_expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::set_intersection, $1, $3, driver.env, @$); }
;
colon_expr : oper_expr COLON oper_expr
{ $$ = make_shared<Array>($1, $3, driver.env, @$); }
| oper_expr COLON oper_expr COLON oper_expr
{ $$ = make_shared<Array>($1, $3, $5, driver.env, @$); }
;
expr : oper_expr
{ $$ = $1; }
| colon_expr
{ $$ = $1; }
| expr EQUAL_EQUAL expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::equal_equal, $1, $3, driver.env, @$); }
| expr NOT_EQUAL expr
@ -431,20 +449,6 @@ expr : LPAREN expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::logical_or, $1, $3, driver.env, @$); }
| expr IN expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::in, $1, $3, driver.env, @$); }
| expr UNION expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::set_union, $1, $3, driver.env, @$); }
| expr INTERSECTION expr
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::set_intersection, $1, $3, driver.env, @$); }
| MAX LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::max, $3, $5, driver.env, @$); }
| MIN LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::min, $3, $5, driver.env, @$); }
| MOD LPAREN expr COMMA expr RPAREN
{ $$ = make_shared<BinaryOp>(codes::BinaryOp::mod, $3, $5, driver.env, @$); }
| NORMPDF LPAREN expr COMMA expr COMMA expr RPAREN
{ $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normpdf, $3, $5, $7, driver.env, @$); }
| NORMCDF LPAREN expr COMMA expr COMMA expr RPAREN
{ $$ = make_shared<TrinaryOp>(codes::TrinaryOp::normcdf, $3, $5, $7, driver.env, @$); }
;
%%