Y L i s p 3.7
= Дополнительные возможности системы =
В данном файле перечисляются наиболее существенные расширения, включен-
ные в систему YLisp 3.7, дополнительные переменные и функции, не специ-
фицированные в стандарте [CLTL], диалоговые средства, которые обеспечи-
вают удобный интерфейс и отладку программ. Для получения подробной
информации о функциях и переменных, упомянутых здесь, используйте
справку (F1 на имени функции).
Свертка-развертка (rolling)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Свертка образа Лисп-среды (rolling out) есть копирование (дамп) текуще-
го содержимого основных областей памяти интерпретатора: списковых яче-
ек, ячеек символов и кучи - в файл на диске. Развертка образа Лисп-сре-
ды (rolling in) есть восстановление содержимого памяти интерпретатора
из файла свертки.
Традиционно, в качестве расширения файла свертки используется ".ROL".
Помимо указанных областей, в этом .ROL-файле сохраняются параметры ин-
терпретатора: размеры регионов, цвет окон, значения некоторых режимов и
т.п. Механизм свертки-развертки позволяет осуществить быстрый рестарт
без загрузки исходных файлов, а также используется при вызове подпро-
цесса (spawn). Ниже описываются встроенные примитивы, обеспечивающие
пользователю непосредственный контроль к перечисленным средствам.
- Специальная переменная *roll-pathname* всегда связана с именем пути
ROL-файла, с которым была выполненa последняя операция свертки или
развертки.
- Функцию rollin вызывает развертку файла, указанного в качестве аргу-
мента.
- Функция rollout осуществляет свертку текущего образа Лисп-среды в
файл на диске.
Создание подпроцесса (spawn)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Система YLisp предоставляет возможность выполнения любой программы
(подпроцесса) без выхода из среды интерпретатора. Это осуществляется
обращением к функции spawn, которая выгружает текущую Лисп-среду во
временный файл, освобождает выделенную под Лисп-структуры память и за-
пускает указанную в качестве аргумента программу.
Редактор
~~~~~~~~
Система YLisp допускает использование любого внешнего редактора,
который вызывается в режиме подпроцесса (с помощью spawn). Путь
выполняемого файла этого редактора должен быть помещен в качестве
значения специальной переменной *editor-pathname*. Установить значение
этой переменной необходимо для правильной работы встроенной функции ed
и других компонентов системы, например, отладчика. Сохранить установку
для последующих сеансов можно вызовом функции rollout.
Символьный отладчик (break-loop debugger)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Система программирования YLisp имеет достаточно мощный отладчик,
который позволяет
- просматривать стек вызовов, перемещаясь по нему вверх и вниз,
- просматривать значения параметров функций (встроенных и определя-
емых), локальных переменных (как лексических, так и специальных),
- редактировать формы, находящиеся в стеке,
- редактировать определения функций и макросов,
- модифицировать значения переменных и параметров, включая ключевые,
- оценить любую форму так, словно это делается на верхнем уровне.
Выход из отладчика возможен как в точку вызова, так и следующими двумя
способами:
1) Продолжение - переход в среду ранее установленного прерывания, ли-
бо в такую точку вычисления, в которой возможно повторная оценка
выражения. Последнее допускается некоторыми специальными формами,
и продолжение означает возобновление нормального хода оценивания.
2) Возврат значения - вместо значения некоторых форм допустимо вер-
нуть другое, так называемое козначение. Такой возврат возможен из
точек прерываний, вызванных некоторыми `непродолжаемыми' в обычном
смысле ошибками, а также из состояния пошагового оценивания (step)
для самой нижней формы.
Осуществляется возврат козначения вводом
"(return )"
в ответ на подсказку отладчика "debug>" или обработчика прерываний
"break>".
К сожалению, выдаваемая отладчиком информация выглядит несколько сум-
бурно - следствие отсутствия развитого оконного интерфейса.
Суперскобки { }
~~~~~~~~~~~~~~~~
Известную трудность для программирующих на Лиспе представляет синтакси-
ческий баланс скобок ( ). Дабы избавить программиста от утомительного
подсчета числа необходимых закрывающих скобок, в YLisp встроены так на-
зываемые суперскобки (super parentheses) - макрознаки '{' и '}'. Тако-
вые существуют в диалектах Interlisp и FranzLisp. Как и круглые скобки,
суперскобки должны быть сбалансированы. Открывающая '{' ведет себя в
точности так же, как и '('. За ней могут следовать какие-либо вложенные
подсписки. Закрывающая '}' завершает все эти подсписки, "вставляя" ав-
томатически требуемое число круглых ')'. Примеры синтаксически эквива-
лентных S-выражений:
{a b (c d (e f} эквивалентно (a b (c d (e f)))
{a {b (1 2} (c d (e f} эквивалентно (a (b (1 2)) (c d (e f)))
Программа структурной печати (вызываемая, когда переменная
*print-pretty* отлична от nil) для списков со вложенными подсписками
автоматически формирует такой печатный вид, который содержит суперскоб-
ки вместо обычных на каждом третьем уровне вложенности.
При вводе выражений с суперскобками нужно учитывать следующее.
- Информация о вложенности суперскобок не сохранятся между различными
вызовами функции read и между считыванием из различных файлов.
- Сочетание #{ отнюдь не предназначено для ввода вектора, как это
делает сочетание #(. Так что конструкция
#{1.0 2.0 (3.0 4.0}
недопустима. Но допустима форма
{1.0 2.0 #(3.0 4.0}.
- Синтаксис #{ } зарезервирован в системе YLisp в качестве печатного
вида стандартных объектов (см. файл CLOS.TXT), который не зависит от
значения *print-pretty*.
Загрузка файлов и формирование проекта (build project)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Коммон Лисп-программа, естественно, может состоять из нескольких моду-
лей, каждый из которых может, в свою очередь, включать несколько исход-
ных файлов. Загрузка каждого их них выполняется с помощью функция load.
В системе YLisp ключевой аргумент :verbose этой функции несет дополни-
тельную нагрузку: если явно указать его значение, отличное от nil, то
содержимое загружаемого файла будет отображаться на экране, в окне
*terminal-io*.
По-особенному реализована возможность автоматической загрузки неск-
ольких модулей с целью формирования проекта (ala утилита make). Гло-
бальная переменная *modules* содержит список, в котором, вместе с име-
нем каждого из файлов проекта, сохранена дата его последней модификации
в универсальном формате времени (universal time), какой она была в мо-
мент последней загрузки файла. Функция require сама формирует значение
*modules* (оно запоминается в файле свертки) и автоматически загружает
все исходные файлы, которые были изменены позже сохраненной даты.
Ввод команд, среда системы
~~~~~~~~~~~~~~~~~~~~~~~~~~
Интерфейс программы использует консольный режим Win32, с использованием
функций управления консолью. Определены несколько окон, в которые
происходит вывод. Строка ввода позволяет обычные действия - перемещение
курсора, редактирование, работу с буфером обмена. Имеются функции авто-
дополнения и подсказки по символу под курсором. Особенностью системы
ввода команд является наличие двух различных состояний ввода: перед
редактированием (доступны горячие клавиши вызова команд, управление
отладчиком и т.п.) и в процессе редактирования (работают в основном
только клавиши редактора). Перейти в первое состояние можно клавишей
ESC (с очисткой набранной строки).
Таблицы клавиш (keymaps)
~~~~~~~~~~~~~~~~~~~~~~~~
Таблица клавиш содержит информацию о назначении клавиатуры, которое
действует в конкретной среде работы, или конкретном диалоге, системы.
В YLisp эти таблицы реализуются ассоциативными списками, в которых зна-
ки, представляющие клавиши (возможны аккорды, задаваемые битами
Control, Alt или Shift), связываются с функциями без аргументов (точ-
нее, объектами типа function). В системе предусмотрены следующие гло-
бальные переменные, имеющие в качестве значений таблицы клавиш.
*keymap* Таблица клавиш верхнего уровня интерпретатора.
*break-keymap* Таблица клавиш, предопределяющая действия в среде пре-
рывания.
*step-keymap* Назначение клавиш при пошаговом оценивании (step).
*debug-keymap* Назначение клавиш, действующих в сеансе отладчика.
Изменить назначение клавиатуры, действующее в том или ином режиме, до-
бавить или переопределить реакцию системы на нажатие определенной кла-
виши можно с помощью макроса defkey. Выяснить печатный вид интересующей
клавиши легче всего при помощи такого рода кода:
(dotimes (i 10) (print (read-char)))
Экранный ввод-вывод, управление курсором
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Понятие потока расширено классом "окно". При запуске системы создается
три таких объекта: *terminal-io* (а также *query-io* и несколько
других переменных, связанных с одним потоком), *status-output* и
*gc-output*. Все стандартные потоки, кроме *terminal-io* и
*gc-output* можно переназначать. *terminal-io* не рекомендуется
переназначать в CLTL2, а *gc-output* - потому, что выводу
сборщика мусора это не помешает. Дополнительные окна можно создать
функцией MAKE-WINDOW, а закрыть - функцией CLOSE. Обычные функции
вывода и чтения поддерживают такие потоки. Ниже перечислены
функции, которые могут быть полезны при реализации интерфейса.
(MAKE-WINDOW rect color) - создание окна в области экрана, заданной
вектором rect #(top left bottom right). Координаты области экрана
задаются начиная с нуля. Color: старый - добрый BIOS - цвет: байт,
биты в котором отвечают за цвета и дополнительные атрибуты
7 6 5 4 3 2 1 0
| | | | | | | Синий текст
| | | | | | Зеленый текст
| | | | | Красный текст
| | | | Повышенная яркость текста
| | | Синий фон
| | Зеленый фон
| Красный фон
Повышенная яркость фона
При задании цвета удобно пользоваться шестнадцатеричными константами,
например, #x1D. Цвет, указанный при создании окна может быть изменен
позднее. Операция создания окна не производит никакого вывода на
экран.
(CLOSE stream) - обычная функция закрытия потока. Необходимо закрывать
ненужные окна, так как при открытии окна выделяется память. При
попытке закрыть одно из трех стандартных окон выдается ошибка.
(WINDOW-SIZE wstream) - форма, доступная для setf, устанавливает и
возвращает вектор #(rows columns), содержащий размеры окна, заданного
параметром wstream. Чтобы узнать размер всего экрана, нужно передать в
запросе в качестве wstream NIL.
(WINDOW-POSITION wstream) - форма, доступная для setf - чтение и
изменение позиции окна. Может понадобиться, например, чтобы подвинуть
или скрыть, убрав за пределы экрана некоторые из стандартных окон.
Позиция в начале координат - #(0 0). Будет выдана ошибка, если одна из
координат устанавливается меньшей 0, однако, координату, большую чем
размер консоли, усановить можно. Этим можно пользоваться, чтобы скрыть
вывод сборщика мусора.
(CURSOR-POSITION wstream) - форма, доступная для setf - чтение и
установка позиции курсора, одновременно с текущей позицией вывода. При
установке возвращает предыдущую позицию курсора.
(SET-CURSOR-SHAPE shape) - установить вид курсора. Параметр shape
может принимать следующие значения: NIL - скрыть курсор, возвращается
T/NIL, соответствующее прежнему состоянию курсора, T - показать
курсор, возвращается T/NIL, fixnum > (<) 0 - установить заданное в
процентах заполнение курсора (используется абсолютное значение) и
показать (скрыть) курсор. Возвращается +/- прежнее заполнение курсора.
(WINDOW-COLOR wstream) - форма, доступная для setf - чтение и
установка текущего цвета вывода. При установке возвращает предыдущий
цвет.
(CLEAR-WINDOW wstream) - заполняет всю область окна пробелами текущего
цвета.
(WINDOW-SHOT wstream) - запоминает содержимое экрана в области,
принадлежащей окну во внутренний буфер.
(WINDOW-RESTORE wstream) - восстанавливает область экрана,
принадлежащую окну содержимым буфера, сохраненным при вызове
предыдущей функции. Возможно только поочередное использование этих
функций. При их разработке имелись в виду две возможности: 1 -
сохранение содержимого окна, которое будет временно закрыто другим
окном; 2 - сохранение экрана с содержимым нижележащего окна в буфер
закрывающего его окна. CLOSE так же как и WINDOW-RESTORE и изменение
размера окна освобождает память, выделенную под буфер.
Функции (VIEWSTRINGS strings &optional (title "") (prompt "")) и
(VIEWOBJ obj &optional (title "") (prompt "")) - функции просмотра
списка строк и произвольного (большого) лисп-объекта в окне с
прокруткой.
Обычные функции чтения read, read-line и т.п. поддерживают ввод и
редактирование в пределах окна, а функции чтения одного символа,
такие, как read-char, read-char-no-hang, peek-char могут быть
использованы для организации работы с управляющими клавишами.
Назначение директивы FORMAT изменения регистра изменено: ~n(...~)
изменяет цвет выдачи на n. Атрибут шрифта литеры, описанный в CLTL2
не исключен, как того требует X3J13, а кодирует ее цвет.
Системные функции и переменные
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*arguments* - список строк - аргументов, переданных программе при
запуске. Первый элемент списка - полное имя исполняемого модуля
программы.
(CURRENT-DIRECTORY) - возвращает текущую директорию
(OSDIRECTORY path) - выдает список файлов в виде списка записей
типа OSDIRREC
(SET-CLIPBOARD str) - копирует строку str в буфер обмена Windows.
результат: t - успех, nil - неудача.
(GET-CLIPBOARD) - результатом является строка, содержащая текст из
буфера обмена или nil, если в буфере не текст или
произошла ошибка.
Многопоточность
~~~~~~~~~~~~~~~
Основной лисп-функцией реализации многопоточности является ф-я
thfuncall - аналог funcall, инициирующий выполнение функции в новой
нити. Функция возвращает целое число - идентификатор запущенной нити.
Идентификатор является уникальным в течение лисп-сессии.
Многопоточность реализована с целью использования ylisp в windows-
приложениях.
Данные в стеке (локальные переменные) - собственные данные нити.
Значения символов, списковые ячейки, вектора - общие для всех нитей.
Защиты доступа к общим данным нет, поэтому при одновременном доступе
возможен непредсказуемый результат, вплоть до краха лисп-системы,
(например, при nreverse одного списка из разных нитей). Специальные
переменные принимают новое значение одновременно в разных нитях, если
хоть в одной встречается соответствующая лексическая конструкция.
Несмотря на многопоточность, сборка мусора не может выполняться
независимо. Нить, испытывающая недостаток памяти, начинает ожидать,
пока все остальные нити придут в состояние, подходящее для начала
сборки мусора. В основном это выделение памяти или операция
ввода-вывода. В этот момент все нити синхронизованно занимаются только
сборкой. Все это может привести к замиранию всех ниток, если одна из
них не достигает длительное время точки проверки на недостаток
ресурсов. Очевидное - ожидание ввода, функция sleep - имеют указанные
проверки.
Консольный ввод-вывод имеет некоторую синхронизацию: функции верхнего
уровня захватывают "мутекс" ввода или вывода и осуществляют его без
путаницы. Функции отладочного в/в имеют приоритет, причем это основная
цель синхронизации в/в (отладка многопоточных программ).
|