ANTLR: проблема с жадным правилом - PullRequest
2 голосов
/ 09 марта 2019

Я никогда не работал с ANTLR и порождающими грамматиками, так что это моя первая попытка.

У меня есть собственный язык, который мне нужно проанализировать.Вот пример:

-- This is a comment
CMD.CMD1:foo_bar_123
CMD.CMD2
CMD.CMD4:9 of 28 (full)
CMD.NOTES:
This is an note.
    A line 
      (1) there could be anything here foo_bar_123 & $ £ _ , . ==> BOOM
      (3) same here
CMD.END_NOTES:

Вкратце, может быть 4 типа строк:

1) -- comment
2) <section>.<command>
3) <section>.<command>: <arg>
4) <section>.<command>:
       <arg1>
       <arg2>
       ...
   <section>.<end_command>:

- это буквальное "CMD"

- это одно слово (заглавные, строчные буквы, цифры, '_')

это то же слово, что и , но перед ним стоит буквальный "конец _"

может быть любым символом

Вот что я сделал до сих пор:

grammar MyGrammar;

/*
* Parser Rules
*/

root                : line+ EOF ;

line                : (comment_line | command_line | normal_line) NEWLINE;

comment_line        : COMMENT ;

command_line        : section '.' command ((COLON WHITESPACE*)? arg)? ;

normal_line         : TEXT ;

section             : CMD ;

command             : WORD ;

arg                 : TEXT ;

/*
* Lexer Rules
*/

fragment LOWERCASE  : [a-z] ;
fragment UPPERCASE  : [A-Z] ;
fragment DIGIT      : [0-9] ;

NUMBER          : DIGIT+ ([.,] DIGIT+)? ;

CMD             : 'CMD';

COLON           : ':' ;

COMMENT         : '--' ~[\r\n]*;

WHITESPACE      : (' ' | '\t') ;

NEWLINE         : ('\r'? '\n' | '\r')+;

WORD            : (LOWERCASE | UPPERCASE | NUMBER | '_')+ ;

TEXT            : ~[\r\n]* ;

Это тест для моей грамматики:

$ antlr4 MyGrammar.g4

предупреждение (146): MyGrammar.g4: 45: 0: не фрагментПравило лексера TEXT может соответствовать пустой строке

$ javac MyGrammar * .java

$ grun Корень MyGrammar -tokens

CMD.NEW

[@ 0, 0: 6 = 'CMD.NEW', , 1: 0]

[@ 1,7: 7 = '\ n', , 1: 7]

[@ 2,8: 7 = '', , 2: 0]

Проблема в том, что «CMD.NEW» проглатывается TEXT, потому что это правиложадный.

Кто-нибудь может мне помочь с этим?Спасибо

1 Ответ

2 голосов
/ 11 марта 2019

Есть грамматическая двусмысленность.

В приведенном вами примере CMD.NEW может соответствовать как command_line, так и normal_line.
Таким образом, дано выражение:

 line                : (comment_line | command_line | normal_line) NEWLINE;

синтаксический анализатор не может точно сказать, какое правило принять (command_line или normal_line), поэтому он соответствует ему normal_line, который на самом деле является простым TEXT.

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

UPDATE:

Попробуйте это (я не проверял, но это должно работать):

grammar MyGrammar;

/*
* Parser Rules
*/

root                : line+ EOF ;

line                : (comment_line | command_line) NEWLINE;

comment_line        : COMMENT ;

command_line        : CMD '.' (note_cmd | command);

command             : command_name ((COLON WHITESPACE*)? arg)? ;

note_cmd            : notes .*? (CMD '.' END_NOTES) ;

command_name             : WORD ;

arg                 : TEXT ;

/*
* Lexer Rules
*/

fragment LOWERCASE  : [a-z] ;
fragment UPPERCASE  : [A-Z] ;
fragment DIGIT      : [0-9] ;

NUMBER          : DIGIT+ ([.,] DIGIT+)? ;

CMD             : 'CMD';

COLON           : ':' ;

COMMENT         : '--' ~[\r\n]*;

WHITESPACE      : (' ' | '\t') ;

NEWLINE         : ('\r'? '\n' | '\r')+;

WORD            : (LOWERCASE | UPPERCASE | NUMBER | '_')+ ;

NOTES            : 'NOTES';

END_NOTES        : 'END_NOTES';

TEXT            : ~[\r\n]* ;
...