ANTLR - можно обрабатывать токены с переменной, указанной в грамматике? - PullRequest
1 голос
/ 19 сентября 2011

Пример строки

023abc7defghij

Заголовок

Символы 0, 1 = Размер следующих фрагментов

Куски

Первый символ =длина следующей строки String

Следующие символы = String с указанной длиной

Пример результата

Поэтому в верхнем примере это будет означать:

02 -> 2 следующих фрагмента

3 -> 3-символьная строка будет следовать

abc -> трехсимвольная строка

7 -> 7-символьная строка будет следовать

defghij -> строка из семи символов

Вопрос

Могу ли я написать грамматику, описывающую эту форму строки?Мне нужно будет интерпретировать информацию о «длине» и затем создать токены с указанной длиной, чтобы заполнить мои объекты информацией о длине и строками.

Я надеюсь, что смогу описать это понятным.Я не смог найти информацию, описание или решение моей проблемы.

1 Ответ

2 голосов
/ 19 сентября 2011

Я предполагаю, что ваша реальная проблема немного сложнее, потому что, если "023abc7defghij" - ваш фактический ввод, я бы не использовал генератор синтаксического анализатора, такой как ANTLR, а просто придерживался некоторых простых строковых операций.

Тем не менее, вот возможное решение:

Поскольку ваши chunks не известны заранее, вы не можете создать никаких токенов, кроме одного Digit и Other токена, который был бы любымсимвол, отличный от цифры.Обратите внимание, что вам на самом деле не нужна информация header: вы просто анализируете "3" и затем получаете следующие 3 символа, затем анализируете "7" и получаете следующие 7 символов, ... вплоть доконец файла.

Грамматика для такого языка может выглядеть следующим образом:

grammar T;

parse
  :  file EOF
  ;

file
  :  header chunk*
  ;

header
  :  Digit Digit
  ;

chunk
  :  Digit any*
  ;

any
  :  Digit
  |  Other
  ;

Digit
  :  '0'..'9'
  ;

Other
  :  .
  ;

Но теперь правило chunk неоднозначно: теперь нет необходимости останавливать потребление символов,Это может быть сделано с использованием стробированного семантического предиката , который заставит * из any* перестать потреблять, когда определенное условие выполнено (когда счетчик int n имеетв данном случае это был обратный отсчет).

Приведенная выше грамматика, включающая этот предикат и некоторые println -отношения, будет выглядеть так:

grammar T;

parse
  :  file EOF
  ;

file
  :  header {System.out.println("header=" + $header.text);}
     (chunk {System.out.println("chunk=" + $chunk.text);})*
  ;

header
  :  Digit Digit
  ;

chunk
  :  Digit {int n = Integer.valueOf($Digit.text);} ({n > 0}?=> any {n--;})*
  ;

any
  :  Digit
  |  Other
  ;

Digit
  :  '0'..'9'
  ;

Other
  :  .
  ;

, которую можно протестировать с помощью класса:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String source = "023abc7defghij";
    TLexer lexer = new TLexer(new ANTLRStringStream(source));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

Если вы сейчас сгенерируете лексер и парсер, скомпилируйте весь файл .java и запустите класс Main:

java -cp antlr-3.3.jar org.antlr.Tool T.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

, вы увидите, что на вашем принтере будет напечатано следующееконсоль:

header=02
chunk=3abc
chunk=7defghij
...