ANTLR AST древовидная грамматика + списки
Я много читал, пытаясь найти способ чистого использования списков в древовидной грамматике ANTLR. Вот что я попробовал и их результаты (я очень надеюсь, что мне не хватает чего-то тривиального)...
Использование += Синтаксис
program returns [someInterface result]
: m+=method* EOF {result = new SomeClass(m);};
method returns [SomeMethod result] : <definition here>
Это не с...
Правила списка "+=" не допускаются без возможности вывода
Если я устанавливаю вывод либо "AST", либо "template" (единственные опции), сигнатуры методов сгенерированного класса меняются. То есть, m
будет не списком SomeMethod (ов), а скорее списком узлов или шаблонов соответственно. Я открыт для предложений, если есть способ заставить этот метод работать.
Использование областей действия правил
program returns [CompilesToJavaByteCode result]
scope {
List<SomeMethod> methods;
}
@init {
$program::methods = new ArrayList<SomeMethod>();
}
: (m=method {$program::methods.add(m);})*
EOF {result = new SomeClass($program::methods);};
Кажется, это работает, хотя я признаю, что я еще не тестировал его с вложенными / рекурсивными случаями.
Конечная цель
Я хочу создать набор классов, представляющих мой язык (Class, Method, Variable, Statement, ect), чтобы я мог провести некоторый статический анализ и оптимизацию, прежде чем создавать скомпилированный код. Для этого мне нужно иметь возможность использовать списки. Я ожидал, что синтаксис += "просто сработает", но я мог что-то упустить. Второй метод работает, но кажется слишком многословным и не элегантным.
Вопрос
Как правильно использовать список в древовидной грамматике ANTLR для передачи моим конкретным классам?
1 ответ
Вы можете вырезать область из вашего примера и делать все это с локальными переменными.
program returns [CompilesToJavaByteCode result]
@init {
List<SomeMethod> methods = new ArrayList<SomeMethod>();
}
: (m=method { methods.add($m.result); })* EOF
{ $result = new SomeClass(methods); };
Это то, что мы делаем для этого случая на работе. Другой вариант - это обработать правило вашего метода:
program returns [CompilesToJavaByteCode result]
@init {
List<SomeMethod> methods = new ArrayList<SomeMethod>();
}
: method[methods]* EOF { $result = new SomeClass(methods); };
method [List<SomeMethod> methods]
: ...
{ methods.add(new SomeMethod(...); };
Мне не очень нравится второй вариант, так как правило метода, вероятно, не должно заботиться о том, что делается с такими результатами. Но вы можете представить структуру, в которой верхнее правило создает ClassBeingCompiled
а остальная часть кода постепенно заполняет его .addMethod()
,