ANTLR: правило Lexer не совпадает - PullRequest
1 голос
/ 02 мая 2020

Я хочу сопоставить следующий текст: test.define_shared_constant (: testConst, "12", false)

С этой грамматикой она соответствует правильно:

grammar test;

statement: shared_constant_defioniton | method_call;
KEY: ':' ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'?'|'!'|'|'|'-'|'()')+;
expr: STRING;
STRING: '"' (~'"')* ('"' | NEWLINE) | '\'' (~'\'')* ('\'' | NEWLINE);
NEWLINE: '\r'? '\n' | '\r'; 
BOOLEAN: 'true' | 'false';
ID: ('a'..'z'|'A'..'Z'|'!') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'!'|'?')*;
WS : [ \t\n\r]+ -> channel(HIDDEN);
DEF_SHARED_CONSTANT: 'define_shared_constant';

shared_constant_defioniton
  : ID('.define_shared_constant' '(' KEY ',' expr ',' (BOOLEAN) ')')
;

method_call
  : ID '.' ID? '('expr*(',' expr)*')'
;

С этой грамматикой она не совпадает. Это соответствует method_call, который даже не корректен.

 shared_constant_defioniton
  : ID('.' DEF_SHARED_CONSTANT '(' KEY ',' expr ',' (BOOLEAN) ')')
;

Это интерпретирует define_shared_constant как ID. Поэтому я должен указать, что ID не должен содержать 'define_'. Но как я могу это сделать?

Ответы [ 2 ]

1 голос
/ 02 мая 2020
ID: ('a'..'z'|'A'..'Z'|'!') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'!'|'?')*;
WS : [ \t\n\r]+ -> channel(HIDDEN);
DEF_SHARED_CONSTANT: 'define_shared_constant';

Здесь и ID, и DEF_SHARED_CONSTANT могут соответствовать входу define_shared_constant. В таких случаях, когда несколько правил могут совпадать и приводить к совпадению одинаковой длины, правило, определенное первым, выигрывает. Так что defined_shared_constant распознается как токен ID, потому что сначала определяется ID.

Чтобы получить желаемое поведение, вы должны переместить определение DEF_SHARED_CONSTANT перед определением ID. Если для него вообще не определено именованное правило лексера и вместо этого используется 'define_shared_constant' непосредственно в правиле синтаксического анализатора, это также работает, поскольку неявно определенные правила лексера действуют так, как если бы они были определены в начале файла.

0 голосов
/ 03 мая 2020

Это работает в соответствии со спецификацией ANTLR. Но запускать его как плагин IntelliJ Language не удалось. Я использовал предикат, и окончательное решение выглядит так:

ID: { getText().indexOf("define") == 0}? ('a'..'z'|'A'..'Z'|'!') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'!'|'?')*;
...