Чтение онлайн

на главную - закладки

Жанры

Программирование. Принципы и практика использования 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> после следующего выражения. Эта программа на самом деле не настолько плоха, она просто немного медленно реагирует.

Как исправить этот недостаток? Очевидное решение — потребовать немедленно выполнить вывод. Договоримся считать, что каждое выражение завершается точкой с запятой, которая одновременно служит триггером вывода. Кроме того, добавим в программу команду выхода. Для этого подходит символ

q
(первая буква слова
quit
(выход)). Функция
main
содержит инструкцию

while (cin) cout << "=" << expression << '\n'; // version 1

Заменим ее более запутанной, но более полезной инструкцией.

double val = 0;

while (cin) {

Token t = ts.get;

if (t.kind == 'q') break; // 'q' для выхода

if (t.kind == ';') // ';' для команды "печатать немедленно"

cout << "=" << val << '\n';

else

ts.putback(t);

val = expression;

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

Наваждение генерала драконов

Лунёва Мария
3. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Наваждение генерала драконов

Средневековая история. Тетралогия

Гончарова Галина Дмитриевна
Средневековая история
Фантастика:
фэнтези
попаданцы
9.16
рейтинг книги
Средневековая история. Тетралогия

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле

Тайный наследник для миллиардера

Тоцка Тала
Любовные романы:
современные любовные романы
5.20
рейтинг книги
Тайный наследник для миллиардера

Лорд Системы 4

Токсик Саша
4. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 4

Вперед в прошлое 5

Ратманов Денис
5. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 5

Энфис 4

Кронос Александр
4. Эрра
Фантастика:
городское фэнтези
рпг
аниме
5.00
рейтинг книги
Энфис 4

Князь

Мазин Александр Владимирович
3. Варяг
Фантастика:
альтернативная история
9.15
рейтинг книги
Князь

В теле пацана

Павлов Игорь Васильевич
1. Великое плато Вита
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
В теле пацана

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Сонный лекарь 7

Голд Джон
7. Сонный лекарь
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Сонный лекарь 7

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Огни Эйнара. Долгожданная

Макушева Магда
1. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Огни Эйнара. Долгожданная

Я – Орк. Том 3

Лисицин Евгений
3. Я — Орк
Фантастика:
юмористическое фэнтези
попаданцы
5.00
рейтинг книги
Я – Орк. Том 3