有很多支持包含迷你语言的编程语言。 PHP嵌入在HTML中。 XML可以嵌入到JavaScript中。 Linq可以嵌入到C#中。正则表达式可以嵌入到Perl中。可组合语法
// JavaScript example
var a = <node><child/></node>
想一想,大多数编程语言都可以建模为不同的迷你语言。 Java中,例如,可以细分成至少四个不同的小语言:
- 一个类型声明的langauge(package指令,导入指令,类声明)
- 成员声明语言(访问修饰符,方法声明,构件乏)
- 声明语言(控制流程中,顺序执行)
- 的表达式语言(文字,作业,比较,运算)
由于能够要将这四种概念语言实现为四种不同的语法,肯定会减少我通常在复杂的解析器和编译器实现中看到的大量意大利面。我使用ANTLR,JavaCC和自定义递归下降解析器实现了各种不同语言的解析器,当语言变得非常庞大而复杂时,通常最终会生成一个huuuuuuge语法,并且解析器的实现真的很难看。
理想情况下,为这些语言之一编写解析器时,最好将它作为可组合的解析器的集合实现,并在它们之间来回传递控制。
棘手的是,通常,包含的语言(例如Perl)为包含的语言(例如,正则表达式)定义它自己的终点标记。这里有一个很好的例子:
my $result ~= m|abc.*xyz|i;
在这段代码,主要Perl代码定义了一个非标准的终点“|”为正则表达式。实现正则表达式解析器完全不同于perl解析器会非常困难,因为正则表达式解析器不知道如何在不查询父解析器的情况下找到表达式终点。
或者,可以说我有这使得LINQ表达式中包含一种语言,但不是以分号结束(如C#一样),我想责成LINQ表达式出现在方括号内:
var linq_expression = [from n in numbers where n < 5 select n]
如果我在母语语法中定义了Linq语法,我可以使用语法向量来轻松地为“LinqExpression”编写一个明确的生成以找到括号。但是,那么我的父语法将不得不吸收整个Linq规范。这是一个阻力。另一方面,一个单独的子Linq解析器将会很难找出停止的地方,因为它需要为外部的令牌类型实现前瞻。
而且这几乎排除使用单独的lexing/parsing阶段,因为Linq解析器会定义一个完全不同于父解析器的不同标记化规则集。如果您一次扫描一个令牌,您怎么知道何时将控制权交还给母语的词法分析器?
你们认为什么?现在可用的最佳技术是实现用于在较大的父语言中包含迷你语言的独特的,分离的和可组合的语言语法?
OMeta有这个!您可以将多个语法组合在一起,或者甚至可以继承OOP样式中的现有语法。 – CMCDragonkai 2014-11-05 13:31:38