本文的内容来源于本人阅读 flex & bison的笔记和项目工程学习中遇到的问题。如果你能从中获得一丝丝帮助,本人将不胜荣幸。
文章目录
- Ⅰ、目录与批注
- 前四章 引言和使用介绍
- flex 规范参考
- bison 参考规范
- 其余内容
- Ⅱ、相关练习代码
- 学习历程
- 代码实例
- 参考文献
Ⅰ、目录与批注
前四章 引言和使用介绍
页 码 | 批注 | 备注 |
---|---|---|
19 | 各部分通过%% 分割,其分别为 声明;模式与动作 和 C代码 | |
24 | atoi :ascii to integer yylval:这个变量用来储存记号值,定义为整型 | |
25 | yacc:yet another compiler compiler antlr:another tool for language recognition | java 的一个自定义语法编译器 和 bison 前身的全称 |
26 | 上下文无关文法 CFG 巴克斯范式 31BNF | |
31 | 如果一种文法是有歧义的,bison会报告在冲突(conflicts),而且标示出针对给定的输入哪里会有两种不同的分析。优先级 和 分组会解决二义性 还有 GLR处理二义性和任意的向前看符号 | |
ChapterⅡ | flex 的 使用 | |
35 | 正则表达式使用元语言?? | 与对象语言相对,指描写和分析某种语言所使用的一种语言或符号集合;《语言与语言学词典》对语言学的解释是:纯理语言,指用来分析和描写另一种语言的语言或一套符号 |
36 | 正则表达式字符 | |
38 | flex如何处理二义性 | 尽可能多地匹配字符;匹配更早出现的模式 |
40 | 开头设定%option noyywarp 来要求其不使用yywarp yyrestart(f)读取输入输出文件 f; | |
42 | flex有灵活的三层输入结构 yyin 来读取所需文件 输入缓冲区 重定义yy_input 其使用yy_buffer_state的数据结构来处理输入 | |
43 | unput(c)的调用可以把字符 c 退回输入流 | |
44 | 所有没有被匹配的输出都将拷贝到yyout中 设置%option nodefault,使其不添加默认的规则,这样当输入无法被给定的模式匹配时,词法分析器可以报告一个错误。 起始状态:其运行在特定时刻哪些状态被匹配 %x %s | |
47 | flex 提供一个叫yylineno的变量,其被用来记录行号。我们可以直接使用它。 | |
49 | case_insensitive 其要求flex生成一个大小写无关的词法分析器 | |
51 | 符号表 名字的查找:线性探索的哈希法。每个字符用 9 承之前的哈希值,让后再异或这个值。 | |
52 | yytext中的字符串被在下一个词法记号被分析时替换掉。 | |
58 | fiFL的作用 字符常量 单引号 开始 ,单引号结尾 ‘ ’ | 问题 |
Chapter Ⅲ | bison 的 使用 | |
63 | flex讲输入流分解成若干个片段,bison则分析这些记号并基于逻辑进行组合。 左部:LHS 右部:RHS | |
64 | bison不会自动地为我们创建语法分析树,需要我们自己实现。 | |
65 | bison处理时,其创建一组状态,每个状态都反映出一个或多个分析过的规则在可能的位置 移进:当语法分析器读取记号,无法结束一条规则时,将其压入一个堆栈,让后切换到一个新的状态,此状态反映了刚刚读取的记号。 规约:如果压入的符号可以组成规则的右部,将其全部从堆栈弹出,让后左部符号压入堆栈。 | (例子) |
66 | LALR(1):LALR(1)全称为lookahead-LR(1),是由LR(1)语法分析器变来的,其中L(Left Scan)表示自左向右处理输入,R(Right Reduce)表示生成最右推导,而数字1表示使用先行1个符号。 第三章 LALR(1)的构造_lalr(1)_Bash_linux的博客-CSDN博客 而LALR(1)简化了LR(1),采用合并同心集方法,大大缩小了LR(1)的自动机状态规模,功能介于SLR(1)与LR(1)之间,但应用于目前的语言,已经绰绰有余。YACC就是使用这种分析方法。 | |
67 | 三部分组成:定义;语法分析器的规则;C代码 bison定义的规则会被编译成数组的形式,其内容代表了可以匹配输入记号的状态机。 | |
69 | %union定义符号值的类型,定义完后要声明%type <> 没有显示的语义动作时,规则默认语义$$ = $1; | |
70 | 文字字符记号:记号的ASCII 就是记号的编号。 | |
71 | yyval 现在是联合类型,双精度浮点数的值不不给yyval.d | |
72 | eval(调用计算)和 free是都采用深度优先 | |
73 | flex 的 -o 参数 | |
76 | 声明优先级:%left %right %noassoc 负数规则%prec | |
77 | 一个高级计算器的flex bison 代码实现(错误恢复机制) | |
79 | 用户自定义的函数 ufcall 节点; 控制流使用 flow节点。 | |
81 | list的 定义是右递归的,否则使用更麻烦。 | |
83 | 简单的错误恢复:放弃错误后续的语法符号,直到达到一个记号为error为有效的点;接着开始忽略后续的输入,直到找到一个可以被移进的记号,让后从此处继续开始分析。 | |
Chapter Ⅳ | 分析 SQL | |
96 | MySql的输入是bison分析的。 | |
100 | 逆波兰式的优点 | |
105 | btwode 的切换(因为 and 有 &&的意思 还有 between and的意思) | |
107 | 问题:mysql中的 = 号除了比较 | |
109 | 语法分析器 匹配长度可变的项目列表 | |
113 | 子代码是基于位编码的 | |
114 | 函数 | |
116 | select 语句的 语法规则**(可选的)** |
flex 规范参考
页 码 | 批注 | 备注 |
---|---|---|
20 | flex 基础命名 | |
133 | 结构规范 | |
134 | BEGIN 宏 | |
135 | 上下文相关性 特殊的行首模式 ^ $ ;起始状态;显示代码; 2.07 Flex如何处理上下文相关性_如何做上下文相关性处理_ronnie88597的博客-CSDN博客 定义 替换 | |
137 | echo | |
137 | 标准输入文件链 yyrestart(file)来使得词法分析器读取任意标准输入文件 | |
137 | 输入缓冲区 | |
139 | 使用c++编辑 input 改为 yy_input 避免冲突 | |
140 | 交互 和 批处理模式下的 词法分析器 | |
141 | 文字块 | |
142 | 多重词法分析器 | |
143 | 144 | 字符集 EBCDIC |
146 | 可重入词法分析器 嵌套文件 多重词法分析器 | |
150 | yylex 的返回值 %s 共享模式 %x 独占模式 yylex | |
flex 的变量 与 函数 | ||
151 | unput()返回字符给输入流; yyless 和 unput 效果一样,但yyless 通常更快 | |
152 | yyleng () = strlen(yytext) | |
153 | 问题 yy_decl | |
154 | /第四部分 函数 function/ int yywrap() { /此函数必须由用户提供,或者声明 %option noyywrap当词法分析程序遇到文件结尾时,它调用例程yywrap()来找出下一步要做什么如果返回0,扫描程序继续扫描,如果返回1,扫描程序就返回报告文件结尾/ return 1; } yywarp 的 作用 |
bison 参考规范
页 码 | 批注 | 备注 |
---|---|---|
155 | 三部分组成 定义 %% 规则 %% 用户子例程 | |
156 | 定义;动作 | |
157 | 嵌入动作 | |
159 | 移进 规约冲突 输入字符存在两种可能的语法分析器 一般bison选择移进 归约 归约冲突 一个记号可以结束两条不同规则的时候 选择先出现的那条规则进行归约 当GLR语法分析器遇到冲突时,理论上其会分裂出并行的两种可能的分析 %expect | |
161 | bison 列表中一个结束标记 伪符号 $end %code | |
162 | bison从 错误分析中恢复,其从分析器堆栈中 抛弃符号 和 符号值 | 错误恢复 |
163 | 继承属性 ($0) | |
164 | 词法反馈 :从语法分析器反馈上下文信息 给 词法分析器 | |
166 | 位置 %location | |
168 | 优先级声明 | |
170 | bison 处理左递归 要比 右递归 (如果列表中的元素个数很少而且你需要把他们存到一个链表中时,右递归更有用)更有效率。 规则堆栈大小 TTINITDEPTH | |
173 | 特殊字符 $ 引入一个值引用 @ 引入一个位置引用 | |
174 | %start 声明 声明符号类型 %union | |
176 | 记号 编号 -d生成的文件内 查看 tab.h包含了与语法分析器相关的声明、常量和数据结构。其他源文件(如Flex的源文件)需要包含此头文件,以便正确地使用语法分析器生成的标记(tokens)和语法规则。 | |
177 | %union %type | |
178 | 可变语法和多重语法;合并的语法分析器 | |
179 | %name-prefix 或者 -p标志 注意:在运行项目的时候,编译器对我进行警告,这个已经过时,最新的用法应该是 %define api.prefix { xxx } | |
180 | y.output文件 --report = all | |
181 | bison 库文件 yyabort yyaccept yybackup 移出当前符号并替换为 另一个记号 yyclearin 放弃预读符号 yydebug yyerrork 其用来让语法分析器回到正常 yyerror yyparse |
其余内容
页 码 | 批注 | 备注 |
---|---|---|
CHAPTER Ⅶ | 二义性冲突 | |
187 | 指针模型:一个指针将会在每次读到一个记号时在bison语法中移动。 | |
188 | ||
189 | 冲突类型 | |
191 | 语法分析器状态 -v 生成 output文件(其内为所有状态机的) | |
192 | 6A 的归约 | 问题(解决) |
193 | 归约 归约冲突:在冲突发生时,未被选择的规则在方括号中,其总是选择更早出现的规则来解决 归约 归约冲突 | |
195 | 移进 归约冲突: bison 总是选择移进来解决 冲突 | |
198 | 常见的三种 冲突情况 表达式语句(语法是递归的);if/then/else;嵌套列表(嵌套循环) 移进归约 冲突;规则的重叠 (归约 归约 -> GLR语法) 大多数的移进 归约冲突来源于 bison有限的向前查看 | |
CHAPTER Ⅷ | 错误报告 与 恢复 | |
213 | 为语法分析器添加位置信息 使用了yyloc内的位置 信息 和一个新的 lyyerror | |
215 | 带有文件名的位置信息 | |
218 | 错误恢复技巧:尝试在输入流中向前移进足够远,这样新的输入就不会被旧的输入所影响 | |
219 | %destructor 声明:让bison知道弹出一个具体语义值符号时应该做什么 | |
220 | 交互式语法分析器 的 恢复;先用yyclearin 放弃预读的内容;再用yyerrok 重新开始正常的分析; | |
CHAPTER Ⅸ | 两者的进阶 | |
223 | 纯 词法 语法 分析器的概念: <> 把所有静态数据结构替换为参数传递给词法分析器和语法分析器中的例程 | |
224 | 纯 flex | |
225 | 将原本的静态数据改为 指向我们的实例数据 | ⭐ |
228 | %option bison-bridge bison-location reentrant | |
244 | GLR分析 | |
247 | 设定GLR语法分析器 | |
249 | c版 的 flex 和 C++的bison联合 |
Ⅱ、相关练习代码
学习历程
在学习过程中,根据龙书的前几个章节又重新了解了一下编译原理,这个方向还是比较难理解的。我是由于工程的原因需要去使用flex and bison。因此我的工作停留在应用层面应该是足够了的。想深度理解编译原理这个课题龙书应该是最专业的入门了,有需求的同学可以去看一下。这些教材的中文版github都是可以找到pdf版本的。
我的学习历程是先阅读了两本书才接触的代码,虽然在阅读过程中也结合着例子进行代码编写,但理解程度远不如去看工作中的一整个项目理解的快和好。在接触工程代码前,推荐先认真去看一下flex and bison 第三章的那个两者结合的例子,代码包含在下方代码链接的bison文件夹下。
代码实例
这个算是flex 和 bison一起使用来进行一个计算机程序的编写,从中可以理解如何运用flex进行词法分析,使用bison进行语法分析并且两者结合起来后的一些规范,如重命名,flex的c代码在bion中进行使用。对于初学者建议注意bison -d 生成的 tab.h 文件,对理解会有所帮助。
额外提一点,虽然编译器是先进行词法分析,在进行语法分析。但对于flex 和 bison的编译则是先进行bison -d 的选项,详细看上文行。因为bison文件内含有预先定义好的 token 等一些列关键字,而flex的作用就是去识别他们。具体也可去看下方flex-bison-code内的makefile文件。
参考文献的第三篇也可以好好读一下,可以更好地理解两者的工作原理和他们在工程中的应用。
flex-bison-code
参考文献
- flex & bison
- Compilers: Principles, Techniques, and Tools
- Flex(scanner)/Bison(parser)词法语法分析工作原理
- 第三章 LALR(1)的构造_lalr(1)_Bash_linux的博客-CSDN博客