Эй, я начал использовать Antlr с java, и я хотел знать, как я могу хранить некоторые значения непосредственно в массиве 2d и возвращать этот массив? Я вообще не могу найти никаких руководств по этому вопросу, вся помощь необходима.
Справка по массиву Antlr
Ответы (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]]
ХТН
Вот несколько выдержек из созданной мной грамматики, которая анализирует имена людей и возвращает объект 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();
}