Приступим к разработке типа Token_stream
. Что пользователь ждет от него? Очевидно, что нам нужны функции get()
и putback()
— именно поэтому мы ввели понятие потока лексем. Класс Token_stream
должен создавать объекты класса Token
из символов, считанных из потока ввода, поэтому нам необходима возможность создавать объекты класса Token_stream
, способные считывать данные из потока cin
. Таким образом, простейший вариант класса Token_stream
выглядит примерно так:
class Token_stream {
public:
Token_stream(); // создает объект класса Token_stream,
// считывающий данные из потока cin
Token get(); // получает объект класса Token
void putback(Token t); // возвращает объект класса Token
// обратно
private:
// детали реализации
};
Это все, что требуется от пользователя для использования объектов класса Token_stream
. Опытные программисты могут поинтересоваться, почему поток cin
является единственным возможным источником символов, — просто мы решили вводить символы с клавиатуры. Это решение можно пересмотреть в упражнении, приведенном в главе 7.
Почему мы использовали “длинное” имя putback()
, а не логичное имя put()
? Тем самым мы подчеркнули асимметрию между функциями get()
и putback()
: мы возвращаем лексему в поток ввода, а не вставляем ее в поток вывода. Кроме того, функция putback()
есть в классе istream
: непротиворечивость имен — полезное свойство. Это позволяет людям запоминать имена функций и избегать ошибок.
Теперь можем создать класс Token_stream и использовать его.
Token_stream ts; // объект класса Token_stream с именем ts
Token t = ts.get(); // получаем следующий объект класса Token из
объекта ts
// ...
ts.putback(t); // возвращает объект t класса Token обратно в объект ts
Это все, что нам нужно, чтобы закончить разработку калькулятора.
6.8.1. Реализация класса Token_stream
Теперь необходимо реализовать три функции класса Token_stream
. Как представить класс Token_stream
? Иначе говоря, какие данные необходимо хранить в объекте класса Token_stream
, чтобы он мог выполнить свое задание? Необходима память для лексемы, которая будет возвращена обратно в объект класса Token_stream
. Для простоты будем считать, что лексемы возвращаются в поток по одной. Этого вполне достаточно для нашей программы (а также для очень многих аналогичных программ). Таким образом, нужна память для одного объекта класса Token
и индикатор ее занятости.
class Token_stream {
public:
Token_stream(); // создает объект класса Token_stream,
// считывающий данные из потока cin
Token get(); // получает объект класса Token
// (функция get() определена в разделе 6.8.2)
void putback(Token t); // возвращает объект класса Token
// обратно
private:
bool full; // находится ли в буфере объект класса Token?
Token buffer; // здесь хранится объект класса Token,
// возвращаемый в поток функцией putback()
};
Теперь можно определить (написать) три функции-члена. Конструктор и функция putback()
никаких трудностей не вызывают, поскольку они невелики. Мы определим их в первую очередь. Конструктор просто устанавливает настройки, свидетельствующие о том, что буфер пуст.
Token_stream::Token_stream()
:full(false), buffer(0) // в буфере нет ни одного объекта