Flex和Bison协同工作(下)

2023-11-15

Flex和Bison协同工作(下)

上一篇文章我们写了一个稍微复杂一点点的词法解析器,这篇我们开始搞定语法分析器。

文法与语法分析

语法分析器的任务其实就是找出输入记号之间的关系。通常使用语法分析树(parse tree)。例如:算术表达式12+34+5有下图所示的语法分析树。

1
2
3
4
5
*
*
+
+

乘法比加法有更高的优先级,所以前两个表达式是12和34。接着这两个表达式被加在一起,它们的和再加上5。这棵树的每个分支都显示了记号之间或者记号与下面子树的关系。

那什么是文法呢?
文法(Grammar)是一种用来描述语言的形式化工具,它可以帮助我们定义语言的规则和结构。通俗来说,就是一套规则,用来描述一种语言的语法,它告诉我们这种语言可以使用哪些单词、如何组成句子、句子之间的关系等等。

上下文无关文法
上下文无关文法(Context-Free Grammar,CFG)是一种形式化的语法表示方法,用于描述一类形式语言的语法结构。上下文无关文法是指在语法分析时,每个非终结符所对应的产生式的右部都不依赖于上下文(即不依赖于其他符号的左右环境),只和非终结符本身有关。
文法规则的形式如下:

<非终结符> ::= <符号串>
其中,'<非终结符>'表示非终结符号,它可以被其他规则所引用;'<符号串>'表示由终结符和非终结符组成的串,它定义了如何生成一类符号串。

BNF文法
书写上下文无关文法的标准格式就是Backus-Naur范式(BackusNaur Form,BNF),大致创立于1960年,用来描述Algol 60语言,由两名Algol 60委员会的成员命名。

<exp> ::= <factor>
	| <exp> + <factor>
<factor> ::= NUMBER
	| <factor> * NUMBER

每一行就是一条规则,用来说明如何创建语法分析树的分支。在BNF里::=被读作"是"或者“变成”,|是“或者”,创建同类分支的另一种方式。规则左边的是语法符号(symbol)。大致来说,所有的记号都被认为是语法符号,但是有一些语法符号并不是记号。

有效的BNF总是带有递归性的,规则会直接或者间接的指向自身。这些简单的规则被递归地使用来匹配任何极端复杂的加法和乘法序列。

Bison的规则描述语言

bison的规则基本上就是BNF,但是做了一点点简化以易于输入。
例如:calc.y

%{
#include <stdio.h>
%}

%token NUMBER
%token ADD SUB MUL DIV ABS
%token EOL

%%
calclist: /* 空规则 */
    | calclist exp EOL { printf("= %d\n", $2); }
    ;
    
exp: factor
    | exp ADD factor { $$ = $1 + $3; }
    | exp SUB factor { $$ = $1 - $3; }
    ;
    
factor: term
    | factor MUL term { $$ = $1 * $3; }
    | factor DIV term { $$ = $1 / $3; }
    ;
    
term: NUMBER { $$ = $1; }
    | ABS term { $$ = $2 >= 0 ? $2 : -$2; }
    ;
%%

main(int argc, char **argv)
{
    yyparse();
}

yyerror(char *s)
{
    fprintf(stderr, "error: %s\n", s);
}

bison程序包含了(不是巧合)与flex程序相同的三部分结构:声明部分、规则部分和C代码部分。**%token记号声明,以便于告诉bison在语法分析程序中记号的名称。**通常来说,记号总是使用大写字母。

第二部分包含了通过简单的BNF定义的规则。**bison使用单一的冒号而不是::=,**同时由于行间隔并不那么明显,分号被用来表示规则的结尾。同样,向flex那样,C的动作代码在每条规则之后用花括号括起。

每个bison规则中的语法符号都有一个语义值,**目标符号(冒号左边的语法符号)的值在动作中代码用$$代替,右边语法符号的语义值依次为$1、$2,直到这条规则的结束。**当词法分析器返回记号时,记号值总是储存在yylval里,其他语法符号的语义值则在语法分析器的规则里进行设置。在本例中,factor、term和exp符号的语义值就是它们所描述的表达式的值。

