Flex在Action中处理EOF遇异常:无限输出/段错误求解决
环境
- OS: MacOS Monterey 12.6(搭载Apple M1 Pro)
- 版本: flex 2.6.4 Apple(flex-34)
问题
我编写了以下Flex代码,想要在Action中自行处理EOF,用于测试文件末尾存在unclosed comment(未闭合注释)的场景:
%{ #include <stdio.h> int yywrap(void) { return 1; } %} ID [a-z][a-zA-Z0-9]* DIGIT [0-9] %% {DIGIT}+ {printf("num");} {ID} printf("id: %s\n", yytext); "/*" { int c; for ( ; ; ) { while ( (c = input()) != '*' && c != EOF ) printf("%x\n", c); if ( c == '*' ) { while ( (c = input()) == '*' ) printf("%x\n", c); if ( c == '/' ) break; /* found the end */ } if ( c == EOF ) { printf( "EOF in comment" ); break; } } } %% int main(int argc, char **argv) { ++argv, --argc; if (argc > 0) { yyin = fopen(argv[0], "r"); } else { yyin = stdin; } yylex(); return 0; }
测试用的注释文件内容:
/* **jfiowejfiowe * *
执行编译命令:
lex test.lex gcc lex.yy.c -o lextest ./lextest comment.c
程序出现无限输出0的异常。我尝试修改yywrap()返回0,运行后触发segmentation fault;改用yyterminate()的写法,依然出现段错误。
问题分析与解决
1. 异常原因拆解
- 无限输出
0:原代码缺少默认匹配规则,Flex会将未匹配的字符直接输出到标准输出;同时注释处理逻辑中,EOF的判断分支可能因循环逻辑疏漏,导致重复触发输出操作。另外,未正确使用换行符\n可能引发输出缓冲异常,看起来像是无限输出。 - Segmentation Fault:
yywrap()返回0的语义是告知Flex还有后续输入文件需要处理,但你并未设置新的yyin文件指针,Flex会尝试读取空指针,直接触发段错误。用yyterminate()的写法本质是返回0,和上述情况一致,同样会导致错误。
2. 修正后的代码
%{ #include <stdio.h> int yywrap(void) { return 1; // 返回1表示无后续输入,是正常终止的正确写法 } %} ID [a-z][a-zA-Z0-9]* DIGIT [0-9] %% {DIGIT}+ {printf("num\n");} {ID} {printf("id: %s\n", yytext);} "/*" { int c; while (1) { // 读取直到'*'或EOF while ((c = input()) != '*' && c != EOF) { printf("%x\n", c); } if (c == EOF) { printf("EOF in comment\n"); break; } // 读取连续的'*' do { printf("%x\n", c); c = input(); } while (c == '*'); if (c == '/') { // 找到注释结束符,退出循环 break; } else if (c == EOF) { printf("EOF in comment\n"); break; } } } . { /* 忽略未匹配的单个字符,避免Flex默认输出 */ } %% int main(int argc, char **argv) { ++argv; --argc; if (argc > 0) { yyin = fopen(argv[0], "r"); if (!yyin) { // 添加文件打开失败的错误处理 perror("fopen failed"); return 1; } } else { yyin = stdin; } yylex(); if (yyin != stdin) { fclose(yyin); // 关闭打开的文件,避免资源泄漏 } return 0; }
3. 关键修正点
- 保留
yywrap()返回1的写法,符合无后续输入的场景语义; - 优化注释处理的循环逻辑,确保EOF触发后能直接退出循环;
- 添加默认规则
.忽略未匹配字符,避免Flex自动输出无关内容; - 增加文件打开失败判断和文件关闭操作,完善错误处理与资源管理;
- 统一
printf使用\n换行,避免输出缓冲异常。
编译运行修正后的代码,测试未闭合注释场景时,会正确打印EOF in comment,且无无限输出或段错误问题。
内容的提问来源于stack exchange,提问作者hstk
相关产品推荐
相关产品推荐

