最近在学习编译原理,利用flex和bison编写一个基于文本识别的简单计算器程序,参考《flex于bison》中内容,对程序进行一些简单的修改,加入Makefile。该计算器程序主要实现识别文本中的整数和运算符,进行加减乘除四则运算,暂不考虑括号对运算顺序的影响。
flex用于词法分析器的构建,bison用于语法分析器构建,两者可以结合使用,利用bison生成源程序可以直接调用flex生成源程序中yylex()函数,提取标准输入文本中的目标字符,虽然main函数可以放到flex或bison的源码文件的用户自定义部分,但是不便于阅读和理解。因此将main函数单独放到一个cpp文件中,调用bison源码文件中的yyparse()函数对输入内容进行解析和处理。将计算器的运算实现放到bison源码的规则部分。
创建test.l文件,编写词法分析规则(数字和符号识别)
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53%{ #include <stdio.h> #include "test_yacc.h" //因为使用了bison在test_yacc.h中自动生成的token枚举 extern int yylval; //yylval定义在bison库中 %} number [0-9] %% {number}+ { yylval = atoi(yytext); printf("number: %d ", yylval); return INT; } "+" { printf("operator: + "); return ADD; } "-" { printf("operator: - "); return SUB; } "*" { printf("operator: * "); return MUL; } "/" { printf("operator: / "); return DIV; } n { return EOL; } [ t] {} . { //该条规则匹配除以上字符外的剩余字符,并且报错 printf("error: input illegal character '%s'.n", yytext); } %% void yyerror(const char *msg) //该函数的重写可以放在任意位置,bison的yyparse()会调用该函数,需在.y文件中声明此函数 //传参必须为const,不然编译会报warning { fprintf(stderr, "error: %s.n", msg); }
创建test.y文件,编写语法分析规则(计算器的运算处理),cal为创建的空规则,专门用于判断是否有换行,如果有换行,完成一次cal的规约,exp属性栈弹出,即exp清零。根据BNF表示方法,将首处理符号INT放在最底层规则,其次优先匹配乘除法,在处理乘除法之后再匹配加减法。
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%{ #include <stdio.h> extern int yylex(); extern void yyerror(const char *); %} %token INT %token ADD SUB MUL DIV %token EOL %% cal : | cal exp EOL { printf("n<archerfoo> caculation result: %dn", $2); } ; exp : factor | exp ADD factor { $$ = $1 + $3; } | exp SUB factor { $$ = $1 - $3; } ; factor : term | factor MUL term { $$ = $1 * $3; } | factor DIV term { $$ = $1 / $3; } ; term : INT ; %%
创建testMain.cpp,编写main函数内容:
1
2
3
4
5
6
7
8
9
10
11
12#include <stdio.h> //extern int yylex(); extern int yyparse(); int main(int argc, char ** args) { //yylex(); yyparse(); //调用bison的yyparse()函数 return 0; }
编写编译Makefile脚本
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
36ECHO = echo CXX = g++ TARGET = ./testDemo LIBS = -lfl CFLAGS = -Wall CFLAGS += -std=c++11 OBJECTS = testMain.o OBJECTS += test_yacc.o OBJECTS += test_lex.o $(TARGET) : $(OBJECTS) $(CXX) -o $(TARGET) $(OBJECTS) $(LIBS) $(CFLAGS) .cpp.o : $(CXX) -o $@ -c $< #生成test_yacc.cpp、test_yacc.h #test_yacc.h会生成token的相关枚举 test_yacc.cpp : test.y bison -d $< -b test_yacc mv test_yacc.tab.c test_yacc.cpp mv test_yacc.tab.h test_yacc.h #生成test_lex.cpp test_lex.cpp : test.l flex -o $@ $< .PHONY : clean clean: rm $(OBJECTS) $(TARGET) test_yacc.h test_yacc.cpp test_lex.cpp
编译:
yylex()返回记号token标志,标志0-255被保留作为字符值,可以自己定义token标志的值,一般由bison产生的token标志默认从258开始。本例中,由bison生成的test_yacc.h文件,其中token枚举定义:
调试结果:
最后
以上就是悦耳白开水最近收集整理的关于flex和bison实例分析的全部内容,更多相关flex和bison实例分析内容请搜索靠谱客的其他文章。
发表评论 取消回复