0

我正在创建一个解析器,它创建一个 AST,然后重写它以解决所有歧义,然后遍历它并计算结果。

重写的一部分是将节点^(QUERY ID)转换为^(DECIMALQUERY ID)^(DATEQUERY ID)取决于ID表示的变量的类型。

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

即基于type值,QUERYtoken 转换为DECIMALQUERY,DATEQUERYSTRINGQUERY

问题是 ANTLR 拒绝为这个语法生成代码。命令是:

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

和错误:

.\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@[])

但是当我删除最后一个语义谓词时,一切正常:

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

但我不喜欢 typestring是“默认”分支的想法。如果三个谓词都不为真,我宁愿有一个例外(即一个新类型被添加到枚举中,但没有被添加到语法中;如果我删除最后一个谓词,它仍然会退回到字符串)。

所以,我的问题是:

如何明确指定这种基于类型的切换的所有情况?如果三个选项都没有满足,有没有办法强制例外?

完整的解析器和树转换器语法在这里:

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

4

1 回答 1

2

为了最大限度地支持正确的错误消息,您应该使用以下内容:

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

然后,您可以报告INVALIDQUERY出现在树中的案例,而不会导致解析器失败。

PS:[$QUERY]我添加的参数确保令牌行/列信息保留在重写的树中。

于 2013-08-23T17:03:36.340 回答