使用Lex和Yacc解析Shell输入时捕获命令字符串值遇段错误求助
解决Lex/Yacc解析Shell管道命令时的段错误问题
我之前刚用Lex/Yacc写类似解析器的时候也踩过这个坑!你的代码里有两个关键问题导致了段错误,咱们一步步来解决:
核心问题:Lex不知道yylval的类型
你在Yacc里定义了YYSTYPE为char*,但Lex默认会把yylval当成int类型处理。当你用strdup(yytext)把字符串指针赋值给yylval时,64位系统下指针是8字节,会被截断成int的4字节,传到Yacc里的$1就变成了无效的垃圾地址,打印时自然触发段错误。
修改步骤
1. 修复Lex文件的类型声明
在Lex的%{ ... %}块里,添加extern YYSTYPE yylval;,确保Lex知道yylval是字符串指针类型。另外还要补充空白字符的忽略规则,避免输入空格换行时触发错误:
%{ #include <stdio.h> #include "y.tab.h" #include <string.h> // 显式声明yylval的类型,让Lex正确处理指针 extern YYSTYPE yylval; %} %% (grep|vim|ls|who) { yylval = strdup(yytext); return COMMAND; } "|" return PIPE; [ \t\n]+ ; // 忽略空格、制表符和换行 . { yyerror("invalid character"); } // 处理非法字符 %%
2. 补充内存释放(可选但推荐)
strdup会在堆上分配内存,用完后记得释放避免内存泄漏,修改Yacc里的command规则:
%{ #include <stdio.h> #include <string.h> #include <stdlib.h> // 要包含stdlib.h才能用free #define YYSTYPE char* void yyerror(const char* str) { fprintf(stderr, "error: %s\n", str); } int yywrap() { return 1; } main() { yyparse(); } %} %token PIPE COMMAND %% statement: command | statement PIPE command ; command: COMMAND { printf("command: %s encountered\n", $1); free($1); // 释放strdup分配的内存 } ; %%
编译运行顺序
别忘按正确顺序编译:
yacc -d parser.y flex scanner.l gcc y.tab.c lex.yy.c -o shell_parser ./shell_parser
现在输入ls | grep test,就能正常打印命令,不会再出现段错误啦!
内容的提问来源于stack exchange,提问作者Kareem Aboughazala
相关产品推荐
相关产品推荐

