You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

YACC中@1/@2等位置未自动更新,需手动维护yylloc吗?

解决Lex/Yacc中位置变量@n未自动更新的问题

你遇到的问题核心是:Yacc不会自动维护token的位置信息,必须在Lex中手动更新yylloc结构体,才能让@1、@2等位置变量获取到正确的行号。

解决步骤

要让位置变量正常工作,需要完成以下两步:

  1. 在Yacc文件中启用位置跟踪
    在Yacc文件的声明部分添加%locations指令,告诉Yacc生成位置相关的代码,这样@n变量才能被正确识别和使用。

  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 11:52:56