(三十九)深度解析领域特定语言(DSL)第七章——语法制导翻译——参数验证DSL语法分析器实现
所以您会在图 7.10看到类似new CompareNode(“#e > 0”)的代码,表示新建一个“比较”类型的语法树节点,其中的字符串表示具体的比较表达式,不过仅用于展示的目的。同样的道理,代码new LogicalNode("or", "#e > 20", "#e < 30")表示新建一个“逻辑运算”类型的语法树节点,其内部引用了两个比较类型的节点,具体的引用目标也需要通过对应的语义规则索引
了解过L型SDD的基本概念及其对应的递归下降语法分析器实现模式之后,下面继续对前文所遗留的内容进行阐述。对于参数验证DSL案例所涉及的语义模型和文法,笔者已经在前文中给出说明,可参考如下两篇:语义模型、文法,此处不再赘述。另外,由于原始文法之中存在左递归,并不适合自顶向下的语法分析,所以笔者在文法7-2中给出了变换后的文法,其对应的SDD自然也会以新文法为基础进行设计,如SDD 7-4所示:
p1) START -> GROUP REST |
SDD (7-4) |
r1) REST.inh = GROUP.node r2) START.node = REST.syn |
|
p2) REST -> LOGICAL GROUP REST1 |
|
r3) REST1.inh = new LogicalNode(LOGICAL.syn, REST.inh, GROUP.node) r4) REST.syn = REST1.syn |
|
p3) REST -> ε |
|
r5) REST.syn = REST.inh |
|
p4) GROUP -> '(' START ') ' |
|
r6) GROUP.node = START.node |
|
p5) GROUP -> COMPARE |
|
r7) GROUP.node = COMPARE.node |
|
p6) COMPARE -> '#e' RELATION 'number' |
|
r8) COMPARE.node = new CompareNode(number, RELATION.syn) |
|
p7) COMPARE -> 'number' RELATION '#e' |
|
r9) COMPARE.node = new CompareNode(number, RELATION.syn) |
|
p8) RELATION -> '>=' | '>' | '<=' | '<' | '=' |
|
r10) RELATION.syn = relation.lexeme |
|
p9) LOGICAL -> 'and' | 'or' |
|
r11) LOGICAL.syn = logical.lexeme |
文法与语义规则内容较多,所以笔者变更了一下SDD的书写方式。另外,按照惯例,我们通常会使用inh来表示继承属性,其他属性如syn、node等如无特别说明的话则一般用于表示综合属性。下面,让我们以DSL“#e > 0 and (#e > 20 or #e < 30)”为例,看一下它所对应的语法分析树,如图 7.9所示。
图 7.9 表达式#e > 0 and (#e > 20 or #e < 30)所对应的语法分析树
尽管图 7.9看起来比较复杂,但却可以反应出示例表达式的分析过程。设计SDD的时候,笔者个人的经验如下:
- 首先按照文法规则及输入示例,画出一棵语法分析树,以此来验证语法的正确性。
- 在语法分析树基础上加入语义规则,形成一棵注释语法分析树。
- 以注释语法分析树为基础,观察数据在节点之间是如何传递的,并验证语义规则是否正确。
图 7.9所示的语法分析树引入语义规则后,将生成如图 7.10所示的注释语法分析树。为降低图示复杂度,笔者有意移除部分可能干扰阅读的节点,并对属性值内容进行适当简化,避免图示过于繁杂。实际操作中,建设读者手动绘制注释语法分析树——尽管专业绘图软件能产出美观图形,但所需时间成本较高。
图 7.10 表达式#e > 0 and (#e > 20 or #e < 30)所对应的注释语法分析树
尽管经过了简化,但本案例所涉及的注释语法分析树还是非常复杂的,以至于笔者不得不将属性信息放置到单独的表中进行展示。请读者结合SDD 7-4及图 7.10,按照图中序号的顺序一步一步地对表达式“#e > 0 and (#e > 20 or #e < 30)”所对应的语义规则进行验证。与减法表达式求值SDD不同的是,此处的语义规则主要用于构建语法树。所以您会在图 7.10看到类似new CompareNode(“#e > 0”)的代码,表示新建一个“比较”类型的语法树节点,其中的字符串表示具体的比较表达式,不过仅用于展示的目的。而GROUP.node = ("#e > 0")则表示使用了某个节点的引用,至于引用的是哪个节点,则需要通过语义规则信息索引进行查看。以图 7.10中表格的第二行为例,通过查看语义规则r7,我们可以知道GROUP.node的值所引用的是其子树的综合属性。同样的道理,代码new LogicalNode("or", "#e > 20", "#e < 30")表示新建一个“逻辑运算”类型的语法树节点,其内部引用了两个比较类型的节点,具体的引用目标也需要通过对应的语义规则索引进行查看。
需要再次强调的是,单纯的语法分析仅能验证源代码是否符合语法规则,而在实际应用中,通常还需要将语言翻译为某种中间形式(如语法树),或直接对语言进行翻译以获取最终结果,这些操作均需借助SDD相关知识。因此,本篇内容至关重要,建议读者务必充分理解后再开展后续内容的学习。
了解过SDD的定义之后,接下来开始代码展示环节。语法分析逻辑主要包含了如下三方面内容:
- 构建语法树。
- 遍历语法树,构建语义模型。
- 调用语义模型接口,对用户输入进行验证。
本篇内容虽然不多,但却非常的重要。再次强调一下:请读者首先理解,尤其是SDD 7-4和图 7.10间原关系,之后再学习其他的内容。
上一章 下一章
更多推荐
所有评论(0)