ANTLR4 Semantic Predicate Called Before @init

2019-05-30 07:57发布

问题:

I have grammar with a semantic predicate in a subrule which requires initialization to be done in the invoking rule in order to execute properly e.g..

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
;

But some tests show that the semantic predicate throws NullPointerException because it is called before the initialization in the @init{} block of the invoking rule is ever called.

After checking the generated Parser code, I found that there is another function containing my semantic predicate:

private boolean decl_specifier_sempred(Decl_specifierContext _localctx, int predIndex) 

It seems that this function is called before my @init{} block is called to do the initialization. Is it a bug or something by design? The exception contains the name of the above function:

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

The exception is encountered before the @init{} block is called.

回答1:

ANTLR 4 determines the behavior of predicates based on whether or not they are "context sensitive". Context sensitive predicates use the $ syntax to reference a parameter, label, local, or rule/token defined in the current rule. It appears in your case you are defining and initializing state information outside of the standard ANTLR syntax, so it has no way to know the predicate is context sensitive. There are two ways to address this issue:

  1. Define one or more of your state variables which are used in the predicate in a locals block for the rule instead of in a @members block.
  2. Add a reference to $ctx inside of a comment in the predicates. For example, you could add /*$ctx*/ at the end of the predicate.

If a context sensitive predicate is encountered but no context information is available (as is the case for your code), the predicate is assumed to be true.



标签: antlr4