У меня есть некоторая грамматика бизона:
input: /* empty */
| input command
;
command:
builtin
| external
;
builtin:
CD { printf("Changing to home directory...\n"); }
| CD WORD { printf("Changing to directory %s\n", $2); }
;
Я задаюсь вопросом, как я заставляю Бизона не принимать (YYACCEPT?) что-то как a command
пока это не читает ВЕСЬ вход. Таким образом, у меня могут быть все эти правила ниже той рекурсии использования или безотносительно создавать вещи, который или приводит к допустимой команде или чему-то, что это не собирается работать.
Один простой тест, который я делаю с кодом выше, просто вводит "CD mydir mydir". Синтаксические анализы бизона CD
и WORD
и идет "эй! это - команда, поместите ее в вершину!". Затем следующий маркер это находки справедливо WORD
, который не имеет никакого правила, и затем это сообщает об ошибке.
Я хочу, чтобы это считало целую строку и поняло CD WORD WORD
не правило, и затем сообщите об ошибке. Я думаю, что пропускаю что-то очевидное и был бы очень признателен за любую справку - Спасибо!
Также - я попытался использовать input command NEWLINE
или что-то подобное, но это все еще продвигает CD WORD
к вершине как команда и затем анализирует дополнительное WORD
отдельно.
Иногда я работаю с этими случаями, выравнивая свои грамматики.
В вашем случае, возможно, имеет смысл добавить токены в ваш лексер для разделителей новой строки и команд (;), чтобы вы могли явно поместить их в грамматику Bison, чтобы синтаксический анализатор ожидал полную строку ввода для команды перед принимая как команду.
sep: NEWLINE | SEMICOLON
;
command: CD sep
| CD WORD sep
;
Или для произвольного списка аргументов, например реальной оболочки:
args:
/* empty */
| args WORD
;
command:
CD args sep
;
Не могли бы вы просто изменить свои действия по сопоставлению правил, чтобы добавить их к списку действий, которые вы хотите выполнить, если все работает? Затем, после того, как весь ввод будет обработан, вы решаете, хотите ли вы сделать то, что было в этом списке действий, в зависимости от того, видели ли вы какие-либо ошибки синтаксического анализа.
Обычно все делается не так, как вы описываете.
С Bison / Yakk / Lex обычно тщательно разрабатывают синтаксис, чтобы делать именно то, что им нужно. Поскольку Bison / Yakk / Lex от природы жадные свои регулярные выражения, это должно вам помочь.
А как насчет этого?
Поскольку вы анализируете целые строк за раз, я думаю, что мы можем использовать этот факт в наших интересах и пересмотреть синтаксис.
input : /* empty */
| line
command-break : command-break semi-colon
| semi-colon
line : commands new-line
commands : commands command-break command
| commands command-break command command-break
| command
| command command-break
...
Где новая строка
, точка с запятой определена в исходном тексте
lex как что-то вроде
\ n ,
\ t `. Это должно дать вам синтаксис в стиле UNIX для команд, которые вы ищете. Возможны всевозможные вещи, и он немного раздут, допускает использование нескольких точек с запятой и не принимает во внимание пробелы, но вы должны уловить идею.
Лекс и Якк - мощный инструмент, и я считаю их весьма приятными - по крайней мере, когда вы не уложились в срок.