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

на главную

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

7.8.2. Использование имен

Все это очень хорошо, но, к сожалению, не работает. Это не должно было стать для нас сюрпризом. Первый вариант никогда — почти никогда — не работает. В данном случае мы даже не закончили программу — она даже не скомпилируется. У нас нет лексемы

'='
, но это легко исправить, добавив дополнительный раздел
case
в функцию
Token_stream::get
(см. раздел 7.6.3). А как представить ключевые слова
let
и
name
в виде лексем? Очевидно, для того чтобы распознавать эти лексемы, необходимо модифицировать функцию
get
. Как? Вот один из способов.

const char name = 'a'; //
лексема name

const char let = 'L'; // лексема let

const string declkey = "let"; // ключевое слово let

Token Token_stream::get

{

if (full) { full=false; return buffer; }

char ch;

cin >> ch;

switch (ch) {

// как и прежде

default:

if (isalpha(ch)) {

cin.putback(ch);

string s;

cin>>s;

if (s == declkey) return Token(let); // ключевое
слово let

return Token(name,s);

}

error("Неправильная лексема");

}

}

В первую очередь обратите внимание на вызов функции

isalpha(ch)
. Этот вызов отвечает на вопрос “Является ли символ
ch
буквой?”; функция
isalpha
принадлежит стандартной библиотеке и описана в заголовочном файле
std_lib_facilities.h
. Остальные функции классификации символов описаны в разделе 11.6. Логика распознавания имен совпадает с логикой распознавания чисел: находим первый символ соответствующего типа (в данном случае букву), а затем возвращаем его назад в поток с помощью функции
putback
и считываем все имя целиком с помощью оператора
>>
.

К сожалению, этот код не компилируется; класс

Token
не может хранить строку, поэтому компилятор отказывается распознавать вызов
Token(name,s)
. К счастью, эту проблему легко исправить, предусмотрев такую возможность в определении класса
Token
.

class Token {

public:

char kind;

double value;

string name;

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

Token(char ch, double val) :kind(ch), value(val) { }

Token(char ch, string n) :kind(ch), name(n) { }

};

Для представления лексемы

let
мы выбрали букву
'L'
, а само ключевое слово храним в виде строки. Очевидно, что это ключевое слово легко заменить ключевыми словами
double
,
var
,
#
, просто изменив содержимое строки
declkey
, с которой сравнивается строка
s
.

Попытаемся снова протестировать программу. Если напечатать следующие выражения, то легко убедиться, что программа работает:

let x = 3.4;

let y = 2;

x + y * 2;

Однако

следующие выражения показывают, что программа еще не работает так, как надо:

let x = 3.4;

let y = 2;

x+y*2;

Чем различаются эти примеры? Посмотрим, что происходит. Проблема в том, что мы небрежно определили лексему

Имя
. Мы даже “забыли” включить правило вывода
Имя
в грамматику (раздел 7.8.1). Какие символы могут бы частью имени? Буквы? Конечно. Цифры? Разумеется, если с них не начинается имя. Символ подчеркивания? Нет? Символ
+
? Неужели?

Посмотрим на код еще раз. После первой буквы считываем строку в объект класса

string
с помощью оператора
>>
. Он считывает все символы, пока не встретит пробел. Так, например, строка
x+y*2;
является отдельным именем — даже завершающая точка с запятой считывается как часть имени. Это неправильно и неприемлемо.

Что же сделать вместо этого? Во-первых, мы должны точно определить, что представляет собой имя, а затем изменить функцию

get
. Ниже приведено вполне разумное определение имени: последовательность букв и цифр, начинающаяся с буквы. Например, все перечисленные ниже строки являются именами.

a

ab

a1

Z12

asdsddsfdfdasfdsa434RTHTD12345dfdsa8fsd888fadsf

А следующие строки именами не являются:

1a

as_s

#

as*

a car

За исключением отброшенного символа подчеркивания это совпадает с правилом языка С++. Мы можем реализовать его в разделе

default
в функции
get
.

default:

if (isalpha(ch)) {

string s;

s += ch;

while (cin.get(ch) && (isalpha(ch) || isdigit(ch)))

s+=ch;

cin.putback(ch);

if (s == declkey) return Token(let); // ключевое слово let

return Token(name,s);

}

error("Неправильная лексема");

Вместо непосредственного считывания в объект

string s
считываем символ и записываем его в переменную
s
, если он является буквой или цифрой. Инструкция
s+=ch
добавляет (приписывает) символ
ch
в конец строки
s
. Любопытная инструкция

while (cin.get(ch) && (isalpha(ch) || isdigit(ch)) s+=ch;

считывает символ в переменную

ch
(используя функцию-член
get
потока
cin
) и проверяет, является ли он символом или цифрой. Если да, то она добавляет символ
ch
в строку
s
и считывает символ снова. Функция-член
get
работает как оператор
>>
, за исключением того, что не может по умолчанию пропускать пробелы.

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

Live-rpg. эволюция-3

Кронос Александр
3. Эволюция. Live-RPG
Фантастика:
боевая фантастика
6.59
рейтинг книги
Live-rpg. эволюция-3

Пушкарь. Пенталогия

Корчевский Юрий Григорьевич
Фантастика:
альтернативная история
8.11
рейтинг книги
Пушкарь. Пенталогия

Хроники разрушителя миров. Книга 8

Ермоленков Алексей
8. Хроники разрушителя миров
Фантастика:
фэнтези
5.00
рейтинг книги
Хроники разрушителя миров. Книга 8

Адъютант

Демиров Леонид
2. Мания крафта
Фантастика:
фэнтези
6.43
рейтинг книги
Адъютант

Эфир. Терра 13. #2

Скабер Артемий
2. Совет Видящих
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эфир. Терра 13. #2

Кодекс Крови. Книга VI

Борзых М.
6. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга VI

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Я – Орк. Том 2

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

Законы Рода. Том 2

Flow Ascold
2. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 2

Корпулентные достоинства, или Знатный переполох. Дилогия

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.53
рейтинг книги
Корпулентные достоинства, или Знатный переполох. Дилогия

Тринадцатый

NikL
1. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
6.80
рейтинг книги
Тринадцатый

Темный Патриарх Светлого Рода

Лисицин Евгений
1. Темный Патриарх Светлого Рода
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода

Раб и солдат

Greko
1. Штык и кинжал
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Раб и солдат

Волк 5: Лихие 90-е

Киров Никита
5. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 5: Лихие 90-е