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