【问题标题】:Tiny DSL implementation in PythonPython 中的微型 DSL 实现
【发布时间】:2015-06-26 19:30:25
【问题描述】:

我正在研究用 Python 实现 DSL,我正在寻找一种小型 DSL 语言,它对没有设计和实现语言经验的人很友好。到目前为止,我回顾了 Hy 和 Mochi 两个实现。 Hy 实际上是一种 lisp 方言,而 Mochi 似乎与 Elixir 非常相似。两者对我来说都很复杂,因为我的目标是对语言进行原型设计并进行尝试,以发现它是否真的有助于解决问题并适合问题所需的风格。我知道 Python 通过标准库中提供的语言工具得到了很好的支持。到目前为止,我实现了一种非常简单的 lisp 方言,我没有使用任何 python AST,它纯粹是通过字符串处理实现的,这对于我正在寻找的东西绝对不灵活。

除了上面提到的两种语言之外,有没有任何实现,小到可以研究?

关于这个主题有哪些好书(在某种意义上是实用的,不仅限于理论和学术方面)?

什么是学习和使用 Python AST 的好方法?

在实际生成的字节码开销方面,是否存在与基于 Python 构建的语言(如 Hy)相关的任何重大性能问题?

谢谢

【问题讨论】:

  • 您是否对可以嵌入到 Python 代码中的语言(即它被 Python 解析器识别)感兴趣,或者您想设计一种独立于 Python 解析器的全新语法?
  • 我想设计一种新的语法。
  • 好吧,那么 Python 并没有什么特别之处。获取一个解析器(LL(k)、LR(k)、Yacc 等等),编写你的语法,并为其编写操作/转换语义。
  • 我在回答中添加了一些细节,以防您可能想跳过语法部分并专注于操作语义部分......

标签: python dsl


【解决方案1】:

您可以将创建(又一种!)新语言的任务拆分为至少两个大步骤:

  • 语法
  • 语义和解释

语法

您需要为您的语言定义语法,并使用生产规则指定如何从简单的表达式创建复杂的表达式。

示例:LISP 的语法:

expression ::= atom   | list
atom       ::= number | symbol    
number     ::= [+-]?['0'-'9']+
symbol     ::= ['A'-'Z''a'-'z'].*
list       ::= '(' expression* ')'

如何阅读:表达式要么是原子,要么是列表atomnumbersymbol数字是...等等。

您通常还会定义一些标记化规则,因为大多数语法都在标记级别工作,而不是在字符级别。

一旦你定义了你的语法,你想要一个解析器,给定一个句子(一个程序)能够构建派生树或抽象语法树。

例如,对于表达式x=f(y+1)+2,你想获取树:

有几个解析器(LL、LR、递归下降,...)。您不一定需要自己编写语言解析器,因为有一些工具可以根据语法规范生成解析器(LEX & YACCFlex & BisonJavaCCANTLR;也可以查看this list of parsers available for Python)。

如果你想跳过设计新语法的步骤,你可能想从一个简单的开始,比如 LISP 的语法。 Pyperplan 项目中甚至还有一个用 Python 编写的 LISP 解析器。他们使用它来解析PDDL,这是一种基于 LISP 的特定领域规划语言。

有用的读物​​:

语义与解释

一旦你有了程序的抽象语法树,你就想执行你的程序。有几种形式可以指定执行(部分)程序的“规则”:

  • 操作语义:非常流行的一种。它分为两类:
    • 小步语义:描述计算的各个步骤
    • Big Step Semantics:描述计算的整体结果
  • 归约语义:一种基于 lambda 演算的形式
  • 转换语义:如果您将解释器视为transition system,则可以使用转换语义指定其语义。这对于不终止(即连续运行)的程序(如控制器)特别有用。

有用的读物​​:

【讨论】:

  • 非常感谢,这很有帮助。我有《计算机程序的结构和解释》一书,但在一章后跳过了它,现在有充分的理由完成它。我认为使用您提到的工具重新实现 Lisp 解释器是一个好的开始。我曾经实现它来查询我的机器并表达数据转换的逻辑。我的目标是针对 Python VM,但这个想法仍然模糊不清 ast 如何在没有运行时成本的情况下转换为字节码。我的意思是现在我正在递归地将树映射到 python 全局框架内的函数。
  • 更好地说,我应该能够以某种方式将其编译为 python 代码,这样就不会有任何开销。您对此有何建议?
  • 你可以使用 Python 的 ast 模块。将你的 DSL AST 转换成 Python ast 的 AST,然后 compile() 它。
  • 我在 PDF 链接中添加了“操作语义的结构方法”,我强烈建议您先阅读它
【解决方案2】:

编写自己的语言并不需要太多关于解析的知识。

我编写了一个库,让您可以轻松地做到这一点:https://github.com/erezsh/lark

这是我的一篇博文,解释了如何使用它来编写自己的语言:http://blog.erezsh.com/how-to-write-a-dsl-in-python-with-lark/

我希望你不要介意我的无耻插件,但这似乎与你的问题非常相关。

【讨论】:

  • 你好,@Erez!感谢您的图书馆,但是否有一些与创造条件相关的文档?
  • 有很多文档。在示例目录中还有 Python 的完整语法。你能说得更具体点吗?
  • 你能解释一下,什么意思吗?和 !在声明之前 ?action_operator: ACTION_OPERATOR ACTION_OPERATOR : ""|"="|">="|"pydot__tree_to_png(tree, "tree_1.png") 修复错误FileNotFoundError: [Errno 2] "dot" not found in path. @埃雷兹
  • 我已经写了 issue github.com/erezsh/lark/issues/118,如果你能回答我,我将不胜感激@Erez
猜你喜欢
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多