Самореферентные PPCompositeParsers PetitParser
У меня есть грамматика языка программирования, которую я хотел бы разбить на несколько подклассов PPCompositeParser (например, один класс будет обрабатывать инструкции, другой класс будет обрабатывать выражения, другой класс с обработкой структуры программы). Я хочу сделать это, чтобы избежать большого класса с десятками переменных экземпляра.
Моя проблема заключается в том, что эти подпрограммы имеют циклическую зависимость: структурная грамматика ссылается на правило 'Statement' грамматики оператора, которое ссылается на правило 'expression' грамматики выражения, которое ссылается на 'subroutineName' грамматики структуры (закрытие цикла зависимости). Я попробовал простой подход, чтобы, например, иметь метод #subroutineName в грамматике выражения, который выглядит следующим образом:
MyExpressionGrammar>>subroutineName
^ N2TJStructureParser newStartingAt: #subroutineName
но это не удается при инициализации из-за бесконечной рекурсии (очевидно).
Чтобы решить эту проблему, я создал PPDeferedParser:
PPParser subclass: #PPDeferedParser
instanceVariableNames: 'creationBlock'
classVariableNames: ''
poolDictionaries: ''
category: 'PetitParser-Tools'
PPDeferedParser>>parseOn: aStream
^ creationBlock value parseOn: aStream
что делает предыдущее имя #subroutineName следующим образом:
MyExpressionGrammar>>subroutineName
^ PPDederedParser creationBlock: [N2TJStructureParser newStartingAt: #subroutineName]
Кажется, это работает, но мне интересно, есть ли другое решение.
1 ответ
В настоящее время разделение составного парсера на несколько PPCompositeParser
подклассы напрямую не поддерживаются PetitParser.
Имейте в виду, что если вы используете браузер PetitParser, вам не нужно беспокоиться о переменных экземпляра, они автоматически управляются для вас. Кроме того, вам не обязательно нужна переменная экземпляра для каждого производства. Например, терминалы могут быть в методах, которые вы вызываете напрямую.
Ваше решение, конечно, тоже работает, но оно не так уж и приятно, потому что требует от вас внимательного отношения к тому, как вы хотите соединить свои грамматики. Также в вашей реализации вы должны лениво кэшировать результаты, так как в противном случае ваш код будет создавать новые составные парсеры при разборе. Это очень дорого.
Все это в стороне, конечно, можно было бы улучшить PPCompositeParser
поддерживать зависимости между несколькими подклассами, например, путем объявления зависимых других анализаторов, которые конструктор должен подготовить, инициализировать и в конечном итоге разрешить.