ANTLR - неявные и токены в дереве - PullRequest
4 голосов
/ 03 августа 2010

Я пытаюсь построить грамматику, которая интерпретирует введенный пользователем текст, стиль поисковой системы. Он будет поддерживать логические операторы AND, OR, NOT и ANDNOT. У меня почти все работает, но я хочу добавить правило, согласно которому два соседних ключевых слова вне строки в кавычках неявно обрабатываются как в предложении AND. Например:

сыр и крекеры = сыр и крекеры

(вверх и вниз) или (влево и вправо) = (вверх и вниз) ИЛИ (влево и вправо)

кошка-собака «брюшная свинья» = кошка-собака и «брюшная свинья»

У меня проблемы с последним, и я надеюсь, что кто-то может указать мне правильное направление. Вот мой файл * .g, и, пожалуйста, будьте добры, мой опыт работы с ANTLR занимает меньше рабочего дня:

grammar SearchEngine;

options { language = CSharp2; output = AST; }

@lexer::namespace { Demo.SearchEngine }
@parser::namespace { Demo.SearchEngine }

LPARENTHESIS : '(';
RPARENTHESIS : ')';

AND    : ('A'|'a')('N'|'n')('D'|'d');
OR     : ('O'|'o')('R'|'r');
ANDNOT : ('A'|'a')('N'|'n')('D'|'d')('N'|'n')('O'|'o')('T'|'t');
NOT    : ('N'|'n')('O'|'o')('T'|'t');

fragment CHARACTER : ('a'..'z'|'A'..'Z'|'0'..'9');
fragment QUOTE     : ('"');
fragment SPACE     : (' '|'\n'|'\r'|'\t'|'\u000C');

WS     : (SPACE) { $channel=HIDDEN; };
PHRASE : (QUOTE)(CHARACTER)+((SPACE)+(CHARACTER)+)+(QUOTE);
WORD   : (CHARACTER)+;

startExpression  : andExpression;
andExpression    : andnotExpression (AND^ andnotExpression)*;
andnotExpression : orExpression (ANDNOT^ orExpression)*;
orExpression     : notExpression (OR^ notExpression)*;
notExpression    : (NOT^)? atomicExpression;
atomicExpression : PHRASE | WORD | LPARENTHESIS! andExpression RPARENTHESIS!;

1 Ответ

6 голосов
/ 03 августа 2010

Поскольку ваше AND-правило имеет необязательное ключевое слово AND, вы должны создать воображаемый токен AND и использовать правило перезаписи, чтобы «внедрить» этот токен в ваше дерево. В этом случае вы не можете использовать сокращенный корневой оператор ^ ANTLR. Вам придется использовать оператор перезаписи ->.

Ваш andExpression должен выглядеть так:

andExpression
  :  (andnotExpression        -> andnotExpression)
     (AND? a=andnotExpression -> ^(AndNode $andExpression $a))* 
  ;

Подробное описание этой (возможно, загадочной) нотации дано в главе 7, раздел Правила переписывания в подправлениях , стр. 173-174 из Полная ссылка ANTLR от Terence Parr.

Я провел быстрый тест, чтобы проверить, выдает ли грамматика правильный AST с новым правилом andExpression. После анализа строки cat dog "potbelly and pig" and FOO сгенерированный синтаксический анализатор выдает следующий AST:

альтернативный текст http://img580.imageshack.us/img580/7370/andtree.png

Обратите внимание, что AndNode и Root являются воображаемыми токенами .

Если вы хотите узнать, как создать изображение AST выше, см. Эту ветку: Визуализация AST, созданного с помощью ANTLR (в среде .Net)

EDIT

При синтаксическом анализе one two three и (one two) three создается следующий AST:

альтернативный текст http://img203.imageshack.us/img203/2558/69551879.png

А при разборе (one two) OR three создается следующий AST:

альтернативный текст http://img340.imageshack.us/img340/8779/73390353.png

, что кажется правильным во всех случаях.

...