Допустим, вы хотите проанализировать плоский текстовый файл, содержащий числа, разделенные пробелами.Вы хотели бы разбить это на 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
выглядит примерно так же, только оно возвращает 1размерный список чисел:
line returns [List<Integer> row]
@init {
$row = new ArrayList<Integer>();
}
: Number+ (LineBreak | EOF)
;
Следующим шагом является заполнение List
s фактическими значениями, которые анализируются.Это можно сделать, вставив код {$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]]
HTH