建立有效的外部DSL

时间:2020-03-06 14:25:58  来源:igfitidea点击:

有什么工具可以帮助我构建真正的,诚实的外部DSL。不,我不是在谈论滥用Ruby,Boo,XML或者其他现有语言或者语法,我的意思是说一种真正的外部DSL-我自己的语言用于我的目的。

我知道正在开发一些语言工作台,并且听说过.NET的" Irony"之类的东西。而且,当然还有ANTLR,Lex / Yaac等,但是恐怕这些对于我想做的事情来说太复杂了。

请谈谈我们可能使用或者听说过的DSL构建器工具,以及对它的帮助和负面影响的印象。

解决方案

我们应该真正查看Ragel。这是一个将状态机嵌入到常规源代码中的框架。 Ragel支持C,C ++,Objective-C,D,Java和Ruby。

Ragel非常擅长编写文件和协议解析器,以及逐步浏览外部DSL内容。主要是因为它允许我们在状态转换等上执行任何类型的代码。

Mongrel是几个使用Ragel的著名项目,它是一个很棒的ruby Web服务器。而Hpricot,一个基于红宝石的html解析器,受到了jQuery的启发。

Ragel的另一个重要功能是它如何生成基于graphviz的图表,以可视化状态机。以下是Zed Shaw关于ragel状态图的文章中的示例。

拉吉尔状态图http://www.zedshaw.com/tips/HelloMachine_small.png

如果我们正在考虑编写独立的DSL,那么我们正在考虑构建编译器-远没有解决之道。编译器的构建是必不可少的编程知识,并且实际上并不像通常认为的那么难。 Steve Yegge的Righ Programmer Food总结了了解如何很好地构建编译器的价值。

有很多入门方法。我建议检查一下文章中提到的2篇论文:是否要编写编译器?只需阅读这两篇论文。第一个,让我们构建一个编译器,非常容易访问。它使用Turbo Pascal作为实现语言,但是我们可以轻松地以任何其他语言实现它-源代码非常清晰。 Pascal是一种简单的语言。

一旦我们对事物的工作方式和所涉及的术语有了很好的了解,我建议我们深入研究一下ANTLR之类的东西。 ANTLR有一个不错的IDE,ANTLRWorks,它带有解释器和调试器。它还可以实时生成语法的非常好的可视化。我发现它对学习无价。

ANTLR有一些很好的教程,尽管起初可能有些不知所措。尽管它是针对ANTLR 2.0的,但它很不错,因此我们可能会遇到与较新版本(当前最新为3.1)不兼容的情况。

最后,还有另一种用于DSL的方法:Lisp方法。鉴于Lisp的语法少的本质(代码基本上是抽象的语法树),只要我们习惯了括号,就可以用它来塑造无穷无尽的语言。

如果我们确实采用了这种方法,则希望使用可嵌入的Lisp。在Java下,我们拥有Clojure(一种Lisp方言),可以与JVM及其库完美地互操作。我没有亲自使用过,但是看起来不错。对于Scheme,有GNU Guile(根据LGPL许可)。对于Common Lisp,LGPL下也有ECL。两者都使用C接口来实现互操作性,因此我们几乎可以将它们嵌入任何其他语言中。 ECL在Lisps中是独一无二的,因为每个Lisp函数都实现为C函数,因此我们可以使用C编写Lisp代码(例如,在自己的扩展方法中,可以创建对Lisp对象进行操作的C函数,然后从Lisp致电给他们)。我已经将ECL用于我的副项目有一段时间了,我喜欢它。维护者非常活跃且反应迅速。

我已经在Boo,Irony.NET和一个名为Grammatica的工具包中编写了DSL。我们说解析器生成器太复杂了,但是判断可能太草率了,实际上,一旦我们克服了一个很小的学习曲线,它们就很容易使用,并且打开了一个很容易被超越的广阔世界的努力。我发现学习为大多数解析器生成器编写语法所需的符号有点类似于学习正则表达式,我们必须稍稍下定决心才能让它们进入,但是收获是巨大的。

我的看法是:如果目标语言足够简单,可以由笨拙的视觉设计师处理,那么使用解析器生成器为其编写语法应该非常容易。

如果目标DSL非常复杂,以至于我们需要花些时间来编写语法,那么笨拙的可视化工具就不会割芥末,我们最终将不得不学习编写语法。

从长远来看,我同意内部DSL与外部DSL。我在Boo中编写了一个内部DSL,并且不得不修改我的DSL语法才能使其正常工作,并且始终感觉像是黑客。使用Irony.NET或者ANTLR进行相同的语法同样容易实现,并且具有更大的灵活性。

我有一篇博客文章讨论了一些选择。这篇文章的重点是编写用于运行时表达式评估的DSL,但是这些工具都是相同的。

我对Irony.NET的经验一直很积极,并且使用它实现了几种参考语言,这是一个很好的起点。如果语言很简单,那么启动和运行它绝对不会很复杂。 CodeProject上还有一个名为TinyParser的库,这真的很有趣,因为它将解析器生成为纯源代码,这意味着最终产品完全没有任何第三方参考。不过,我自己还没有使用过它。

我一直在使用Irony,效果很好。具有讽刺意味的是,我们可以很轻松地将其包含在使用DSL的任何运行时中。我正在创建一个外部DSL,并将其填充到用Cso反讽编写的语义模型中。然后,我使用语义模型通过StringTemplate生成代码。

如果我们打算实现外部DSL,则Spoofax(http://strategoxt.org/Spoofax)是执行此操作的不错的语言工作台。这是一个基于解析器的文本Langauge Workbench,它利用了几种最先进的技术,例如SDF,Stratego。除了DSL的实现外,我们还可以获得非常丰富的编辑器服务,例如代码完成,大纲视图,智能感知等。它已被用来构建多种语言,例如http://mobl-lang.org/。检查一下,以了解有关所提供支持的想法。

Spoofax项目随附了一个开箱即用的DSL示例实现示例和一个Java代码生成器。它可以作为开始使用这些工具的起点。

以下教程详细介绍了该语言工作台的用法:http://strategoxt.org/Spoofax/Tour。

希望能帮助到你!