[antlr-interest] A rule can be mutually left-recursive with itself?
Gavin Lambert
antlr at mirality.co.nz
Fri Sep 28 16:00:06 PDT 2007
At 09:06 29/09/2007, Jeremy Sheldon wrote:
>[14:00:29] Aborting because the following rules are mutually
>left-recursive:
> [table_reference]
> [non_join_query_term]
[...]
>This leads me to believe that table_reference and
>non_join_query_term are not mutually left-recursive
>with each other. Would this assumption be correct?
Kind of. They're not recursive with each other, but they are
recursive with themselves.
>Here are the rules themselves:
>
>table_reference
> : table_name correlation_specification?
> | derived_table correlation_specification
> | (table_reference CROSS JOIN table_reference
> | table_reference NATURAL? join_type? JOIN table_reference
>join_specification?
> | LEFT_PAREN joined_table RIGHT_PAREN);
See, in table_reference you've got two alternatives that start
with table_reference itself. You can't do that in LL(*), since it
leads to an infinite loop. (It's ok to refer to the same rule
away from the left edge, because it will consume some tokens each
time and will eventually exit. But on the left edge it can keep
recursing in infinitely since it doesn't consume anything
beforehand.)
(I'm also not sure why you've grouped the last three alts together
as a single bigger alt of the main rule body. That won't have any
effect as far as I can tell. And I don't know what
join_specification contains, but by putting it after the
table_reference like that it can end up pretty far away from the
JOIN keyword that it's actually applying to. Are you sure that's
where it's supposed to go?)
You'll need to resolve this by creating another rule that contains
only a subset of the alternatives, avoiding the recursion, or
rearrange the rule structure so that you can put a * loop in a
strategic place. Or both :) For example, this ought to work in
this case (although it will alter the meaning subtly, so test it):
table_reference
: table_ref_atom (NATURAL? join_type? JOIN table_ref_atom
join_specification?)*
;
table_ref_atom
: table_name correlation_specification?
| derived_table correlation_specification
| LEFT_PAREN joined_table RIGHT_PAREN
;
(Assuming you add CROSS to join_type. And shouldn't NATURAL be
part of join_type too?)
Alternatively, if you don't want to change the behaviour of the
CROSS JOIN matching, then this ought to work too:
table_reference
: table_ref_atom
( CROSS JOIN table_reference
| NATURAL? join_type? JOIN table_reference
join_specification?
)?
;
table_ref_atom
: table_name correlation_specification?
| derived_table correlation_specification
| LEFT_PAREN joined_table RIGHT_PAREN
;
Note that this uses right-recursion, which is ok.
More information about the antlr-interest
mailing list