Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
УМК по СПО.doc
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

8.4.Дополнительные возможности программ yacc и lex

8.4.1.Обработка ошибок

Обработка ошибок - это чрезвычайно сложная область; многие связанные с ней проблемы являются семантическими. Когда ошибка найдена, может потребоваться, например, очистить память, в которой хранилось дерево разбора, удалить или изменить содержимое таблицы символов и (или), чаще всего, установить переключатели, препятствующие дальнейшему формированию выходных данных.

Далеко не всегда приемлемо при обнаружении ошибки вообще прекратить обработку. Полезнее продолжить сканирование исходного текста для того, чтобы обнаружить и другие синтаксические ошибки. При этом возникает проблема нейтрализации ошибки и возобновления разбора. Широкий класс алгоритмов нейтрализации достигает цели, пропуская несколько лексем во входной цепочке и пытаясь найти состояние, в котором можно возобновить разбор исходного текста.

Чтобы позволить пользователю как-то управлять данным процессом, в yacc'е зарезервирована лексема с именем error. Это имя можно использовать в грамматических правилах. Оно используется для указания мест, где ожидаются ошибки и может потребоваться их нейтрализация. Алгоритм разбора очищает стек, пока не окажется в состоянии, в котором допустима лексема error. Затем он поступает так, будто лексема error является текущей предварительно просмотренной, и выполняет действие, оказавшееся текущим. Предварительно просмотренная лексема затем устанавливается равной лексеме, которая вызвала ошибку. Если специальных "ошибочных" правил не задано, после того, как ошибка обнаружена, обработка прекращается.

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

Например, правило вида

stat : error

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

Со специальными "ошибочными" правилами такого вида могут быть ассоциированы действия, которые могут пытаться заново инициализировать таблицы и т.д.

Такие правила, как предыдущее, универсальны, но ими трудно управлять. Правила, подобные

stat : error ';'

несколько удобнее. Здесь, когда возникает ошибка, алгоритм пытается перескочить оператор, переходя на следующую точку с запятой. Все лексемы после ошибочной и до следующей точки с запятой пропускаются. После того как точка с запятой найдена, для данного правила делается свертка и выполняется связанное с ним действие по нейтрализации ошибки.

Еще одна форма error правила возникает в интерактивных приложениях, где может потребоваться разрешить после ошибки перенабрать строку. Пример

input : error '\n'

{

printf ("Перенаберите последнюю строку: ");

}

input

{

$$ = $4;

}

;

показывает, как это можно сделать. Такой подход имеет, однако, и недостатки. Алгоритм должен корректно обработать три входные лексемы перед тем, как вернется в корректное состояние. Если перенабранная строка содержит ошибки в первых двух лексемах, алгоритм молча удалит их, что, конечно, неприемлемо. Имеется механизм, который принуждает алгоритм разбора завершить нейтрализацию ошибок. Включенный в действие оператор

yyerrok ;

возвращает алгоритм в нормальное состояние. Последний пример можно переписать в виде:

input : error '\n'

{

yyerrok;

printf ("Перенаберите последнюю строку: ");

}

input

{

$$ = $4;

}

;

Как упоминалось выше, сразу после символа error предварительно просмотренная лексема равна входной лексеме, на которой была обнаружена ошибка. Иногда это неуместно; задачу выбора корректного места для возобновления разбора может взять на себя действие, соответствующее правилу, содержащему error. В этом случае предыдущая предварительно просмотренная лексема должна быть очищена. Оператор

yyclearin ;

помещенный в действие, даст желаемый результат. Предположим, например, что действие после error должно вызывать некоторую замысловатую процедуру нейтрализации (определенную пользователем), пытающуюся возобновить разбор с начала следующего корректного оператора. Предполагается, что после того, как вызвана данная процедура, следующая лексема, возвращаемая yylex() – это первая лексема в корректном операторе. Старая недопустимая лексема должна быть отброшена и установлено состояние error. К цели ведет правило, подобное следующему:

stat : error

{

resynch ();

yyerrok;

yyclearin;

}

;

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