YACC中@1/@2等位置未自动更新,需手动维护yylloc吗?
解决Lex/Yacc中位置变量@n未自动更新的问题
你遇到的问题核心是:Yacc不会自动维护token的位置信息,必须在Lex中手动更新yylloc结构体,才能让@1、@2等位置变量获取到正确的行号。
解决步骤
要让位置变量正常工作,需要完成以下两步:
在Yacc文件中启用位置跟踪
在Yacc文件的声明部分添加%locations指令,告诉Yacc生成位置相关的代码,这样@n变量才能被正确识别和使用。在Lex文件中手动维护
yylloc
Lex默认不会更新yylloc,需要我们在Lex规则中处理行号变化,并为每个token设置对应的位置信息。
修改后的代码
1. 修改y.tab.y
添加%locations指令,位置在%union之前:
%{ #include <stdio.h> int yyerror(char* msg); int yylex(void); int table[100][10]; int isValidTime(char *time); int isValidDate(char *date); %} %locations // 新增:启用位置跟踪 %union { char * string; int integer; } %token IDF EOL DATE TIME INT %type<string> DATE TIME %type<integer> INT %% file : first_line EOL content ; first_line : first_line IDF | ; content : content one_line EOL | ; one_line : DATE TIME values { if (!isValidDate($1)) { fprintf( stderr, "Warning line %d : invalid date\n", @1.last_line ); } if (!isValidTime($2)) { fprintf( stderr, "Warning line %d : invalid time\n", @2.first_line ); } } ; values : values INT | ; %% int isValidTime(char *time) { return 0; } int isValidDate(char *date) { return 0; }
2. 修改lex.yy.l
添加行号变量,并在规则中更新yylloc:
%{ #include "y.tab.h" static int line_num = 1; // 初始化行号为1 %} c [0-9] %% [a-zA-Z][a-zA-Z0-9]* { yylloc.first_line = yylloc.last_line = line_num; return IDF; } {c}{c}:{c}{c}:{c}{c} { yylval.string = yytext; yylloc.first_line = yylloc.last_line = line_num; return TIME; } {c}{c}\/{c}{c}\/{c}{c} { yylval.string = yytext; yylloc.first_line = yylloc.last_line = line_num; return DATE; } {c}* { yylval.integer = atoi(yytext); yylloc.first_line = yylloc.last_line = line_num; return INT; } \n { line_num++; // 换行时行号加1 yylloc.first_line = yylloc.last_line = line_num; return EOL; } . {;} %%
编译与测试
按以下命令重新编译:
yacc -d y.tab.y flex lex.yy.l gcc -o main y.tab.c lex.yy.c main.c -ll
运行测试:
./main < input.txt
此时错误提示会显示正确的行号,比如:
Warning line 2 : invalid date Warning line 2 : invalid time Warning line 3 : invalid date Warning line 3 : invalid time [...]
内容的提问来源于stack exchange,提问作者Ter Maxima
相关产品推荐
相关产品推荐

