Программирование. Принципы и практика использования C++ Исправленное издание, стр. 96
case '+': return primary(); default: error("ожидается первичное выражение"); }}Этот код настолько прост, что работает с первого раза.
7.5. Остаток от деления: %
Обдумывая проект калькулятора, мы хотели, чтобы он вычислял остаток от деления — оператор
%Это должно быть простым делом.
1. Добавляем символ % как Token.
2. Преобразовываем число типа
doubleint%Вот как изменится код функции
term()case '%': { double d = primary(); int i1 = int(left); int i2 = int(d); return i1%i2; }Для преобразования чисел типа
doubleintint(d)doubleint> 2%3;= 0> 3%2;= 1> 5%3;= 2Как обработать операнды, которые не являются целыми числами? Каким должен быть результат следующего выражения:
> 6.7%3.3;Это выражение не имеет корректного результата, поэтому запрещаем применение оператора
%Вот как выглядит результат функции
term()double term(){ double left = primary(); Token t = ts.get(); // получаем следующую лексему // из потока Token_stream while(true) { switch (t.kind) { case '*': left *= primary(); t = ts.get(); break; case '/': { double d = primary(); if (d == 0) error("Деление на нуль"); left /= d; t = ts.get(); break; } case '%': { double d = primary(); int i1 = int(left); if (i1 != left) error ("Левый операнд % не целое число"); int i2 = int(d); if (i2 != d) error ("Правый операнд % не целое число"); if (i2 == 0) error("%: деление на нуль"); left = i1%i2; t = ts.get(); break; } default: ts.putback(t); // возвращаем t обратно в поток // Token_stream return left; } }}Здесь мы лишь проверяем, изменилось ли число при преобразовании типа
doubleint%%narrow_castcase '%': { int i1 = narrow_cast<int>(left); int i2 = narrow_cast<int>(term()); if (i2 == 0) error("%: деление на нуль"); left = i1%i2; t = ts.get(); break; }Это очевидно короче и яснее, но не позволяет получать осмысленные сообщения об ошибках.
7.6. Приведение кода в порядок