Как заставить Bison / YACC не распознавать команду, пока она не проанализирует всю строку? - PullRequest
5 голосов
/ 08 апреля 2010

У меня есть грамматика зубров:

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?) Что-то как command, пока он не прочитает ВСЕ входные данные. Таким образом, я могу иметь все эти правила ниже, которые используют рекурсию или что-то еще для построения вещей, что приводит либо к допустимой команде, либо к чему-то, что не будет работать.

Один простой тест, который я делаю с приведенным выше кодом, просто вводит "cd mydir mydir". Зубр разбирает CD и WORD и говорит: «Эй! Это команда, поставь ее наверх!». Тогда следующий найденный токен - это просто WORD, у которого нет правила, и затем он сообщает об ошибке.

Я хочу, чтобы он прочитал всю строку и понял, что CD WORD WORD не является правилом, а затем сообщит об ошибке. Я думаю, что упускаю что-то очевидное и буду очень признателен за любую помощь - спасибо!

Также - я пытался использовать input command NEWLINE или что-то подобное, но он все равно выдвигает CD WORD в качестве команды, а затем анализирует дополнительные WORD отдельно.

Ответы [ 4 ]

2 голосов
/ 08 апреля 2010

Иногда я имею дело с этими случаями, уплощая мои грамматики.

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

sep:   NEWLINE | SEMICOLON
   ;

command:  CD  sep
   |  CD WORD sep
   ;

Или, для произвольного списка аргументов, подобных реальной оболочке:

args:
    /* empty */
  | args WORD
  ;

command:
      CD args sep
   ;
1 голос
/ 18 марта 2011

Вместо непосредственного вызова действий, сначала создайте себе абстрактное синтаксическое дерево. Затем в зависимости от результата и ваших предпочтений вы либо выполняете его часть, либо ничего. Если во время построения дерева возникает ошибка синтаксического анализа, вы можете использовать директиву% destructor, чтобы сообщить bison, как выполнить очистку.

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

0 голосов
/ 08 апреля 2010

Не могли бы вы просто изменить действия по совпадению правил, чтобы добавить их в список действий, которые вы хотите выполнить, если все это работает? Затем, после обработки всего ввода, вы решаете, хотите ли вы делать то, что было в этом списке действий, на основании того, что вы обнаружили ошибки синтаксического анализа.

0 голосов
/ 08 апреля 2010

Обычно все не так, как вы описали.

С помощью 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

...

Где new-line, 'точка с запятой is defined in your lex source as something like \ n , \ t`. Это должно дать вам синтаксис в стиле UNIX для команд, которые вы ищете. Все виды вещей возможны, и это немного раздутый, допускающий несколько точек с запятой и не учитывает пробел, но вы должны понять.

Лекс и Якк - мощный инструмент, и я нахожу их весьма приятными - по крайней мере, когда вы не в срок.

...