ANTLR (поле = значение), как это выразить? - PullRequest
1 голос
/ 24 июня 2009

Я новичок в лексере и парсере, поэтому наберитесь терпения. В конце концов я хочу иметь возможность выражать строки запросов в стиле LDAP, например, '(foo = bar)', '(! foo = bar)', '(& (foo = bar) (! zip = zap))' и в конце есть дерево, которое я мог бы использовать для создания фактического запроса к базе данных (или что угодно)

Поэтому я подумал начать с самой простой формы, чтобы разобрать выражения вроде (foo = bar) и (! Foo = bar), но у меня уже есть некоторые проблемы с пониманием. Я просто хочу выразить, что поля отделены от значения символом '=', но ANTLR, кажется, съедает все символы одновременно, потому что идентификатор очень похож на значение. Что я должен сделать, чтобы предотвратить это?

grammar FilterExpression;

options
{
    language=Java;
    k=2;
}

tokens
{
    NOT='!';
}

term    :   '(' NOT? FIELD '=' VALUE ')';
// lexer
FIELD   :   NAME;
VALUE   :   CDATA;

fragment NAME
    :   ALPHA+;
fragment CDATA
    :   ALPHA*;
fragment ALPHA
    :   ('a'..'z' | 'A'..'Z');

Ответы [ 2 ]

2 голосов
/ 30 июля 2009

Хорошо, вы здесь на правильном пути. Просто несколько вещей, которые вам нужно изменить. Вам нужно будет выразить имя поля и значение поля в синтаксическом анализаторе, а не в лексере, так как лексер не может определить разницу между этими двумя. Наличие нескольких выражений Lexer, в которых используется один и тот же фрагмент, очень трудно (невозможно!) Для Lexer определить, какое из них вы хотите. Перемещение определения этих двух (имя и значение) в синтаксический анализатор делает это очень легко. Чтобы сделать значение необязательным, просто сделайте этот термин синтаксического анализатора необязательным (с «?» За ним). Ниже приведено дерево разбора, созданное с измененной грамматикой (надеюсь, это то, что вам нужно). Я также вставил измененную грамматику в конец моего ответа для вас.
альтернативный текст http://img268.imageshack.us/img268/7374/graphw.png

grammar FilterExpression;

options
{
    language=Java;
    k=2;
}

tokens
{
    NOT='!';
}

term    :       '(' NOT? field '=' value? ')';
// lexer
field   :       ID;
value   :       ID;

ID  :   ALPHA+
    ;

fragment ALPHA
    :   ('a'..'z' | 'A'..'Z');
0 голосов
/ 26 июня 2009

Если поля и значения являются идентификаторами, где идентификатор - это непустая строка буквенных символов (допускающая пустое значение, как в вашем примере), вы можете сделать что-то вроде:

term    :       '(' NOT? field '=' value ')';

field : IDENTIFIER ;

value : IDENTIFIER? ;

// lexer
IDENTIFIER : ALPHA+ ;

fragment ALPHA
    :   ('a'..'z' | 'A'..'Z');

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

...