Чтение онлайн

на главную

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

Рассмотрим пример.

1++2*3; 4+5;

Эти выражения вызывают ошибку, и лексемы

2*3; 4+5
останутся в буферах потоков
Token_stream
и
cin
после того, как второй символ
+
породит исключение.

У нас есть две возможности.

1. Удалить все лексемы из потока

Token_stream
.

2. Удалить из потока все лексемы

Token_stream
, связанные с текущими вычислениями.

В

первом случае отбрасываем все лексемы (включая
4+5;
), а во втором — отбрасываем только лексему
2*3
, оставляя лексему
4+5
для последующего вычисления. Один выбор является разумным, а второй может удивить пользователя. Обе альтернативы одинаково просто реализуются. Мы предпочли второй вариант, поскольку его проще протестировать. Он выглядит проще. Чтение лексем выполняется функцией
get
, поэтому можно написать функцию
clean_up_mess
, имеющую примерно такой вид:

void clean_up_mess // наивно

{

while (true) { // пропускаем,

// пока не обнаружим инструкцию "печать"

Token t = ts.get;

if (t.kind == print) return;

}

}

К сожалению, эта функция не всегда работает хорошо. Почему? Рассмотрим следующий вариант:

1@z; 1+3;

Символ

@
приводит нас к разделу
catch
в цикле
while
. Тогда для выявления следующей точки с запятой вызываем функцию
clean_up_mess
. Функция
clean_up_mess
вызывает функцию
get
и считывает символ
z
. Это порождает следующую ошибку (поскольку символ
z
не является лексемой), и мы снова оказываемся в блоке
catch
внутри функции
main
и выходим из программы. Ой! У нас теперь нет шансов вычислить лексему
1+3
. Вернитесь к меловой доске!

Можно было бы уточнить содержание блоков

try
и
catch
, но это внесет в программу еще большую путаницу. Ошибки в принципе трудно обрабатывать, а ошибки, возникающие при обработке других ошибок, обрабатывать еще труднее. Поэтому стоит попытаться найти способ удалять из потока
Token_stream
символы, которые могут породить исключение. Единственный путь для ввода данных в калькулятор пролегает через функцию
get
, и он может, как мы только что выяснили, порождать исключения. Таким образом, необходима новая операция. Очевидно, что ее целесообразно поместить в класс
Token_stream
.

class Token_stream {

public:

Token_stream; // создает поток Token_stream,
считывающий

// данные из потока cin

Token get; // считывает лексему

void putback(Token t); // возвращает лексему

void ignore(char c); // отбрасывает символы,

// предшествующие символу с включительно

private:

bool full; // есть лексема в буфере?

Token buffer; // здесь хранится лексема, которая возвращается

// назад с помощью функции putback

};

Функция

ignore
должна быть членом класса
Token_stream
, так как она должна иметь доступ к его буферу. Мы выбрали в качестве искомого символа аргумент функции
ignore
. Помимо всего прочего, объект класса
Token_stream
не обязан знать, что калькулятор считает хорошим символом для исправления ошибок. Мы решили, что этот аргумент должен быть символом, потому что не хотим рисковать, работая с составными лексемами (мы уже видели, что при этом происходит). Итак, мы получаем следующую функцию:

void Token_stream::ignore(char c)

// символ c обозначает разновидность лексем

{

// сначала проверяем буфер:

if (full && c==buffer.kind) {

full = false;

return;

}

full = false;

// теперь проверяем входные данные:

char ch = 0;

while (cin>>ch)

if (ch==c) return;

}

В этом коде сначала происходит проверка буфера. Если в буфере есть символ

c
, прекращаем работу, отбрасывая этот символ
c
; в противном случае необходимо считывать символы из потока
cin
, пока не встретится символ
c
. Теперь функцию
clean_up_mess
можно написать следующим образом:

void clean_up_mess

{

ts.ignore(print);

}

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

Поделиться:
Популярные книги

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21

Неудержимый. Книга VIII

Боярский Андрей
8. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
6.00
рейтинг книги
Неудержимый. Книга VIII

Бальмануг. Студентка

Лашина Полина
2. Мир Десяти
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бальмануг. Студентка

Энфис 2

Кронос Александр
2. Эрра
Фантастика:
героическая фантастика
рпг
аниме
5.00
рейтинг книги
Энфис 2

Мастер Разума VII

Кронос Александр
7. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума VII

Попаданка

Ахминеева Нина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка

Опер. Девочка на спор

Бигси Анна
5. Опасная работа
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Опер. Девочка на спор

Возвращение

Кораблев Родион
5. Другая сторона
Фантастика:
боевая фантастика
6.23
рейтинг книги
Возвращение

Волк 4: Лихие 90-е

Киров Никита
4. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 4: Лихие 90-е

Бальмануг. (Не) Любовница 2

Лашина Полина
4. Мир Десяти
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бальмануг. (Не) Любовница 2

Невеста вне отбора

Самсонова Наталья
Любовные романы:
любовно-фантастические романы
7.33
рейтинг книги
Невеста вне отбора

Большая игра

Ланцов Михаил Алексеевич
4. Иван Московский
Фантастика:
альтернативная история
5.00
рейтинг книги
Большая игра

Идеальный мир для Лекаря 17

Сапфир Олег
17. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 17