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(),

Другие вопросы по тегам