Peter Siebel - Practical Common Lisp
Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.
- Название:Practical Common Lisp
- Автор:
- Издательство:Apress
- Жанр:
- Год:2005
- ISBN:1-59059-239-5
- Рейтинг книги:4 / 5. Голосов: 1
-
Избранное:Добавить в избранное
- Отзывы:
-
Ваша оценка:
- 80
- 1
- 2
- 3
- 4
- 5
Practical Common Lisp: краткое содержание, описание и аннотация
Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.
Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком
Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.
Интервал:
Закладка:
(#\< "<")
(#\> ">")
(#\' "'")
(#\" """)
(t (format nil "~d;" (char-code char)))))
You can use this function as the basis for a function, escape
, that takes a string and a sequence of characters and returns a copy of the first argument with all occurrences of the characters in the second argument replaced with the corresponding character entity returned by escape-char
.
(defun escape (in to-escape)
(flet ((needs-escape-p (char) (find char to-escape)))
(with-output-to-string (out)
(loop for start = 0 then (1+ pos)
for pos = (position-if #'needs-escape-p in :start start)
do (write-sequence in out :start start :end pos)
when pos do (write-sequence (escape-char (char in pos)) out)
while pos))))
You can also define two parameters: *element-escapes*
, which contains the characters you need to escape in normal element data, and *attribute-escapes*
, which contains the set of characters to be escaped in attribute values.
(defparameter *element-escapes* "<>&")
(defparameter *attribute-escapes* "<>&\"'")
Here are some examples:
HTML> (escape "foo & bar" *element-escapes*)
"foo & bar"
HTML> (escape "foo & 'bar'" *element-escapes*)
"foo & 'bar'"
HTML> (escape "foo & 'bar'" *attribute-escapes*)
"foo & 'bar'"
Finally, you'll need a variable, *escapes*
, that will be bound to the set of characters that need to be escaped. It's initially set to the value of *element-escapes*
, but when generating attributes, it will, as you'll see, be rebound to the value of *attribute-escapes*
.
(defvar *escapes* *element-escapes*)
Indenting Printer
To handle generating nicely indented output, you can define a class indenting-printer
, which wraps around an output stream, and functions that use an instance of that class to emit strings to the stream while keeping track of when it's at the beginning of the line. The class looks like this:
(defclass indenting-printer ()
((out :accessor out :initarg :out)
(beginning-of-line-p :accessor beginning-of-line-p :initform t)
(indentation :accessor indentation :initform 0)
(indenting-p :accessor indenting-p :initform t)))
The main function that operates on indenting-printer
s is emit
, which takes the printer and a string and emits the string to the printer's output stream, keeping track of when it emits a newline so it can reset the beginning-of-line-p
slot.
(defun emit (ip string)
(loop for start = 0 then (1+ pos)
for pos = (position #\Newline string :start start)
do (emit/no-newlines ip string :start start :end pos)
when pos do (emit-newline ip)
while pos))
To actually emit the string, it uses the function emit/no-newlines
, which emits any needed indentation, via the helper indent-if-necessary
, and then writes the string to the stream. This function can also be called directly by other code to emit a string that's known not to contain any newlines.
(defun emit/no-newlines (ip string &key (start 0) end)
(indent-if-necessary ip)
(write-sequence string (out ip) :start start :end end)
(unless (zerop (- (or end (length string)) start))
(setf (beginning-of-line-p ip) nil)))
The helper indent-if-necessary
checks beginning-of-line-p
and indenting-p
to determine whether it needs to emit indentation and, if they're both true, emits as many spaces as indicated by the value of indentation
. Code that uses the indenting-printer
can control the indentation by manipulating the indentation
and indenting-p
slots. Incrementing and decrementing indentation
changes the number of leading spaces, while setting indenting-p
to NIL
can temporarily turn off indentation.
(defun indent-if-necessary (ip)
(when (and (beginning-of-line-p ip) (indenting-p ip))
(loop repeat (indentation ip) do (write-char #\Space (out ip)))
(setf (beginning-of-line-p ip) nil)))
The last two functions in the indenting-printer
API are emit-newline
and emit-freshline
, which are both used to emit a newline character, similar to the ~%
and ~& FORMAT
directives. That is, the only difference is that emit-newline
always emits a newline, while emit-freshline
does so only if beginning-of-line-p
is false. Thus, multiple calls to emit-freshline
without any intervening emit
s won't result in a blank line. This is handy when one piece of code wants to generate some output that should end with a newline while another piece of code wants to generate some output that should start on a newline but you don't want a blank line between the two bits of output.
(defun emit-newline (ip)
(write-char #\Newline (out ip))
(setf (beginning-of-line-p ip) t))
(defun emit-freshline (ip)
(unless (beginning-of-line-p ip) (emit-newline ip)))
With those preliminaries out of the way, you're ready to get to the guts of the FOO processor.
HTML Processor Interface
Now you're ready to define the interface that'll be used by the FOO language processor to emit HTML. You can define this interface as a set of generic functions because you'll need two implementations—one that actually emits HTML and another that the html
macro can use to collect a list of actions that need to be performed, which can then be optimized and compiled into code that emits the same output in a more efficient way. I'll call this set of generic functions the backend interface . It consists of the following eight generic functions:
(defgeneric raw-string (processor string &optional newlines-p))
(defgeneric newline (processor))
(defgeneric freshline (processor))
(defgeneric indent (processor))
(defgeneric unindent (processor))
(defgeneric toggle-indenting (processor))
(defgeneric embed-value (processor value))
(defgeneric embed-code (processor code))
While several of these functions have obvious correspondence to indenting-printer
functions, it's important to understand that these generic functions define the abstract operations that are used by the FOO language processors and won't always be implemented in terms of calls to the indenting-printer
functions.
That said, perhaps the easiest way to understand the semantics of these abstract operations is to look at the concrete implementations of the methods specialized on html-pretty-printer
, the class used to generate human-readable HTML.
The Pretty Printer Backend
You can start by defining a class with two slots—one to hold an instance of indenting-printer
and one to hold the tab width—the number of spaces you want to increase the indentation for each level of nesting of HTML elements.
Интервал:
Закладка:
Похожие книги на «Practical Common Lisp»
Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.
Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.