- •Оглавление
- •Предисловие
- •Предисловие к русскому изданию
- •Глава 1. Введение
- •1.1. Новые инструменты
- •1.2. Новые приемы
- •1.3. Новый подход
- •Глава 2. Добро пожаловать в Лисп
- •2.1. Форма
- •2.2. Вычисление
- •2.3. Данные
- •2.4. Операции со списками
- •2.5. Истинность
- •2.6. Функции
- •2.7. Рекурсия
- •2.8. Чтение Лиспа
- •2.9. Ввод и вывод
- •2.10. Переменные
- •2.11. Присваивание
- •2.12. Функциональное программирование
- •2.13. Итерация
- •2.14. Функции как объекты
- •2.15. Типы
- •2.16. Заглядывая вперед
- •Итоги главы
- •Упражнения
- •Глава 3. Списки
- •3.1. Ячейки
- •3.2. Равенство
- •3.3. Почему в Лиспе нет указателей
- •3.4. Построение списков
- •3.5. Пример: сжатие
- •3.6. Доступ
- •3.7. Отображающие функции
- •3.8. Деревья
- •3.9. Чтобы понять рекурсию, нужно понять рекурсию
- •3.10. Множества
- •3.11. Последовательности
- •3.12. Стопка
- •3.13. Точечные пары
- •3.14. Ассоциативные списки
- •3.15. Пример: поиск кратчайшего пути
- •3.16. Мусор
- •Итоги главы
- •Упражнения
- •Глава 4. Специализированные структуры данных
- •4.1. Массивы
- •4.2. Пример: бинарный поиск
- •4.3. Строки и знаки
- •4.4. Последовательности
- •4.5. Пример: разбор дат
- •4.6. Структуры
- •4.7. Пример: двоичные деревья поиска
- •4.8. Хеш-таблицы
- •Итоги главы
- •Упражнения
- •Глава 5. Управление
- •5.1. Блоки
- •5.2. Контекст
- •5.3. Условные выражения
- •5.4. Итерации
- •5.5. Множественные значения
- •5.6. Прерывание выполнения
- •5.7. Пример: арифметика над датами
- •Итоги главы
- •Упражнения
- •Глава 6. Функции
- •6.1. Глобальные функции
- •6.2. Локальные функции
- •6.3. Списки параметров
- •6.4. Пример: утилиты
- •6.5. Замыкания
- •6.6. Пример: строители функций
- •6.7. Динамический диапазон
- •6.8. Компиляция
- •6.9. Использование рекурсии
- •Итоги главы
- •Упражнения
- •Глава 7. Ввод и вывод
- •7.1. Потоки
- •7.2. Ввод
- •7.3. Вывод
- •7.4. Пример: замена строк
- •7.5. Макрознаки
- •Итоги главы
- •Упражнения
- •Глава 8. Символы
- •8.1. Имена символов
- •8.2. Списки свойств
- •8.3. А символы-то не маленькие
- •8.4. Создание символов
- •8.5. Использование нескольких пакетов
- •8.6. Ключевые слова
- •8.7. Символы и переменные
- •8.8. Пример: генерация случайного текста
- •Итоги главы
- •Упражнения
- •Глава 9. Числа
- •9.1. Типы
- •9.2. Преобразование и извлечение
- •9.3. Сравнение
- •9.4. Арифметика
- •9.5. Возведение в степень
- •9.6. Тригонометрические функции
- •9.7. Представление
- •9.8. Пример: трассировка лучей
- •Итоги главы
- •Упражнения
- •Глава 10. Макросы
- •10.1. Eval
- •10.2. Макросы
- •10.3. Обратная кавычка
- •10.4. Пример: быстрая сортировка
- •10.5. Проектирование макросов
- •10.6. Обобщенные ссылки
- •10.7. Пример: макросы-утилиты
- •10.8. На Лиспе
- •Итоги главы
- •Упражнения
- •Глава 11. CLOS
- •11.1. Объектно-ориентированное программирование
- •11.2. Классы и экземпляры
- •11.3. Свойства слотов
- •11.4. Суперклассы
- •11.5. Предшествование
- •11.6. Обобщенные функции
- •11.7. Вспомогательные методы
- •11.8. Комбинация методов
- •11.9. Инкапсуляция
- •11.10. Две модели
- •Итоги главы
- •Упражнения
- •Глава 12. Структура
- •12.1. Разделяемая структура
- •12.2. Модификация
- •12.3. Пример: очереди
- •12.4. Деструктивные функции
- •12.5. Пример: двоичные деревья поиска
- •12.6. Пример: двусвязные списки
- •12.7. Циклическая структура
- •12.8. Неизменяемая структура
- •Итоги главы
- •Упражнения
- •Глава 13. Скорость
- •13.1. Правило бутылочного горлышка
- •13.2. Компиляция
- •13.3. Декларации типов
- •13.4. Обходимся без мусора
- •13.5. Пример: заранее выделенные наборы
- •13.6. Быстрые операторы
- •13.7. Две фазы разработки
- •Итоги главы
- •Упражнения
- •Глава 14. Более сложные вопросы
- •14.1. Спецификаторы типов
- •14.2. Бинарные потоки
- •14.3. Макросы чтения
- •14.4. Пакеты
- •14.5. Loop
- •14.6. Особые условия
- •Глава 15. Пример: логический вывод
- •15.1. Цель
- •15.2. Сопоставление
- •15.3. Отвечая на запросы
- •15.4. Анализ
- •Глава 16. Пример: генерация HTML
- •16.1. HTML
- •16.2. Утилиты HTML
- •16.3. Утилита для итерации
- •16.4. Генерация страниц
- •Глава 17. Пример: объекты
- •17.1. Наследование
- •17.2. Множественное наследование
- •17.3. Определение объектов
- •17.4. Функциональный синтаксис
- •17.5. Определение методов
- •17.6. Экземпляры
- •17.7. Новая реализация
- •17.8. Анализ
- •Комментарии
- •Алфавитный указатель
16
Пример: генерация HTML
В этой главе мы напишем небольшой HTML-генератор – программу, ав томатически производящую набор связанных веб-страниц. Она не толь ко демонстрирует различные концепции Лиспа, но и является хорошим примером разработки «снизу-вверх». Мы начнем с создания HTML-ути лит общего назначения, которые затем будем рассматривать как язык, на котором и будем писать собственно генератор.
16.1. HTML
HTML (HyperText Markup Language, язык разметки гипертекста) – это то, из чего состоят веб-страницы. Это очень простой язык, не имеющий продвинутых возможностей, но зато он легок в изучении. В этом разде ле представлен обзор HTML.
Веб-страницы просматриваются с помощью веб-браузера, который по лучает код страницы (как правило, с удаленного компьютера), преобра зовывает его в читаемый вид и выводит на экран. HTML-файл – это тек стовый файл, содержащий разметку, воспринимаемую браузером как инструкции.
На рис. 16.1 приведен пример простого HTML-файла, а на рис. 16.2 по казано, как он будет отображаться в браузере. Обратите внимание, что текст между угловыми скобками не отображается. Это и есть разметка. HTML имеет два вида меток. Одни используются попарно:
<метка> ... </метка>
Первая метка обозначает начало некоторого окружения, вторая помеча ет его окончание. Одной из меток такого рода является <h2>. Весь текст, находящийся между <h2> и </h2>, отображается увеличенным шрифтом. (Наибольший шрифт задается <h1>.)
264 |
Глава 16. Пример: генерация HTML |
<center>
<h2>Your Fortune</h2> </center>
<br><br>
Welcome to the home page of the Fortune Cookie Institute. FCI is a non-profit institution dedicated to the development of more realistic fortunes. Here are some examples of fortunes that fall within our guidelines:
<ol>
<li>Your nostril hairs will grow longer. <li>You will never learn how to dress properly. <li>Your car will be stolen.
<li>You will gain weight. </ol>
Click <a href="research.html">here</a> to learn more about our ongoing research projects.
Рис. 16.1. HTML-файл
Your Fortune
Welcome to the home page of the Fortune Cookie Institute. FCI is a nonprofit institution dedicated to the development of more realistic fortunes. Here are some examples of fortunes that fall within our guidelines:
1.Your nostril hairs will grow longer.
2.You will never learn how to dress properly.
3.Your car will be stolen.
4.You will gain weight.
Click here to learn more about our ongoing research projects.
Рис. 16.2. Внешний вид веб-страницы
Другие парные метки: <ol> («ordered list», упорядоченный список) для создания нумерованного списка; <center> для центрирования текста; <a...> («anchor», якорь) для создания ссылки.
Именно ссылки превращают текст в гипертекст. Текст, находящийся между <a...> и </a>, отображается браузерами особым образом, как пра вило, с подчеркиванием. При нажатии на ссылку осуществляется пере ход на другую страницу, адрес которой содержится внутри метки. Сле дующая метка
16.2. Утилиты HTML |
265 |
<a href="foo.html">
означает ссылку на другой HTML-файл, находящийся в том же катало ге. Таким образом, при нажатии на ссылку на рис. 16.2 браузер загру зит и отобразит файл "research.html".
Ссылки не обязаны указывать на файлы в одном и том же каталоге, но могут указывать и на любой адрес в Интернете (хотя в нашем примере это не используется) .
Другая разновидность меток не имеет маркера окончания. В нашем примере (см. рис. 16.1) используются метки <br> («break», разрыв) для перехода на новую строку и <li> («list item», элемент списка) для обозна чения элемента внутри окружения списка. Разумеется, HTML содер жит и другие метки, но в этой главе нам понадобятся лишь те, которые упомянуты на рис. 16.1.
16.2.Утилиты HTML
Вэтом разделе мы определим некоторые утилиты для генерации HTML. На рис. 16.3 показаны базовые утилиты для генерации разметки. Все они направляют вывод в *standard-output*, но мы всегда сможем перена править его, переназначив эту переменную.
(defmacro as (tag content) ‘(format t "<~(~A~)>~A</~(~A~)>"
’,tag ,content ’,tag))
(defmacro with (tag &rest body) ‘(progn
(format t "~&<~(~A~)>~%" ’,tag) ,@body
(format t "~&<~(~A~)>~%" ’,tag)))
(defun brs (&optional (n 1)) (fresh-line)
(dotimes (i n) (princ "<br>"))
(terpri))
Рис. 16.3. Утилиты для генерации разметки
Макросы as и with предназначены для генерации выражений, окружен ных парой меток. Первый принимает строку и печатает ее между мет ками:
> (as center "The Missing Lambda") <center>The Missing Lambda</center> NIL
266 Глава 16. Пример: генерация HTML
Второй принимает тело кода и выводит результат его выполнения меж ду метками:
> (with center
(princ "The Unbalanced Parenthesis")) <center>
The Unbalanced Parenthesis </center>
NIL
Оба эти макроса используют управляющие директивы ~( и ~) для печа ти меток в нижнем регистре. На самом деле, HTML не чувствителен к регистру, но метки в нижнем регистре легче воспринимаются, особен но если их много.
В то время как макрос as пытается разместить весь вывод на одной стро ке, макрос with располагает метки на отдельных строках. (Директива ~& обеспечивает начало вывода с новой строки.) Это делается лишь для то го, чтобы HTML-файлы лучше читались. При отображении страниц пробельные символы вокруг меток не показываются.
Последняя утилита на рис. 16.3, brs, генерирует множественные разры вы строк. Во многих браузерах они могут использоваться для управле ния вертикальными отступами.
Рисунок 16.4 содержит утилиты для непосредственной генерации HTML. Первая возвращает имя файла по заданному символу. В реальном при ложении она могла бы вернуть полный путь к файлу в указанном ката логе. Здесь же она просто присоединяет к имени расширение ".html".
Макрос page служит для генерации всей страницы. Он схож с with-open- file, на основе которого построен. Выражения в его теле будут выполне ны с привязкой *standard-output* к потоку, созданному при открытии файла, соответствующего символу name.
(defun html-file (base)
(format nil "~(~A~).html" base))
(defmacro page (name title &rest body) (let ((ti (gensym)))
‘(with-open-file (*standard-output* (html-file ,name) :direction :output :if-exists :supersede)
(let ((,ti ,title)) (as title ,ti) (with center
(as h2 (string-upcase ,ti))) (brs 3)
,@body))))
Рис. 16.4. Утилиты создания файлов
16.2. Утилиты HTML |
267 |
В разделе 6.7 было показано, как присваивать временные значения спе циальным переменным. В примере на стр. 124 мы устанавливали значе ние *print-base* в 16 в теле let. Раскрытие page похожим образом связы вает *standard-output* с потоком, указывающим на HTML-файл. Если мы вызовем as или princ в теле page, то вывод будет перенаправлен в со ответствующий файл.
Заголовок title будет напечатан в самом верху страницы. За ним следу ет весь остальной вывод. Таким образом, вызов:
(page ’paren "The Unbalanced Parenthesis"
(princ "Something in his expression told her..."))
приведет к тому, что файл "paren.html" будет иметь (поскольку html-file уже определен) следующее содержание:
<title>The Unbalanced Parenthesis</title> <center>
<h2>THE UNBALANCED PARENTHESIS</h2> </center>
<br><br><br>
Something in his expression told her...
Здесь нам знакомы все метки, кроме <title>. Текст, заключенный в мет ку <title>, не будет появляться нигде на странице, но зато он будет ото бражаться браузером в заголовке окна.
(defmacro with-link (dest &rest body) ‘(progn
(format t "<a href=\"~A\">" (html-file ,dest)) ,@body
(princ "</a>")))
(defun link-item (dest text) (princ "<li>")
(with-link dest (princ text)))
(defun button (dest text) (princ "[ ") (with-link dest
(princ text)) (format t " ]~%"))
Рис. 16.5. Утилиты для генерации ссылок
На рис. 16.5 представлены утилиты для генерации ссылок. Макрос with-link похож на with. Он принимает тело кода и вычисляет его между выражениями, которые генерируют ссылку на HTML-файл, имя кото рого было передано вторым аргументом: