Путаница с грамматикой бизонов / YACC - PullRequest
1 голос
/ 19 сентября 2009

С помощью следующей грамматики я получаю синтаксическую ошибку с такого рода вводом:

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

Я думаю, что это может иметь какое-то отношение к тому, как работает lookahead, но это моя первая грамматика, и меня немного смущает, почему это не работает таким образом: 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;
    }

Ответы [ 3 ]

2 голосов
/ 19 сентября 2009

Синтаксическая ошибка исходит от вашего ВТОРОГО вызова yyparse. Когда у вас есть перенаправление, ваша грамматика выполняет YYACCEPT, что заставляет синтаксический анализатор немедленно возвращаться, не читая больше ничего. При втором вызове первое чтение токена - это NEWLINE, что приводит к ошибке (ваша грамматика не допускает пустых строк.)

Без перенаправления нет YYACCEPT, поэтому грамматика продолжает работать, читая новую строку и возвращаясь при достижении конца ввода.

1 голос
/ 19 сентября 2009
  1. Вы действительно действительно должны использовать левую рекурсию с генераторами синтаксических анализаторов LALR (1). Правая рекурсия требует, чтобы все элементы были сдвинуты в стек состояния анализатора, прежде чем может произойти хотя бы одно сокращение. Вы можете представить, что это делает для восстановления после ошибок.

  2. Что именно является external_cmd? Похоже, что оно сокращается рано, но трудно сказать, потому что вы его не включили.

  3. Почему YYACCEPT вызывается после любого перенаправления? Если вы собираетесь перезапускать анализатор в каждой строке, у вас не должно быть рекурсивного сборщика ввода. Пока у вас есть, не делайте YYACCEPT.

0 голосов
/ 20 сентября 2009

Нашел, в моем правиле перенаправления отсутствует канал, поэтому вместо двух компонентов есть один с действием в середине правила, а это не то, что мне нужно.

...