[ Содержание ] [ Предыдущая ] [ Следующая ]

Глава 7. Обработка ошибок

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

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

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

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

    В качестве примера, правило вида

stat : error

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

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

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

stat : error ';'

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

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

input: error '\n' { printf( "Reenter last line: " ); } input { $$ = $4; } ;

    Существует потенциальная трудность с этим подходом; парсер должен корректно обработать три входных токена перед тем, как он решит, что корректно пересинхронизировался после ошибки. Если повторно введенная строка содержит ошибку в первых двух токенах, парсер удаляет ошибочные токены без выдачи сообщения; это совершенно неприемлемо. По этой причине существует механизм, который может использоваться, чтобы заставить парсер поверить, что ошибка была полностью устранена. Оператор yyerrok; есть действие, которое возвращает парсер в нормальный режим. Последний пример лучше можно написать

input: error '\n' { yyerrok; printf( "Reenter last line: " ); } input { $$ = $4; } ;

    Как уже упоминалось выше, токен, увиденный немедленно после символа "error" есть входной токен, в котором была обнаружена ошибка. Иногда это не подходит; например, действие по восстановлению ошибки может взять на себя поиск корректного места для возобновления обработки входных данных. В этом случае предыдущий LA-токен должен быть очищен. Оператор yyclearin; в действии будет иметь именно такой эффект. Hапример, предположим, что действием после ошибки был вызов сложной процедуры пересинхронизации, написанной пользователем, которая попыталася продвинуть входные данные до начала следующего разрешенного оператора. После того, как была вызвана эта процедура, следующий токен, возвращенный yylex, по видимому, будет первым токеном в разрешенном операторе; старый, неверный токен должен быть отброшен, а состояние ошибки - обнулиться. Это может быть сделано с помощью такого правила, как

stat : error { resynch(); yyerrok ; yyclearin ; } ;

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

[ Содержание ] [ Предыдущая ] [ Следующая ]



c 1998-2000 SoloTony (Antonio Solo) solotony@mail.ru