【问题标题】:How to implement better error messages for flex/bison [duplicate]如何为 flex/bison 实现更好的错误消息 [重复]
【发布时间】:2020-05-31 12:07:15
【问题描述】:

我需要为我正在编写的语法的语法错误提供适当的错误消息。我发现我可以在 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】:

    输出意外和预期的令牌

    只要使用

    #define YYERROR_VERBOSE 1
    

    yyerror 输出已经类似于

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

    打印行号

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

    声明它
    extern int yylineno;
    

    在 .y 文件中。

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

    %option yylineno
    

    打印列

    要获取列信息,您必须跟踪词法分析器文件中的列。因此,在您读取令牌后,您可以简单地添加令牌的长度(例如,通过使用 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);
    }
    

    构建命令

    根据您的系统,构建命令类似于以下内容:

    flex calc.l  
    yacc -d calc.y
    cc -Wextra -Wall lex.yy.c y.tab.c 
    

    【讨论】:

    • YYERROR_VERBOSE 是野牛扩展,所以只有当你的“yacc”真的是野牛时才有效。如果您使用的是野牛,那么解析器中的位置也有内置支持,@
    • @ChrisDodd 是的,确实可以使用 %locations。在词法分析器方面,然后是 %option bison-locations。使用 YY_USER_ACTION,您可以填写 yylloc。结果是一个 yyerror 变体,其中第一个参数是 YYLTYPE 类型。默认情况下,这将为我们提供所需的令牌行和列的开始和结束(请参阅gnu.org/software/bison/manual/html_node/Location-Type.html)。
    • 但问题还要求输出有问题的行。但是,为此,您仍然必须自己管理词法分析器中的输入行。当然,这可能有一个 bison/flex 方法,我只是不知道。有这种事吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    相关资源
    最近更新 更多