Bison 采用自底向上( bottom-up)的分析方法。

bottom-up 算法是 LR(1),最先由knuth 1965年提出,以 BNF 文法为指引,比 top-down 算法更为强大。算法构造用到有限状态机 (Finite State Machine),占用内存多,很复杂,实际中编译程序难以用纯手工构造,而是采用自动工具如 yacc/bison 辅助构造。

bison 实现的是 LR(1) 的一个子集 LALR(1),但已足够强大。文法采用上下文无关文法BNF,支持左递归、右递归和一般递归,不支持扩展 BNF。

Bison 的使用说明

一、使用 Bison 的流程

1. 创建语言描述文件 (.y 文件)
    2. 编写词法分析器函数 yylex()
    3. 编写错误报告函数 yyerror()
    4. 在 main() 中调用分析器函数 yyparse()
    5. 执行 bison -d,由 .y 文件 产生 .tab.c 和 .tab.h 文件
    6. 执行 gcc,把 .tab.c 文件编译和链接成可执行程序

例. 计算器项目 calc。
    calc.y
       |  bison -d calc.y
    calc.tab.c
    calc.tab.h
       |  gcc calc.tab.c -o calc
    calc

二、语言描述文件的组成

%{
1. 序言 (Prologue)
   声明全局标识符,定义数据类型、变量和宏,包含头文件,等。
%}

2. 声明 (declarations)
   声明终结符,非终结符,运算符的优先级,符号语义值的各种类型。

%%

3. 文法 (Grammar rules)
   定义每一非终结符的文法规则。

%%

4. 结言 (Epilogue)
   定义序言中声明的函数,以及剩余的所有程序。如 yylex(), yyerror(), main(), 等。

三、语言描述文件中的声明

1. 语素类型的结合性
    %left       声明左结合操作符
    %right      声明右结合操作符
    %token      声明无结合性的语素类型
    单字符语素原本不用声明,声明它们是指出其结合性。

2. token 的语义值
    若有,存储在全局变量 yylval (类型 YYSTYPE) 中。

四、词法分析器函数 yylex()

该函数实现功能:读入下一 token,返回它的编号。

例. 对于简化的 C语言。

1. 对于各种各样的数,编号 NUM。

2. 对于各种各样的字符串,编号 STR。

3. 对于各种各样的名称, 编号 ID。

4. 每一关键字有唯一的编号。
    例.
    关键字      编号
    int         INT
    double      DOUBLE
    if          IF
    while       WHILE
    return      RETURN
说明:这里把编号取为相应的大写,是为了方便记忆,并非必须。

5. 单字符 token 包括运算符和分隔符,如 '+', '-', ';', ',', 等。它们的编号为其自身,直接返回即可。

6. 输入结束,编号为 0。

如果把 token 的编号视作符号的分类,那么每个单字符自成一类。
    编号是一个整数,定义在 .tab.h 文件中,形如
    #define NUM 257
    #define ID  258
    ...

五、基本概念

1. BNF (Backus-Naur Form, 或 Backus Normal Form)
    John Backus 提出的描述上下文无关文法的范式。在 Peter Naur 的 Algol60 报告中做了少许改进。

2. 上下文无关文法 (Context-free grammars)
    描述不考虑上下文的规则的文法。如某规则说整数是表达式,那么,整数在任何地方都是一个允许的表达式。

3. 左递归 (Left recursion)
    规则中,右端的第一个符号与左端相同。如
exprs:    exprs ',' expr
        ;

4. 右递归 (Right recursion)
    规则中,右端的最后一个符号与左端相同。如
exprs:    expr ',' exprs
        ;

辨析:左递归比右递归更为自然,分析时占用内存也更少些。

5. 符号表 (Symbol table)
    用来存储和查询已存在符号的名称和相关数据的数据结构。

6. 终结符 (Terminal symbol)
    不可再分的文法符号。也称 token,中文称作语素、词法记号、记号、单词、符号等。

7. 非终结符 (Nonterminal symbol)
    可以表达为更小结构的文法结构。每一非终结符用一条规则来定义。

8. 开始符号 (Start symbol)
    一个特殊的非终结符,代表语言的开始。通常作为文法中的第一个规则。

9. LR(1)
    一种用于自底向上分析的上下文无关文法,大多数时侯需要一个预读语素来消除任何输入片段的歧义。

10. LALR(1)
    LR(1)的子集。Bison 采用的文法。

11. parser stack  分析栈
    自底向上分析算法用到的栈。

12. shift  移进
    把输入流中的下一个 token 移入分析栈。

13. reduce  归约
    归约分析栈顶中已识别的规则。当分析栈顶的符号序列匹配某规则右端时,用该规则的左端替换之。

14. look-ahead token  预读语素
    已读取、尚未移进的 token。

五、Bison 分析器算法

bison 采用自底向上 (bottom-up) 的分析方法。它用到一个分析栈 (parser stack),关键有两个动作:

1. 移进 (shift)
    读取的 token 移进到分析栈中。

2. 归约 (reduce)
    当分析栈顶的 n 个符号匹配某规则的右端时,用该规则的左端取代之。

自底向上算法要做的事情是,对于一个接一个读入的 token,何时移进,何时归约。LR(1) 中的 1表示,只需预读 1个语素,就可以确定是移进,还是归约。

在移进和归约的过程中,可能出现两类冲突。

1. 移进/归约冲突 (shift/reduce conflicts)
    在某一时刻,可以移进,也可以归约。是选择移进,还是归约?这就是移进/归约冲突。这种冲突可以接受。
    在出现移进/归约冲突时,bison 选择移进。

