数据库修化神篇二——使用flex和bison编写程序

自制编译器学习3:Flex和Bison简介 阅读详情

使用flex和bison编写程序

我们将用flex和bison实现一个计算器。

词法分析(token识别)

使用flex生成词法分析器。

/* 这里是声明部分 */
%%
"+"         { printf("加\n"); }
"-"         { printf("减\n"); }
"*"         { printf("乘\n"); }
"/"         { printf("除\n"); }
"|"         { printf("绝对值\n"); }
[0-9]+      { printf("数字 %s\n", yytext); } /*yytext:指向本次匹配的输入串*/
\n          { printf("换行\n"); }
[ \t]       {}
.           { printf("输入数字 %s\n", yytext); } 
%%
/* 这里是用户代码段(user code) */

使用如下命令生成词法分析器:

flex cacl.l

运行上面的命令后生成了一个名为lex.yy.c的文件。

[coder@25e5a4630172 code]$ ls
cacl.l  lex.yy.c

也可以指定生成的文件名,命令如下:

# 指定生成的文件名
[coder@25e5a4630172 code]$ flex -o cacl.yy.c cacl.l
[coder@25e5a4630172 code]$ ls
cacl.l  cacl.yy.c

有了.c文件此时就可以使用gcc或者llvm编译生成可执行文,到这里我们的.c文件已经可以实现了识别数字以及加减乘除符号的功能。下面我们进行编译:

[coder@25e5a4630172 code]$ gcc -o cacl cacl.yy.c -lfl
[coder@25e5a4630172 code]$ ls
cacl  cacl.l  cacl.yy.c

下面进行简单的测试:

[coder@25e5a4630172 code]$ ./cacl
123
数字 123
换行
456
数字 456
换行
3*4
数字 3
乘
数字 4
换行

我们可以把现在的编译流程写入一个makefile里,后面可以直接复用,然后只用关心.l文件。其内容如下:

all: 
	flex -o cacl.yy.c cacl.l
	gcc -o cacl cacl.yy.c -lfl
clean:
	rm -rf cacl.yy.c cacl

编译时执行如下命令:

make clean && make

其执行结果如下:

[coder@25e5a4630172 code]$ make clean && make
rm -rf cacl.yy.c cacl
flex -o cacl.yy.c cacl.l
gcc -o cacl cacl.yy.c -lfl
[coder@25e5a4630172 code]$ ls
cacl  cacl.l  cacl.yy.c  Makefile

语法分析

前面的例子中仅仅是识别了数字和算术符号,并没有对识别出来的符号和数字进行计算。要实现计算功能,需要增加语法分析。

简单计算

首先需要增加一个cacl.y的文件,用来处理计算规则,其内容如下:

%token NUMBER
%left '+' '-' '*' '/'

%{
    #include <stdio.h>
    #include <math.h>
    void yyerror(char *s);
    int yylex();    
%}

%%
    
    prog: 
       | prog expr '\n' { printf("= %d\n", $2); };
    expr:
        NUMBER {{ printf("read number %d\n", $$); }};
        | expr '+' expr {{ $$ = $1 + $3; }}
        | expr '-' expr {{ $$ = $1 - $3; }}
        | expr '*' expr {{ $$ = $1 * $3; }}
        | expr '/' expr {{ $$ = $1 / $3; }}
        ;
%%

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

int main() {
    yyparse();
    return 0;
}

编写完成后使用bison来进行编译,生成.c和.h文件,其中.h文件是提供给外部文件引用的。

# --defines指定生成的头文件名称, -o指定生成的.c文件名称
# 如果只指定了-o参数,则所有内容都在一个文件中
bison -d cacl.y --defines=cacl.tab.h -o cacl.tab.c

此时有了.y文件,同时确定了.y文件对外的.h文件后,我们需要修改.l文件,使其生成的token能够作为语法分析的输入,并进行计算。我们修改cacl.l,修改后的内容如下:

%{
    #include<stdlib.h>
    void yyerror(char *);
    #include "cacl.tab.h"
%}

/* 以上是声明部分 */
%%
[0-9]+      { yylval=atoi(yytext); return NUMBER;}
[-+*/\n]   {return *yytext;}
[ \t]       ;

yyerror("Error");
%%
/* 以上是编译规则 */

int yywarp(void)
{
    return 1;
}

/* 以上是用户代码*/

修改完成后,还是像之前一样编译。

