概述
最近在学习编译原理,利用flex和bison编写一个基于文本识别的简单计算器程序,参考《flex于bison》中内容,对程序进行一些简单的修改,加入Makefile。该计算器程序主要实现识别文本中的整数和运算符,进行加减乘除四则运算,暂不考虑括号对运算顺序的影响。
flex用于词法分析器的构建,bison用于语法分析器构建,两者可以结合使用,利用bison生成源程序可以直接调用flex生成源程序中yylex()函数,提取标准输入文本中的目标字符,虽然main函数可以放到flex或bison的源码文件的用户自定义部分,但是不便于阅读和理解。因此将main函数单独放到一个cpp文件中,调用bison源码文件中的yyparse()函数对输入内容进行解析和处理。将计算器的运算实现放到bison源码的规则部分。
创建test.l文件,编写词法分析规则(数字和符号识别)
%{
#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放在最底层规则,其次优先匹配乘除法,在处理乘除法之后再匹配加减法。
%{
#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函数内容:
#include <stdio.h>
//extern int yylex();
extern int yyparse();
int main(int argc, char ** args)
{
//yylex();
yyparse(); //调用bison的yyparse()函数
return 0;
}
编写编译Makefile脚本
ECHO = 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实例分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复