在@init之前调用的ANTLR4语义谓词

在@init之前调用的ANTLR4语义谓词,antlr4,Antlr4,我有一个子规则中带有语义谓词的语法,它需要在调用规则中进行初始化,以便正确执行,例如 decl_specifier_seq @init { //some initialization required by a semantic predicate } : decl_specifier+ ; decl_specifier : storage_class_specifier //auto, register, static, extern, mutable | {/

我有一个子规则中带有语义谓词的语法,它需要在调用规则中进行初始化,以便正确执行,例如

decl_specifier_seq
 @init {
   //some initialization required by a semantic predicate
 }
: decl_specifier+ ;

decl_specifier
:
      storage_class_specifier //auto, register, static, extern, mutable
    | {/*semantic predicate requiring the initialization*/}? type_specifier 
    | function_specifier //inline, virtual, explicit
;
但是一些测试表明语义谓词抛出NullPointerException,因为它是在调用规则的@init{}块中的初始化之前调用的

检查生成的解析器代码后,我发现还有另一个函数包含我的语义谓词:

private boolean decl_specifier_sempred(Decl_specifierContext _localctx, int predIndex) 
这个函数似乎是在调用@init{}块进行初始化之前调用的。这是一个bug还是设计的东西?异常包含上述函数的名称:

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:249)
        at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:211)
        at org.antlr.v4.runtime.misc.TestRig.main(TestRig.java:143)
Caused by: java.lang.NullPointerException
        at cppParser.CPPProcessorParser.decl_specifier_sempred(CPPProcessorParse
r.java:10989)
        at cppParser.CPPProcessorParser.sempred(CPPProcessorParser.java:10853)
        at org.antlr.v4.runtime.atn.SemanticContext$Predicate.eval(SemanticConte
xt.java:119)
        at org.antlr.v4.runtime.atn.ParserATNSimulator.evalSemanticContext(Parse
rATNSimulator.java:1295)
        at org.antlr.v4.runtime.atn.ParserATNSimulator.execATN(ParserATNSimulato
r.java:539)
        at org.antlr.v4.runtime.atn.ParserATNSimulator.adaptivePredict(ParserATN
Simulator.java:415)
        at cppParser.CPPProcessorParser.cppCompilationUnit(CPPProcessorParser.ja
va:330)
        ... 7 more

在调用@init{}块之前遇到异常。

ANTLR 4根据谓词是否“上下文敏感”来确定谓词的行为。上下文相关谓词使用$syntax引用当前规则中定义的参数、标签、本地或规则/令牌。在您的例子中,似乎是在标准ANTLR语法之外定义和初始化状态信息,因此无法知道谓词是上下文敏感的。解决这个问题有两种方法:

  • 定义一个或多个状态变量,这些变量在规则的
    locals
    块的谓词中使用,而不是在@members块中使用
  • 在谓词中的注释内添加对
    $ctx
    的引用。例如,您可以在谓词末尾添加
    /*$ctx*/

  • 如果遇到上下文敏感谓词,但没有可用的上下文信息(代码就是这样),则假定该谓词为true

    为了安全起见,您可以尝试一种惰性初始化方法。在没有看到语法的情况下,无法判断解析器是否正在探索在预期初始化发生之前到达子规则的替代可行路径。实际上,我在语义谓词的第一个版本中使用了$ctx。然而,事实证明,这一预测是错误的。看起来像“type_说明符”但语义谓词不允许的标记仍然被错误地认为是type_说明符(并导致解析失败)。也许我应该作为一个单独的问题提供一个关于这个问题的具体例子。似乎这两个建议对我的案例都不起作用