可以使用语义谓词来访问语法符号

时间:2018-01-31 11:04:22

标签: antlr4

antlr书中有以下示例代码,用于使用语义谓词来解决语法歧义:

// predicates/PredCppStat.g4
@parser::members {
  Set<String> types = new HashSet<String>() {{add("T");}};
  boolean istype() { return types.contains(getCurrentToken().getText());}
}
stat:   decl ';'  {System.out.println("decl "+$decl.text);}
    |   expr ';'  {System.out.println("expr "+$expr.text);}
    ;
decl:   ID ID
    |   {istype()}? ID '(' ID ')'
    ;
expr:   INT
    |   ID
    |   {!istype()}? ID '(' expr ')'
    ;
ID  :   [a-zA-Z]+ ;
INT :   [0-9]+ ;
WS  :   [ \t\n\r]+ -> skip ;

这里,谓词是规则中调用的第一个函数,用于确定是否应该触发规则。它使用getCurrentToken()来做出决定。

但是,如果我们稍微改变语法,使用分层名称而不是简单ID,如下所示:

decl:   ID ID
    |   {istype()}? hier_id '(' ID ')'
    ;
expr:   INT
    |   ID
    |   {!istype()}? hier_id '(' expr ')'
    ;
hier_id : ID ('.' ID)* ;

然后istype()谓词不能再使用getCurrentToken来做出决定。它需要hier_id中的整个标记链来确定链是否是类型符号。

这意味着,我们需要执行以下操作之一:

(1)将谓词放在hier_id之后,并从istype()访问这些值。这可能吗?我试过了,我在生成的代码上遇到了编译器错误。

(2)将语法分解为子规则,然后在消耗hier_id标记之后放置istype()。但这会破坏语法的可读性,我不想这样做。

解决此问题的最佳方法是什么?我使用的是antlr-4.6。

1 个答案:

答案 0 :(得分:0)

一种解决方案是使ID本身包含&#39;。&#39;,从而使hier_id成为词法分析器。在这种情况下,语义谓词对getCurrentToken()的调用将可以访问完整的名称链。

请注意,如果hier_id成为词法分析器,hier_id将包含ID。这需要付出代价。如果语法只有ID的其他引用(我猜它会有),那么你必须在所有这些情况下添加谓词以避免错误匹配。这会降低解析器的速度。

所以我猜这个问题,就其一般意义而言(即如果当前的知识信息不足以做出决定,如何通过修脚来限制规则)仍然需要Antlr4专家来回答。