ANTLR AST древовидная грамматика + списки - PullRequest
4 голосов
/ 03 апреля 2011

Я прочитал много , пытаясь найти способ чистого использования списков в древовидной грамматике 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);};

Кажется, это работает, хотя я признаю, что я еще не тестировал его с вложенными / рекурсивными случаями.

Конечная цель

Я хочу создать набор классов, представляющих мой язык (класс, метод, переменная, оператор и т. Д.), Чтобы я мог провести некоторый статический анализ и оптимизацию перед созданием скомпилированного кода. Для этого мне нужно иметь возможность использовать списки. Я ожидал, что синтаксис + = «просто сработает», но я мог что-то упустить. Второй метод работает, но кажется слишком многословным и не элегантным.

Вопрос

Как правильно использовать список в древовидной грамматике ANTLR для перехода к моим конкретным классам?

1 Ответ

6 голосов
/ 03 апреля 2011

Вы можете вырезать область из вашего примера и сделать все это с локальными переменными.

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

...