flex&bison安装与简单使用

flex&bison安装与简单使用

1.wls安装

这里使用的是wls,wls安装教程可以参考这一篇,亲测可用,安装后是自带gcc的,但是相关依赖没有,需要运行以下两个命令

1
2
sudo apt-get update
sudo apt-get install build-essential

可能会遇到一些问题,可以广泛参考网上的错误解决方案~

2.安装flex bison并尝试第一个flex程序

在Ubuntu系统系统下安装flex bison,输入以下命令

1
sudo apt-get install flex bison

一会就装好了,然后我们尝试我们的第一个flex程序(feb1-1.l),该程序参考flex与bison中文版第二版(可以买来看看!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
%%
[a-zA-Z]+ {words++; chars+= strlen(yytext);}
\n {chars++; lines++;}
. {chars++;}
%%
main(int argc, char** argv){
yylex();
printf("%d,%d,%d\n", lines, words, chars);
}

这个程序就是C代码,flex程序包含三个部分,各个部分通过%%行进行分割

  • 第一部分是声明部分,%{和}%之间的代码会原样照抄到生成的C文件的开头部分,在上面的栗子中,我们使用其设定了行数、单词书与字符数的变量
  • 第二部分是模式匹配部分,学习过正则表达式的同学对着肯定不会陌生(这里就不对正则表达式做详细介绍了~),每一行的开始处对应一个模式(用一个正则表达式表示),后面是当模式匹配时会执行的C语言代码(变量yytext总是被设定为指向本次匹配输入的文本)
  • 第三部分是我们的主程序,它负责调用flex体用的词法分析例程yylex(),并输出结果。在没有其他改变的情况下,词法分析器将读取标准输入。

我们首先编译flex生成C程序(lex.yy.c

1
flex fb-1-1.l

然后将它与相应的flex库文件(-lfl)链接,生成a.out

1
cc lex.yy.c -lfl

最后运行程序

1
./a.out

尝试输入以下内容:

1
2
The boy stood on the burning deck
shelling peanuts by the peck

输出为(行数、单词数、字符数)

1
2,12,63

0ODirQ.png

对于flex正则表达式匹配的一些说明:

  • 默认贪婪匹配(匹配更长的字符串)
  • 优先匹配程序里先出现的模式

3.让Flex和Bison协同工作

我们现在需要完成一个简单的计算器

首先使用编写一个简单的flex词法分析器,不显示的定义记号值,而是直接包含头文件,因为我们希望在语法分析器中直接调用它

文件名:fb-1-5.l

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
%{
#include"fb-1-5.tab.h"
int yylval;
%}
%%
"+" {return ADD;}
"-" {return SUB;}
"*" {return MUL;}
"/" {return DIV;}
"|" {return ABS;}
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
\n {return EOL;}
[ \t] {return EOL;}
. {printf("Mystery character %c\n", *yytext);}
%%

然后bison程序部分,bison的规则基本上就是BNF(可参考编译原理),bison程序和flex一样分成三部分:

  • 第一部分首先也是声明,会拷贝到目标程序开头,随后事%token标记声明,以便告诉bison在语法分析中的记号名称
  • 第二部分就是BNF定义的规则,使用单一的冒号:表示,和flex一样,匹配每一条规则后,就会执行后面用花括号括起来的动作代码,我们一般使用动作代码维护每个语法对应的符号关联语义值,目标符号的值在动作代码中用$$表示,右边语法符号的语义值依次为$1, $2…,直到这条规则结束。记号值总是存储在yyval中,这就对应我们上面的flex程序。
  • 第三部分就是主程序,运行我们的语法分析程序。

文件名:fb-1-5.y

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
%{
#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 factor {$$ = $1 * $3;}
| factor DIV term {$$ = $1 / $3;}
;
term:NUMBER
| ABS term {$$ = $2 >= 0? $2 : -$2;}
;
%%
main(int argc, int **argv){
yyparse();
}
yyerror(char *s)
{
fprintf(stderr, "error:%s\n", s);
}

然后联合编译flex与bison程序,由于编译的步骤比较复杂,所以我们写一个Makefile,运行vim Makefile, 写入如下内容

1
2
3
4
fb-1-5:fb-1-5.l fb-1-5.y
bison -d fb-1-5.y
flex fb-1-5.l
cc -o $@ fb-1-5.tab.c lex.yy.c -lfl

然后我们编译:

1
make

得到程序fb-1-5,直接运行就可以了,一个简易的计算器就完成了~

0OyXy8.png