我有什么工具可以构建一个真实的、诚实的外部 DSL。不,我不是在谈论滥用 Ruby、Boo、XML 或其他现有语言或语法,我的意思是一种真正的外部 DSL——我自己的语言用于我自己的目的。
我知道有一些语言工作台正在开发中,而且我听说过诸如 .NET 的“讽刺”之类的东西。当然,还有 ANTLR、Lex/Yaac 等,但恐怕这些对于我想要做的事情来说太复杂了。
请谈谈您可能使用或听说过的 DSL 构建器工具,以及您对它的帮助和缺点的印象。
我有什么工具可以构建一个真实的、诚实的外部 DSL。不,我不是在谈论滥用 Ruby、Boo、XML 或其他现有语言或语法,我的意思是一种真正的外部 DSL——我自己的语言用于我自己的目的。
我知道有一些语言工作台正在开发中,而且我听说过诸如 .NET 的“讽刺”之类的东西。当然,还有 ANTLR、Lex/Yaac 等,但恐怕这些对于我想要做的事情来说太复杂了。
请谈谈您可能使用或听说过的 DSL 构建器工具,以及您对它的帮助和缺点的印象。
我用 Boo、Irony.NET 和一个名为 Grammatica 的工具包编写了 DSL。你说解析器生成器太复杂了,但你的判断可能太仓促了,事实上,一旦你克服了一个小的学习曲线,它们就很容易使用,并打开了一个可以轻松覆盖的广阔可能性世界努力。我发现学习为大多数解析器生成器编写语法所需的符号有点类似于学习正则表达式 - 你必须稍微弯曲一下才能让它们进入,但回报是显着的。
我的观点是:如果您的目标语言足够简单,可以由一个愚蠢的视觉设计师处理,那么使用解析器生成器为其编写语法应该很容易。
如果您的目标 DSL 足够复杂,以至于您需要费力地编写语法,那么愚蠢的可视化工具无论如何都不会减少芥末,您最终将不得不学习编写语法。
不过,从长远来看,我同意内部与外部 DSL。我在 Boo 中编写了一个内部 DSL,并且不得不修改我的 DSL 语法以使其工作,而且它总是感觉像是一个 hack。使用 Irony.NET 或 ANTLR 的相同语法同样容易以更大的灵活性完成。
我有一篇博客文章讨论了一些选项。这篇文章的重点是为运行时表达式评估编写 DSL,但工具都是一样的。
我对 Irony.NET 的体验都是积极的,并且有几种使用它实现的参考语言,这是一个很好的起点。如果您的语言很简单,那么启动和运行绝对不复杂。CodeProject 上还有一个名为 TinyParser 的库——这个库非常有趣,因为它将解析器生成为纯源代码,这意味着您的最终产品完全没有任何第三方引用。不过我自己没用过。
如果您正在研究编写独立的 DSL,那么您正在研究构建编译器——没有办法绕过它。编译器的构建是必不可少的编程知识,其实并没有大家想象的那么难。Steve Yegge 的Righ Programmer Food总结了知道如何很好地构建编译器的价值。
有很多方法可以开始。我建议查看文章中提到的 2 篇论文:想要编写编译器吗?只需阅读这两篇论文。第一个,让我们构建一个编译器,非常易于访问。它使用 Turbo 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,有ECL,也在 LGPL 下。两者都使用 C 接口来实现互操作性,因此您几乎可以将它们嵌入到任何其他语言中。ECL 在 Lisp 中是独一无二的,因为每个 Lisp 函数都是作为 C 函数实现的,所以如果你愿意,你可以用 C 编写 Lisp 代码(比如,在你自己的扩展方法中——你可以创建对 Lisp 对象进行操作的 C 函数,然后从 Lisp 调用它们)。我已经将 ECL 用于我的一个副项目有一段时间了,我喜欢它。维护者非常活跃且反应迅速。
你真的应该看看Ragel。这是一个将状态机嵌入到常规源代码中的框架。Ragel 支持 C、C++、Objective-C、D、Java 和 Ruby。
Ragel 非常适合编写文件和协议解析器以及单步执行外部 DSL 内容。主要是因为它允许您在状态转换等方面执行任何类型的代码。
使用 Ragel 的几个值得注意的项目是Mongrel,一个很棒的 ruby Web 服务器。还有Hpricot,一个基于 ruby 的 html 解析器,有点受 jQuery 的启发。
Ragel 的另一个重要功能是它如何生成基于graphviz的图表,以可视化您的状态机。下面是取自Zed Shaw 关于 ragel state charts 的文章的示例。
Xtext就是为此而构建的。
从网站:
Xtext 是一个用于开发编程语言和领域特定语言的框架。
它涵盖了完整语言基础架构的所有方面,从解析器、链接器、编译器或解释器到成熟的顶级 Eclipse IDE 集成。它为所有这些方面提供了良好的默认设置,同时每个方面都可以根据您的需求进行定制。
我一直在使用 Irony,效果很好。具有讽刺意味的是,您可以轻松地将其包含在您将使用 DSL 的任何运行时中。我正在创建一个外部 DSL,我将其填充到用 C# 编写的语义模型中,因此具有讽刺意味的是。然后我使用语义模型生成带有 StringTemplate 的代码。
如果您计划实现外部 DSL,Spoofax ( http://strategoxt.org/Spoofax ) 是一个很好的语言工作台来执行此操作。它是一个基于解析器的文本语言工作台,它利用了多种最先进的技术,例如 SDF、Stratego。除了 DSL 实现之外,您还可以获得非常丰富的编辑器服务,例如代码完成、大纲视图、智能感知等。它已被用于构建多种语言,例如http://mobl-lang.org/。查看此内容以了解有关所提供支持的想法。
Spoofax 项目带有一个开箱即用的好示例 DSL 实现和一个 java 代码生成器。它可以作为开始使用这些工具的起点。
以下有关此语言工作台用法的教程详细信息:http: //strategoxt.org/Spoofax/Tour。
希望能帮助到你!
对于严重的外部DSL,无法避免解析问题;ANTLR 是您最不需要的。您要检查的是程序转换系统,它可用于将任意 DSL 语法映射到 Java 等目标语言。