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

на главную

Жанры

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

6.5.2.2. Выражения: вторая попытка

Итак, что же мы делаем? Каждый Терм является Выражением, но не любое Выражение является Термом; иначе говоря, можно начать поиск с Терма и переходить к поиску полного Выражения, только обнаружив символ + или . Рассмотрим пример.

double expression

{

double left = Term; // считываем и вычисляем Терм

Token t = get_token; //
получаем следующую лексему

switch (t.kind) { // определяем вид лексемы

case '+':

return left + expression; // считываем и вычисляем

// Выражение, затем

// выполняем сложение

case '–':

return left – expression; // считываем и вычисляем

// Выражение, затем

// выполняем вычитание

default:

return left; // возвращаем значение Терма

}

}

Этот программный код действительно — более или менее — работает. Мы включим его в окончательный вариант программы для грамматического разбора правильных выражений и отбраковки неправильных. Он позволяет правильно вычислить большинство выражений. Например, выражение 1+2 считывается как Терм (имеющий значение 1), за которым следует символ +, а за ним — Выражение (которое оказывается Термом, имеющим значение

2
). В итоге получаем ответ, равный 3. Аналогично, выражение 1+2+3 дает ответ 6. Можно было бы много говорить о том, что эта программа делает хорошо, но мы сразу поставим вопрос ребром: а чему равно выражение 1–2–3? Функция
expression
считает число 1 как Терм, затем переходит к считыванию 2–3 как Выражения (состоящего их Терма 2, за которым следует Выражение 3). Таким образом, из 1 будет вычтено значение выражения 2–3. Иначе говоря, программа вычисляет выражение 1–(2–3). Оно равно 2. Однако мы еще со школьной скамьи знаем, что выражение 1–2–3 означает (1–2)–3 и, следовательно, равно –4.

Итак, мы написали превосходную программу, которая выполняет вычисления неправильно. Это опасно. Это особенно опасно, поскольку во многих случаях программа дает правильный ответ. Например, выражение 1+2+3 будет вычислено правильно (6), так как 1+(2+3) эквивалентно (1+2)+3.

Что же мы сделали неправильно с точки зрения программирования? Этот вопрос следует задавать себе каждый раз, когда обнаружите ошибку. Именно так мы можем избежать повторения одних и тех же ошибок. По существу, мы просто просмотрели программный код и угадали правильное решение. Это редко срабатывает! Мы должны понять, как работает программа, и объяснить, почему она работает правильно.

Анализ ошибок — часто лучший способ найти правильное решение. В данном случае функция

expression
сначала искала Терм, а затем, если за Термом следовал символ + или , искала Выражение. На самом деле функция реализовала немного другую грамматику.

Выражение:

Терм

Терм '+' Выражение // сложение

Терм '–' Выражение // вычитание

Отличие от нашей грамматики заключается именно в том, что выражение 1–2–3 должно трактоваться как Выражение 1–2, за которым следует символ и Терм 3, а на самом деле функция интерпретирует выражение 1–2–3 как Терм 1, за которым следует символ и Выражение 2–3. Иначе говоря, мы хотели, чтобы выражение 1–2–3 было эквивалентно (1–2)–3 , а не 1–(2–3).

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

Обратите внимание на то, что мы могли бы определить выражение 1–2–3 как 1–(2–3), а не (1–2)–3 и вообще избежать этой дискуссии. Довольно часто самые трудные программистские проблемы возникают тогда, когда мы работаем с привычными для людей правилами, которые изобрели задолго до компьютеров.

6.5.2.3. Выражения: третья попытка (удачная)

Итак, что теперь? Еще раз взгляните на грамматику (правильная грамматика приведена в разделе 6.5.2): любое Выражение начинается с Терма, за которым может следовать символ + или . Следовательно, мы должны найти Терм, проверить, следует ли за ним символ + или , и делать это, пока символы “плюс” и “минус” не закончатся. Рассмотрим пример.

double expression

{

double left = term; // считываем и вычисляем Терм

Token t = get_token; // получаем следующую лексему

while (t.kind=='+' || t.kind=='–') { // ищем + или –

if (t.kind == '+')

left += term; // вычисляем Терм и добавляем его

else

left –= term; // вычисляем Терм и вычитаем его

t = get_token;

}

return left; // финал: символов + и – нет; возвращаем ответ

}

Этот вариант немного сложнее: мы ввели цикл для поиска символов + и . Кроме того, дважды повторили проверку символов + и , а также дважды вызвали функцию

get_token
. Поскольку это запутывает логику кода, просто продублируем проверку символов + и .

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

Наваждение генерала драконов

Лунёва Мария
3. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Наваждение генерала драконов

Средневековая история. Тетралогия

Гончарова Галина Дмитриевна
Средневековая история
Фантастика:
фэнтези
попаданцы
9.16
рейтинг книги
Средневековая история. Тетралогия

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле

Тайный наследник для миллиардера

Тоцка Тала
Любовные романы:
современные любовные романы
5.20
рейтинг книги
Тайный наследник для миллиардера

Лорд Системы 4

Токсик Саша
4. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 4

Вперед в прошлое 5

Ратманов Денис
5. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 5

Энфис 4

Кронос Александр
4. Эрра
Фантастика:
городское фэнтези
рпг
аниме
5.00
рейтинг книги
Энфис 4

Князь

Мазин Александр Владимирович
3. Варяг
Фантастика:
альтернативная история
9.15
рейтинг книги
Князь

В теле пацана

Павлов Игорь Васильевич
1. Великое плато Вита
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
В теле пацана

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Сонный лекарь 7

Голд Джон
7. Сонный лекарь
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Сонный лекарь 7

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Огни Эйнара. Долгожданная

Макушева Магда
1. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Огни Эйнара. Долгожданная

Я – Орк. Том 3

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