Как исправить порядок, в котором анализируются простые команды оболочки?

#bison #context-free-grammar #bnf

#bison #контекстно-свободная грамматика #bnf

Вопрос:

Используя правила грамматики, определенные ниже, я пытаюсь проанализировать простую команду оболочки, скажем, как cd testFolder .

Это мои правила, определенные в parser.y:

 %union{
    char *str;
}

%type <str> WORD

%%
command_list:/*empty*/
            |command_list command_line{  
                printf("myShell > ");
            }
            ;

arg_list:/*empty*/ 
        | arg_list WORD{
            printf("Args: %sn", $2);
            free($2);
        }
        ;

cmd_and_args:
             WORD arg_list {
                printf("CMD: %sn", $1);
                free($1);
             }
            ;

command_line:
            cmd_and_args NEWLINE {printf("NULLn");
            }
            | NEWLINE {
                printf("NULLn");
            }
%%

  

Итак, я хотел, чтобы результат был:

 CMD: cd
Args: testFolder
NULL
  

но то, что я получаю, это:

 Args: testFolder
CMD: cd
NULL
  

Для такой команды, как vim -O test.c test1.c , я получаю :

 Args: -O
Args: test.c
Args: test1.c
CMD: vim
NULL
  

Аргументы приведены в порядок, но команда в конечном итоге появляется последней. Как мне расположить их в правильном порядке?

Комментарии:

1. Почему вас волнует, в каком порядке они печатаются?

2. Мне нужно заполнить массив команд, char **arguments чтобы я мог передать его execvp() для выполнения команды. Это не сработает, если они не в порядке.

3. Было бы нормально работать, если бы вы начали заполнять аргументы с индекса 1, а затем вставили команду в индекс 0 в конце 🙂

4. Да, я мог бы это сделать, но я просто хотел знать, где я ошибся в своей грамматике.

Ответ №1:

Bison производит синтаксический анализ снизу вверх, что означает, что если вы представляете синтаксический анализ в виде дерева, узлы обрабатываются раньше своих родителей. (Другими словами, это повторный порядок.)

Итак, действие для

  cmd_and_args:  WORD arg_list { … }
  

выполняется после действия для arg_list .

Я не понимаю, почему это может быть проблемой, но вы могли бы изменить это либо с помощью промежуточного действия, либо с помощью unit production для извлечения командного слова.

Промежуточное действие

 cmd_and_args:  WORD { /* print $1*/ arg_list { /* arg_list is now $3 */ }
  

Производство единиц

 cmd_and_args: command_word arg_list { … }

command_word: WORD { /* print $1 */ }
  

Примечание: грамматика не представляет реальную грамматику командной строки, которая позволяет назначениям предшествовать командному слову (например. LC_ALL=C sort file.txt ).

Комментарии:

1. Ах, действие среднего правила, к сожалению, это не поразило меня, даже когда я прочитал об этом в руководстве Bison. Я думаю, что вторая грамматика, которую я придумал, использует Unit production. Спасибо за ответ.

Ответ №2:

Я думаю, что решил это, вот обновленная грамматика:

 %union{
    char *str;
}

%type <str> WORD
%%

command_list:/*empty*/
            |com

    mand_list command_line{  
                    printf("myShell > ");
                }
                ;

    command_line: simple_command NEWLINE{
                    printf("NULLn");
                }
                | NEWLINE{
                    printf("NULLn");
                }
                ;

    simple_command: simple_command words
                  | WORD{
                    printf("CMD: %sn", $1);
                  }
                  ;

    words: WORD{
            printf("Args: %sn", $1);
         }
    %%