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

在将自己深深地嵌入到grako源代码中之后,我相信我终于了解了人们是如何从AST返回到生成的文档的。有人可以检查一下我的理解是否正确,然后让我知道是否有更直接的方法吗?

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

  • 这样可以吗?这似乎一点都不直观。
  • 为什么人们要经过步骤2和3的巨大努力,除了存储已经包含在AST中的信息外,什么也要做?
  • 与直接从AST工作相比,此方法的优点是什么?
  • 如果只想按照原始语法重新创建文档,是否有一种方法可以自动执行或避开步骤2和3?
  • 给定PEG语法定义,理论上是否有可能像创建“解析器生成器”一样自动创建“代码生成器生成器”?
  • 最佳答案

    如果查看 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完成的分派(dispatch)中内联指定CodeGenerator模板,这是我首选的翻译方式。但是,当我只需要从模型中提取信息时(例如生成符号表或计算指标时),我就使用grako.model.DepthFirstNodeWalker

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

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

    最后, Grako 不会强加一种方法来创建已解析内容的模型,也不会强加将其转换为其他内容的方法。在基本形式中, Grako 仅在合理使用元素命名的情况下才提供具体语法树(CST)或抽象语法树(AST)。其他所有内容均由特定的语义类生成,可以随心所欲。

    关于python - Grako "code"世代,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35565052/

    10-13 03:15