2

バイソンマニュアルから:

各入力が1行である単純な対話型コマンドパーサーでは、エラー時にyyparseが1を返し、それが発生したときに呼び出し元が入力行の残りを無視するようにするだけで十分な場合があります(その後、yyparseを再度呼び出します)。

これは私が望んでいることとほぼ同じですが、仕事に取り掛かるのに苦労しています。基本的には、flexでエラーを検出してエラーを検出し、エラーが検出された場合は、Bisonに行全体を破棄してもらいます。私が今持っているものは、私のコマンドがまだ実行されているため、正しく機能していません:

kbsh: ls '/home
Error: Unterminated Single Quote
admin  kbrandt  tempuser
syntax error
kbsh: 

私のBisonファイル:

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

そして私のフレックスでは:

'   {BEGIN inQuote; }

<inQuote>\n {printf("Error: Unterminated Single Quote\n"); BEGIN(0); return(ERROR);}
4

1 に答える 1

6

レクサーでこれらのタイプの解析エラーを処理するための簡単な解決策が見つかるとは思いません。

lexer (flex/lex) をできるだけ馬鹿げたものにして、基本的なトークン (識別子、キーワードなど) のストリームを提供し、パーサー (yacc/bison) にエラー検出を行わせる必要があります。実際、アプローチを少し再構築することで、まさにあなたが望むものに合わせてセットアップされています...

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

ここで注意すべき点が 2 つあります。

  1. NEWLINE のようなものを yacc 側に移すことで、ユーザーがいつコマンドを実行したかを判断できるようになり、それを消去して最初からやり直すことができます (int yywrap() {return 1;}どこかに " " があると仮定します)。フレックスの早い段階で検出しようとすると、いつエラーを発生させることがわかりますか?
  2. chdir は 1 つのコマンドではありません (サブルール化されていて表示されていない場合を除きます)、chdir_command STRING (chdir への引数) が追加されました。これにより、パーサーが何が問題なのかを把握できるようになり、そのディレクトリが存在しない場合は yyerror を実行できます...

このようにして、次のようになります(chdirがどのように見えるかを推測します):

cd 'some_directory
構文エラー
cd 'some_directory'
あなたは some_directory にいます!

そして、それはすべて、トークナイザーではなく、yacc グラマーによって処理されます。

flex をできるだけシンプルに保つことで、最も ***柔軟な*** 柔軟性が得られることがわかりました。:)

于 2009-09-17T01:26:46.577 に答える