引入
在查询语句的原始解析过程中,应用到Flex和Bison工具:
/*
* raw_parser
* 原始解析器
* Given a query in string form, do lexical and grammatical analysis.
* 输入查询字符串,做词法和语法分析
* Returns a list of raw (un-analyzed) parse trees.
* 返回原始语法解析树列表
*/
List* raw_parser(const char* str, List** query_string_locationlist)
{
......
/* 初始化 flex scanner */
yyscanner = scanner_init(str, &yyextra.core_yy_extra, ScanKeywords, NumScanKeywords);
......
/* 初始化 bison parser */
parser_init(&yyextra);
/* 解析! */
yyresult = base_yyparse(yyscanner);
/* 清理释放内存*/
scanner_finish(yyscanner);
......
return yyextra.parsetree;
}
Flex/Bison简述
从使用的角度讲,Flex和Bison是Linux下两个用来生成程序的工具,它们生成的程序分别叫做词法分析器和语法分析器。Flex和Bison可以处理结构化输入,一般结合使用来处理复杂的文件解析工作。
Flex生成的词法分析器将输入拆分成一个个记号(token),例如:
// eg1
A = B + C ;
// tokens
A, =, B, +, C, ;
其中变量名A,B,C被识别为标识符,=,+被识别为运算符,;被识别为终结符代表着语句中止。
// eg2
SELECT c_id FROM client ;
// tokens
SELECT, c_id, FROM, client, ;
其中SELECT,FROM被识别为关键字,而列名c_id,表名client为标识符,;为终结符。
而Bison生成的语法分析器根据已有的规则,分析这些tokens的组合,是否符合语法规范。
Flex&Bison的工作原理大致如上图示;felx文件(.l)和bison文件(.y)通过flex&bison处理之后产生felx和bison输出文件,在经过编译链接就可以得到一个词法&语法分析器的可执行程序,对输入进行原始解析。
文件结构
Flex文件(.l文件)和Bison文件(.y文件)由三部分组成:
- 定义部分
- %%
- 规则部分
- %%
- 用户附加的C语言部分
其中%%是段分隔符,位于两相邻部分之间(不可省略)。
定义部分
定义部分可以进行声明和选项设置。另外,如果有被 “%{” 和 “%}” 包围的部分,其中的内容会被完整地复制到 .yy.c 生成文件的开头,通常会用来放置include、define的信息。例如:
%{
#include "stdio.h"
%}
对于bison文件,在这之后,一般还要进行token设置。token设置的语法是:%token 记号,例如:%token NUMBER;一行可以声明多个记号,例如:%token ADD SUB MUL DIV。
记号大概就是每个语法树的节点,比如一个变量、一个数字/字符串常量、一个运算符,这些记号将被用于规则部分:通常是:flex中匹配到某个词,然后{return NUMBER;}返回一个记号,然后在bison的规则中查找应该进行的动作。
规则部分
这部分主要描述规则,形式为:正则表达式 {匹配到之后执行的C代码}。例如(注:行首不可留白):
[0-9] {printf(“NUMBER %s\n”,yytext);}
C语言部分
这部分是C语言代码,它们会被复制到 .yy.c 生成文件的最末。通常用于一些未定义接口的定义以及用户自定义函数,例如:
int yywrap()
{
return 1;
}
总结
通过查询资料,在本篇博客中我简单总结了flex&bison的工作原理和文件结构,在下一篇中我将对 /parser/scan.l 的文件内容进行简单的学习和解读。