[antlr-interest] Help with syntactic predicates vs. non-LL(*) decisions.

Robin Davies rerdavies at rogers.com
Thu Jun 7 07:24:51 PDT 2007


Before I resort to turning backtrackingon, I was wondering if someone could 
help me out with this point.

I'm dealing with the dreaded C# 2.generic vs. expression ambiguity. The core 
issue is that generic type arguments require non-LL() infinite lookahead 
predicate to correctly recognize expressions like the following:

    E(X<Y,Z   ...  <-- Is '<' start of a generic, or a binary operator??
    E(X<Y,Z>.Q())      It's a generic. X<Y,Z>
    E(X<Y,A)            It's an expression. X<Y
    E(X<Y,Z>A)       It's ambigious, so prefer "generic" interpretation, per 
the standard and issue an error.

The solution is supposed to be a fairly symple syntactic predicate that 
scans incoming tokens for a blanced matching '>'. (Published C# parsers 
pre-scan the incoming token stream looking for a closing '>'0.

Sure enough, as soon as I add the first rule for generics, ANTLR complains 
about non-LL(*) recursive expressions. (Quite correctly so).

I was under the impression that an ANTL semantic predicate would cure the 
issue. But maybe I'm missing a subtlety.

Here are the offending rules, with a semantic predicate applied:

    qualifiedname
        :    ID '::' type_or_generic
                    -> ^(EXTERNQNAME ID type_or_generic)
        | type_or_generic('.' type_or_generic)*
                    -> ^(QNAME type_or_generic*)
        ;
type_or_generic
    :     (ID '<' {TypeArgumentPredicateTest()}?) =>
            ID '<' typedeclaration (',' typedeclaration)* '>'
    |    ID
    ;

typedeclaration recurses into qualified name. And the fundamental problem: 
'<' is ambiguous with respect to
     expr '<' expr

(where expr recurses to qualifiedname)

With the syntactic predicate in place, I still get the non-LL(*) error. 
It's possible that I have other non-LL(*) issues. So an answer of "Yes that 
*should* work" would be really helpful.

The question:

Isn't the semantic predicate supposed to cure the non-LL(*) conflict? Or is 
there a deeper issue that I need to chase.

Possible answers: Yes it *should* work. Maybe there's another LL(*) problem. 
Close, but...  or <eyeroll>, no you're totally missing it, go read section 
12.2 again <grin>

Any help or insight appreciated.




More information about the antlr-interest mailing list