编写便携式域特定语言

时间:2009-10-04 08:45:18

标签: c# java dsl

我想了解部署特定于域的语言的良好策略,该语言必须至少运行2种语言(Java,C#)以及更多(Python,可能还有Javascript)。

一些背景知识。我们已经开发并部署了目前用C#编写的特定于域的语言。它通过一系列方法调用进行部署,这些方法调用的参数是公共语言基元(字符串,双精度等),集合(IEnumerable,HashSet,...)或特定于域的库(CMLMolecule,Point3,RealSquareMatrix)中的对象。该库经过了充分测试,对象必须符合稳定部署的XML模式,因此更改将是渐进式和管理式的(至少这是希望)。

我们希望该语言将被广泛且部分由计算机识字的社区所使用,用于在没有中央控制的情况下攻击他们自己的解决方案。理想情况下,DSL将创建一定程度的封装并产生他们所需的基本功能。这些库将管理详细的算法,这些算法有很多种,但却众所周知。在Domain-specific languages vs. library of functions中,DSL的要求有很多共同之处。

我很欣赏有关最佳架构的想法(显然,一旦部署,我们就不能轻易回溯)。选择至少包括:

  • 创建IDL(例如通过CORBA)。 W3C为XML DOM做了这个 - 我讨厌它 - 而且似乎有点矫枉过正
  • 为每个平台手动创建类似的签名,并尽最大努力使其保持同步。
  • 创建可解析语言(例如CSS)。
  • XML中的声明性编程(c.f。XSLT)。这是我的首选解决方案,因为它可以被搜索,操纵等。

表现并不重要。目的明确是。

编辑讨论了应用程序调用是否构成DSL。我发现了Martin Fowler对DSL(http://martinfowler.com/dslwip/Intro.html)的介绍,他认为简单的方法调用(或链式调用)可以称为DSL。所以系列如:

point0 = line0.intersectWith(plane);
point1 = line1.intersectWith(plane);
midpoint = point0.midpoint(point1);

可以被视为DSL

7 个答案:

答案 0 :(得分:7)

语言和图书馆之间的问题似乎有些含糊不清。术语“内部DSL”和“外部DSL”很有用,我认为是Martin Fowler

“外部”DSL可能是一个独立的命令行工具。它传递了一串源代码,它以某种方式解析它,并用它做一些事情。语法和语义如何工作没有实际限制。它也可以作为一个主要由eval类方法组成的库提供;一个常见的例子是将SQL查询构建为字符串并在RDBMS库中调用execute方法;不是一个非常愉快或方便的使用模式,如果在大规模的程序中传播可怕的话。

“内部”DSL是一种以这样一种方式编写的库,它利用主机(通用)语言的怪癖来创建一种新语言可嵌入现有语言的印象。在语法丰富的语言(C ++,C#)中,这意味着以严重拉伸(或忽略)运算符符号的通常含义的方式使用运算符重载。 C ++中有很多例子;在C#中也有一些 - Irony parser toolkit以相当克制的方式模拟BNF,效果很好。

最后,有一个普通的旧库:类,方法,属性,具有精心选择的名称。

外部DSL将允许您完全忽略跨语言集成问题,因为唯一类似于库的部分将是eval方法。但发明自己的工具链并非易事。人们总是忘记调试,智能感知,语法高亮等重要性。

如果你想在C#和Java上做得好,内部DSL可能是毫无意义的努力。问题是,如果你利用一种主语言的怪癖,你不一定能够用另一种语言重复这个技巧。例如Java没有运算符重载。

这留下了一个普通的旧图书馆。如果你想跨越C#和Java(至少),那么你就会选择一种实现语言。你真的想写两次图书馆吗?一种可能性是用Java编写库,然后使用IKVM将其交叉编译为.NET程序集。这可以保证在这两个平台上都有相同的界面。

缺点是,API将以最低公分母特征表示 - 也就是说,Java特性:)。没有属性,只有getX / setX方法。避免使用泛型,因为这两个系统在这方面完全不同。甚至标准的命名方法也不同(camelCasePascalCase),因此一组用户会闻到一只老鼠。

答案 1 :(得分:3)

如果您愿意使用ANTLR重新描述您的语言,您可以使用多种语言生成DSL解释器,而无需手动维护它们,包括您提到的所有语言以及更多语言。

Antlr是一个解析器/词法分析器生成器,拥有大量目标语言。这使您可以描述一次语言,而无需维护它的多个副本。

查看目标语言的完整列表here

答案 2 :(得分:2)

虽然我不想过多推广我自己的项目,但我想提一下PIL, a Platform Independent Language,这是我一直致力于支持多种软件平台(如Java,Python ,. ..),特别适用于外部DSL。一般的想法是你在PIL(Java的一个子集)中生成代码,然后PIL编译器可以将其转换为许多其他语言之一,目前只是Java或Python,但将来会添加更多。

我在大约2天前在软件和语言工程会议上发表了一篇关于此问题的论文,如果您有兴趣,可以找到PIL网站(pil-lang.org)出版物的链接。

答案 3 :(得分:1)

如果您需要执行DSL不支持的操作,或出于性能原因(虽然我意识到这不是优先事项),但能够转换为实现语言。

我正在研究用于在C#中的规则引擎中实现规则的DSL,一些规则非常复杂并且将来可能会发生重大变化,因此能够逃脱到C#非常有用。当然,这会打破跨平台兼容性,但它实际上只是一种无需更改DSL就可以解决边缘情况的方法。

答案 4 :(得分:0)

你最好用C语言编写库(或者像rpython这样生成C代码的语言),然后使用SWIG或类似的方法为C#,Java Python等生成语言特定的绑定。

请注意,如果您在浏览器中使用Javascript,这种方法将无济于事 - 您必须单独编写javascript库。如果您通过Rhino使用javascript,那么您将能够使用Java绑定。

答案 5 :(得分:0)

可以直接使用脚本引擎从Java程序内部解释JavaScript,显然也可以从C#解释。 Python可以在JVM和.NET引擎上运行。

我建议您调查这些选项,然后将库编写在您选择的语言可用的执行路径的公共子集中。我不会考虑用一种需要翻译和转换的语言来编写它,因为你引入的步骤在出现问题时非常非常难以调试。

答案 6 :(得分:0)

我想扩展Darien的答案。我认为ANTLR带来了一些其他词法分析器/解析器工具提供的东西(至少据我所知)。如果你想创建一个最终生成Java和C#代码的DSL,ANTLR真的很棒。

ANTLR提供了四个基本组成部分:

  • Lexer Grammar(将输入流分解为令牌)
  • Parser Grammar(将令牌组织成抽象语法树)
  • Tree Grammar(遍历抽象语法树并将元数据传递到模板引擎中)
  • StringTemplate(基于函数式编程原理的模板引擎)

您的词法分析器,解析器和树语法可以保持独立于最终生成的语言。实际上,StringTemplate引擎支持模板定义的逻辑组。它甚至提供模板组的接口继承。这意味着当最初提供的所有内容都是java和C#输出时,您可以让第三方使用您的ANTLR解析器来创建说python,assembly,c或ruby。随着需求随时间的变化,您可以轻松扩展DSL的输出语言。

为了充分利用ANTLR,您需要阅读以下内容:

The Definitive ANTLR Reference: Building Domain-Specific Languages

Language Implementation Patterns: Create Your Own Domain-Specific and General Programming Languages