Грако "код" генерация
Я пытаюсь понять, как можно воссоздать документ, проанализированный парсером, сгенерированным grako.
Погрузившись глубоко в исходный код Grako, я думаю, что наконец понял, как можно вернуться из AST к сгенерированному документу. Может ли кто-нибудь проверить, правильное ли мое понимание, и дайте мне знать, если есть более прямой метод?
- Каждый создает грамматику PEG, которую хочет разобрать. Grako создает класс синтаксического анализатора и класс семантики на его основе.
- Один создает (вручную) модуль Python, содержащий (более или менее) отдельный класс (подкласс
grako.model.Node
) для каждого правила в своей грамматике. Каждый класс должен по крайней мере иметь конструктор с параметрами для каждого именованного элемента в соответствующем правиле и хранить его значения в свойстве класса. - Один подкласс (вручную) сгенерированный класс семантики, чтобы заменить ast для каждого правила на соответствующий класс, созданный на шаге 2.
- Один создает (вручную) модуль Python подкласс
grako.codegen.ModelRenderer
определение шаблона для генерации "кода" (более или менее) каждого правила в грамматике. - Один из них передает AST, состоящий из подклассов Node и модуля python, содержащего шаблоны, в
grako.codegen.CodeGenerator().render(...)
создать выход.
Это может быть правильно? Это не кажется интуитивно понятным.
- Зачем предпринимать значительные усилия на шагах 2 и 3, чтобы ничего не делать, кроме как хранить информацию, которая уже содержится в AST?
- В чем преимущество этого подхода вместо того, чтобы работать напрямую с AST?
- Есть ли способ автоматизировать или обойти шаги 2 и 3, если нужно только воссоздать документ в исходной грамматике?
- Учитывая определение грамматики PEG, теоретически возможно ли автоматически создать "генератор генератора кода" так же, как и "генератор парсера"?
1 ответ
Если вы посмотрите, как Grako анализирует грамматики, вы заметите, что классы шага 2 создаются синтетически ModelBuilderSemantics
потомок:
# from grako/semantics.py
class GrakoSemantics(ModelBuilderSemantics):
def __init__(self, grammar_name):
super(GrakoSemantics, self).__init__(
baseType=grammars.Model,
types=grammars.Model.classes()
)
self.grammar_name = grammar_name
self.rules = OrderedDict()
...
Классы синтезируются, если их нет в types=
paramenter. Все это ModelBuilderSemantics
требует, чтобы каждое правило грамматики содержало параметр, который дает имя класса для соответствующего Node
:
module::Module = .... ;
или же,
module(Module) = ... ;
Шаг 3 неизбежен, потому что перевод должен быть указан "где-то". Путь Грако позволяет str
шаблоны, указанные в строке с диспетчеризацией CodeGenerator
, который является моим предпочтительным способом сделать перевод. Но я пользуюсь grako.model.DepthFirstNodeWalker
когда мне просто нужно извлечь информацию из модели, например, при генерации таблицы символов или вычислительных метрик.
Шаг 3 не может быть автоматизирован, потому что отображение семантики исходного языка на семантику целевого языка требует умственных способностей, даже когда источник и цель одинаковы.
Можно также обойти обход JSON-подобной структуры Python, которая parse()
или же grako.model.Node.asjson()
генерирует (AST), как вы предлагаете, но код обработки будет полон if-then-elseif
отличить один словарь от другого или один список от другого. В моделях каждый диктант в иерархии имеет класс Python как тип.
В конце концов, Grako не навязывает ни способа создания модели того, что было проанализировано, ни способа перевести это во что-то еще. В своей базовой форме Grako предоставляет либо конкретное синтаксическое дерево (CST), либо абстрактное синтаксическое дерево (AST), если именование элементов используется с умом. Все остальное создается конкретным классом семантики, который может быть любым.