### 引言
本文介绍查询解析的第二步:语法分析。语法分析是从词法分析器中获得带有属性的token后,根据tokens的属性匹配语法规则,最后获得一棵分析树。本文首先介绍词法分析基本原理,然后介绍海山数据库中使用的yacc工具,最后对语法分析gram.y进行解析。
基本原理
语法分析器识别模式的方法主要分为两种:自顶而下的分析方法和自底而上的分析方法。自顶而下的方法从分析树的根节点开始向叶节点构建,自底而上的方法反之,从叶节点开始构建。两种分析方法中,语法分析树总是按照从左到右的方式被扫描,每次通过词法分析器获得一个词法单元,如下图所示:
语法分析器依次从词法分析器中获得词法单元,类似于词法分析器中依次读入字符,然后从词法单元中匹配语法规则。
海山数据库中使用的yacc工具采用自底向上的方法,因此本文主要介绍该类方法。
在介绍该方法的具体实现之前,首先介绍文法的概念。
文法:
文法是描述词法、语法规则的工具。用一组规则严格定义句子的结构,一个例子如下:
E -> E + T | T
T -> T * F | F
F -> (E) | id
E
是开始符号,代表了所描述语言的最顶层结构。所有合法的句子都是从开始符号开始推导得到的。
这里的每一个表达式被称为产生式
,式中的|
为或,表示E
可以被E+T
或者T
替换。
产生式中的
E
、T
、F
是非终结符号
,相当于一个非叶节点,如T
可以被进一步展开为T * F | F
,而这里的id
,+
,*
,(
,)
是终结符
号,相当于一个叶节点,无法再被展开。
自底向上的文法分析过程可以被看做输入tokens规约为文法开始符号的过程。
假设由词法分析器获得的tokens属性为id*id
,自底向上的分析流程如下:
第一次规约将最左边的id
规约为F
,得到F*id
;
第二次规约将F
规约为T
,生成T*id
;
第三次规约将id
规约为F
,得到T*F
;
第四次规约将T*F
规约为T
;
第五次将T
规约为E
,到达文法开始符,规约结束。
在具体的实现中,采用了移入-规约的语法分析技术,使用一个栈来保存文法符号,使用输入缓存区来存放将要进行语法分析的其他符号,上面的例子具体的实现方式如下图所示:
step | 栈 | 输入 | 动作 |
---|---|---|---|
1 | $ | id*id | 移入 |
2 | $id | *id | 按照F ->id规约 |
3 | $F | *id | 按照T -> F规约 |
4 | $T | *id | 移入 |
5 | $T* |