Ubuntu下GNU make示例中Flex Scanner陷入无限循环求助
问题描述
在Ubuntu系统中复现《Managing projects with GNU make》第5页的Flex Scanner示例时,执行./count_words This is a test fue后出现空白输出,疑似陷入无限循环。已确认Flex和libfl.a已安装,补充了书中遗漏的stdlib.h,添加了推荐的.\n规则,但问题仍未解决。
相关代码如下:
count_words.c(应用源码)
#include <stdio.h> #include <stdlib.h> extern int fee_count, fie_count, foe_count, fum_count; extern int yylex( void ); int main( int argc, char ** argv ) { yylex(); printf( "%d %d %d %d\n", fee_count, fie_count, foe_count, fum_count ); exit( 0 ); }
lexer.l(Flex Scanner输入文件)
int fee_count = 0; int fie_count = 0; int foe_count = 0; int fum_count = 0; %% fee fee_count++; fie fie_count++; foe foe_count++; fum fum_count++;
Makefile
count_words: count_words.o lexer.o -lfl gcc count_words.o lexer.o -lfl -ocount_words count_words.o: count_words.c gcc -c count_words.c lexer.o: lexer.c gcc -c lexer.c lexer.c: lexer.l flex -t lexer.l > lexer.c
故障原因
- 未处理命令行参数:当前代码里
yylex()默认从标准输入(stdin)读取内容,但执行时传入的命令行参数(比如This is a test fue)完全没被程序处理,程序会卡在那里等待键盘输入,看起来像无限循环,实际是在等待输入。 - 缺少终止逻辑与默认规则:原lexer.l没有定义非目标文本的处理规则,且Flex生成的扫描器需要
yywrap()函数判断输入是否结束,原代码缺失该函数,加上输入源未正确指定,导致扫描器无法正常退出。
修复方案
方案1:修改代码处理命令行参数
Flex生成的扫描器用yyin作为输入文件指针,我们可以在main函数里把命令行参数拼接后传入:
修改后的count_words.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> extern int fee_count, fie_count, foe_count, fum_count; extern int yylex( void ); extern FILE *yyin; // Flex内置的输入文件指针 int main( int argc, char ** argv ) { if (argc > 1) { // 把所有命令行参数写入临时文件,供扫描器读取 FILE *temp_file = tmpfile(); for (int i = 1; i < argc; i++) { fprintf(temp_file, "%s ", argv[i]); } rewind(temp_file); // 回到文件开头 yyin = temp_file; } yylex(); printf( "%d %d %d %d\n", fee_count, fie_count, foe_count, fum_count ); exit( 0 ); }
方案2:完善lexer.l的规则与终止逻辑
在lexer.l里添加默认规则忽略非目标字符,同时补充yywrap()函数让扫描器能正常结束:
修改后的lexer.l:
int fee_count = 0; int fie_count = 0; int foe_count = 0; int fum_count = 0; %% fee fee_count++; fie fie_count++; foe foe_count++; fum fum_count++; .|\n ; // 忽略所有不匹配的字符(包括换行) %% // Flex需要这个函数判断输入是否结束,返回1表示结束 int yywrap(void) { return 1; }
方案3:不修改代码,用管道传入输入
如果不想改代码,直接通过管道把内容传给程序:
echo "This is a test fee fie foe fum" | ./count_words
内容的提问来源于stack exchange,提问作者yossi-matkal
相关产品推荐
相关产品推荐

