flex和bison实例分析
? ? ? ? 最近在學(xué)習(xí)編譯原理,利用flex和bison編寫(xiě)一個(gè)基于文本識(shí)別的簡(jiǎn)單計(jì)算器程序,參考《flex于bison》中內(nèi)容,對(duì)程序進(jìn)行一些簡(jiǎn)單的修改,加入Makefile。該計(jì)算器程序主要實(shí)現(xiàn)識(shí)別文本中的整數(shù)和運(yùn)算符,進(jìn)行加減乘除四則運(yùn)算,暫不考慮括號(hào)對(duì)運(yùn)算順序的影響。
? ? ? ? flex用于詞法分析器的構(gòu)建,bison用于語(yǔ)法分析器構(gòu)建,兩者可以結(jié)合使用,利用bison生成源程序可以直接調(diào)用flex生成源程序中yylex()函數(shù),提取標(biāo)準(zhǔn)輸入文本中的目標(biāo)字符,雖然main函數(shù)可以放到flex或bison的源碼文件的用戶自定義部分,但是不便于閱讀和理解。因此將main函數(shù)單獨(dú)放到一個(gè)cpp文件中,調(diào)用bison源碼文件中的yyparse()函數(shù)對(duì)輸入內(nèi)容進(jìn)行解析和處理。將計(jì)算器的運(yùn)算實(shí)現(xiàn)放到bison源碼的規(guī)則部分。
? ? ? ?創(chuàng)建test.l文件,編寫(xiě)詞法分析規(guī)則(數(shù)字和符號(hào)識(shí)別)
%{#include <stdio.h>#include "test_yacc.h"?//因?yàn)槭褂昧薭ison在test_yacc.h中自動(dòng)生成的token枚舉extern int yylval;?//yylval定義在bison庫(kù)中
%}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] {}. { //該條規(guī)則匹配除以上字符外的剩余字符,并且報(bào)錯(cuò)printf("error: input illegal character '%s'.\n", yytext);
}
%%void yyerror(const char *msg)?
//該函數(shù)的重寫(xiě)可以放在任意位置,bison的yyparse()會(huì)調(diào)用該函數(shù),需在.y文件中聲明此函數(shù)
//傳參必須為const,不然編譯會(huì)報(bào)warning
{fprintf(stderr, "error: %s.\n", msg);
}
? ? ? ? 創(chuàng)建test.y文件,編寫(xiě)語(yǔ)法分析規(guī)則(計(jì)算器的運(yùn)算處理),cal為創(chuàng)建的空規(guī)則,專門(mén)用于判斷是否有換行,如果有換行,完成一次cal的規(guī)約,exp屬性棧彈出,即exp清零。根據(jù)BNF表示方法,將首處理符號(hào)INT放在最底層規(guī)則,其次優(yōu)先匹配乘除法,在處理乘除法之后再匹配加減法。
%{#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: %d\n", $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;
%%
? ? ? ? 創(chuàng)建testMain.cpp,編寫(xiě)main函數(shù)內(nèi)容:
#include <stdio.h>//extern int yylex();
extern int yyparse();int main(int argc, char ** args)?
{//yylex();?yyparse(); //調(diào)用bison的yyparse()函數(shù)return 0;
}
? ? ? ? 編寫(xiě)編譯Makefile腳本
ECHO = echo
CXX ?= g++TARGET = ./testDemoLIBS ? = -lflCFLAGS = -Wall
CFLAGS += -std=c++11OBJECTS = ?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會(huì)生成token的相關(guān)枚舉
test_yacc.cpp : test.ybison -d $< -b test_yaccmv test_yacc.tab.c test_yacc.cppmv test_yacc.tab.h test_yacc.h#生成test_lex.cpp
test_lex.cpp : test.lflex -o $@ $<.PHONY : cleanclean:rm $(OBJECTS) $(TARGET) test_yacc.h test_yacc.cpp test_lex.cpp
? ? ? ? 編譯:
? ? ?yylex()返回記號(hào)token標(biāo)志,標(biāo)志0-255被保留作為字符值,可以自己定義token標(biāo)志的值,一般由bison產(chǎn)生的token標(biāo)志默認(rèn)從258開(kāi)始。本例中,由bison生成的test_yacc.h文件,其中token枚舉定義:
? ? ? ?調(diào)試結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的flex和bison实例分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我的灰姑娘是哪首歌啊?
- 下一篇: Linux C/C++解析xls