安装配置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
,随后安装即可,如下图:
使用方法为:在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
文件也没有相关函数声明,因此导致警告信息的产生。