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

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


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


Ответы (2)


arrow_upward
7
arrow_downward

Допустим, вы хотите проанализировать простой текстовый файл, содержащий числа, разделенные пробелами. Вы хотели бы разобрать это в массив 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

arrow_upward
0
arrow_downward

Вот несколько выдержек из созданной мной грамматики, которая анализирует имена людей и возвращает объект 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