Добавлена ​​поддержка строк в кавычках в грамматике Antlr3 - PullRequest
2 голосов
/ 22 января 2012

Я пытаюсь реализовать грамматику для разбора запросов. Один запрос состоит из items, где каждый элемент может быть либо name, либо name-ref.

name это либо mystring (только буквы, без пробелов), либо "my long string" (буквы и пробелы, всегда в кавычках). name-ref очень похож на name, и единственное отличие состоит в том, что он должен начинаться с ref: (ref:mystring, ref:"my long string"). Запрос должен содержать как минимум 1 элемент (name или name-ref).

Вот что у меня есть:

NAME: ('a'..'z')+;
REF_TAG: 'ref:';
SP: ' '+;

name: NAME;
name_ref: REF_TAG name;
item: name | name_ref;
query: item (SP item)*;

Эта грамматика демонстрирует то, что мне в основном нужно получить, и единственная особенность в том, что она не поддерживает строки в длинных кавычках (она отлично работает для имен без пробелов).

SHORT_NAME: ('a'..'z')+;
LONG_NAME: SHORT_NAME (SP SHORT_NAME)*;
REF_TAG: 'ref:';
SP: ' '+;
Q: '"';

short_name: SHORT_NAME;
long_name: LONG_NAME;
name_ref: REF_TAG (short_name | (Q long_name Q));
item: (short_name | (Q long_name Q)) | name_ref;
query: item (SP item)*;

Но это не работает. Есть идеи, в чем проблема? Возможно, это важно: my first query следует рассматривать как 3 item с (3 name с), а "my first query" равно 1 item (1 long_name).

Ответы [ 2 ]

3 голосов
/ 22 января 2012
Лексер

ANTLR жадно совпадает: поэтому входные данные типа my first query маркируются как LONG_NAME вместо 3 SHORT_NAME с пробелами между ними.

Просто удалите правило LONG_NAME и определитеэто в правиле синтаксического анализатора long_name.

Следующая грамматика:

SHORT_NAME : ('a'..'z')+;
REF_TAG    : 'ref:';
SP         : ' '+;
Q          : '"';

short_name : SHORT_NAME;
long_name  : Q SHORT_NAME (SP SHORT_NAME)* Q;
name_ref   : REF_TAG (short_name | (Q long_name Q));
item       : short_name | long_name | name_ref;
query      : item (SP item)*;

проанализирует входные данные:

my first query "my first query" ref:mystring

следующим образом:

enter image description here

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

SHORT_NAME : ('a'..'z')+;
LONG_NAME  : '"' ~'"'* '"' {setText(getText().substring(1, getText().length()-1));};
REF_TAG    : 'ref:';
SP         : ' '+ {skip();};

name_ref   : REF_TAG (SHORT_NAME | LONG_NAME);
item       : SHORT_NAME | LONG_NAME | name_ref;
query      : item+ EOF;

, который будет анализировать один и тот же вход следующим образом:

enter image description here

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

1 голос
/ 22 января 2012

Вот грамматика, которая должна работать в соответствии с вашими требованиями:

  SP: ' '+;
  SHORT_NAME: ('a'..'z')+;
  LONG_NAME: '"' SHORT_NAME (SP SHORT_NAME)* '"';
  REF: 'ref:' (SHORT_NAME | LONG_NAME);

  item: SHORT_NAME | LONG_NAME  | REF;
  query: item (SP item)*;

Если вы поставите это сверху:

  grammar Query;

  @members {
      public static void main(String[] args) throws Exception {
          QueryLexer lex = new QueryLexer(new ANTLRFileStream(args[0]));
           CommonTokenStream tokens = new CommonTokenStream(lex);

          QueryParser parser = new QueryParser(tokens);

          try {
              TokenSource ts = parser.getTokenStream().getTokenSource();
              Token tok = ts.nextToken();
              while (EOF != (tok.getType())) {
                 System.out.println("Got a token: " + tok);
                 tok = ts.nextToken();
              }
          } catch (Exception e) {
              e.printStackTrace();
           }
      }
  }

Вы должны увидеть, как лексер прекрасно разбивает все на части (янадеюсь ;-))

hi there "long name" ref:shortname ref:"long name"

Должно дать:

Got a token: [@-1,0:1='hi',<6>,1:0]
Got a token: [@-1,2:2=' ',<7>,1:2]
Got a token: [@-1,3:7='there',<6>,1:3]
Got a token: [@-1,8:8=' ',<7>,1:8]
Got a token: [@-1,9:19='"long name"',<4>,1:9]
Got a token: [@-1,20:20=' ',<7>,1:20]
Got a token: [@-1,21:33='ref:shortname',<5>,1:21]
Got a token: [@-1,34:34=' ',<7>,1:34]
Got a token: [@-1,35:49='ref:"long name"',<5>,1:35]

Я не уверен на 100%, в чем проблема с вашей грамматикой, но я подозреваю, что проблема связана с вашим определениемLONG_NAME без кавычек.Возможно, вы можете увидеть, в чем заключается различие?

...