Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

Модифицируем функцию

expression
так, чтобы она не “съедала” лексемы. Куда поместить следующую лексему (
t
), если программа никак не использует ее? Можно рассмотреть много сложных схем, но давайте просто перейдем к очевидному ответу (его очевидность станет ясной позднее): поскольку лексема будет использована другой функцией, которая будет считывать ее из потока ввода, давайте вернем лексему обратно в поток ввода, чтобы ее могла считать другая функция! Действительно, мы можем вернуть символ обратно в поток ввода, но это не совсем то, что мы хотим. Мы хотим работать с лексемами, а не возиться с символами. Итак, хотелось бы, чтобы поток ввода работал с лексемам, а мы имели бы возможность записывать в него уже считанные лексемы.

Предположим, в нашем распоряжении есть поток лексем — “

Token_stream
” — с именем
ts
. Допустим также, что поток
Token_stream
имеет функцию-член
get
, возвращающую следующую лексему, и функцию-член
putback(t)
, возвращающую лексему
t
обратно в поток.

Мы реализуем класс

Token_stream
в разделе 6.8, как только увидим, как его следует использовать. Имея поток
Token_stream
, можем переписать функцию
expression
так, чтобы она записывала неиспользованную лексему обратно в поток
Token_stream
.

double expression

{

double left = term; // считываем и вычисляем Терм

Token t = ts.get; // получаем следующую лексему

// из потока лексем

while(true) {

switch(t.kind) {

case '+':

left += term; // вычисляем и добавляем Терм

t = ts.get;

break;

case '–':

left –= term; // вычисляем и вычитаем Терм

t = ts.get;

break;

default:

ts.putback(t); // помещаем объект t обратно

// в поток лексем

return left; // финал: символов + и – нет;

// возвращаем ответ

}

}

}

Кроме того, такие же изменения следует внести в функцию

term
.

double term

{

double left = primary;

Token t = ts.get; // получаем следующую лексему

// из потока лексем

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;

}

default:

ts.putback(t); // помещаем объект t обратно в поток лексем

return left;

}

}

}

Для последней функции программы грамматического анализа

primary
достаточно заменить функцию
get_token
функцией
ts.get
; функция
primary
использует каждую лексему, которую она считывает.

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

Итак, мы готовы к испытанию второй версии. Введем число

2
и символ перехода на новую строку. Нет ответа. Попробуйте ввести еще один символ перехода на новую строку, чтобы убедиться, что компьютер не завис. По-прежнему нет ответа. Введите число
3
и символ перехода на новую строку. Ответ равен
2
. Попробуйте ввести выражение
2+2
и символ перехода на новую строку. Ответ равен 3. Экран выглядит следующим образом:

2

3

=2

2+2

=3

Хм... Может быть, наша функция

putback
и ее использование в функции
expression
и
term
не решает проблему. Попробуем другой тест.

2 3 4 2+3 2*3

= 2

= 3

= 4

= 5

Да! Это правильные ответы! Но последний ответ (

6
) пропущен. Проблема следующей лексемы не решена. Однако на этот раз она заключается не в том, что наш программный код “съедает” символы, а в том, что он вообще не получает информации, пока не будет введено следующее выражение. Результат вычисления выражения не выводится на экран немедленно; он откладывается до тех пор, пока программа не увидит первую лексему следующего выражения. К сожалению, программа не видит эту лексему, пока мы не нажмем клавишу <Enter> после следующего выражения. Эта программа на самом деле не настолько плоха, она просто немного медленно реагирует.

  • Читать дальше
  • 1
  • ...
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: