1

使用以下语法,我收到这种输入的语法错误:

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

我认为这可能与前瞻的工作方式有关,但这是我的第一个语法,我有点困惑为什么它不能这样工作:external_cmd GT WORD 是重定向,redirect 是命令,命令是命令,因此输入命令 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 的第二次调用。当您进行重定向时,您的语法会执行 YYACCEPT,这会导致解析器立即返回而无需再读取任何内容。在第二次调用中,读取的第一个标记是 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

找到它,在我的重定向规则中缺少一个管道,因此不是两个组件,而是一个具有中间规则操作的组件,这不是我想要的。

于 2009-09-20T14:19:31.343 回答