[coder@25e5a4630172 code]$ flex -o cacl.yy.c cacl.l
[coder@25e5a4630172 code]$ ls
cacl.l      cacl.tab.h  cacl.y     Makefile
cacl.tab.c  cacl.test   cacl.yy.c
[coder@25e5a4630172 code]$ gcc cacl.yy.c cacl.tab.c -o cacl -lfl
[coder@25e5a4630172 code]$ ls 
cacl    cacl.tab.c  cacl.test  cacl.yy.c
cacl.l  cacl.tab.h  cacl.y     Makefile

进行一个简单的测试,测试结果如下:

[coder@25e5a4630172 code]$ ./cacl
2*3
read number 2
read number 3
= 6
34-12
read number 34
read number 12
= 22
56d
read number 56
d= 56

我们还可以完善一下makefile。

all: 
	bison -d cacl.y --defines=cacl.tab.h -o cacl.tab.c
	flex -o cacl.yy.c cacl.l
	gcc -o cacl cacl.yy.c cacl.tab.c -lfl
clean:
	rm -rf cacl.yy.c cacl cacl.tab.c cacl.tab.h

然后编译如下:

[coder@25e5a4630172 code]$ make clean && make
rm -rf cacl.yy.c cacl cacl.tab.c cacl.tab.h
bison -d cacl.y --defines=cacl.tab.h -o cacl.tab.c
flex -o cacl.yy.c cacl.l
gcc -o cacl cacl.yy.c cacl.tab.c -lfl
[coder@25e5a4630172 code]$ ls
cacl    cacl.tab.c  cacl.y     Makefile
cacl.l  cacl.tab.h  cacl.yy.c

运算优先级

在上面实现的计算器例子中,是按从左到右的顺序来执行的,并没有运算符号的优先级。如下面的加法和乘法的结合就会计算出错:

[coder@25e5a4630172 code]$ ./cacl
1*3+2*6
read number 1
read number 3
read number 2
read number 6
= 30
  • 使用%left来实现优先级

更改内容如下:

--- a/code/cacl.y
+++ b/code/cacl.y
@@ -1,5 +1,6 @@
 %token NUMBER
-%left '+' '-' '*' '/'
+%left '+' '-'
+%left '*' '/'
 
 %{

此时的执行结果如下:

[coder@25e5a4630172 code]$ ./cacl
1*3+2*6
read number 1
read number 3
read number 2
read number 6
= 15
  • 修改规则实现优先级

代码变更如下:

diff --git a/code/cacl.y b/code/cacl.y
index 862939e..323448c 100644
--- a/code/cacl.y
+++ b/code/cacl.y
@@ -11,13 +11,15 @@
 %%
     
     prog: 
-       | prog expr '\n' { printf("= %d\n", $2); };
+        | prog expr '\n' { printf("= %d\n", $2); };
     expr:
+        expr '+' term { $$ = $1 + $3; }
+        | expr '-' term { $$ = $1 - $3; }
+        | term
+    term:
         NUMBER {{ printf("read number %d\n", $$); }};
-        | expr '+' expr {{ $$ = $1 + $3; }}
-        | expr '-' expr {{ $$ = $1 - $3; }}
-        | expr '*' expr {{ $$ = $1 * $3; }}
-        | expr '/' expr {{ $$ = $1 / $3; }}
+        | term '*' term { $$ = $1 * $3; }
+        | term '/' term { $$ = $1 / $3; }        
         ;
 %%

执行结果如下:

[coder@25e5a4630172 code]$ ./cacl
1*4-6/2
read number 1
read number 4
read number 6
read number 2
= 1

实现括号指定顺序

首先需要修改词法分析,即修改cacl.l,其内容修改如下,主要是增加对括号的识别:

diff --git a/code/cacl.l b/code/cacl.l
index c07b94c..188590f 100644
--- a/code/cacl.l
+++ b/code/cacl.l
@@ -7,7 +7,7 @@
 /* 以上是声明部分 */
 %%
 [0-9]+      { yylval=atoi(yytext); return NUMBER;}
-[-+*/\n]    { return *yytext; }
+[-+*/()\n]   {return *yytext;}
 [ \t]       ;
 
 yyerror("Error");

然后要修改语法分析,增加对括号的解析,主要修改内容如下:

diff --git a/code/cacl.y b/code/cacl.y
index 323448c..4a7b015 100644
--- a/code/cacl.y
+++ b/code/cacl.y
@@ -9,7 +9,6 @@
 %}
 
 %%
-    
     prog: 
         | prog expr '\n' { printf("= %d\n", $2); };
     expr:
