如何为弹性/野牛实现更好的错误消息

问题描述 投票:2回答:1

我需要针对我正在编写的语法的语法错误提供适当的错误消息。我发现我可以在flex文件中为换行定义一个规则(?不确定术语),以增加行号计数器,我可以在yyerror(const char*)中使用它。但是,我还需要知道发生错误的确切位置,以获得更好的错误消息。这就是我希望错误消息看起来像的样子:

Syntax error on line X:
SOME ERRONEOUS TEXT ON LINE X
_______________^
Expected other text.

如何获得列信息以及错误行上的文本?

谢谢你。

c++ c parsing bison flex-lexer
1个回答
0
投票

输出意外和期望的令牌

只需使用

#define YYERROR_VERBOSE 1

yyerror已经输出类似

syntax error, unexpected '+', expecting NUM or '('  

打印行号

要打印当前行号,您可以使用yylineno。您需要使用

进行声明
extern int yylineno;

在.y文件中。

在.l flex文件中,您需要添加:

%option yylineno

打印列

要获取列信息,必须跟踪lexer文件中的列。因此,在读取令牌后,您可以简单地添加令牌的长度(例如,使用strlen(yytext))。对于错误报告,您对令牌开始的列感兴趣,因此需要设置第二个变量,并在读取令牌之前记住该列的位置。

您可以使用一个简单的宏:

#define HANDLE_COLUMN column = next_column; next_column += strlen(yytext)

打印当前输入行

要打印当前输入行,您必须自己进行跟踪。您可以自己从yyin中读取行,并通过相应地定义宏YY_INPUT在词法分析器中使用此数据。这个很好的答案https://stackoverflow.com/a/43303098解释了它是如何工作的。

作者还显示了如何使用宏YY_USER_ACTION确定当前列的示例。

简单示例

一个简单,独立的计算器示例,可以处理加法和减法,看起来像这样

[输入5 + 3 + 2 + 1,它给出作为输出:

5+3+2+1
=11

错误输入,例如'5 + 2 ++ 1'作为输出结果:

error: syntax error, unexpected '+', expecting NUM or '(' in line 3, column 5
5+2++1
____^

calc.l

%{
    #include "y.tab.h"
    extern int yylval;
    static int next_column = 1;
    int column = 1;

    #define HANDLE_COLUMN column = next_column; next_column += strlen(yytext)

    char *lineptr = NULL;
    size_t n = 0;
    size_t consumed = 0;
    size_t available = 0;

    size_t min(size_t a, size_t b);
    #define YY_INPUT(buf,result,max_size) {\
        if(available <= 0) {\
            consumed = 0;\
            available = getline(&lineptr, &n, yyin);\
            if (available < 0) {\
                if (ferror(yyin)) { perror("read error:"); }\
                    available = 0;\
                }\
        }\
        result = min(available, max_size);\
        strncpy(buf, lineptr + consumed, result);\
        consumed += result;\
        available -= result;\
    }
%}

%option noyywrap noinput nounput yylineno

%%

[\t ]+   { HANDLE_COLUMN; }
[0-9]+   { HANDLE_COLUMN; yylval = atoi(yytext);  return NUM; }
\n       { HANDLE_COLUMN; next_column = 1; return '\n'; }
.        { HANDLE_COLUMN; return yytext[0]; }

%%

size_t min(size_t a, size_t b) {
    return b < a ? b : a;
}

calc.y

%{
    #include <stdio.h>
    int yylex(void);
    void yyerror(const char *s);
    extern int yylineno;
    extern int column;
    extern char *lineptr;
    #define YYERROR_VERBOSE 1
%}

%token NUM
%left '-' '+'
%left '(' ')'

%%
LINE:                   { $$ = 0; }
       | LINE EXPR '\n' { printf("%s=%d\n", lineptr, $2); }
       | LINE '\n'
       ;


EXPR:    NUM            { $$ = $1; }
     |   EXPR '-' EXPR  { $$ = $1 - $3; }
     |   EXPR '+' EXPR  { $$ = $1 + $3; }
     |   '(' EXPR ')'   { $$ = $2; }
     ;


%%

void yyerror(const char *str)
{
    fprintf(stderr,"error: %s in line %d, column %d\n", str, yylineno, column);
    fprintf(stderr,"%s", lineptr);
    for(int i = 0; i < column - 1; i++)
    fprintf(stderr,"_");
    fprintf(stderr,"^\n");
}

int main()
{
   yyparse();
   free(lineptr);
}

Build Command

取决于您的系统,构建命令的外观类似于以下内容:

flex calc.l  
yacc -d calc.y
cc -Wextra -Wall lex.yy.c y.tab.c 
© www.soinside.com 2019 - 2024. All rights reserved.