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

    keep_window_open();

    return 0;

  }

  ts.putback(t);

  cout << result << expression() << endl;

}

7.6.2. Использование функций

Функции должны отражать структуру программы, и их имена должны обеспечивать логическое разделение кода на отдельные части. В этом отношении наша программа до сих пор не вызывала нареканий: функции

expression()
,
term()
и
primary()
непосредственно отражают наше понимание грамматики, а функция
get()
выполняет ввод и распознавание лексем. Тем не менее анализ функции
main()
показывает, что ее можно разделить на две логически разные части.

1. Функция

main()
описывает общую логическую структуру: начало программы, конец программы и обработку фатальных ошибок.

2. Функция

main()
выполняет цикл вычислений.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Теоретически любая функция выполняет отдельное логическое действие (см. раздел 4.5.1). Если функция
main()
выполняет оба эти действия, то это затемняет структуру программы. Напрашивается выделение цикла вычислений в виде отдельной функции
calculate()
.

void calculate() // цикл вычисления выражения

{

  while (cin) {

    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;

  }

}

int main()

try {

  calculate();

  keep_window_open(); // обеспечивает консольный режим Windows

  return 0;

}

catch (runtime_error& e) {

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

  keep_window_open("~~");

  return 1;

}

catch (...) {

  cerr << "exception \n";

  keep_window_open("~~");

  return 2;

}

Этот код намного более четко отражает структуру программы, и, следовательно, его проще понять.

7.6.3. Расположение кода

Поиск некрасивого кода приводит нас к следующему фрагменту:

switch (ch) {

case 'q': case ';': case '%': case '(': case ')':

case '+': case '–': case '*': case '/':

  return Token(ch); // пусть каждый символ обозначает сам себя

Этот код был неплох, пока мы не добавили символы

'q'
,
';'
и
'%'
, но теперь он стал непонятным. Код, который трудно читать, часто скрывает ошибки. И конечно, они есть в этом фрагменте! Для их выявления необходимо разместить каждый раздел
case
в отдельной строке и расставить комментарии. Итак, функция
Token_stream::get()
принимает следующий вид:

Token Token_stream::get()

  // считываем символ из потока cin и образуем лексему

{

  if (full) { // проверяем, есть ли в потоке хотя бы одна лексема

    full=false;

    return buffer;

  }

  char ch;

  cin >> ch; // Перевод:" оператор >> игнорирует разделители пробелы,

             // переходы на новую строку, табуляцию и пр.)"

  switch (ch) {

  case quit:

  case print:

  case '(':

  case ')':

  case '+':

  case '–':

  case '*':

  case '/':

  case '%':

    return Token(ch); // пусть каждый символ обозначает сам себя

  case '.': // литерал с плавающей точкой может начинаться с точки

  case '0': case '1': case '2': case '3': case '4':

  case '5': case '6': case '7': case '8': case '9': // числовой

                                                    // литерал

  { cin.putback(ch); // возвращаем цифру обратно во входной

                     // поток

    double val;

    cin >> val; // считываем число с плавающей точкой

    return Token(number,val);

  }

  default:

    error("Неправильная лексема");

  }

}

Разумеется, можно было бы поместить в отдельной строке раздел

case
для каждой цифры, но это нисколько не прояснит программу. Кроме того, в этом случае функция
get()
вообще осталась бы за пределами экрана. В идеале на экране должны поместиться все функции; очевидно, что ошибку легче скрыть в коде, который находится за пределами экрана. Расположение кода имеет важное значение. Кроме того, обратите внимание на то, что мы заменили простой символ
'q'
символическим именем
quit
. Это повышает читабельность кода и гарантирует появление сообщения компилятора при попытке выбрать для имени
quit
значение, уже связанное с другим именем лексемы.

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