《领域特定语言》一3.4 解析中的数据

3.4 解析中的数据

当解析器执行时,它需要存储解析过程中的数据。这些数据可能是一个完整的语法树,但大多数情况下不是这样的。即使这种情况出现了,还是需要存储其他的一些数据,以便解析工作可以正常进行。
解析本质上是一种树遍历(见图3-3),当处理某一部分DSL脚本时,对于正在处理的语法树分支,我们可以得到其上下文的一些相关信息。然而,通常我们还会用到这个分支以外的信息。我们再从状态机的例子里选取一段代码看看:

commands
  unlockDoor D1UL
end

state idle
  actions {unlockDoor}
end

我们在这里看到了一种常见的情况:命令定义在语言的某个地方,然后在其他地方引用。当命令在语句的行为中引用时,我们所在的语法树分支不同于命令定义的分支。如果语法树的表示只存在于调用栈中,那么到这里,命令定义就已经消失了。因此,要把命令对象保存下来以备后用,这样,在行为代码中就可以引用了。

为了做到这一点,我们用到了“符号表”(第12章),它本质上是一个字典,其键是标识符unlockDoor,值是在解析中表示命令的对象。当处理文本unlockDoor D1UL时,创建一个对象持有数据,然后,把它存放在符号表里,键为unlockDoor。存放的对象可能是命令的语义对象,也可能针对局部语法树的中间对象。稍后,当处理actions {un lockDoor}时,我们会通过符号表查找这个对象,以获得状态同行为之间的关系。因此,符号表对于交叉引用至关重要。如果在解析中创建一棵完整的语法树,理论上,可以省略符号表,虽然通常它依然是一个有用的结构,可以把事物关联起来。
在本节结束之前,我们看两个具体的模式。之所以在这里提起它们,是因为内部DSL和外部DSL都会用到。所 以,这里是个合适的地方,即便本章讨论的大多是一些高层次的内容。
当进行解析时,要保存结果。有时,所有结果都可以放到符号表里;有时,许多信息要保存在调用栈里;还有时,要在解析器里有额外的数据结构。在所有这些情况里,最明显要做的一件事是,创建“语义模型”(第11章)对象保存结果。然而,在很多情况下,要到解析的最后时刻才能创建语义模型,所以,还要创建一些中间对象。对于这种中间对象,一个常见的例子是“构造型生成器”(第14章),它是一个对象,包含语义模型所需的全部数据。如果语义模型在创建后就是只读的,这种做法就非常有用了,可以在解析过程中逐步地为它收集数据。构造型生成器拥有同语义模型一样的字段,但这些字段是可读写的,这样,就有地方保存数据了。一旦有了所有数据,就可以创建语义模型对象了。使用构造型生成器会让解析器变得复杂,但相比于改变语义模型的只读属性,我宁愿选择这么做。
事实上,有时候,我们会在处理完所有DSL脚本时,再创建语义模型对象。在这种情况下,解析就会有不同的阶段:首先,读取DSL脚本,创建中间的解析数据,其次,处理中间数据,组装语义模型。在文本处理阶段做多少工作,后面做什么,这取决于语义模型如何组装。
表达式的解析方式取决于我们处理的上下文。查看下面这段文本:

state idle
  actions {unlockDoor}
end

state unlockedPanel
  actions {lockDoor}
end

当处理actions{lockDoor}时,有一点很重要,它处于unlockedPanel状态的上下文中,而非空闲态。通常,解析器构建以及遍历解析树的方式,就提供了这个上下文,但还有很多情况,很难做到这一点。如果检查解析树无法获得上下文,那么一种好的做法就是,持有上下文,对于这个例子,我们可以把当前状态保存在一个变量里。我将这种变量称为“语境变量”(第13章)。这种语境变量类似于符号表,可以持有语义模型对象,或者一些中间对象。
虽然语境变量用起来很简单,但一般来说,我倾向于尽可能避免使用。语境变量会让解析代码难于理解,正如大量的可变变量会让过程式代码变得复杂。当然,肯定会有无法避免使用语境变量的情况,但我更倾向于将其视为应该避免的坏味道。

时间: 2024-09-20 23:41:36

《领域特定语言》一3.4 解析中的数据的相关文章

《领域特定语言》一导读

前 言 在我开始编程之前,DSL(Domain–Specific Language,领域特定语言)就已经成了程序世界中的一员.随便找个UNIX或者Lisp老手问问,他一定会跟你滔滔不绝地谈起DSL是怎么成为他的镇宅之宝的,直到你被烦得痛不欲生为止.但即便这样,DSL却从未成为计算领域的一大亮点.大多数人都是从别人那里学到DSL,而且只学到了有限的几种技术. 我写这本书就是为了改变这个现状.我希望通过本书介绍的大量DSL技术,让你有足够的信息来做出决策:是否在工作中使用DSL,以及选择哪一种DSL

《领域特定语言》一第2章 使用DSL 2.1定义DSL