@@ -17,9 +16,13 @@
         | expr '-' term { $$ = $1 - $3; }
         | term
     term:
+        | term '*' factor { $$ = $1 * $3; }
+        | term '/' factor { $$ = $1 / $3; }        
+        | factor
+        ;
+    factor:
         NUMBER {{ printf("read number %d\n", $$); }};
-        | term '*' term { $$ = $1 * $3; }
-        | term '/' term { $$ = $1 / $3; }        
+        | '(' expr ')' { $$ = $2; }
         ;
 %%

重新编译后运行,运行结果如下:

[coder@25e5a4630172 code]$ ./cacl
3*(2+4)+3*4
read number 3
read number 2
read number 4
read number 3
read number 4
= 30

refernce

  1. https://www.less-bug.com/posts/flex-and-bison-of-actual-combat-a-simple-calculator/
flex&bison编写语法分析器 问题总结 这次实验碰到了许多问题,前后花了好几天的时间,做完后感觉收获颇多。 问题1:字符串指针的内存分配 char* p1="Linwhite"; char* p2; p2=p1; p1初始化时分配了内存空间,p2=p1将p2指向p1指向的内存空间,即p1和p2指向同一内存。 yytext是一个字符指针,它的值是当前扫描到的词。词法分析开始时,yytext指向一块内存(缓冲区)的首 阅读详情

相关推荐

简单用用flex和bison

参考博文: https://www.ibm.com/developerworks/cn/linux/sdk/lex/ https://www.jianshu.com/p/8da9ed3d30a7 https://www.jianshu.com/p/ee814a020624 flex:词法分析器会将输入序列与定义的常规表达式匹配,匹配往往会返回标记。 bison:语法分析器在查看到某个标记序列时,可能会触发某些动作,这便是语法。 bas.y通过yacc会生成y.tab.c包含了标记序列的语法规则,y.tab

pourtheworld的博客 2099

flex & bison 基础概述

编译器,编译原理,flex & bison

JiMoKuangXiangQu的专栏 5646

【手写数据库toadb】语言解析器,编程语言是这样被解析理解,解析器利器flex和bison,解析树与逆波兰式

在当今信息化时代,数据已经成为企业和个人最为宝贵的资产之一。为了有效地管理和利用这些数据,数据库技术应运而生,并得到了广泛的应用。目前市场上已经有很多成熟的数据库产品,如MySQL、Oracle、PostgreSQL等,它们提供了丰富的功能和性能,满足了不同场景的需求。然而,这些数据库产品的庞大和复杂也让很多人感到困惑和不解,不知道数据库内部的运作机制和原理。为了解决这个问题,我们开发了toadb数据库。toadb的目标是以最基础的骨架来搭建一个数据库,让人们能够更清晰地了解数据库的本质和运作原理。

一个追逐梦想的码农 2万+

《Flex 与 Bison》学习笔记

第一部分 简单了解Flex和Bison 1、Flex 和 Bison 简介 Flex和Bison(前身分别为Lex和Yacc),是Linux下两个用来生成程序的工具,它们生成的程序分别叫做词法分析器和语法分析器。词法分析把输入分割成一个个有意义的词块,称为记号(token);语法分析则确定这些记号是如何彼此关联的。 举个例子:Flex文件定义pattern(什么是黄豆,什么是绿豆……),输入文件(一袋豆子)通过Flex处理(词法分析),将输入划分为一段段的token(将输入的豆子一个个摘出来),从而执行不同

qq_39632811的博客 8209

【手写数据库内核miniToadb】第3天 SQL解析工具的准备,flex与bison

解析器准备解析器准备额,SQL发展到今天已经是非常庞大的体系,要想将它完全实现已经不可能,即使是商业数据库中也是大部分的实现。对于如此复杂的语言,从头开始字符的解析程序开发,已经没有意义,也与数据库内核的内容不符,所以在SQL解析模块中引入两个成熟的工具flex和bison,它们是业界著名的语言解析工具,在编译器,数据库等各领域的前端语言分析中应用广泛。1 词法分析工具flexFlex起源于1975年由Mike Lesk和Eric Schmidt编写的lex工具。

一个追逐梦想的码农 4778

Innovus Function ECO实战:5步搞定数字后端设计中的网表修正(含Calibre LVS验证技巧)

