Flex/Bison 小 学 习
lex/flex yacc/bison
lex 和 flex(the fast lexical analyser generator) 可以认为没什么区别 如果等你用到了有区别的地方时 你就知道有什么区别了
Bison 是 GNU 的 Yacc 实现/拓展 Flex 是 Lex 的继承者
更推荐用 Flex/Bison 替代 Lex/Yacc
byacc 是 Berkeley 的 Yacc 实现
ubuntu20.04:
lrwxrwxrwx 1 root root 4 8月 7 2018 /usr/bin/lex -> flex
yacc -V
bison (GNU Bison) 3.5.1
Written by Robert Corbett and Richard Stallman.
1
2
3
2
3
Flex
文件后缀为 l
VSCode的插件:Yash
文件结构
%{
// 定义段
#include<stdio.h>
%}
/* 可以定义变量 */
ALPHA [a-zA-Z]
/* 用两个 % 分割段 下一个段为规则段 指定规则和行为 */
%%
{ALPHA} puts("匹配到字母");
[0-9]+ puts("匹配到数字串");
%%
int main(int argc, char **argv)
{
printf("Lexer Begin\n");
yylex(); // 执行到结束或者 return
printf("Lexer End\n");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
规则的匹配
规则的格式
REGEX {/*code block*/}
1
Lex/Flex 匹配规则
- 贪婪模式
- 多个匹配项选择最早的模式(更早定义的)
flex 编译
flex demo.l # 默认生成文件名为 lex.yy.c
flex -t demo.l > demo.lex.c # 生成文件名为 demo.lex.c
1
2
2
Bison
flex可以单独使用 但bison不行 bison通过yylex()
获取输入
bison的三个部分和flex相同
下面是简单的四则运算代码
%{
#include<stdio.h>
#include<stdlib.h>
void yyerror(const char*);
%}
%union{
double value;
char ch;
/* 定义节点类型 */
}
%token<value> NUM /* 定义终结符类型 */
%token EOL ADD SUB DIV MUL /* 非定义类型则默认为int 无法获取到值 */
%type<value> term
%%
cal_list : cal EOL cal_list {/* 表达式后的符号 $表示cal_list $1-$n依次表示cal EOL cal_list */}
| /*cal_list -> cal EOL cal_list | empty*/
; /* 分号作为产生式的结束符号 */
cal : {/* 空匹配 相当于empty或者\epsilon */ printf("> "); }
| term ADD term{ printf("= %lf\n> ",$1+$3); }
| term SUB term{ printf("= %lf\n> ",$1-$3); }
| term{ printf("= %lf\n> ",$1); }
;
term: NUM MUL NUM { $ = $1 * $3; }
| NUM DIV NUM { $ = $1 / $3; }
| NUM { $=$1; }
;
%%
int main(){
printf("> ");
yyparse();
return 0;
}
void yyerror(const char*msg){
fprintf(stderr,"%s\n",msg);
}
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
31
32
33
34
35
36
37
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
31
32
33
34
35
36
37
bison 需要定义
yyerror
函数
bison 编译
bison -d cal.y
# 默认生成 cal.tab.h cal.tab.c
# cal.tab.h 里面定义了终结符(enum)
1
2
3
2
3
cal
下面展示一个flex和bison联合使用的例子
bison代码同上
%{
#include"y.tab.h"
#include<string.h>
%}
%option noyywrap
NUMS [0-9]+
%%
{NUMS} {yylval.value = atoi(yytext); return NUM;}
"-" {return SUB;}
"+" {return ADD;}
"*" {return MUL;}
"/" {return DIV;}
"\n" {return EOL;}
%%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
通过
yylval
来设置终结符的值 值类型和名在bison的%union
联合体中定义
Makefile编译
# yacc/bison flags
YFLAGS=-d
cal: lex.c
lex.c: cal.l
lex -t $< > $@
cal.c cal.h:cal.y
demo: demo.c
demo.c: demo.l
clean:
-rm cal
-rm lex.*
-rm cal.tab.* cal.c y.tab.h
-rm demo.c demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15