例. if 语句的文法。
stmt_if:  IF expr THEN stmt
        | IF expr THEN stmt ELSE stmt
        ;
    分析栈顶的符号序列是 IF expr THEN stmt,而当前符号是 ELSE。是移进?还是归约?bison 选择移进。

2. 归约/归约冲突 (Reduce/Reduce Conflicts)
    当分析栈顶的符号序列可归约到多于一个规则时,选择哪一个规则?这就是归约/归约冲突。这种冲突不可接受。这是文法中的严重错误,必须修改文法。
    在出现归约/归约冲突时,bison 选择归约到第一个匹配的规则。这十分冒险。

例. 定义包含 word 或 redirect 的序列。
sequence: /* empty */
        | sequence words
        | sequence redirects
        ;

words:    /* empty */
        | words word
        ;

redirects: /* empty */
        | redirects redirect
        ;

sequence, words 和 redirects 的定义单独来看没问题,但放在一起产生了歧义:一个空输入可以归约到这三个规则中的任何一个。

Bison 的构成与使用相关推荐

  1. flex和bison实例分析

    最近在学习编译原理,利用flex和bison编写一个基于文本识别的简单计算器程序,参考<flex于bison>中内容,对程序进行一些简单的修改,加入Makefile.该计算器程序主要实现识 ...

  2. ubuntu下安装flex和bison

    做编译原理作业时需要用到flex和bison,于是在Linux下安装了flex和bison apt install flex bison 新建一个文件,名为test.l %% [0-9]+ print ...

  3. PHP语法分析器:RE2C BISON 总结

    在这之前,我曾经尝试过一个项目,就是将我们的PHP代码自动生成so扩展, 编译到PHP中,我叫它 phptoc. 但是由于各种原因,暂停了此项目. 写这篇文章一是因为这方面资料太少,二是把自己的收获总 ...

  4. 【错误记录】编译 Linux 内核报错 ( /bin/sh: 1: bison: not found )

    文章目录 一.报错信息 二.解决方案 一.报错信息 编译 Linux 内核 , 执行 make menuconfig 配置菜单命令 , 报如下错误 : root@ubuntu:~/kernel/lin ...

  5. Flex和Bison简介和Windows下使用入门

    flex用作词法分析,而bison用作语法分析.词法分析把输入分解成一个个有意义的词块,称作token:语法分析则确定这些词块彼此之间如何关联(使用语法树表达). Flex可生成词法分析器:Bison ...

  6. 在windows下安装flex和bison、GCC

    学习Stellar-core 需要依赖项flex .bison .gcc三个依赖项 下载得网址: 链接: https://pan.baidu.com/s/1mitCLcs 密码: 3jaj   通过 ...

  7. 编译与解释实践(1)-flex and bison 配置安装

    sudo dnf instal flex bison 下面先开始测试flex 编辑test.l %option noyywrap //增加的语句 %{int chars = 0; int words ...

  8. 使用Flex Bison 和LLVM编写自己的编译器[zz]

    1.介绍 我总是对编译器和语言非常感兴趣,但是兴趣并不会让你走的更远.大量的编译器的设计概念可以搞的任何一个程序员迷失在这些概念之中.不用说,我也曾 今尝试过,但是并没有取得太大的成功,我以前的尝试都 ...

  9. 使用flex和bison实现的sql引擎解析

    因为老师要求,近期在做oceanbase存储过程的实现,在oceanbase 0.4曾经是不支持存储过程的.实现的主要步骤主要包含 1.语法解析 2.词法解析 3.详细运行语法树的步骤 如今先来说说语 ...

  10. 编译原理:利用yacc/bison进行语法分析

    YACC(Yet Another Compiler-Compiler)是一个LALR(1)分析器自动生成器,是贝尔实验室在UNIX上首次实现,与LEX有直接的接口.此外GNU(GNU is not U ...

最新文章

  1. Dockerfile构建实践
  2. Django中提供的6种缓存方式
  3. 美团面试:JVM 堆内存溢出后,其他线程是否可继续工作?
  4. linux route命令深入浅出与实战案例精讲
  5. response设置响应头
  6. 前端测试框架 jasmine 的使用
  7. python os.access_os.access(path, mode)
  8. 继续教育自动听课软件_荣耀小口哨app下载-华为荣耀小口哨软件v1.9.9 安卓最新版 - 极光下载站...
  9. linux调用堆栈函数,使用 backtrace 获得 Linux 函数调用栈
  10. C语言实现windows进程遍历
  11. 【原创】洛谷 LUOGU P3371 【模板】单源最短路径
  12. 基于J2EE的门诊挂号收费系统设计与实现.rar(毕业论文+程序源码+数据库文件)
  13. Linux文件压缩解压命令
  14. 仿射变换再次秒杀2011山东理科高考压轴题(圆锥曲线)
  15. 【游戏开发解答】Unity发布微信小游戏,中文字无法显示的问题(自制字体库 | Font | Custom set | 动态字体 | 静态字体)
  16. Code Review关注点
  17. 彷徨 | office快捷键大全
  18. Glide框架高斯模糊图片处理
  19. die_visual
  20. Eclipse官方汉化方法

热门文章

  1. 一行代码实现shell if else逻辑
  2. 网页导出pdf不完整_PDF 文件编辑方法和工具大全
  3. wps在线预览接口_金山文档在线编辑 - 快速接入 - 《WPS开放平台技术文档》 - 书栈网 · BookStack...
  4. 如何访问同一局域网内的其他电脑文件
  5. Java计算一个时间段与当前时间的进度百分比
  6. 10M/s,保姆级教程,制作自己的网盘不限速工具!
  7. SpringBoot系列之i18n国际化多语言支持教程
  8. C语言数组制作拼图游戏,C语言自制拼图游戏.doc
  9. 自制html5拖拽功能实现的拼图游戏
  10. Android 多窗口适配