在 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()
.
捕获
是否可以在我的 .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()
.