12. Реализация “ключевого слова” let
использует несколько символов. Как обеспечен ввод этой лексемы как единого целого в модифицированном коде?
13. Сформулируйте правило, определяющее, что является именем в калькуляторе и что нет?
14. Чем хороша идея о постепенной разработке программ?
15. Когда следует начинать тестирование?
16. Когда следует проводить повторное тестирование?
17. Как вы принимаете решение о том, какие функции следует сделать отдельными?
18. Как вы выбираете имена для переменных и функций? Обоснуйте свой выбор.
19. Зачем нужны комментарии?
20. Что следует писать в комментариях, а что нет?
21. Когда следует считать программу законченной?
Термины
Упражнения
1. Предусмотрите использование символа подчеркивания в именах внутри программы–калькулятора.
2. Реализуйте оператор присваивания =
, чтобы можно было изменять значение переменной после ее объявления с помощью инструкции let
.
3. Реализуйте именованные константы, которые действительно не могут изменять свои значения. Подсказка: в класс Variable
необходимо добавить функцию-член, различающую константы и переменные и проверяющую это при выполнении функции set_value()
. Если хотите дать пользователю возможность объявлять собственные именованные константы (а не только pi
и e
), то необходимо добавить соответствующее обозначение, например const pi = 3.14;
.
4. Функции get_value()
, set_value()
, is_declared()
и define_name()
оперируют переменной var_table
. Определите класс Symbol_table
с членом var_table
типа vector
и функциями-членами get()
, set()
, is_declared()
и define()
. Перепишите программу так, чтобы использовать переменную типа Symbol_table
.
5. Модифицируйте функцию Token_stream::get()
так, чтобы, обнаружив символ перехода на следующую строку, она возвращала лексему Token(print)
. Для этого требуется обеспечить поиск разделителей и обработку символа '\n'
. Для этого можно использовать стандартную библиотечную функцию isspace(ch)
, возвращающую значение true
, если символ ch
является разделителем.
6. Каждая программа должна содержать подсказки для пользователя. Пусть при нажатии клавиши <Н>
калькулятор выводит на экран инструкции по эксплуатации.
7. Измените команды q
и h
на quit
и help
соответственно.
8. Грамматика в разделе 7.6.4 является неполной (мы уже предостерегали вас от чрезмерного увлечения комментариями); в ней не определена последовательность инструкций, например 4+4;
5–6;
, и не учтены усовершенствования, описанные в разделе 7.8. Исправьте грамматику. Кроме того, добавьте в первый и все остальные комментарии программы все, что считаете нужным.
9. Определите класс Table
, содержащий объект типа vector
и функции-члены get()
, set()
и define()
. Замените вектор var_table
в калькуляторе объектом класса Table
с именем symbol_table
.
10. Предложите три усовершенствования калькулятора (не упомянутых в главе). Реализуйте одно из них.
11. Модифицируйте калькулятор так, чтобы он работал только с целыми числами; предусмотрите ошибки, возникающие при потере точности и переполнении.
12. Реализуйте оператор присваивания, чтобы значение переменной можно было изменять после ее инициализации. Объясните целесообразность этого новшества и потенциальные проблемы, связанные с ним.
13. Переработайте две программы, написанные вами при выполнении упражнений к главам 4 и 5. Приведите в порядок их код в соответствии с правилами, приведенными в данной главе. Найдите ошибки.
Послесловие
Итак, на простом примере мы увидели, как работает компилятор. Наш калькулятор анализирует входные данные, разбитые на лексемы, и распознает их по правилам грамматики. Именно так функционирует компилятор. Однако после анализа входных данных компилятор создает представление (объектный код), который впоследствии можно выполнить, а калькулятор немедленно вычисляет анализируемые выражения; такие программы называются интерпретаторами, а не компиляторами.
Глава 8. Технические детали: функции и прочее
“Ни один талант не может преодолеть
пристрастия к деталям”.
Восьмой закон Леви
В этой и следующей главах мы перейдем от общих рассуждений о программировании к нашему основному инструменту программирования — языку С++. Мы приведем технические детали, чтобы дать более широкое и систематическое представление о функциональных возможностях языка С++. Кроме того, эти главы представляют собой обзор многих понятий программирования, введенных ранее, и позволяют исследовать язык без привлечения новых методов и концепций.
8.1. Технические детали