本文参考龙书,分析了Flex生成词法分析器代码
首先给出一个可以运行的模板,修改其中
%%
转换规则
%%
的转换规则部分即可测试不同正则表达式生成代码并编译运行查看结果
%{ #include "stdio.h" %} %% a { printf("match%s\n", yytext); } %% int yywrap() { return 1; } int main() { yylex(); }
生成的代码lex.yy.c主要包括两部分内容:字符串缓存处理与自动机逻辑处理,学习词法分析主要关心自动机逻辑处理
Flex编译的时候如果加参数 -Cf,则编译结果代码中自动机转换函数是一个二维表yy_nxt[][128],否则,则为龙书3.9.8中的4个数组结构
生成代码中有些内容做些说明:
#line 3 "lex.yy.c" // 下一行表示lex.yy.c第3行
关于do...while(0)使用,可以参考一片转载的文章。
生成代码中有很多宏定义,比如YY_USER_ACTION 每次匹配成功执行的代码,详细信息Flex文档中有详细说明
如果不压缩转换表,以匹配正则表达式a为例,则得到:
共6个状态
yy_accept={0, 0, 0, 3, 2, 1);
yy_nul_trans={0, 4, 4, 0, 0, 0};
自动机:
0 | * | a | |
0 | 0 | 0 | 0 |
1 | 3 | 4 | 5 |
2 | 3 | 4 | 5 |
3 | -3 | -3 | -3 |
4 | 3 | -4 | -4 |
5 | 3 | -5 | -5 |
yy_accept有4种可能值:0-需要回溯,1-匹配成功,2-匹配失败,3-匹配结束(对应状态3)
yy_nul_trans有待继续研究
yy_nxt为二维转换表
对于一个正则表达式,怎么将其对应到lex生成的文件中
yy_nxt中状态0无用
1为初始状态
2跟1完全一样,可能有别的用
3为结束状态,读取完毕,需要从读入更多字符进行识别
4表示不匹配
5以后状态为正则表达式对应状态
首先调用yy_get_next_buffer()读取串到缓存中
如果读取完毕
如果读取完毕但是上次匹配成功
如果读取成功则开始识别yy_match:
根据二维状态表进行转换,如果转换结果<0,则取绝对值,然后根据yy_accept表执行相应的流程
1
匹配成功,执行函数(打印匹配成功),进行下一轮匹配
2
匹配不成功,直接将yytext中yyleng长的字符串打印出来
3
碰到字符串结尾
4
退出程序
#include <stdio.h> #include <string.h> static const int yy_nxt[][128] = { {...}} static const int yy_accept[6] = { 0, 0, 0, 3, 2, 1 } ; int yylex(unsigned char *buf) { int yy_current_state; int yy_act; unsigned char yy_hold_char; unsigned char *yy_cp, *yy_bp; yy_cp = buf; while(1) { yy_current_state = 1; yy_bp = yy_cp; while((yy_current_state=yy_nxt[yy_current_state][*yy_cp])>0) ++yy_cp; yy_current_state = -yy_current_state; yy_act = yy_accept[yy_current_state]; switch(yy_act) { case 0: printf("o?\n"); return; case 1: yy_hold_char = *yy_cp; *yy_cp = '\0'; printf("match(%s)", yy_bp); *yy_cp = yy_hold_char; break; case 2: yy_hold_char = *yy_cp; *yy_cp = '\0'; printf(yy_bp); *yy_cp = yy_hold_char; break; case 3: yy_current_state = 1; yy_cp = yy_bp; while(*yy_cp) { yy_current_state = yy_nxt[yy_current_state][*yy_cp]; ++yy_cp; } yy_act = yy_accept[yy_current_state]; if(yy_act==1) printf("match(%s)", yy_bp); else printf(yy_bp); return; default: return; } } } int main () { unsigned char buffer[4096]; while( gets(buffer) ) { int iLen = strlen(buffer); buffer[iLen] = buffer[iLen+1] = 0; if(iLen>=4 && buffer[0]=='q') break; yylex(buffer); printf("\n"); } return 0; }