ben*_*ith 8 dsl grammar parsing mini-language
有很多编程语言支持包含迷你语言.PHP嵌入在HTML中.XML可以嵌入JavaScript中.Linq可以嵌入C#中.正则表达式可以嵌入Perl中.
// JavaScript example
var a = <node><child/></node>
Run Code Online (Sandbox Code Playgroud)
想想看,大多数编程语言都可以建模为不同的迷你语言.例如,Java可以分为至少四种不同的迷你语言:
能够将这四种概念语言实现为四种不同的语法肯定会减少我在复杂的解析器和编译器实现中经常看到的许多意义.
我之前已经为各种不同类型的语言实现了解析器(使用ANTLR,JavaCC和自定义递归下降解析器),当语言变得非常庞大和复杂时,你通常会得到一个huuuuuuge语法,并且解析器实现得到非常难看真的很快.
理想情况下,在为其中一种语言编写解析器时,最好将它作为可组合解析器的集合实现,在它们之间来回传递控制.
棘手的是,通常,包含语言(例如,Perl)为包含的语言(例如,正则表达式)定义其自己的终点标记.这是一个很好的例子:
my $result ~= m|abc.*xyz|i;
Run Code Online (Sandbox Code Playgroud)
在此代码中,主perl代码定义了一个非标准的终端"|" 用于正则表达式.实现与perl解析器完全不同的正则表达式解析器将非常困难,因为正则表达式解析器不知道如何在不咨询父解析器的情况下找到表达式终结符.
或者,假设我有一种允许包含Linq表达式的语言,但不是用分号终止(如C#所做的那样),我想强制Linq表达式出现在方括号内:
var linq_expression = [from n in numbers where n < 5 select n]
Run Code Online (Sandbox Code Playgroud)
如果我在父语言语法中定义了Linq语法,我可以轻松地使用语法前瞻为"LinqExpression"编写一个明确的生成来查找括号外壳.但是我的父语法必须吸收整个Linq规范.这是一个阻力.另一方面,单独的子Linq解析器将很难确定停止的位置,因为它需要为外部令牌类型实现前瞻.
这几乎排除了使用单独的lexing/parsing阶段,因为Linq解析器将定义一组完全不同于父解析器的标记化规则.如果您一次扫描一个令牌,您如何知道何时将控制权传递回母语词法分析器?
你们有什么感想?今天有哪些最佳技术可用于实现不同的,解耦的和可组合的语言语法,以便在较大的父语言中包含迷你语言?
解析是问题的一个方面,但我怀疑与每种迷你语言相关的各种可执行解释器之间的互操作可能更难解决。为了有用,每个独立的语法块必须与整体上下文一致(否则最终的行为将是不可预测的,因此无法使用)。
虽然我不明白他们真正在做什么,但FoNC是一个非常有趣的寻找更多灵感的地方。他们似乎(我猜)正朝着一个允许各种不同的计算引擎无缝交互的方向发展。