在这个语法分析器里,头两条规则定义了calclist语法符号,它们通过循环来读入用换行符结束的表达式并且打印结果。calclist的定义使用一种常见的双规则递归定式来实现一个序列或者列表:第一个规则为空所以不进行任何匹配,第二个规则添加一个项目到列表中。第二个规则中的动作通过$2打印出exp的值。

其余的规则实现了计算器。带有操作符的规则(例如,exp ADD factor和ABS term)在语义值上进行相应的算术操作。右边仅有一个语法符号的规则可以像黏合剂一样组合文法,例如,一种表达式(exp)就是一个因子(factor)。如果一个规则缺少显式的动作,语法分析器将把 1 赋予 1赋予 1赋予$。这是一个内部设定,不过很有用,因为在大部分情况下它总是对的。

联合编译Flex和Bison程序

在我们把词法分析器和语法分析器构造为一个可以工作的程序前,我们需要对将之前的词法分析器做一些小小的改动,改成如下所示:

calc.l

%{
#include "calc.tab.h"
%}

%%
"+"    { return ADD; }
"-"    { return SUB; }
"*"    { return MUL; }
"/"    { return DIV; }
"|"    { return ABS; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
\n     { return EOL; }
[ \t]  { }
.      { printf("Mystery character %c\n", *yytext); }
%%

区别如下:

  • 添加bison头文件,去除yyval的声明,因为bison中会有声明
  • 删除main函数,因为语法分析器会调用词法分析器。

接下来我们开始联合编译,并进行测试

  • bison -d calc.y
  • flex calc.l
  • gcc -o calc calc.tab.c lex.yy.c

首先使用-d(用于生成calc.tab.h)参数运行bison。生成calc.tab.h和calc.tab.c
接着运行flex来创建lex.yy.c。
最后使用gcc编译生成可执行程序

大功告成,去运行测试吧,就这点代码一个简易的计算器就弄好了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flex和Bison协同工作(下) 的相关文章

随机推荐

  • springboot项目接口给null给前端返回空字符串。

    代码 Configuration public class JacksonConfig Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageCo
  • 使用docker搭建Grafana+influx 实时监控Jmeter压测平台

    准备工作 jmeter 压测工具 产生压测数据 IfluxDB 开源时序数据库 特别适合用于处理和分析资源监控数据 用于存储压测数据 Grafana 度量分析与可视化图标展示工具 可以支持不用种类的数据源 用于将存储于InfluxDB中的数
  • Qt实现图片的简单压缩

    在编程过程中 涉及到网络传输或资源加载时 过大的图片往往是编程人员的噩梦 加载时间过长 体验效果差 特别在即时通讯的发送图片时 大图往往半天加载不出来 于是 先对图片进行压缩 暂时显示模糊图片 然后下载大图最后更新下载的大图 这一过程成为解
  • 任务长期不释放和占用单节点持续的cpu,导致hivesever2本身内存泄漏造成

    任务长期不释放和占用单节点持续的cpu 导致hivesever2本身内存泄漏造成 产生的原因在于 查询过于复杂或者数据量过大 当有复杂的查询或处理大量数据的请求时 HiveServer2可能会出现高负载 这可能涉及大量的计算 IO操作或涉及
  • macm1环境下jdk版本切换

    macm1环境下jdk版本切换 本文目录 macm1环境下jdk版本切换 下载jdk 安装 动态切换jdk 终端生效 全局生效 参考 下载jdk oracle官方源下载地址 https www oracle com java technol
  • 一个新的微型JSON开源框架

    Snack3 一个新的微型JSON框架 一个作品 一般表达作者的一个想法 因为大家想法不同 所有作品会有区别 就做技术而言 因为有很多有区别的框架 所以大家可以选择的框架很丰富 snack3 基于jdk8 60kb 无其它依赖 非常小巧 强
  • OperationalError: (2005, "Unknown MySQL server host 'localhost' (11001)")

    在调试Django时突然报OperationalError 2005 Unknown MySQL server host localhost 11001 这个错误 根据提示信息判断是说mysql server 无法识别 localhost
  • $nextTick的作用和使用场景

    nextTick的作用和使用场景 vue中的nextTick主要用于处理数据动态变化后 DOM还未及时更新的问题 用nextTick就可以获取数据更新后最新DOM的变化 适用场景 第一种 有时需要根据数据动态的为页面某些dom元素添加事件
  • 解决延迟有 Wi-Fi 6 就够了!

    最近二狗子家里的路由器坏了 而家里的数据网络信号又非常差 失去了路由器基本上就等于和世界隔离 所以二狗子打算去附近商城随便买一个新的路由器 结果售货员张口就问 买 Wi Fi 6 的路由器吗 Wi Fi 6 这直接把二狗子问懵了 Wi Fi
  • Serverless Kubernetes 应用部署及扩缩容

    作者 邓青琳 轻零 阿里云技术专家 导读 本文分为三个部分 首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署 其次介绍 Serverless Kubernetes 的常用功能 最后对应用扩缩容的操作进行
  • 医学图像分割研究思路

    医学图像分割的主流方法之一是基于水平集 Level Set 的分割方法 目前针对主流的分割方法 我们主体研究思路如下图 在模型凸化以及形状先验两个方面 未开展相关工作 参考文献 部分演示代码 参数随图像需要调整 7 Xiaomeng Xin
  • 重新生成一堆rpm目录的repo库步骤

    createrepo c repo2module s stable modules yaml modifyrepo c mdtype modules modules yaml repodata
  • IntelliJ IDEA插件搜索下载缓慢

    我用的版本是2019 2 1 搜索插件特别慢 有时候加载不出来 看到别人说是用 Setting Appearance Behavior Syetem Setting Updates 将Use secure connection 的勾选去掉
  • java----面向对象和面向过程

    1 面向对象思想 面向对象四星思想就是把关注点放在一件事或一个活动中设计的人或事物上的思想 2 面向过程思想 面向过程思想就是把关注点放在一件事或一个活动中设计的人或事物所涉及的步骤上的思想 3 面向过程关键字 步骤 过程 4 面向对象关键
  • 一周 8k Star 的 Notion 开源替代品 AppFlowy 诞生

    近日 Notion 的开源替代品 AppFlowy 正式发布了 一经发布 在短短一周就获得了近 8k Star 这个成绩对于一个开源项目来说是非常不错的 那么为什么有了 Notion AppFlowy 团队却要从头开始开发一个类似的产品呢
  • 框架--SpringWeb

    文章目录 一 springweb 1 概述 2 springWeb层搭建 3 请求中的地址如何定义 4 如何接收请求中的数据 5 直接使用对象接收 6 post请求中文乱码处理 7 Ajax 返回 JSON 8 跨域问题 9 拦截器 10
  • string头文件常用方法(C++)

    string 定义字符串 如果未赋初值 则默认是 即空字符串 结尾也没有结束标志 0 include
  • 排序算法-希尔排序

    属性 1 希尔排序是对直接插入排序的优化 2 当gap gt 1时都是预排序 目的是让数组更接近于有序 当gap 1时 数组已经接近有序的了 这样就会很 快 这样整体而言 可以达到优化的效果 我们实现后可以进行性能测试的对比 3 希尔排序的
  • C++ 异常处理 入门

    C 异常处理 入门 异常 程序执行期间 可检测到的不正常情况 例如 0作除数 数组下标越界 打开不存在的文件 远程机器连接超时 malloc失败等等 程序的两种状态 正常状态和异常状态 发生不正常情况后 进入异常状态 从当前函数开始 按调用
  • Flex和Bison协同工作(下)

    Flex和Bison协同工作 下 上一篇文章我们写了一个稍微复杂一点点的词法解析器 这篇我们开始搞定语法分析器 文法与语法分析 语法分析器的任务其实就是找出输入记号之间的关系 通常使用语法分析树 parse tree 例如 算术表达式12