第2章 使用DSL 看过上一章的例子后,即便尚未给出DSL的一般定义,对于何为DSL,你也应该已经有了自己的认识.(第10章中有更多例子.)现在,要开始讨论DSL的定义及其优势与问题.这样就可以为下一章讨论DSL实现提供一些上下文. 2.1定义DSL "领域特定语言"是一个很有用的术语和概念,但其边界很模糊.一些东西很明显是DSL,但另一些可能会引发争议.这一术语由来已久,不过,正如软件行业中的很多东西一样,它也从未有过一个确切的定义.然而,就本书而言,定义是非常有价值的.领域特定语言

如何设计一门编程语言(十) 正则表达式与领域特定语言(DSL)

几个月前就一直有博友关心DSL的问题,于是我想一想,我在gac.codeplex.com里面也创建了一些DSL,于是今天就来说一说这个事情. 创建DSL恐怕是很多人第一次设计一门语言的经历,很少有人一开始上来就设计通用语言的.我自己第一次做这种事情是在高中写这个傻逼ARPG的时候了.当时做了一个超简单的脚本语言,长的就跟汇编差不多,虽然每一个指令都写成了调用函数的形态.虽然这个游戏需要脚本在剧情里面控制一些人物的走动什么的,但是所幸并不复杂,于是还是完成了任务.一眨眼10年过去了,现在在写Gac

《领域特定语言》一第1章 入 门 例 子1.1 哥特式建筑安全系统

第1章 入 门 例 子 落笔之初,我需要快速地解释一下本书的内容,就是解释什么是领域特定语言(Domain– Specific Language,DSL).为达此目的,我一般都会先展示一个具体的例子,随后再给出抽象的定义.因此,我会从一个例子开始,展示DSL可以采用的不同形式.在第2章里,我会试着把这个定义概括为一些更广泛适用的东西. 1.1 哥特式建筑安全系统 在我的童年记忆里,电视上播放的那些低劣的冒险电影是模糊却持久的.通常,这些电影的场景会安排某个古旧的城堡.密室或走廊在其中起着重要的作

《领域特定语言》一1.3 为格兰特小姐的控制器编写程序

1.3 为格兰特小姐的控制器编写程序 至此,我们已经实现了状态机模型,接下来,就可以为格兰特小姐的控制器编写程序了,如下所示: Event doorClosed = new Event("doorClosed", "D1CL"); Event drawerOpened = new Event("drawerOpened", "D2OP"); Event lightOn = new Event("lightOn&quo

《领域特定语言》一第3章 实现DSL 3.1DSL处理之架构

第3章 实现DSL 至此,对于什么是DSL,以及为何要用DSL,我们已经透彻理解.如果要开始构建DSL,那么现在该深入研究所用的技术了.虽然构建内部DSL和外部DSL所用的技术有所不同,但它们还是有一些共通之处的.本章主要关注内部DSL和外部DSL的一些共通问题,而下一章再讨论各自具体的问题.本章先不谈语言工作台,留待后续探讨. 3.1DSL处理之架构 关于DSL实现的大体结构(见图3-1),也就是所谓的DSL系统架构─可能是我们要谈论的最重要的内容之一. 迄今为止,你应该已经厌倦了听我说了无数

《领域特定语言》一2.4 广义的语言处理

2.4 广义的语言处理 本书是关于领域专用语言的,但它也涉及语言处理技术.之所以二者重合,是因为在普通的开发团队里,用到语言处理技术的情况,90%都是为了DSL.但是,这些技术也可以用于其他方面,若不讨论这些情况,将是我的失职.我曾遇到过这方面一个很好的例子,那是在一次拜访ThoughtWorks项目团队时.他们有一个任务,要与某第三方系统通信,发送的消息以COBOL copybook定义.COBOL copybook是一种用来描述记录的数据结构格式.因为系统中有很多地方要用到,所以我的同事Br

《领域特定语言》一3.2解析器的工作方式

3.2解析器的工作方式 所以,内部DSL和外部DSL的差别主要体现在解析上.虽然二者确实存在一些细节上的不同,但它们也有很多共通之处.一个最重要的共同点就是,解析都是一个很强的层级操作.当解析文本时,把数据块组织成一个树结构.考虑一个简单结构,状态机中的事件列表.在外部DSL语法中,它看起来如下所示: events doorClosed D1CL drawerOpened D2OP end 这个复合结构是一个事件列表,包含一系列事件,每个事件都有名字和代码.用Ruby编写的内部DSL与上述代码很

《领域特定语言》一1.2 状态机模型

1.2 状态机模型 一旦团队达成共识,认为对于指定控制器如何运作而言,状态机是一个恰当的抽象,那么,下一步就是确保这个抽象能够运用到软件自身.如果人们在考虑控制器行为时,也要考虑事件.状态和转换,那么,我们希望这些词汇也可以出现在软件代码里.从本质上说,这就是领域驱动设计(Domain–Driven Design)中的Ubiquitous Language [Evans DDD] 原则,也就是说,我们在领域人员(那些描述建筑安全该如何运作的人)和程序员之间构建的一种共享语言.对于Java程序来说