在 Bison 中抛出异常并在 main() 中捕获

Throw Exception in Bison and catch in main()

是否可以在我的 .y 文件中抛出异常并在启动 yyparse() 的 .l 中捕获它?

让我们写一些示例代码。这是我的 .y 文件的一部分:

%{
#include <stdio.h>
#include <string>
#include <cstring>

using namespace std;

extern int yylex();
extern void yyerror(char*);

typedef enum {  ZERO_DIVISION = 0,
                VAR_DUPLICATE_NAME = 1,
                ...
                GENERAL = 100
             } e_errors;
const char* e_errNames[] = {"ZERO_DIVISION","VAR_DUPLICATE_NAME",...,"GENERAL"};
...

%}

//Symbols
%union
{
    ...
};

%token ...

%start X1

%%

X1:
    BEGIN
    ....
    END
    ;
    {
        ...

        if(myCheck(i)>=0) throw VAR_DUPLICATE_NAME;

        ...
    }
    ;
...

%%

这就是我试图在我的 .l 文件中以错误的方式捕获 VAR_DUPLICATE_NAME 的方式:

%{
#include <string.h>
#include "proxydata.tab.h"

void yyerror(char*);
int yyparse(void);

char linebuf[500]; //for output the row in case of syntax error

%}

%option yylineno

blanks          [ \t\n]+
text            [a-zA-Z0-9]+|[0-9]+.[0-9]+
%%

\n.*            { /* saving the next row in case of syntax error */
                  strncpy(linebuf, yytext+1, sizeof(linebuf)); /* save the next line */
                  yyless(1);      /* give back all but the \n to rescan */
                }

{blanks}        { /* ignore */ };


...             return(...);

{text}          { yylval.str_val=(char*)strdup(yytext);
                  return(IDENTIFIER);
                }

.               return yytext[0];

%%

void yyerror(char *s){ 
    printf("LINE %d: %s at %s in this line:\n%s\n", yylineno, s, yytext, linebuf);
    }

int yywrap (void){
    ;
    }

int main(int num_args, char** args){
    if(num_args != 2) {printf("usage: ./parser filename\n"); exit(0);}
    FILE* file = fopen(args[1],"r");
    if(file == NULL) {printf("couldn't open %s\n",args[1]); exit(0);}
    yyin = file;

    try{
    yyparse();
    }catch(int err){
        printf("ERROR! %s",e_errNames[err]);
    }

    fclose(file);
}

这样,解析器就被正确创建了,但是当我输入一个生成异常的文件时,我会遇到以下消息:

terminate called after throwing an instance of 'e_errors' Aborted (core dumped)

我知道在写printf("ERROR! %s",e_errNames[err])之前,我也应该声明一下。这个 extern const char* e_errNames[]; 在 flex 文件的顶部是否足够?

据我所知,如果你抛出 e_errors,你需要捕获 e_errors,而不是 int。尽管 enum 是整数类型,但它不是 int 并且 catch 不进行转换。

但是,您最好还是使用 YYABORT,这将使解析器有机会进行清理。 (如果您使用的是 C++ 框架,那可能不是必需的,但它应该仍然有效。)当然,您需要将错误代码存储在某个地方。

您应该按照设计者的意图调用 yyerror() 或 YY_ABORT。解析器不应抛出异常,除非它们出现故障。而且您不希望解析中只有一个错误,您需要所有错误。

注意,您并没有真正在 flex 中发现错误。 您在 main() 中发现错误,它可以在任何地方。 yyparse() 调用 yylex(),而不是相反。 yyparse() 抛出的任何东西都可能被 main() 或您提供的任何其他调用它的东西捕获,但不会被 yylex().

捕获