Flex/Bison 小 学 习

lex/flex yacc/bison

lex/flex yacc/bisonopen in new window

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

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

规则的匹配

规则的格式

REGEX {/*code block*/}
1

Lex/Flex 匹配规则

  1. 贪婪模式
  2. 多个匹配项选择最早的模式(更早定义的)

flex 编译

flex demo.l # 默认生成文件名为 lex.yy.c
flex -t demo.l > demo.lex.c # 生成文件名为 demo.lex.c
1
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

bison 需要定义yyerror函数

bison 编译

bison -d cal.y
# 默认生成 cal.tab.h cal.tab.c
# cal.tab.h 里面定义了终结符(enum)
1
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

通过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

参考与学习