Шрифт:
/*
Простой калькулятор
История версий:
Переработан Бьярне Страуструпом в мае 2007 г.
Переработан Бьярне Страуструпом в августе 2006 г.
Переработан Бьярне Страуструпом в августе 2004 г.
Разработан Бьярне Страуструпом
(bs@cs.tamu.edu) весной 2004 г.
Эта программа реализует основные выражения калькулятора.
Ввод из потока с in; вывод в поток cout.
Грамматика для ввода:
Инструкция:
Выражение
Печать
Выход
Печать:
;
Выход:
q
Выражение:
Терм
Выражение + Терм
Выражение – Терм
Терм:
Первичное выражение
Терм * Первичное выражение
Терм / Первичное выражение
Терм % Первичное выражение
Первичное выражение:
Число
(Выражение)
– Первичное выражение
+ Первичное выражение
Число:
литерал_с_плавающей_точкой
Ввод из потока cin через поток Token_stream с именем ts.
*/
Здесь мы использовали блок комментариев, который начинается символами
/*
и заканчивается символами */
. В реальной программе история пересмотра может содержать сведения о том, какие именно изменения были внесены и какие улучшения были сделаны. Обратите внимание на то, что эти комментарии помещены за пределами кода. Фактически это несколько упрощенная грамматика: сравните правило для Инструкции с тем, что на самом деле происходит в программе (например, взгляните на код в следующем разделе). Этот комментарий ничего не говорит от цикле в функции calculate
, позволяющем выполнять несколько вычислений в рамках одного сеанса работы программы. Мы вернемся к этой проблеме в разделе 7.8.1. 7.7. Исправление ошибок
Почему мы прекращаем работу программы, когда находим ошибку? В свое время это казалось простым и очевидным решением, но почему? Почему бы не вывести сообщение об ошибке и продолжить работу? Помимо всего прочего, мы часто делаем опечатки, и такие ошибки не означают, что мы решили не выполнять вычисления. Итак, попробуем исправить ошибки. Это по существу значит, что мы должны перехватить исключение и продолжить работу после исправления ошибки.
До сих пор все ошибки представлялись в виде исключений и обрабатывались функцией
main
. Если мы хотим исправить ошибку, то функция calculate
должна перехватывать исключения и попытаться устранить неисправность прежде, чем приступить к вычислению следующего выражения.
void calculate
{
while (cin)
try {
cout << prompt;
Token t = ts.get;
while (t.kind == print) t=ts.get; // сначала
// игнорируем все
//
инструкции
"печать"
if (t.kind == quit) return;
ts.putback(t);
cout << result << expression << endl;
}
catch (exception& e) {
cerr << e.what << endl; // выводим сообщение об ошибке
clean_up_mess;
}
}
Мы просто поместили цикл
while
в блоке try
, который выводит сообщения об ошибке и устраняет неисправности. После этого работу можно продолжать по-прежнему. Что означает выражение “устранить неисправность”? В принципе готовность к выполнению вычислений после исправления ошибки означает, что все данные находятся в полном порядке и вполне предсказуемы. В калькуляторе единственные данные за пределами отдельных функций находятся в потоке Token_stream
. Следовательно, мы должны убедиться, что в потоке нет лексем, связанных с прекращенными вычислениями и способных помешать будущим вычислениям.