本文提供了一份完整的Innovus Function ECO实战指南,详细解析了数字后端设计中网表修正的五步流程。从理解Function ECO概念、准备关键文件,到在Innovus中执行逻辑比对、自动布线及GUI检查,并重点攻克了ECO后Calibre LVS验证的难点与调试技巧,帮助工程师高效、精准地完成流片前的设计微调。

day7的博客 950

linux--Flex and Bison

linux--Bison12参考 1 2 参考 1、Bison 3.4 2、GNU Operating System 3、

天道酬勤 8233

FusionCompute8.0.0实战指南:从零部署CNA与VRM环境

本文以华为FusionCompute 8.0.0为例,详细介绍了如何利用老旧硬件从零开始部署CNA计算节点与VRM管理节点的完整实战指南。内容涵盖实验环境准备、CNA安装与网络配置、VRM虚拟机部署方案对比,并提供了典型故障排查与性能调优技巧,帮助读者低成本构建可用的虚拟化学习环境。

weixin_29306317的博客 315

postgresql 词法/语法(scanner/parser)中flex/bison介绍

在数据库内核中,语法解析和词法分析已经非常成熟,本文来介绍一下它使用的基本知识点,后面介绍数据库内容时,也能更好的理解。本文是基于postgresql 15的代码进行分析解读,演示是在centos8系统上进行。其中有两个重要的工具来协助完成词法和语法分析,它们是:flex词法分析(lexical analysis 或称为scanning)bison是语法分析(systax analysis 或称为parsing)

一个追逐梦想的码农 6154

SAP FI 会计科目表(COA)可直接套用配置模板

摘要:本文提供了SAP S/4HANA环境下可直接套用的会计科目表(COA)配置模板,包含科目编码规则、号段规划、科目组设置等核心内容。模板采用10位数字编码,按资产(1000)、负债(2000)、权益(3000)、成本(4000)、收入(5000)、费用(6000)六大类划分号段,并预设科目组控制字段状态。适用于集团/单一公司、国内/跨国企业场景,支持多表架构映射,配置完成后可通过事务码SAKO验证科目清单。模板遵循"前4位固定一级科目"原则,企业可根据行业特性调整明细科目。

金牌架构师 268

YOLO系列专栏(六):YOLO26热力图可视化 | 解析模型推理逻辑,定位检测关键区域

YOLO26作为新一代目标检测模型,其核心优势是高效的特征提取和精准的目标定位,但模型内部的推理过程的“黑盒”特性,给我们的优化带来了很大困扰:❌ 检测精度低:不知道是模型没学到关键特征,还是特征提取不充分;❌ 出现误检/漏检:无法定位问题根源——是锚框不合适?还是特征图未捕捉到目标?❌ 模型优化盲目:调参、修改网络结构全靠“猜”,缺乏针对性;❌ 难以解释模型行为:实际项目中,需要说明模型“为什么检测到这个目标”,尤其是医疗、工业等对可解释性要求高的场景。而热力图可视化。

qq_36130719的博客 738

postgresql flex bison

https://my.oschina.net/postgresqlchina/blog/5065475

weixin_41685257的博客 392

代码复现3—VLN-CE

运行训练完后在 data文件下会自动生成一个“checkpoints”文件,文件下包含任务文件“seq2seq”,该文件下会包括训练出来的权重和评估结果。数据集下载完后路径提取:data/scene_datasets/mp3d/{scene}/{scene}.glb。注意这里下载的数据集并不是所有的matterport3d,只需要一部分,包含90个场景,大小压缩后约16G。在“eval”时,会在data文件下生成videos文件,里面存放的是可视化的轨迹视频。

qq_44100524的博客 3202

编译内核报错 bison not found

$ make defconfig YACC scripts/kconfig/zconf.tab.c/bin/sh: 1: bison: not found make[1]: *** [scripts/Makefile.lib:196:scripts/kconfig/zconf.tab.c] 错误 127 make: *** [Makefile:534:defconfig] 错误 2 $ sudo apt install bison flex 正在读取软件包列表... 完成 正在分析软件包的依赖关...

shipinsky的博客 6755

orin+96712接GMSL2相机调试经验

orin gmsl camera调试

乐于分享 4457

14.建立时间、保持时间以及vivado时序report的参考使用

