Обработка ошибок
Поскольку программа достаточно проста, не надо особо беспокоиться об обработке ошибок. Функция error просто подсчитывает число ошибок, выдает сообщение о них и возвращает управление обратно:
int no_of_errors;
double error(const char* s) { cerr << "error: " << s << "\n"; no_of_errors++; return 1; }
Небуферизованный выходной поток cerr обычно используется именно для выдачи сообщений об ошибках. Управление возвращается из error() потому, что ошибки, как правило, встречаются посреди вычисления выражения. Значит надо либо полностью прекращать вычисления, либо возвращать значение, которое не должно вызвать последующих ошибок. Для простого калькулятора больше подходит последнее. Если бы функция get_token() отслеживала номера строк, то функция error() могла бы указывать пользователю приблизительное место ошибки. Это было бы полезно при неинтерактивной работе с калькулятором. Часто после появления ошибки программа должна завершиться, поскольку не удалось предложить разумный вариант ее дальнейшего выполнения. Завершить ее можно с помощью вызова функции exit(), которая заканчивает работу с выходными потоками и завершает программу, возвращая свой параметр в качестве ее результата. Более радикальный способ завершения программы - это вызов функции abort(), которая прерывает выполнение программы немедленно или сразу же после сохранения информации для отладчика (сброс оперативной памяти).
Более тонкие приемы обработки ошибок можно предложить, если ориентироваться на особые ситуации, но предложенное решение вполне приемлемо для игрушечного калькулятора в 200 строк.