простой синтаксический анализатор выражения критериев с помощью antlr3

Я хочу создать простой парсер выражения критериев с помощью antlr3

Обновлено: отдельные правила выражения И ИЛИ для поддержки другой иерархии И / ИЛИ, но возникли другие проблемы: если выражение выглядит примерно так: a = 1 и b = 2 и c = 3 Дерево должно иметь вид следующие в соответствии с текущим агрегатом:

       =      =
 (a = 1)(b = 2)(c = 3)
But I want to generate it as follows:
          =       =
    (a = 1)(b = 2)
               (c = 3)
First "and" should be higher priority than another, because I want to parse all the expression as left exp and right exp.

Думаю, мне нужно переписать правило в «подсекунду», чтобы сделать a = 1 и b = 2 и c = 3 -> (a = 1 и b = 2) и c = 3

но безуспешно пытался много раз. Кто-нибудь знает, как этого добиться? Спасибо.


Моя цель - разобрать какой-то SQL-запрос в стиле предложения, и создать AST, чтобы пройти через него.

Например:

    a = 1 and (b = 2 or c = 3)            //This one can parse correctly.
    a = 1 and ((b = 2 or c = 3) or d = 4) //This one cannot parse correctly, missing last d = 4 in the tree. 
                                          //Tree is not correct.

Мой текущий файл грамматики не может проанализировать выше сложное условие. Поскольку я новичок в antlr, не уверен, как изменить мою грамматику, чтобы более правильно достичь вышеуказанного подхода. Может кто-нибудь помочь в этом? ! Любые предложения или комментарии приветствуются.

и моя грамматика (обновлено в соответствии с комментариями. Проблема с предупреждением устранена):

grammar CriteriaExpression;

options {
  output       = AST;
  ASTLabelType = CommonTree;
  language     = Java;
}

tokens {
  AND    = 'and';
  OR     = 'or';
  LPAREN = '(';
  RPAREN = ')';
}

@lexer::header {
package com.antlr;
}

@parser::header {
package com.antlr;
}

eval
:
expression
;

выражение: andExp (OR ^ andExp) *;

andExp: субсекунда (И ^ субсекунда) *;

подсекунда: LPAREN выражение RPAREN | atom;

atom
  :
  EXPR OPERATOR EXPR
  ;

OPERATOR
  :
  '='| '<>'| '!='| '<='| '!>'| '<'| '>='| '!<'| '>'| 'like'
  ;

EXPR
  :
  ('a'..'z'| 'A'..'Z'| '0'..'9')+
  ;

 WILDCARD
  :
  '%'
  ;

WS
  :
  ('\t'| ' '| '\r'| '\n'| '\u000C')*
   {$channel = HIDDEN;}
  ;

((a = 1)) ((a = 1))

a = 1 и ((b = 2 или c = 3) или d = 4) a = 1 и ((b  = 2 или c = 3) или d = 4)


person phyerbarte    schedule 20.02.2013    source источник
comment
показать входящий файл для вашего примера   -  person Aleksei Bulgak    schedule 20.02.2013
comment
Привет, @Aleksei Bulgak, какой у тебя входящий файл? Пример - это всего лишь возможная ценность, о которой я думаю. Реальная входная строка может быть намного сложнее и может быть смешанной. Спасибо.   -  person phyerbarte    schedule 20.02.2013
comment
вы даете эту ссылку в полном дереве. с деревом   -  person Aleksei Bulgak    schedule 20.02.2013
comment
@Aleksei Bulgak, неполное дерево создано antlrworks 1.4.3 с примером a = 1 и ((b = 2 или c = 3) или d = 4), я думаю, что в дереве отсутствует последняя часть d = 4 и не знаю, как это исправить.   -  person phyerbarte    schedule 20.02.2013
comment
Вместо того, чтобы полностью переписывать уже отвеченный вопрос, создайте новый. Или на ваш исходный вопрос нет ответа?   -  person Bart Kiers    schedule 22.02.2013
comment
Привет, @Bart Kiers, на исходный вопрос уже дан ответ, в настоящее время проблемы основаны на исходном вопросе. Я создам новый вопрос.   -  person phyerbarte    schedule 22.02.2013


Ответы (2)


Один недостаток в вашей грамматике - это правило

expression
  :
  LPAREN* subcond RPAREN* (( AND | OR )^ LPAREN* subcond RPAREN*)
  ;

Поскольку у вас может быть любое количество LPAREN или RPAREN, нет гарантии, что они совпадают. Я предлагаю использовать что-нибудь вроде

expression
  : subcond (( AND | OR ) subcond)?
  | subcond
  ;

и для subcond

subcond
  : atom (( AND | OR )^ atom)*
  | LPAREN expression RPAREN
  ;

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

Обновление: в обновленной грамматике вы снова используете LPAREN* и RPAREN*, которые не дадут вам правильно сбалансированных деревьев. Вам нужно смоделировать несколько пар, например ((a = 1)), с рекурсией, как я описал в моем примере выше. Это дало бы такое дерево

((a = 1))
  ^---^--- ATOM
 ^-----^-- Subcond -> Expression
^-------^- Subcond -> Expression

Итак, дерево будет таким:

Expression "((a = 1))"
^
Subcond "(a = 1)"
^
Expression "(a = 1)"
^
Subcond "a = 1"
^
ATOM "a = 1"
person tehlexx    schedule 20.02.2013
comment
Привет, @tehlexx, да, вы правы, мы не можем гарантировать количество LPAREN или RPAREN во входной строке. Но я думаю, что ключевой момент в том, что эта грамматика не может описать приоритет круглых скобок, не так ли? Может я ошибаюсь, я обновил свою грамматику, он может сгенерировать полное дерево со сложным примером: a = 1 и ((b = 2 или c = 3) или d = 4), но я не уверен, что приоритет в этом дереве правильно или нет. - person phyerbarte; 20.02.2013
comment
Как я понял ваш вопрос, должно быть совпадение *PAREN, поэтому, если есть 2 LPAREN, должно быть ровно 2 RPAREN. Вышеупомянутая грамматика также должна охватывать сценарий, в котором нет PAREN вообще, тогда он пойдет по прямому пути expression -> subcond -> ATOM, так что это также должно работать. Главное - моделировать круглые скобки с рекурсией, а не с PAREN*. - person tehlexx; 20.02.2013
comment
Привет, @tehlexx, я понял вашу точку зрения и обновил грамматику, я думаю, что сейчас подход должен быть правильным. Очень благодарны. Сгенерированное дерево с ((a = 1)) кажется более глубоким, чем описанное вами, соответствует ли мой подход вашему описанию сейчас? Не могли бы вы помочь подтвердить? Спасибо. - person phyerbarte; 20.02.2013
comment
Насколько я могу судить, деревья выглядят неплохо! Но вы также должны проверить дерево для a=1 OR b=2 AND c=3 и a=1 AND b=2 OR c=3. В обоих случаях узлы AND должны быть ниже узлов OR. Это важно, поскольку AND обычно предшествует OR. - person tehlexx; 20.02.2013
comment
Привет, @tehlexx, большое спасибо, я обновил грамматику в соответствии с вашим предложением. Теперь это поддержка И перед ИЛИ. Но возникла новая проблема, так как я хочу разобрать все выражение на две части: левое выражение и правое выражение, поэтому, если выражение выглядит примерно так: a = 1 и b = 2 и c = 3, тогда дерево будет иметь 3 прыжка, что будет проблемой при синтаксическом анализе дерева, возможно ли переписать правило, чтобы оно поддерживало a = 1 и b = 2 и c = 3 - ›(a = 1 и b = 2) и c = 3, даже больше ((a = 1 и b = 2) и c = 3) и d = 4? Может это невозможно .. все равно спасибо. - person phyerbarte; 22.02.2013
comment
Я думаю, что a=1 and b=2 and c=3 то же самое, что (a=1 and b=2) and c=3 или a=1 and(b=2 and c=3), поэтому не имеет значения, в каком порядке вы оцениваете дерево синтаксического анализа. Я не уверен, правильно ли я понимаю, что вы имеете в виду, поэтому, вероятно, поможет больше контекста. Может быть, уместно задать новый вопрос. - person tehlexx; 22.02.2013

Может быть, я ошибаюсь, но я думаю, что у вас проблема, связанная с этим LPAREN* something RPAREN*, вы можете написать что-то вроде этого ((что-то), а antlr думает, что это пишет, потому что LParent и Rparent не подключены друг к другу, поэтому можно использовать что-то вроде этого

COMPLEX:
    LPARENT (COMPLEX|subcond) RPARENT;

Но я скажу это еще раз, может я ошибаюсь

ОБНОВЛЕНИЕ

измените это:

subcond
  : 
  //atom (( AND | OR )^ atom)*
  LPAREN* atom RPAREN*
  ;

к этому:

subcond
  : 
  LPAREN (subcond|atom) RPAREN
  ;

используя это, теперь вы можете написать что-то вроде этого ((a=1))

person Aleksei Bulgak    schedule 20.02.2013
comment
Отлично !, ваш ответ открывает мне глаза. Что может устранить предупреждение. Но все же я считаю, что приоритет дерева для круглых скобок по-прежнему не правильный. - person phyerbarte; 20.02.2013
comment
После обновления дерево может быть сгенерировано полностью, но по-прежнему не может описывать приоритет круглых скобок. Это должно быть другой проблемой. - person phyerbarte; 20.02.2013
comment
Спасибо @Aleksei Bulgak, ваше обновление может соответствовать ((a = 1)), но грамматика кажется недостаточно гибкой. Проверьте мою обновленную грамматику, я думаю, что сейчас она правильная. - person phyerbarte; 20.02.2013