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

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

Жанры

Программирование. Принципы и практика использования 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;

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

Последний Паладин. Том 2

Саваровский Роман
2. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 2

Зубных дел мастер

Дроздов Анатолий Федорович
1. Зубных дел мастер
Фантастика:
научная фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Зубных дел мастер

Истребитель. Ас из будущего

Корчевский Юрий Григорьевич
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.25
рейтинг книги
Истребитель. Ас из будущего

Честное пионерское! Часть 3

Федин Андрей Анатольевич
3. Честное пионерское!
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Честное пионерское! Часть 3

Обгоняя время

Иванов Дмитрий
13. Девяностые
Фантастика:
попаданцы
5.00
рейтинг книги
Обгоняя время

Страж. Тетралогия

Пехов Алексей Юрьевич
Страж
Фантастика:
фэнтези
9.11
рейтинг книги
Страж. Тетралогия

Магия чистых душ

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.40
рейтинг книги
Магия чистых душ

Имя нам Легион. Том 4

Дорничев Дмитрий
4. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 4

Девятый

Каменистый Артем
1. Девятый
Фантастика:
боевая фантастика
попаданцы
9.15
рейтинг книги
Девятый

Морской волк. 1-я Трилогия

Савин Владислав
1. Морской волк
Фантастика:
альтернативная история
8.71
рейтинг книги
Морской волк. 1-я Трилогия

Отмороженный 8.0

Гарцевич Евгений Александрович
8. Отмороженный
Фантастика:
постапокалипсис
рпг
аниме
5.00
рейтинг книги
Отмороженный 8.0

Совершенный: охота

Vector
3. Совершенный
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Совершенный: охота

Калибр Личности 1

Голд Джон
1. Калибр Личности
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Калибр Личности 1

Личник

Валериев Игорь
3. Ермак
Фантастика:
альтернативная история
6.33
рейтинг книги
Личник