I am using Bison (AFAIK they use LL(1) parsing as default).
My grammar says something like this:
function_decl: ID '(' params ')' ':' TYPE ... // body may go here
function_call: ID '(' arguments ')'
params: ID ':' TYPE
| params ',' ID ':' TYPE
| %empty
arguments: ID
| arguments ',' ID
| %empty
Now, bison warns saying a reduce/reduce conflict, because params and arguments both are null-able (in case of a zero-parameter function()).
My question is, how can I remove (instead of suppressing) this conflict ?
Although someone suggested to use different parsing technique, I want to make it clear for myself if it is possible (and I should do so) or I should just ignore it.
If you ignore the warning, you will end up with a parser which cannot recognise a function call without arguments. So that is probably not a good idea.
You are quite correct that the conflict is the result of both
paramsandargumentsproducing an empty string. Because the parser can only lookahead at one symbol a when it reads the)infunc(), it needs to decide whether to reduce an emptyparams(which will force it to proceed withfunction_decl) or an emptyarguments(which will commit it tofunction_call). But there is no way to know until the next token is read.The easiest solution is to avoid the empty reductions, although it makes the grammar slightly wordier. In the following, neither
paramsnorargumentsproduce the empty string, and extra productions forfunction_declandfunction_callare used to recognise these cases.This works because it lets the parser defer the decision between call and declaration. An LR parser can defer decisions until it has to reduce; it can keep several productions open at the same time, but it must reduce a production when it reaches its end.
Note that even without the conflict, your original grammar is incorrect. As written, it allows
arguments(orparams) to start with an arbitrary number of commas. Your intention was not to allow%emptyas an alternative base case, but rather as an alternative complete expansion. The correct grammar for an optional comma-separated list requires two non-terminals: