作为上下文依赖的ANTLR4语义谓词不起作用

时间:2014-05-10 11:54:08

标签: antlr4

我正在使用这个按比例缩小的语法解析类似C ++的声明(删除了许多细节以使其成为一个完全有效的示例)。它无法神秘地工作(至少对我而言)。它与上下文相关谓词的使用有关吗?如果是,实现“计算子节点逻辑数量”的正确方法是什么?

grammar CPPProcessor;

cppCompilationUnit : decl_specifier_seq? init_declarator* ';'  EOF;

init_declarator:     declarator initializer?;
declarator:  identifier;
initializer: '=0';

decl_specifier_seq
  locals [int cnt=0]
    @init {  $cnt=0;    }
: decl_specifier+ ;
decl_specifier :   @init {    System.out.println($decl_specifier_seq::cnt);  }
    'const'
  | {$decl_specifier_seq::cnt < 1}? type_specifier {$decl_specifier_seq::cnt += 1;}  ;
type_specifier:  identifier ; 
identifier:IDENTIFIER;
CRLF: '\r'? '\n' -> channel(2);
WS: [ \t\f]+    -> channel(1);
IDENTIFIER:[_a-zA-Z] [0-9_a-zA-Z]* ;

我需要实施标准C ++规则,type_specifier 下允许的decl_specifier_seq不超过1 type_specifier

decl_specifier_seq之前的语义谓词似乎是解决方案。并且计数自然在decl_specifier_seq中声明为局部变量,因为嵌套int t=0; 是可能的。

但似乎与我使用的上下文相关的语义谓词将产生不正确的解析,即引用$ attributes的语义谓词。首先是一个输入文件,结果正确(以说明普通的解析树是什么样的):

int t;

和解析树:

enter image description here

但是,没有'= 0'的输入有助于解析

0
1
line 1:4 no viable alternative at input 't'
1

enter image description here

$decl_specifier_cnt::cnt

解析失败,出现“无可行替代”错误(控制台中打印的数字是t值的调试打印,作为测试条件的验证)。即,语义谓词不能阻止type_specifier被解析为tinit_declarator不再被视为$decl_specifier_seq::cnt。这里有什么问题?是因为使用了$decl_specifier_seq::cnt的上下文相关谓词吗?

是否意味着上下文相关谓词不能用于实现“计算子节点数”的逻辑?

修改

我尝试了新版本,其谓词使用成员变量而不是.... @parser::members { public int cnt=0; } decl_specifier @init {System.out.println("cnt:"+cnt); } : 'const' | {cnt<1 }? type_specifier {cnt++;} ; ,而且令人惊讶的是语法现在可以证明Context Dependent谓词确实导致了先前的语法失败:

/*$ctx*/

产生了一个普通的解析树:

enter image description here

如果我们必须使用成员变量来替换局部变量以避免上下文敏感的谓词,那么这就产生了如何支持嵌套规则的问题?

一个奇怪的结果是,如果我在谓词后添加decl_specifier @init {System.out.println("cnt:"+cnt); } : 'const' | {cnt<1 /*$ctx*/ }? type_specifier {cnt++;} ; ,它会再次失败:

line 1:4 no viable alternative at input 't'

enter image description here

no viable alternative

使用/*$ctx*/解析失败。尽管实际逻辑仅使用成员变量,为什么$decl_specifier_seq::cnt会导致解析失败,就像使用/*$ctx*/时一样? 并且,如果没有{{1}},则会出现与@init块之前调用的谓词相关的另一个问题(described here

1 个答案:

答案 0 :(得分:1)

ANTLR 4在两种情况下评估语义谓词。

  1. 生成的代码在解析期间评估语义谓词,并抛出评估返回false的异常。在解析期间遍历的所有谓词都以这种方式进行评估,包括上下文相关的谓词和谓词,这些谓词和谓词不会出现在决策的左侧。
  2. 预测方法评估谓词,以便在解析期间做出正确的决定。在这种情况下,假定出现在被评估的决策的左边缘之外的任何地方的谓词返回true(即,它们被忽略)。此外,仅在上下文数据可用时才评估依赖于上下文的谓词。预测算法不会创建解析代码尚未提供的上下文结构。如果在预测期间遇到与上下文相关的谓词且没有可用的上下文,则假定谓词返回true(即,该决定忽略它)。
  3. 代码生成器不会评估目标语言的语义,因此当$ctx出现/*$ctx*/时,它无法知道{{1}}在语义上是不相关的。这两种情况都会导致谓词被视为依赖于上下文。