Семантический предикат ANTLR4, вызываемый перед @init

У меня есть грамматика с семантическим предикатом в подправиле, который требует инициализации в правиле вызова для правильного выполнения, например.

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{} правила вызова.

После проверки сгенерированного кода Parser я обнаружил, что есть другая функция, содержащая мой семантический предикат:

private boolean decl_specifier_sempred(Decl_specifierContext _localctx, int predIndex) 

Кажется, эта функция вызывается до того, как мой блок @init{} вызывается для инициализации. Это ошибка или что-то по дизайну? Исключение содержит имя вышеуказанной функции:

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{}.

1 ответ

Решение

ANTLR 4 определяет поведение предикатов на основе того, являются ли они "контекстно-зависимыми". Контекстно-зависимые предикаты используют синтаксис $ для ссылки на параметр, метку, локальный или правило / токен, определенные в текущем правиле. Похоже, что в вашем случае вы определяете и инициализируете информацию о состоянии вне стандартного синтаксиса ANTLR, поэтому нет способа узнать, что предикат является контекстно-зависимым. Есть два способа решения этой проблемы:

  1. Определите одну или несколько переменных состояния, которые используются в предикате в locals блок для правила, а не в блоке @members.
  2. Добавить ссылку на $ctx внутри комментария в предикатах. Например, вы можете добавить /*$ctx*/ в конце предиката.

Если контекстно-зависимый предикат встречается, но контекстная информация недоступна (как в случае с вашим кодом), предикат считается истинным.

Другие вопросы по тегам