Выбрать главу

6.3.3. Реализация лексем

Как должна выглядеть лексема в нашей программе? Иначе говоря, как должен выглядеть тип Token? Класс Token должен предусматривать выполнение операторов, например + и , а также представлять числа, такие как 42 и 3.14. В самой простой реализации нужно придумать, как задать вид лексемы и как хранить числа.

Существует много способов реализации этой идеи в программе на языке С++. Вот ее простейший вариант:

class Token { // очень простой тип, определенный пользователем

public:

  char kind;

  double value;

};

Класс Token — это тип (такой же, как int или char), поэтому его можно использовать для определения переменных и хранения значений. Он состоит из двух частей (членов): kind и value. Ключевое слово class означает “тип, определенный пользователем”; это значит, что он содержит члены (хотя в принципе может их и не содержать). Первый член, kind, имеет тип char и представляет собой символ. С его помощью удобно хранить символы '+' и '*', чтобы представить операции * и +. Рассмотрим пример использования этого типа.

Token t;       // t — объект класса Token

t.kind = '+';  // t представляет операцию +

Token t2;      // t2 — другой объект класса Token

t2.kind = '8'; // цифра 8 означает, что "вид" является числом

t2.value = 3.14;

Для доступа к члену класса используется обозначение имя_объекта.имя_члена. Выражение t.kind читается как “член kind объекта t”, а выражение t2.value — как “член value объекта t2”. Объекты класса Token можно копировать так же, как и переменные типа int.

Token tt = t;    // копирование при инициализации

if (tt.kind != t.kind) error("невозможно!");

t = t2;          // присваивание

cout << t.value; // вывод числа 3.14

Имея класс Token, можно выразить выражение (1.5+4)*11 с помощью семи лексем.

Обратите внимание на то, что для простых лексем значение не требуется, поэтому мы не используем член value. Нам нужен символ для обозначения чисел. Мы выбрали символ '8' просто потому, что он явно не оператор и не знак пунктуации. Использование символа '8' для обозначения чисел немного загадочно, но это лишь на первых порах.

Класс Token представляет пример типа, определенного пользователем. Тип, определенный пользователем, может иметь функции-члены (операции), а также данные члены. Существует много причин для определения функций-членов. В данном примере мы описали две функции-члена для того, чтобы инициализация объекта класса Token стала проще.

class Token {

public:

  char kind;     // вид лексемы

  double value;  // для чисел: значение

  Token(char ch) // создает объект класса Token

                 // из переменной типа char

    :kind(ch), value(0) { }

  Token(char ch, double val)   // создает объект класса Token

    :kind(ch), value(val) { }  // из переменных типа

                               // char и double

};

Эти две функции-члена называют конструкторами (constructors). Их имя совпадает с именем типа, и они используются для инициализации (конструирования) объектов класса Token. Рассмотрим пример.

Token t1('+');      // инициализируем t1, так что t1.kind = '+'

Token t2('8',11.5); // инициализируем t2,

                    // так что t2.kind = '8' и t2.value = 11.5

В первом конструкторе фрагмент :kind(ch), value(0) означает “инициализировать член kind значением переменной ch и установить член value равным нулю”. Во втором конструкторе фрагмент :kind(ch), value(val) означает “инициализировать член kind значением переменной ch и установить член value равным переменной val”. В обоих вариантах нам требуется лишь создать объект класса Token, поэтому тело функции ничего не содержит: { }. Специальный синтаксис инициализации (список инициализации членов класса) начинается с двоеточия и используется только в конструкторах.