Литмир - Электронная Библиотека
A
A

      return left;

    }

  }

}

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 К сожалению, этот код не компилируется: операция вычисления остатка (
%
) для чисел с плавающей точкой не определена. Компилятор вежливо предупредит нас об этом. Когда мы утвердительно ответили на вопрос 5 из раздела 6.3.5 — “Следует ли позволить ввод чисел с плавающей точкой?”, — мы не думали о таких последствиях и просто поддались искушению добавить в программу дополнительные возможности. Вот так всегда! Что же делать? Можно во время выполнения программы проверить, являются ли оба операнда операции
%
целыми числами, и сообщить об ошибке, если это не так. А можно просто исключить операцию
%
из возможностей нашего калькулятора. Эту функцию всегда можно добавить позднее (см. раздел 7.5). Исключив операцию
%
, получим вполне работоспособную функцию: термы правильно распознаются и вычисляются. Однако опытный программист заметит нежелательную деталь, которая делает функцию
term()
неприемлемой. Что произойдет, если ввести выражение
2/0
? На нуль делить нельзя. Если попытаться это сделать, то аппаратное обеспечение компьютера обнаружит это и прекратит выполнение программы, выдав сообщение об ошибке. Неопытный программист обязательно столкнется с этой проблемой. По этой причине лучше провести проверку и выдать подходящее сообщение.

double term()

{

  double left = primary();

  Token t = get_token();

  while(true) {

    switch (t.kind) {

    case '*':

      left *= primary();

      t = get_token();

      break;

    case '/':

    { double d = primary();

      if (d == 0) error("деление на нуль");

      left /= d;

      t = get_token();

    break;

    }

    default:

      return left;

    }

  }

 

}

Почему мы поместили обработку операции

/
внутри блока? На этом настоял компилятор. Если мы хотим определить и инициализировать переменные в операторе
switch
, то должны поместить ее в блоке.

6.5.4. Первичные выражения

Грамматическое правило для первичных выражений также простое.

Первичное выражение:

  Число

  '('Выражение')'

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

double primary()

{

  Token t = get_token();

  switch (t.kind) {

  case '(': // обработка варианта '('выражение')'

    { double d = expression();

    t = get_token();

    if (t.kind != ')') error("')' expected");

    return d;

    }

  case '8':         // используем '8' для представления числа

    return t.value; // возвращаем значение числа

  default:

    error("ожидается первичное выражение");

  }

}

По сравнению с функциями

expression()
и
term()
в этом программном коде нет ничего нового. В нем используются те же самые языковые конструкции и методы, и объекты класса
Token
обрабатываются точно так же.

6.6. Испытание первой версии

Для того чтобы выполнить эти функции калькулятора, необходимо реализовать функции

get_token()
и
main()
. Функция
main()
тривиальна: мы просто вызываем функцию
expression()
и выводим результат на печать.

int main()

try {

  while (cin)

    cout << expression() << '\n';

  keep_window_open();

}

catch (exception& e) {

  cerr << e.what() << endl;

  keep_window_open ();

  return 1;

}

catch (...) {

  cerr << "exception \n";

  keep_window_open ();

  return 2;

}

Обработка ошибок представляет собой обычный шаблон (см. раздел 5.6.3). Отложим реализацию функции

get_token()
до раздела 6.8 и протестируем эту первую версию калькулятора.

ПОПРОБУЙТЕ

Первая версия программы, имитирующей работу калькулятора (включая функцию

get_token()
), содержится в файле
calculator00.cpp
. Запустите его и испытайте.

Нет ничего удивительного в том, что эта первая версия калькулятора работает не совсем так, как мы ожидали. Мы пожимаем плечами и спрашиваем себя: “Почему?”, или “Почему программа работает так, а не иначе?”, или “Что же она делает?” Введите число

2
и символ перехода на новую строку. Ответа вы не получите! Введите символ перехода на новую строку еще раз, чтобы убедиться, что компьютер не завис. Ответа по-прежнему нет. Введите число
3
и символ перехода на новую строку. Ответа нет! Введите число
4
и символ перехода на новую строку. Ответ равен
2
! Теперь экран выглядит так:

85
{"b":"847443","o":1}