WSL下利用flex和bison完成简单四则运算

安装配置Ubuntu WSL

  搜索控制面板,进入控制面板,选择程序,点击启用或关闭Windows功能,勾选适用于Linux的Windows子系统,如下:

  根据提示重启系统。
  重启后在Microsoft Store中搜索Ubuntu,下载并安装18.04版本,如下:

  安装后启动,根据提示设置电脑名称和密码。使用如下命令备份原有源文件并更改软件源:

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo vim /etc/apt/sources.list

  将文件/etc/apt/sources.list中所有源注释掉后,添加如下的清华源信息:

deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse

  保存并退出后使用命令进行更新,如下:

sudo apt-get update

配置VS Code

  由于存在文件和代码编辑部分,故下载VS Code关于WSL的插件Remote WSL来打开并编辑WSL中文件。具体为:在VS Code的扩展部分搜索Remote WSL,随后安装即可,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJfQ9c7a-1602767505568)(C:\Users\lyg\AppData\Roaming\Typora\typora-user-images\image-20201015145055335.png)]

  使用方法为:在WSL中输入code .来启动VS Code即可。

安装flex与bison

  使用如下命令安装flex与bison,如下:

sudo apt-get install flex bison

  安装完成后使用apt list [name]查看安装情况,发现成功安装,如下:

在这里插入图片描述

词法分析

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

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

  其中利用的ADD、SUB等返回值,是由flex已经定义好的,因此直接调用即可。

语义分析

%{
    #include <stdio.h>
    void yyerror();
    void main();
    int yylex();
%}

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

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

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

void main(){
    yyparse();
}

  整个结构的第二部分来完成语言文法的描述,其中$$表示结果,$1、$2...等依次表示文法右侧的非终结符,具体举例说明:

exp: factor { $$ = $1; }
    | exp ADD factor { $$ = $1 + $3; }
    | exp SUB factor { $$ = $1 - $3; }
    ;

  其中所有$$都指代exp这个非终结符,结果也将赋给exp;第一行的$1表示factor的值;第二行exp对应$1,ADD对应$2,factor对应$3;第三行exp对应$1,SUB对应$2,factor对应$3

  yyerror()函数对flex定义的同名函数进行了覆盖,来完成自定义的error响应。利用yyparse()函数完成语义分析。

编译

  由于编译命令较多因此交给make管理,首先新建一个文件夹file将写好的词法分析文件fb_calc_lyg.l和语法分析文件fb_calc_lyg.y放入该文件夹,再创建一个Makefile文件记录命令及相关文件信息,具体如下:

fb_calc_lyg: fb_calc_lyg.l fb_calc_lyg.y
	bison -d fb_calc_lyg.y
	flex fb_calc_lyg.l
	cc -o $@ fb_calc_lyg.tab.c lex.yy.c -lfl

  Makefile的格式为:

TARGET : DEPENDENCIES …

COMMAND …

TARGET:代表将产生的目标文件

DEPENDENCIES:指定用来产生目标的输入文件,一个目标通常依赖于多个文件

COMMAND:命令行

  创建好Makefile后直接再其所在文件夹下执行make命令即可,编译结果如下:

在这里插入图片描述

  忽略警告信息,成功完成编译。

测试

  使用如下命令运行并测试:

./fb_calc_lyg

在这里插入图片描述

  观察到成功完成简单四则运算。

报错及警告的消除

NO.1

bison -d fb_calc_lyg.y
fb_calc_lyg.y:16.21-22: error: invalid characters: ‘$$’
exp: factor default $$ = $1;
^^
fb_calc_lyg.y:16.24: error: syntax error, unexpected =
exp: factor default $$ = $1;
^
fb_calc_lyg.y:16.26: error: invalid character: ‘$’
exp: factor default $$ = $1;
^
fb_calc_lyg.y:17.5: error: syntax error, unexpected |
| exp ADD factor { $$ = $1 + $3; }
^
Makefile:2: recipe for target ‘fb_calc_lyg’ failed
make: *** [fb_calc_lyg] Error 1

  主要原因是该版本bsion不支持default关键字,删掉即可。同时由于$$ = $1;语句是一条C语言的赋值语句,因此也需要加上花括号。

NO.2

fb_calc_lyg.y:29:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main(){
^~~~
fb_calc_lyg.y:33:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
yyerror(char *s)

  函数缺少返回值的警告信息,对两个函数都加上void类型的返回值声明即可。

NO.3

/tmp/ccVulWce.o: In function ‘main’:
lex.yy.c:(.text+0x1d62): multiple definition of ‘main’
/tmp/ccsoplHV.o:fb_calc_lyg.tab.c:(.text+0xa06): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target ‘fb_calc_lyg’ failed
make: *** [fb_calc_lyg] Error 1

  由于刚开始编写时没有将.l文件中的main函数进行删除,因此导致出现两个main函数;删除.l文件中的main函数即可。

NO.4

fb_calc_lyg.tab.c: In function ‘yyparse’:
fb_calc_lyg.tab.c:1126:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration]
yychar = yylex ();

fb_calc_lyg.tab.c:1306:7: warning: implicit declaration of function ‘yyerror’; did you mean ‘yyerrok’? [-Wimplicit-function-declaration]
yyerror (YY_(“syntax error”));
^~~~~~~
yyerrok

  由于yylex()函数是由flex将.l文件转换为lex.yy.c文件时生成的函数,因此在连接过程中.tab.c文件中并不包含该函数的声明,因此会出现警告信息。只需要在.y文件中声明一下int yylex();即可。

  由于yyerror()没有事先声明而直接定义,导致产生警告信息。而gcc编译C程序该写法并不报错,原因在于bison会将.y文件转为.tab.c文件和.tab.h文件,而之后的连接过程会使用该.tab.c文件进行连接,因此在转换过程中由于bison读取到的.y文件的C代码部分没有相关函数声明,因此转换的.tab.c文件也没有相关函数声明,因此导致警告信息的产生。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

D-A-X

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

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

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

打赏作者

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

抵扣说明:

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

余额充值