1

次の文法では、この種の入力で構文エラーが発生します。

ls /home > foo #Runs and works okay, but raises error token
ls /home /foo /bar /etc #works okay

先読みの仕組みと関係があると思いますが、これは私の最初の文法であり、なぜこのように機能しないのかについて少し混乱しています: external_cmd GT WORD はリダイレクト、リダイレクトはコマンド、コマンドはコマンドなので、入力コマンド NEWLINE が機能するはずです。

文法のトップルール:

input:
    error NEWLINE {
        printf("Error Triggered\n");
        yyclearin;
        yyerrok; 
        prompt(); 
    } |
    input NEWLINE {
        prompt();
    } | 
    input commands NEWLINE {
        prompt (); 
    } | 
    /* empty */
    ;   

commands: 
    command |   
    command SEMI | 
    command SEMI commands
    ;   

command:
    builtin_cmd |
    redirect |
    external_cmd { 
        execute_command($1, 0, NULL);
    }
    ;

redirect:
    external_cmd GT WORD  {
        printf("Redirecting stdout of %s to %s\n", $1->cmd, $3);
        //printf("DEBUG: GT\n");
        execute_command($1, STDOUT_FILENO, $3);
    }
    external_cmd LT WORD {
        printf("Redirecting stin of %s to %s\n", $1->cmd, $3);
        //printf("DEBUG: GT\n");
        execute_command($1, STDIN_FILENO, $3);
    }
    ;

エラー トークンが発生したときのデバッグ/詳細入力:

Next token is token WORD ()
Shifting token WORD ()
Entering state 6
Reading a token: Next token is token WORD ()
Shifting token WORD ()
Entering state 24
Reading a token: Next token is token GT ()
Reducing stack by rule 22 (line 115):
   $1 = token WORD ()
-> $$ = nterm arg_list ()
Stack now 0 2 6
Entering state 26
Reducing stack by rule 19 (line 91):
   $1 = token WORD ()
   $2 = nterm arg_list ()
-> $$ = nterm external_cmd ()
Stack now 0 2
Entering state 16
Next token is token GT ()
Shifting token GT ()
Entering state 29
Reading a token: Next token is token WORD ()
Shifting token WORD ()
Entering state 33
Reducing stack by rule 11 (line 68):
Redirecting stdout of ls to foo
DEBUG: redirect mode is 1
DEBUG: Command to run is ls
DEBUG: Adding Argument /home
admin  kbrandt  tempuser
-> $$ = nterm @1 ()
Stack now 0 2 16 29 33
Entering state 34
Reading a token: Next token is token NEWLINE ()
syntax error
Error: popping nterm @1 ()
Stack now 0 2 16 29 33
Error: popping token WORD ()
Stack now 0 2 16 29
Error: popping token GT ()
Stack now 0 2 16
Error: popping nterm external_cmd ()
Stack now 0 2
Error: popping nterm input ()
Stack now 0
Shifting token error ()
Entering state 1
Next token is token NEWLINE ()
Shifting token NEWLINE ()
Entering state 3
Reducing stack by rule 1 (line 38):
   $1 = token error ()
   $2 = token NEWLINE ()
Error Triggered
-> $$ = nterm input ()
Stack now 0
Entering state 2

更新:
external_cmd は:

external_cmd:
    WORD arg_list {
        $$ = malloc( sizeof(struct ext_cmd) );
        if ( $$ == NULL)
            printf("Memory Allocation Error\n");
        $$->cmd = $1;
        $$->args_pp = $2;
    } |
    WORD    {
        $$ = malloc( sizeof(struct ext_cmd) );
        if ( $$ == NULL)
            printf("Memory Allocation Error\n");
        $$->cmd = $<string>1;
        $$->args_pp = NULL;
    }
4

3 に答える 3

2

構文エラーは、yyparseへの2回目の呼び出しから発生しています。リダイレクトがあると、文法はYYACCEPTを実行します。これにより、パーサーは何も読み取らずにすぐに戻ります。2回目の呼び出しでは、最初に読み取られたトークンはNEWLINEであり、エラーが発生します(文法では空白行は使用できません)。

リダイレクトがない場合、YYACCEPTがないため、文法は実行を継続し、改行を読み取り、入力の最後に到達すると戻ります。

于 2009-09-19T18:55:24.873 に答える
1
  1. LALR(1)パーサジェネレータでは、本当に左再帰を使用する必要があります右再帰では、単一の削減が発生する前に、すべての要素をパーサー状態スタックにシフトする必要があります。これがエラー回復に何をするか想像できます。

  2. 正確には何external_cmdですか?早い段階で削減されているように見えますが、含まれていなかったためわかりにくいです。

  3. YYACCEPTリダイレクト後に呼び出されるのはなぜですか?各行でパーサーを再起動する場合は、再帰的な入力コレクターを使用しないでください。あなたがそれを持っている限り、YYACCEPTをしないでください。

于 2009-09-19T18:34:13.183 に答える
0

私のリダイレクトルールにはパイプがありません。そのため、2 つのコンポーネントの代わりに、ルールの途中で動作するものが 1 つありますが、これは私が望んでいるものではありません。

于 2009-09-20T14:19:31.343 に答える