I'm having trouble solving a shift/reduce conflict.
I'm trying to write a while loop syntax:
while expression do code() end
The problem lies in the do keyword.
One of my expressions is a call expression that also accepts an optional do block for callbacks, e.g:
function_call() do print("callback") end
That in turns seems to cause the shift/reduce conflict in the while loop's do keyword.
So if i do:
while call() do stuff() end
It instead tries to match the do with the function call and messes up the entire parsing.
Ruby has a very similar syntax, but it seems to correctly favor the do keyword for the while loop rather than the expression. in Ruby you can put the callback in parenthesis if needed, which is ideally how I'd want to solve this too:
while (call() do stuff() end) do more_stuff() end
How do I get over this? I messed around a lot with operator precedence definitions but nothing seemed to work, how would you solve this? How did ruby manage to do it right?
Here's a complete grammar that reproduces the issue:
%token IDENT DO END WHILE
%%
program:
%empty
|
stmts
;
stmts:
stmt
|
stmts ';' stmt
|
stmts ';'
;
opt_stmts:
%empty
|
stmts
;
opt_semi:
%empty
|
';'
;
term:
';'
|
DO opt_semi
;
while_loop:
WHILE expr term opt_stmts END
|
WHILE term opt_stmts END
;
stmt:
expr
|
while_loop
;
expr:
IDENT
|
call
|
'(' expr ')'
;
do_block:
DO '|' args '|' opt_stmts END
|
DO opt_stmts END
;
call:
IDENT '(' args ')'
|
IDENT '(' args ')' do_block
|
IDENT do_block
;
args:
%empty
|
expr
|
args ',' expr
|
args ','
;
%%
Side note: I'm using Jison which is a bison clone for JavaScript as I'm writing a compiler for JavaScript, however that shouldn't be a problem as this is a general grammar issue and the above minimal snippet I wrote has been ran through original Bison as well.