Grako"代码"代

ARF*_*ARF 5 python code-generation grako

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

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

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

这可能是对的吗?这看起来根本不直观.

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

Apa*_*ala 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()
...
Run Code Online (Sandbox Code Playgroud)

如果参数中不存在这些类,则这些类将被合成types=。所ModelBuilderSemantics需要的只是每个语法规则都带有一个参数,该参数给出相应的类名Node

module::Module = .... ;
Run Code Online (Sandbox Code Playgroud)

或者,

module(Module) = ... ;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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