- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
let v1 = 7;
let v1 = 8;
Мы решили, что повторное определение является ошибкой. Обычно это просто синтаксическая ошибка. Вероятно, мы имели в виду не то, что написали, а следующие инструкции:
let v1 = 7;
let v2 = 8;
Определение объекта класса Variable с именем var и значением val состоит из двух логических частей.
1. Проверяем, существует ли в векторе var_table объект класса Variable с именем var.
2. Добавляем пару (var, val) в вектор var_table.
Мы не должны использовать неинициализированные переменные, поэтому определили функции is_declared() и define_name(), представляющие эти две операции.
bool is_declared(string var)
// есть ли переменная var в векторе var_table?
{
for (int i = 0; i<var_table.size(); ++i)
if (var_table[i].name == var) return true;
return false;
}
double define_name(string var, double val)
// добавляем пару (var,val) в вектор var_table
{
if (is_declared(var)) error(var,"declared twice");
var_table.push_back(Variable(var,val));
return val;
}
Добавить новый объект класса Variable в вектор типа vector<Variable> легко; эту операцию выполняет функция-член вектора push_back().
var_table.push_back(Variable(var,val));
Вызов конструктора Variable(var,val) создает соответствующий объект класса Variable, а затем функция push_back() добавляет этот объект в конец вектора var_table. В этих условиях и с учетом лексем let и name функция declaration() становится вполне очевидной.
double declaration()
// предполагается, что мы можем выделить ключевое слово "let"
// обработка: name = выражение
// объявляется переменная с именем "name" с начальным значением,
// заданным "выражением"
{
Token t = ts.get();
if (t.kind != name) error ("в объявлении ожидается переменная name");
string var_name = t.name;
Token t2 = ts.get();
if (t2.kind != '=') error("в объявлении пропущен символ =",
var_name);
double d = expression();
define_name(var_name,d);
return d;
}
Обратите внимание на то, что мы возвращаем значение, хранящееся в новой переменной. Это полезно, когда инициализирующее выражение является нетривиальным. Рассмотрим пример.
let v = d/(t2–t1);
Это объявление определяет переменную v и выводит ее значение. Кроме того, печать переменной упрощает код функции calculate(), поскольку при каждом вызове функция statement() возвращает значение. Как правило, общие правила позволяют сохранить простоту кода, а специальные варианты приводят к усложнениям.
Описанный механизм отслеживания переменных часто называют таблицей символов (symbol tables). Его можно радикально упростить с помощью стандартной библиотеки map (см. раздел 21.6.1).
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). Какие символы могут бы частью имени? Буквы? Конечно.

