5

我试图了解如何重新创建由grako生成的解析器解析的文档。

在深入研究 grako 源代码之后,我相信我终于明白了如何从 AST 返回到生成的文档。有人可以检查我的以下理解是否正确,如果有更直接的方法,请告诉我?

  1. 一个人创建一个希望解析的 PEG 语法。Grako 创建了一个解析器类和一个基于它的语义类。
  2. 一个人(手动)创建一个python模块,其中包含(或多或少)一个单独的类(的子类grako.model.Node),用于一个人的语法中的每个规则。每个类必须至少有一个构造函数,该构造函数为相应规则中的每个命名元素提供参数,并将其值存储在类属性中。
  3. 一个子类(手动)生成的语义类,以将每个规则的 ast 替换为在步骤 2 中创建的相应类。
  4. 一个人(手动)创建一个python模块,一个grako.codegen.ModelRenderer定义模板的子类,用于(或多或少地)为一个人的语法中的每个规则生成“代码”。
  5. 一个提供由 Node 子类和包含模板的 python 模块组成的 ASTgrako.codegen.CodeGenerator().render(...)以创建输出。

这可能是对的吗?这似乎一点也不直观。

  • 为什么要经过第 2 步和第 3 步的重大努力,除了存储 AST 中已经包含的信息之外什么都不做?
  • 这种方法比直接从 AST 工作有什么优势?
  • 如果只想以原始语法重新创建文档,有没有办法自动化或回避步骤 2 和 3?
  • 给定一个 PEG 语法定义,理论上是否可以像创建“解析器生成器”一样自动创建“代码生成器”?
4

1 回答 1

4

如果您查看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=。所ModelBuilderSemantics需要的只是每个语法规则都带有一个参数,该参数给出相应的类名Node

module::Module = .... ;

或者,

module(Module) = ... ;

第 3 步是不可避免的,因为必须在“某处”指定翻译。Grako的方式允许str内联指定模板与调度完成CodeGenerator,这是我进行翻译的首选方式。但我grako.model.DepthFirstNodeWalker只需要从模型中提取信息时使用,例如生成符号表或计算指标时。

步骤 3 不能自动化,因为将源语言的语义映射到目标语言的语义需要脑力,即使源语言和目标语言相同。

正如您所建议的,人们也可以通过遍历parse()grako.model.Node.asjson()生成的类似 JSON 的 Python 结构(AST)而侥幸,但处理代码将充满if-then-elseif以区分一个字典与另一个字典,或一个列表与另一个字典。对于模型,层次结构中的每个 dict 都有一个 Python 类作为类型。

最后,Grako没有强加一种方法来创建已解析内容的模型,也没有将其转换为其他内容的方法。在其基本形式中,如果元素命名使用得当, Grako仅提供具体语法树(CST) 或抽象语法树(AST)。其他一切都是由特定的语义类产生的,可以是任何人想要的。

于 2016-02-24T14:34:31.567 回答