在设计数字系统时,需要仔细考虑电路元件的选择和布局以及时序设计来满足建立时间和保持时间的要求。建立时间,又称为建立时间窗口或建立期,是指数字信号在触发器的时钟信号前沿到来之前,必须已经稳定存在的时间。在本章节将结婚扫建立时间和保持时间的基本原理,以及如何通过vivado处理建立时间和保持时间。通过使用同步电路,可以更好地控制数据传输的时序并满足建立时间和保持时间的要求。例如,在D触发器中,选择具有适当充电和放电特性的D端口元件可以确保在时钟信号前沿到达前数据已经稳定存在,并在时钟信号前沿到达后保持稳定。

FPGA/MATLAB学习教程/源码/项目合作开发 2987

如何将flex 生成的可重入C词法扫描器与bison生成的C++语法解析器配接起来

 如题,本文主要是flex与bison 的配合问题。 bison设置在bison用户手册中已经详尽说明了,这里不再赘述。 主要说明一下flex 的设置,并给出一个示例工程。1. flex设置 %{/* 由于flex在输入结束时默认的yyterminate()返回值为0,与bison中token::END可以能不一致 */#define yyterminate() return to

MPForwd的专栏 2914

YOLOv9改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制

这篇文章带来一个经典注意力模块的汇总,虽然有些模块已经发布很久了,但后续的注意力模块也都是在此基础之上进行改进的,对于初学者来说还是有必要去学习了解一下,以加深对模块,模型的理解。

Limiiiing的博客 2893

2022-10-04 数据库-语法分析器bison说明

https://www.gnu.org/software/bison/manual/bison.htmlThis manual (10 September 2021) is for GNU Bison (version 3.8.1), the GNU parser generator.Copyright © 1988–1993, 1995, 1998–2015, 2018–2021 Free Software Foundation, Inc.Next: Conditions for Using Bison,

悟世之路 1547

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Ubuntu12.04(32bit)下安装bison和flex

Ubuntu下安装bisonsudo apt-get install bisonsudo dpkg -i libbison-dev_2.5.dfsg-2.1_i386.debsudo dpkg -i bison_2.5.dfsg-2.1_i386.deb 今天安装bison,随手记一下,Ubuntu环境: kd@ubuntu:/home/samba$ cat /proc/version Linu...

wkd_007的博客 4597

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

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

1、介绍 我总是对编译器和语言非常感兴趣,但是兴趣并不会让你走的更远。大量的编译器的设计概念可以搞的任何一个程序员迷失在这些概念之中。不用说,我也曾 今尝试过,但是并没有取得太大的成功,我以前的尝试都停留在语义分析阶段。本文的灵感主要来源于我最近一次的尝试,并且在这一次中我取得一点成就。 幸运的是,最近的几年,我参加了一些项目,这些项目给了我在建立编译器上很多有用的经验和观点。另外一件事是,我...

Chinamming的专栏 250

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

从兼容模式到 Bison:oGRAC SQL 前端框架代码研读

在这里not between a and b中,如果null出现在a,则表示-inf,出现在b则表示+inf。本质上在between and中,null在a则表示+inf,在b表示-inf,因此无论如何都是输出0.not in中如果xxx中存在1个null,则输出为0,这里的null表示全集的意思。not between null and null,则输出0。not between null and b,则表示>b。not between a and null,则表示<a。

2503_91699586的博客 224

【Linux 内核】编译 Linux 内核 ③ ( 安装 ncurses | 安装 flex | 安装 bison | 打开 Linux 内核编译配置菜单 )

一、安装 ncurses、 二、安装 flex、 三、安装 bison、 四、打开 Linux 内核编译配置菜单、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 3878

使用bison和yacc制作脚本语言(3)

我们现在已经可以写好文法了,下一步我们打算开始正式创建工程了 在工程目录下,我们创建如下文件夹 ./include ./memory ./ms include文件夹下我们将放头文件 memory是内存管理模块,检测内存泄漏 ms文件夹主要是放源文件 memory内存管理模块可以参考我另一个随笔 https://www.cnblogs.com/stdpain/p/10484403.html...

aammmmo6653的博客 278

程序中,调用Bison和Flex结合的小例子(语法分析中处理数据)

接着前面的 那一篇,再来整点新东西:  http://www.cnblogs.com/gaojian/archive/2013/05/17/3083662.html 我想,实际的工作中,绝对不会像逆波兰式计算器那样简单,直接就在语法分析器里完成计算。 常常需要构造一颗语法树,然后把它传出来!例如各种数据库系统处理SQL文就是这样子。 上程序: 1 [root@lex tota

Chinamming的专栏 1288
上一篇: 数据库修仙化神篇四——搭建自己的搜索引擎
下一篇: docker搭建C语言开发环境
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我在数据库世界里修仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值