Программы, которые пишут программы
Среди прочих способов для тестирования компилятора Энди Кениг (Andy Koenig) разработал метод написания кода C++, позволяющий проверить, нашел ли компилятор ошибки в программе. Фрагменты кода, которые должны вызвать реакцию компилятора, снабжаются специальными комментариями, в которых описываются ожидаемые сообщения. Каждая строка такого комментария начинается с /// (чтобы их можно было отличить от обычных комментариев) и регулярного выражения, которое должно соответствовать диагностике компилятора, выдаваемой для этой строки. Таким образом, например, следующие два фрагмента кода должны вызвать реакцию компилятора:
Если мы пропустим второй тест через компилятор C++, то он напечатает ожидаемое сообщение, вполне соответствующее регулярному выражению:
% СС х.с "х.с", line 1: error(321): void function may not return a value
Каждый такой фрагмент кода пропускается через компилятор, и вывод сравнивается с прогнозируемой диагностикой, этим процессом управляет схемная оболочка и программа на Awk. Сбоем считается ситуация, когда вывод компилятора не совпадает с ожидаемым. Поскольку комментарии представлены регулярными выражениями, у них получается некоторая свобода в оценке вывода: ее можно делать более или менее строгой к отклонениям в зависимости от надобности.
Идея использования семантических комментариев не нова. Такие комментарии используются в языке PostScript, где они начинаются с символа %. Комментарии, начинающиеся с %%, могут содержать дополнительную информацию о номерах страниц, окаймляющем прямоугольнике (сunding Box), именах шрифтов и т. п.:
В языке Java комментарии, которые начинаются с /** и заканчиваются */, пользуются для создания документации для следующего за ними описания класса. Глобальным вариантом самодокументации кода является к называемое грамотное программирование (literate programming), и котором программа и ее документация интегрируются в один документ, и при одной обработке документ готовится для чтения, а при другой программа готовится к компиляции.
Во всех рассмотренных выше примерах важно отметить роль нотации, применения языков и использования инструментов. Их комбинирование усиливает и подчеркивает мощь отдельных компонентов.
Упражнение 9.15
В программировании давно известна забавная задачка: написать программу, которая при выполнении точно воспроизводила бы саму себя – в виде исходного кода. Это такой гипертрофированный случай программы, пишущей программу. Попробуйте выполнить это – на своем любимом языке.