Справка по массиву Antlr

Эй, я начал использовать Antlr с java, и я хотел знать, как я могу хранить некоторые значения непосредственно в массиве 2d и возвращать этот массив? Я вообще не могу найти никаких руководств по этому вопросу, вся помощь необходима.


person Jay    schedule 04.12.2010    source источник


Ответы (2)


Допустим, вы хотите проанализировать простой текстовый файл, содержащий числа, разделенные пробелами. Вы хотели бы разобрать это в массив 2d int, где каждая строка является «строкой» в вашем массиве.

Грамматика ANTLR для такого «языка» может выглядеть так:

grammar Number;

parse
  :  line* EOF
  ;

line
  :  Number+ (LineBreak | EOF)
  ;

Number
  :  ('0'..'9')+
  ;

Space
  :  (' ' | '\t') {skip();}
  ;

LineBreak
  :  '\r'? '\n'
  |  '\r'
  ;

Теперь вы хотите, чтобы правило parse возвращало List из List<Integer> объектов. Сделайте это, добавив returns [List<List<Integer>> numbers] после правила parse, которое можно инициализировать в блоке @init{ ... }:

parse returns [List<List<Integer>> numbers]
@init {
  $numbers = new ArrayList<List<Integer>>();
}
  :  line* EOF
  ;

Ваше правило line выглядит примерно так же, только возвращает одномерный список чисел:

line returns [List<Integer> row]
@init {
  $row = new ArrayList<Integer>();
}
  :  Number+ (LineBreak | EOF)
  ;

Следующим шагом является заполнение List фактическими анализируемыми значениями. Это можно сделать, внедрив код {$row.add(Integer.parseInt($Number.text));} внутрь цикла Number+ в правило line:

line returns [List<Integer> row]
@init {
  $row = new ArrayList<Integer>();
}
  :  (Number {$row.add(Integer.parseInt($Number.text));})+ (LineBreak | EOF)
  ;

И, наконец, вы захотите добавить List, возвращаемые вашим правилом line, чтобы они были фактически добавлены в ваш 2D-список numbers из вашего правила parse:

parse returns [List<List<Integer>> numbers]
@init {
  $numbers = new ArrayList<List<Integer>>();
}
  :  (line {$numbers.add($line.row);})* EOF
  ;

Ниже приведена окончательная грамматика:

grammar Number;

parse returns [List<List<Integer>> numbers]
@init {
  $numbers = new ArrayList<List<Integer>>();
}
  :  (line {$numbers.add($line.row);})* EOF
  ;

line returns [List<Integer> row]
@init {
  $row = new ArrayList<Integer>();
}
  :  (Number {$row.add(Integer.parseInt($Number.text));})+ (LineBreak | EOF)
  ;

Number
  :  ('0'..'9')+
  ;

Space
  :  (' ' | '\t') {skip();}
  ;

LineBreak
  :  '\r'? '\n'
  |  '\r'
  ;

который можно протестировать с помощью следующего класса:

import org.antlr.runtime.*;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        String source = 
                "1 2       \n" +
                "3 4 5 6 7 \n" +
                "      8   \n" +
                "9 10 11     ";
        ANTLRStringStream in = new ANTLRStringStream(source);
        NumberLexer lexer = new NumberLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        NumberParser parser = new NumberParser(tokens);
        List<List<Integer>> numbers = parser.parse();
        System.out.println(numbers);
    }
}

Теперь сгенерируйте лексер и парсер из грамматики:

java -cp antlr-3.2.jar org.antlr.Tool Number.g

скомпилировать все .java исходных файлов:

javac -cp antlr-3.2.jar *.java

и запустите основной класс:

// On *nix
java -cp .:antlr-3.2.jar Main

// or Windows
java -cp .;antlr-3.2.jar Main

который производит следующий вывод:

[[1, 2], [3, 4, 5, 6, 7], [8], [9, 10, 11]]

ХТН

person Bart Kiers    schedule 04.12.2010
comment
Большое спасибо это здорово - person Jay; 05.12.2010

Вот несколько выдержек из созданной мной грамматики, которая анализирует имена людей и возвращает объект Name. Должно быть достаточно, чтобы показать вам, как это работает. Другие объекты, такие как массивы, выполняются таким же образом.

В грамматике:

grammar PersonNames;

fullname returns [Name name]
@init {
    name = new Name();
}
  : (directory_style[name] | standard[name] | title_without_fname[name] |      family_style[name] | proper_initials[name]) EOF;

standard[Name name]
 : (title[name] ' ')* fname[name] ' ' (mname[name] ' ')* (nickname[name] ' ')? lname[name] (sep honorifics[name])*;

 fname[Name name] : (f=NAME | f=INITIAL)  { name.set(Name.Part.FIRST, toNameCase($f.text)); };

в вашем обычном Java-коде

public static Name parseName(String str) throws RecognitionException {
    System.err.println("parsing `" + str + "`");
    CharStream stream = new ANTLRStringStream(str);
    PersonNamesLexer lexer = new PersonNamesLexer(stream);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    PersonNamesParser parser = new PersonNamesParser(tokens);

    return parser.fullname();
}
person Brad Mace    schedule 04.12.2010