Question

I am creating a parser that creates an AST, then rewrites it to resolve all the ambiguities and then walks it and computes the result.

One part of rewriting is transformation of nodes like ^(QUERY ID) into ^(DECIMALQUERY ID) or ^(DATEQUERY ID) depending on the type of the variable that ID represents.

query
    :   ^(QUERY ID)
    { 
        var type = GetQueryType($ID.text); 
    }
    -> { type == QueryType.Decimal }?   ^(DECIMALQUERY ID)
    -> { type == QueryType.Date }?      ^(DATEQUERY ID)
    -> { type == QueryType.String }?    ^(STRINGQUERY ID)
;

That is, based on type value, QUERY token is transformed into DECIMALQUERY, DATEQUERY or STRINGQUERY.

The problem is that ANTLR refuses to generate code for this grammar. The command is:

java -jar ..\..\binaries\antlr-3.4-complete.jar -message-format vs2005 .\TreeTransform.g

And the error:

.\TreeTransform.g(54,2) : error 100 : syntax error: antlr: MismatchedTokenException(52!=84)
.\TreeTransform.g(53,52) : error 100 : syntax error: assign.types: NoViableAltException(0@[])
org\antlr\grammar\v3\DefineGrammarItemsWalker.g: node from line 53:51 no viable alternative at input ')'
.\TreeTransform.g(53,52) : error 100 : syntax error: buildnfa: NoViableAltException(0@[])
.\TreeTransform.g(53,52) : error 100 : syntax error: codegen: NoViableAltException(0@[])
.\TreeTransform.g(53,52) : error 100 : syntax error: antlr.print: NoViableAltException(0@[])
.\TreeTransform.g(53,52) : error 100 : syntax error: antlr.print: NoViableAltException(0@[])

But when I remove the last semantic predicate, everything works:

query
    :   ^(QUERY ID)
    { 
        var type = GetQueryType($ID.text); 
    }
    -> { type == QueryType.Decimal }?   ^(DECIMALQUERY ID)
    -> { type == QueryType.Date }?      ^(DATEQUERY ID)
    ->                                  ^(STRINGQUERY ID)
;

But I don't like the idea that type string is the 'default' branch. I would rather have an exception if none of the three predicates yielded true (i.e. a new type was added to the enum, but not to the grammar; if I remove the last predicate, it will fall back to string all the same).

So, my question is:

How do I specify explicitly all the cases for such a type-based switching? Is there a way to force an exception if none of the three alternatives were met?

The complete parser and tree transformer grammars are here:

https://bitbucket.org/ik/public/src/8f91e683e79a084138d6b55beabf8d5e18d965d4/AntlrSemanticPredicatesProblem?at=default

Was it helpful?

Solution

For maximum support of sane error messages, you should use the following:

-> { type == QueryType.Decimal }?   ^(DECIMALQUERY[$QUERY] ID)
-> { type == QueryType.Date }?      ^(DATEQUERY[$QUERY] ID)
-> { type == QueryType.String }?    ^(STRINGQUERY[$QUERY] ID)
->                                  ^(INVALIDQUERY[$QUERY] ID)

You can then report cases where INVALIDQUERY appears in your tree without causing the parser to fail.

PS: The [$QUERY] argument I added ensures that the token line/column information is preserved in the rewritten tree.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top