使用Flex(lex)和Bison(yacc)处理错误
从野牛手册: 在一个简单的交互式命令解析器中 如果每个输入为一行,则可能 足以允许yyparse 错误时返回1,并让调用者 在输入时忽略输入行的其余部分 发生这种情况(然后调用yyparse) 再次) 这正是我想要的,但我上班有困难。基本上,我想在flex中检测并纠正错误,如果检测到错误,让Bison丢弃整行代码。我现在所做的工作不太正常,因为我的命令仍在执行:使用Flex(lex)和Bison(yacc)处理错误,c,bison,yacc,lex,flex-lexer,C,Bison,Yacc,Lex,Flex Lexer,从野牛手册: 在一个简单的交互式命令解析器中 如果每个输入为一行,则可能 足以允许yyparse 错误时返回1,并让调用者 在输入时忽略输入行的其余部分 发生这种情况(然后调用yyparse) 再次) 这正是我想要的,但我上班有困难。基本上,我想在flex中检测并纠正错误,如果检测到错误,让Bison丢弃整行代码。我现在所做的工作不太正常,因为我的命令仍在执行: kbsh: ls '/home Error: Unterminated Single Quote admin kbrandt te
kbsh: ls '/home
Error: Unterminated Single Quote
admin kbrandt tempuser
syntax error
kbsh:
在我的野牛档案中:
commands:
/*Empty*/ { prompt(); } |
command { prompt(); }
;
command:
error {return 1; } |
chdir_command |
pwd_command |
exit_command |
WORD arg_list {
execute_command($1, $2);
//printf("%s, %s\n", $1, $2);
} |
WORD { execute_command($1, NULL); }
;
在我的Flex中:
' {BEGIN inQuote; }
<inQuote>\n {printf("Error: Unterminated Single Quote\n"); BEGIN(0); return(ERROR);}
“{BEGIN inQuote;}
\n{printf(“错误:未终止的单引号\n”);开始(0);返回(错误);}
我认为您无法在lexer中找到处理这些类型解析错误的简单解决方案
我希望lexer(flex/lex)尽可能保持沉默,它应该只提供一个基本令牌流(标识符、关键字等),并让解析器(yacc/bison)进行错误检测。事实上,它是为你想要的东西而设置的,只是对你的方法进行了一些调整
在lexer(parser.l)中,保持简单(没有eol/换行处理),类似(不是完整的东西):
然后在parser.y文件中执行所有真正的处理(不是全部):
命令:
错误换行符
{yyclearin;yyerrorok;打印_next_命令_prompt()}
|chdir_命令字符串换行符
{do_the_chdir($2);print_the_next_command_prompt();}
| ... 等等
这里有两件事需要注意:
int yywrap(){return 1;}
”)。如果您试图在flex中过早地检测到它,您知道何时会引发错误语法错误
cd“某些目录”
你在某个目录里,伙计
所有这些都是由yacc语法器处理的,而不是由标记器处理的
我发现让flex尽可能简单能让你获得最大的灵活性 因为我写了一个过于复杂的lexer,所以我经常发现自己脚上有一颗子弹。非常感谢蒂姆,当我有机会的时候,我会尝试将这个应用到我的项目中。我刚刚开始学习这方面的知识,所以假设你的建议是保持flex简单,这是一个很好的建议,这个答案很好!“除非它是子规则的,而你只是没有显示”——是的,它是子规则的,我只是没有显示它……所以在这个例子中,copy_to_tmp_缓冲区会去掉引号字符吗?你可以肯定地去掉copy_to_tmp_缓冲区中的引号。或者编写一个类似于copy_to_tmp_buffer的包装(去掉_引号(yytext))。只要您能在lexer中正确地隔离标识符,您就可以想象将引号解析移到yacc端,就像“chdir\u命令'\''标识符'\''换行符”一样。
}%
/* I don't recall if the backslashify is required below */
SINGLE_QUOTE_STRING \'.*\'
DOUBLE_QUOTE_STRING \".*\"
%%
{SINGLE_QUOTE_STRING} {
yylval.charstr = copy_to_tmp_buffer(yytext); // implies a %union
return STRING;
}
{DOUBLE_QUOTE_STRING} {
yylval.charstr = copy_to_tmp_buffer(yytext); // implies a %union
return STRING;
}
\n return NEWLINE;
command:
error NEWLINE
{ yyclearin; yyerrorok; print_the_next_command_prompt(); }
| chdir_command STRING NEWLINE
{ do_the_chdir($<charstr>2); print_the_next_command_prompt(); }
| ... and so on ...