2

来自野牛手册:

在每个输入为一行的简单交互式命令解析器中,允许 yyparse 在错误时返回 1 并让调用者在发生这种情况时忽略输入行的其余部分(然后再次调用 yyparse)可能就足够了。

这几乎是我想要的,但我在上班时遇到了麻烦。基本上,我想检测 flex 中的错误,如果检测到错误,让 Bison 丢弃整行。我现在拥有的东西不能正常工作,因为我的命令仍然被执行:

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);}
4

1 回答 1

6

我认为您不会在词法分析器中找到一个简单的解决方案来处理这些类型的解析错误。

我会尽可能保持词法分析器(flex/lex)的愚蠢,它应该只提供基本标记流(标识符、关键字等)并让解析器(yacc/bison)进行错误检测。事实上,它是为你想要的而设置的,只是对你的方法进行了一些重组......

在词法分析器(parser.l)中,保持简单(没有 eol/换行处理),类似于(不是完整的东西):

}%

/* 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;

然后在您的 parser.y 文件中进行所有真正的处理(不是完整的事情):

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 ...

这里有两点需要注意:

  1. 将 NEWLINE 之类的东西转移到 yacc 端,以便您可以确定用户何时完成命令,然后您可以清除并重新开始(假设您在int yywrap() {return 1;}某处有“”)。如果你试图在 flex 中过早检测它,你知道什么时候会引发错误?
  2. chdir 不是一个命令(除非它是子规则并且您只是没有显示它),它现在具有 chdir_command STRING(chdir 的参数)。这使得解析器可以找出问题所在,如果该目录不存在,则可以 yyerror 等等...

这样你应该得到类似的东西(猜测 chdir 可能是什么样子):

cd 'some_directory
语法错误
cd 'some_directory'
你在 some_directory 老兄!

它全部由 yacc 语法处理,而不是由分词器处理。

我发现保持 flex 尽可能简单会给你最大的灵活性。:)

于 2009-09-17T01:26:46.577 回答