Y L i s p 2.0 ------------------------------------------------------- Система разработки Коммон Лисп - программ для IBM PC/AT ------------------------------------------------------- ----------------------------------------------------------------------- ¦ 125871, Москва, ГСП, А-80, Волоколамское шоссе, дом 4, ¦ ¦ Московский авиационный институт, факультет "Прикладная математика", ¦ ¦ MS-DOS: Дмитрий Анатольевич Иванов, http://lisp.ystok.ru/ ¦ ¦ Порт в WIN32: Арсений Слободюк, http://www.ich.dvo.ru/~nmr/ylisp/ ¦ ----------------------------------------------------------------------- Система YLisp 2.0 есть реализация подмножества популярнейшего диалекта языка Лисп - Коммон Лиспа (Common LISP), включая его объектно-ориенти- рованное расширение Common LISP Object System (CLOS). Входной язык ин- терпретатора строго следует стандартам: [CLTL]. G.L.Steele. Common LISP: The Language. Digital Press, 1984. [CLOS]. Bobrow D.G., DeMichiel L.G., Gabriel R.P., Keene S.E., Kiczales G., Moon D.A. Common LISP Object System specification. /X3J13 Document 88-002R. Интерпретатор YLisp - функционирует под MS-DOS (версии 3.3 и выше); - является компактной программой, наиболее эффективно использующей ог- раниченный объем памяти, предоставляемой DOS: минимально требуемая конфигурация - 512Кбайт; - полностью русифицирован: гарантируется адекватное преобразование строчных букв в заглавные и наоборот в соответствии с альтернативной кодировкой кирилицы (кроме букв 'Ё' и 'ё'). Freeware - условия применения ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Программа интерпретатора YLisp является общедоступной и бесплатной (Freeware), т.е. ее можно свободно копировать и распространять в любом количестве экземпляров. Исходние тексты поставляются только по особой договорённости. Установка системы YLisp 2.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Установка YLisp-интерпретатора заключается в копировании файлов дистри- бутива на жесткий диск, например в директорий \YLISP. Вы можете копиро- вать не все файлы, в зависимости от конфигурации Вашего компьютера и желанной языковой поддержки, руководствуясь своими собственными сообра- жениями об удобстве. 80x87 ~~~~~ Система YLisp 2.0 может функционировать на компьютере как с математическим сопроцессором, так и без него. Mono vs. Color ~~~~~~~~~~~~~~ Выбор цветов монитора, предоставляемый YLisp, не балует разнообра- зием. Вы можете использовать - YLISP.ROL или ENGLISH.ROL, если хотите иметь темные буквы на белом фоне, - RUSSIAN.ROL, если пожелаете светлые буквы на черном фоне. После того, как выбор подходящей установки сделан, лучше оставить только файл YLISP.ROL, переименовав в него один из двух других при необходимости. Russian vs. English ~~~~~~~~~~~~~~~~~~~ Вы можете варьировать языковую версию двух типов текстов: (i) подсказки, предупреждения и диагностические сообщения о наи- более серьезных ошибках, (ii) основная масса сообщения об ошибках и документация по встро- енным примитивам языка Коммон Лисп. Русифицированную версию текстов типа (i) обеспечивают файлы YLISP.ROL и RUSSIAN.ROL. Русифицированную версию текстов типа (ii) - RUSSIAN.HLL и RUSSIAN.IND. Вдобавок необходимо, чтобы системная возможность RUSSIAN была включена в список *features*. Как добавлять, так и удалять символ RUSSIAN из списка *features* можно в любой момент, и это будет приводить к немедленному изменению языковой версии сообщений типа (ii). Файл RUSSIAN.HLL обязательно должен присутствовать в каталоге \YLISP вместе с RUSSIAN.IND; аналогично, ENGLISH.HLL требует нали- чия ENGLISH.IND. Англоязычная версия документации не является полной и местами не- точна. Временные файлы ~~~~~~~~~~~~~~~ Система YLisp создает два типа временных файлов: бинарные файлы свертки при вызове подпроцесса (функция spawn) и ASCII-файлы, ис- пользуемые редактором. По умолчанию и те, и другие помещаются на текущем дисководе в текущий каталог пользователя. Задание перемен- ной окружения операционной системы YLTMP позволяет переопределить директорий, где YLisp создает такие файлы. Например, установка set YLTMP=I:\ указывает, что временные файлы будут размещаться в корневом ката- логе диска I. Предпочтительней направлять временные файлы на RAM-диск. Запуск программы интерпретатора ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Формат команды запуска программы интерпретатора следующий: [drive:][dir\]YLISP.EXE [pathname] [#+feature|#-feature]... Здесь drive,dir Указывают место расположения системного каталога интерпрета- тора YLisp. pathname Спецификация (возможно, полная) файла свертки, из которого восстанавливается образ Лисп-среды. Если pathname не указан, то для загрузки используется файл YLISP.ROL из системного каталога YLisp. #+feature Включает системную возможность, заданную символом feature, в список *features*. #-feature Выключает системную возможность, заданную символом feature, удаляет его из списка *features*. К числу системных возможностей, управляющих работой системы YLisp 2.0, относятся следующие. Возможность Описание ----------- -------- RUSSIAN Включение данной возможности означает использование фай- ла документации RUSSIAN.HLL (вместе с RUSSIAN.IND) в ка- честве источника текстов сообщений и справочной информа- ции, см.п. "Установка системы". Если возможность выключена, то источником подобной ин- формации служит ENGLISH.HLL (наряду с ENGLISH.IND). STARTUP Включение данной возможности означает выполнение одного из двух следующих действий, выполняемых сразу после старта системы: - если определена Лисп-функция sturtup, то она автомати- чески вызывается без аргументов; - если функция sturtup неопределена, то в текущем ката- логе пользователя ищется файл STARTUP.LSP, который загружается в систему при помощи load. Когда данная возможность отключена, проверка наличия Лисп-функции startup или файла STARTUP.LSP не выполняет- ся. Цикл чтение-оценивание-печать ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ После выполнения стартовых операций, YLisp функционирует в стиле, тра- диционном для всех Лисп-систем, а именно, циклически повторяет следую- щую последовательность шагов. - ввод очередного выражения языка Коммон Лисп, называемого также формой или S-выражением; - интерпретация, или оценивание, введенной формы; - печать каждого из значений формы с новой строки экрана (их будет несколько в случае мультизначения). Подробнее остановимся на способе ввода выражений. Когда система YLisp ждет нажатия очередной клавиши, она переводит строку и выдает приглаше- ние > Считывание с клавиатуры может происходить в одном из двух режимов. Ассоциативный ввод ~~~~~~~~~~~~~~~~~~ В данном режиме обрабатывается одно первое нажатие клавиши. Если соответствующий знак имеет связь в таблице клавиш *keymap* (или другой, см. ADDONS.TXT), то выполняется действие, с ним ассоцииро- ванное. Если же введенный литеру нельзя интерпретировать как команду, то система переходит в режим линейного редактирования, куда и переда- ется данная литера. Линейное редактирование ~~~~~~~~~~~~~~~~~~~~~~~ Данный режим позволяет редактировать форму или ее часть, размещен- ную в одной линии экрана. Через функциональные клавиши он предост- авляет удобный набор команд, свойственных текстовому редактору. Клавиша Выполняемое действие ------- -------------------- Ins Переключить режим вставки/замены Left Курсор влево Right Курсор вправо Home Курсор к началу строки End Курсор к концу строки Tab Табуляция вправо Shift-Tab Табуляция влево Ctrl-Left Курсор на слово влево Ctrl-Right Курсор на слово вправо Del Удалить знак под курсором Backspace Удалить знак слева от курсора Ctrl-Backspace Удалить слово слева от курсора Ctrl-Del Удалить слово справа от курсора Ctrl-Y Очистить редактируемую линию Up/Down Вывести в редактируемую линию предыдущую/следующую введенную строку. Буфер `команд' организован в виде кольцевого стека и хранит до 30 ранее введенных строк. ESC Отказаться от редактируемой формы и перейти в режим ассоциативного ввода. Enter Ввод отредактированной линии в систему. F1 Получить справку по функции, переменной и т.п., символ которой находится под курсором. Оценивание формы начинается лишь тогда, когда она полностью введена в систему. Длинная списковая или структурная форма может не поместиться в одной вводимой строке. В таком случае, набрав часть элементов, следует нажать Enter, причем текущее местоположение курсора несущественно. Пос- ле перевода строки система будет ждать продолжения набора формы, перей- дя опять-таки в режим ассоциативного ввода. При этом, если скобки ( и ) в неполном выражении не сбалансированы, YLisp изменит свое приглашение на n> где n есть целое число открытых левых скобок (, оставшихся незакрытыми. Подсчет данного числа ведется - либо начиная с внешнего уровня формы, - либо от последней суперскобки {, подробнее см.файл ADDONS.TXT. Конкретный вид приглашения системы зависит от текущего состояния рабочей среды и задается значением динамической переменной *read-prompt*, кото- рое может быть Лисп-строкой, символом или строковым знаком, причем - число незакрытых скобок выдается только перед приглашением-знаком, - значение nil отменяет выдачу приглашения вообще. Условно цикл чтение-оценивание-печать изображен на следующей диаграмме Неинтерпретируемая ---------------------¬ клавиша ---------------------¬ ¦ Ассоциативный ввод +----------------->+ Линейное ¦ ¦ (одна клавиша) ¦ ¦ редактирование ¦ ¦ +<----T<-----------+ (вся строка) ¦ L---T--------------T-- ¦ Esc L--------T------------ ¦ Интерпре- ¦ ¦ V Enter ¦ тируемая ¦ ¦ нет -------------+-----------¬ ¦ клавиша ¦ L<-------+ Форма введена целиком? ¦ ¦ V L------------T------------ ¦ ---+----------------¬ ¦ да ¦ ¦ Оценивание +<------------ ¦ L----------T--------- ¦ ¦ ¦ V ¦ -----------+---------¬ L<----------+ Печать результатов ¦ L--------------------- Завершить работу системы YLisp можно нажатием сочетания клавиш Alt-F4 или вызовом функции exit. Технические особенности реализации ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ На разработку YLisp повлияло очное знакомство автора со следующими реа- лизациями языка Лисп на IBM PC: GCLisp 1.01, XLisp 1.4, PC-Lisp 2.11, мuLisp-87, и заочное с GCLisp Developer 3.1, IQLisp/IQClisp, TransLisp Plus, KCL/AKCL и рядом реализаций для ПК Macintosh. Интерпретатор YLisp написан на Microsoft C 6.0. При программировании использовались такие оптимизирующие возможности, предоставляемые вышеу- помянутым инструментом, как - базированные (based) указатели и объекты; - _fastcall соглашение о связях (вызове) подпрограмм. Размер исходного текста: около 30000 строк на Си и 3000 на Лиспе. Число объектных модулей 55. Память интерпретатора организуется по принципу BIBOP (BIg Bag Of Pages). Длинные указатели на Лисп-объекты содержат теги, под которые отводится от 8 до 16 бит, в зависимости от типа. Один бит зарезервиро- ван для сборщика мусора. Все оперативное пространство разбивается на следующие разделы: - Списковые ячейки (cons cells) размером 8 байт. - Ячейки символов размером 16 байт. - Куча, где хранятся вектора, включая строки и печатные имена символов, числа, а также объекты `вмещающих' типов данных: структуры, стан- дартные объекты и т.п. Каждый объект кучи имеет 4х-байтный дескрип- тор. - Хэш-таблица символов. - Защитный стек, куда вносятся адреса Си-переменных, содержащих указа- тели на Лисп-объекты, с целью предотвратить `выметание' их сборщиком мусора. - Стек связей, служащий для двух целей: 1) сохранение адресов фреймов, устанавливающих точки возможных не- локальных переходов; 2) хранение значений Лисп-переменных. Фактически, выделение памяти происходит в порядке, обратном вышеуказан- ному, причем область списковых ячеек распространяется на все остающееся свободным пространство адресов. Реализация лексического связывания переменных глубокая (deep binding) [Allen J. Anatomy of LISP. - McGraw-Hill, 1978]: символы переменных и их значения сводятся в пары, которые объединяются во фрагменты, напоми- нающие ассоциативный список. Реализация динамического связывания поверхностная (shallow binding): новое значение переменной в момент связывания помещается в ячейку сим- вола, а старое сохраняется в стеке. Соответствующие фрагменты стека увязываются в список, чтобы обеспечить правильное развязывание, т.е. восстановление старых динамических связей, при нелокальных выходах. То, что интерпретатор написан на языке Си, облегчает его адаптацию на компьютерах других типов и делает его гибким средством для программиро- вания практических задач, для последующего расширения за счет подключе- ния специализированных алгоритмов, реализованных, как правило, на язы- ках низкого уровня. Возможен также интерфейс с пакетами машинной графи- ки, системами баз данных на внешних носителях и т.п. Y L i s p 2.0 -------------------------------------- Стандартные средства языка Коммон Лисп -------------------------------------- Система разработки YLisp 2.0 поддерживает - 11 основных типов данных и 7 подтипов, - свыше 500 функций, специальных форм, макросов и переменных, - многочисленные синтаксические средства, специфицированные в стандарте [CLTL] языка Коммон Лисп. Встроенные типы данных ~~~~~~~~~~~~~~~~~~~~~~ BIGNUM Подтип INTEGER, объединяющий целые числа большой величины. CHARACTER Тип знаков (букв) допускает задание - шрифтов, т.е. целых в диапазоне [1,255]; - битов со следующими именами: Control для всех знаков; Alt вместо Meta; Shift только для знаков, соответствующих функциональным клавишам (F1, F2, ..., F12) и расширению кла- виатуры (Home, Up, PgUp, GreyMinus и т.д.) COMPILED-FUNCTION Представляет объекты типа `компилированный код', реализующие встроенные в Лисп-систему функции, специальные формы и макросы. CONS Тип непустых списков, или, что то же самое, точечных пар. Является подтипом типа LIST, но не содержит элемент nil. FIXNUM Подтип INTEGER, объединяющий короткие целые числа из диапазона [-32768, 32767]. FLOAT Тип чисел с плавающей точкой двойной точности (т.е. DOUBLE-FLOAT). HASH-TABLE Тип `хэш-таблица'. INTEGER Тип целых чисел. KEYWORD Подтип типа SYMBOL, представляющий ключи. LIST Тип `список', объединяющий всевозможные непустые списки и выделенный пустой список nil. NULL Тип данных, являющийся одновременно подтипом SYMBOL и LIST и содержащий единственный элемент nil, т.е. пустой список (). NUMBER Тип всевозможных чисел, являющийся надтипом FLOAT и INTEGER. SEQUENCE Тип `последовательность', является надтипом для VECTOR и LIST. STREAM Тип `поток' включает файловые потоки, потоки-окна и потоки- строки (string-stream). В данной версии YLisp доступны лишь два окна: - основное окно, с которым изначально связана переменная *terminal-io*, для которого допустимо как чтение, так и выдача; - окно статуса внизу экрана, с которым изначально связана переменная *status-output*, в которое возможна только выдача. STRING Тип `строка', являющийся подтипом типа VECTOR, допускает лишь простые строки. STRING-CHAR Тип `строковый знак' есть подтипом CHARACTER и объединяет знаки, которые могут быть помещены в строку. Любой знак без шрифта и битов, кроме тех, которые соответствуют функциональ- ным клавишам, является строковым. SYMBOL Присутствуют два пространства имен (пакета) символов: стан- дартный, ссылка на который не требует квалификатора (объеди- няет lisp и user), и пакет ключей keyword. VECTOR Реализует простые общие (general simple) вектора. Иерархия типов данных системы YLisp может пополняться за счет: - определяемых типов (deftype), - структурных типов, вводимых с помощью defstruct, - типов стандартных объектов, подробнее см. файл CLOS.TXT. Стратегии связывания переменных (variable binding) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Система YLisp позволяет совместно использовать два типа переменных: - лексические, или статические, (lexical/static) переменные, область видимости (scope) которых ограничена телом функции, а время действия (extent) неопределено. - динамические, или специальные, (dinamic/special) переменные, имеют динамический контекст, т.е. неопределенную область видимости и дина- мическое время действия. Неотъемлемой частью языка являются лексические замыкания: специальная форма function создает замыкание, в котором сохраняются лямбда-выраже- ние и лексические связи переменных. Механизм оценивания ~~~~~~~~~~~~~~~~~~~ Цикл верхнего уровня чтение-оценивание-печать интерпретатора YLisp ак- компанируется специальными переменными журнала +, ++, +++, -, *, **, ***, /, //, ///. Реализована возможность установки `крючка' (hook-механизма) для зацепки - процесса оценивания: специальная переменная *evalhook* и функция evalhook; - процесса применения функции к аргументам: специальная переменная *applyhook* и функция applyhook. Список параметров функций (lambda-list) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В системе YLisp обеспечена синтаксическая и семантическая поддержка лямбда-ключевых слов &optional, &rest, &key, &allow-other-keys и &aux с возможностью указания: - значений по умолчанию (init-form), - параметров, идентифицирующих задание соответствующих аргументов (supplied-p). Макросы (macros) ~~~~~~~~~~~~~~~~ Список параметров макроса в форме defmacro может содержать: - те же лямбда-ключевые слова, что и список параметров функции, плюс &whole, &body и &environment, - деструктурирующий шаблон (destructing facility). Фактическое замещение формы макровызова на результирующее макрорасшире- ние в исходном ЛИСП-коде контролируются жестко прошитым (hard-wired) параметром и может быть двояким: - либо замещение всеми макрорасширениями соответствующих макровызовов, - либо замещение макровызовов, расширения которых являются непустыми списками (менее тяжеловесный код). Поддерживаются также макросы чтения, ассоциируемые с макро-знаками (macro-characters) при помощи таблицы чтения (readtable), включая так называемую обратную блокировку (backquote). Обобщенные переменные (general variables) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ YLisp 2.0 поддерживает макрос присваивания значения обобщенной перемен- ной setf, а также сопутствующие примитивы: defsetf, define-setf-method, get-setf-method и define-modify-macro. Функции, возвращающие множественные значения (multiple value) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Число значений, возвращаемых встроенными функциями values и values-list ограничено лишь размером стека интерпретатора. Форматный вывод в знаковые потоки (format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Шаблон, контролирующий форматирование, может содержать любые из специ- фицированных в [CLTL] директив, кроме ~P, ~R, ~F, ~E, ~G, ~$, ~< и ~>. Структурная печать (pretty print) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Программа структурной печати системы YLisp сочетает три метода формиро- вания отступа при выдаче списков: 1) блочный формат, который управляется шаблоном, приписанным первому символу списка; 2) стандартный формат, эвристически формирующий отступ в зависимости от типа первого элемента, текущей позиции для вывода и ширины вы- ходного потока; 3) мизерный формат, при котором каждый элемент печатается с новой строки. Средства обработки ошибок и отладки ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - стандартные функции выдачи диагностики (error, cerror, warn); - механизм прерыванных состояний (break) с неограниченным числом уровней; - пошаговое оценивание формы (step); - трассировка функций (trace). Система документирования ~~~~~~~~~~~~~~~~~~~~~~~~ YLisp полностью поддерживает средства документирования, специфициро- ванные в [CLTL,CLOS], а именно: - Поясняющие Лисп-строки (documentation-string) в теле специальных форм и макросов defclass, defconstant, defun, defmacro, define-modify-macro, define-setf-method, defparameter, defsetf, defstuct, defvar. - Опция :documentation для классов и слотов. - Функция получения справки documentation и метод для ее установки (setf (documentation ) ), где ::= function | setf | stucture | type | variable. Разумеется, в Лисп-программах допустимы комментарии простейшего вида: - построчные, расположенные после точки с запятой `;', - заключенные в скобки #| |#, которые могут быть вложенными, но должны быть сбалансированными. Y L i s p 2.0 --------------------------------------------------- Средства объектно-ориентированного программирования Common LISP Object System (CLOS) --------------------------------------------------- Система YLisp 2.0 включает частичную реализацию CLOS - объектно-ориен- тированного (ОО) расширения языка Коммон Лисп. Это расширение основано на концепции класса, множественном наследовании, комбинации методов и метаобъектах. Классы образуют естественное расширение системы типов Коммон Лисп. Вместо традиционного механизма передачи сообщений, приня- того в языке Смолтолк (Smalltalk), используются родовые функции (generic functions). Методы, ассоциированные с родовыми функциями, вы- бираются по классам аргументов и осуществляют специфические действия этих функций. YLisp полностью реализует механизм наследования, основанный на построе- нии списка предшествования классов (class precedence list). Последний является тотальным упорядочением множества, включающего данный класс и все его надклассы. Список предшествования вычисляется топологической сортировкой упомянутого множества, исходя из локальных порядков пред- шествования (local precedence order), заданных в определениях классов. Иерархия метаобъектов, специфицированная в [CLOS], включает следующие метаклассы. Built-in-class Экземпляры данного метакласса представляют основные встроенные типы YLisp. Structure-class Экземпляры данного метакласса суть структурные типы, вводимые с помощью defstruct без указания опции :type. Standard-class Экземплярами данного метакласса являются классы, опре- деляемые пользователем с помощью defclass, являющиеся подклассами класса standart-object. Безусловно, главный недостаток ОО-системы YLisp - это отсутствие в ней концепции родовых функций и методов. Он сказывается, в основном, из-за необходимости мультиметодов. Простейшие же методы, навроде системы пе- редачи сообщений Смолтолка или функций-членов языка Си++, легко могут быть смоделированы с помощью разделяемых слотов классов. Определение класса ~~~~~~~~~~~~~~~~~~ Синтаксис макроса defclass полностью совпадает со стандартным [CLOS]. Однако, имеются следующие семантические отличия и особенности реализа- ции. Функции и методы доступа к слотам ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ибо функции доступа, чтения и записи значения слота, специфициро- ванные посредством опций :accessor, :reader и :writer соответствен- но, не являются родовыми, нужно избегать употребления одних и тех же имен для этих функций в определениях различных классов. В принципе, допустимо использование единой функции доступа к раз- деляемым (shared) слотам, которые хранятся в различных классах, но только при условии совпадения имен этих слотов. Для доступа к локальным (local) слотам экземпляра класса, рекомен- дуется применять только функции, непосредственно указанные в опре- делении данного класса. Применение функции доступа к экземпляру класса C1 для получения значения слота, который описан в надклассе C2, допустимо, лишь когда C2 наследуется по единственной или самой правой `генеалогической' ветви, например, так (defclass C1 (C3 C2) ...) В этом случае строение экземпляра класса C1 таково, что наследуе- мые из C2 локальные слоты размещаются раньше (левее), чем слоты, наследуемые из C3 и его надклассов, которые не являются надкласса- ми C2. Значит, смещения таких слотов в экземплярах и C1, и C2 сов- падают. Задание типа значения слота ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Проверка, соответствует ли значение слота типу, специфицированному в опции :type, осуществляется при инициализации и реинициализации зкземпляров посредством initialize-instance и reinitialize-instance. Когда же слоту присваивается значение путем (setf (slot-value ...) value) или (setf (writer-or-accessor-name ...) value), соответствие типов не контролируется, а результаты в случае рас- согласования неопределены, что подтверждается стандартом [CLOS]. Динамическое переопределение ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ YLisp 2.0 поддерживает динамическое переопределение классов, кото- рое выражается в следующих моментах. - Определение класса может быть введено в систему ранее, чем форма defclass, определяющая один из его надклассов; важно лишь, чтобы чтобы все надклассы стали определенными, прежде чем будет порож- ден экземпляр данного класса. - При переопределении класса, т.е. повторном оценивании соот- ветствующей формы defclass, происходит переопределение всех его подклассов. Однако по двум пунктам данная возможность `не дотягивает' до стан- дарта [CLOS]. 1) Явно переопределенный объект-класс не совпадает по реализации (по eq) со старым, если число разделяемых слотов в его новом определении отлично от числа разделяемых слотов в старом. Само собой, это замечание не относится к автоматически переопределя- емым подклассам. 2) Экземпляры, уже порожденные к моменту явного или неявного пере- определения класса, становятся устаревшими и остаются таковыми до конца своего существования. Новое определение класса будет влиять лишь на строение его экземпляров, порожденных в будущем. Модификация устаревших экземпляров в случае неизменности объек- та-класса (например, посредством initialize-instance) или их уничтожение (открепление с целью разрешить утилизацию занимае- мой ими памяти сборщиком мусора) полностью возлагается на пользователя. Порождение и инициализация экземпляров ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Создание экземпляра класса осуществляется вызовом функции make-instance, которая собственно выделяет память (allocate-instance) и инициализирует (initialize-instance) новый объект. Функция initialize-instance, наряду с reinitialize-instance, реализована через shared-initialize. ОО-система YLisp полностью поддерживает механизм инициализирующих аргу- ментов (initialization argument list), список которых аналогичен списку ключевых аргументов и может быть указан при обращении к вышеупомянутым функциям. Печатный вид экземпляров ~~~~~~~~~~~~~~~~~~~~~~~~ Печать стандартного объекта, экземпляра standard-object, выполняется функцией print-object, действие которой можно рассматривать как первич- ный метод (primary method) для ее `родовой версии'. Она выдает нечто следующего вида: #{class-name slot-name1 value1 ... slot-nameN valueN}. Приведенная форма содержит значения всех связанных слотов экземпляра класса class-name. Выдача содержимого разделяемых слотов контролируется значением динамической переменной *print-shared*. Длина и глубина печатного представления регулируется динамическими пе- ременными *print-length* и *print-level*, аналогично тому, как это про- исходит при печати списков и общих векторов. Поскольку функция print-object не является родовой, постольку не следует ее переопределять. Настроить программу печати на конкретный класс мож- но, определив в этом классе разделяемый слот с именем :print-function. Значением этого слота должен стать функциональный объект с двумя аргу- ментами: 1) печатаемый экземпляр, 2) выходной поток. Желательно, чтобы подобные функции учитывали значения переменных *print-pretty* и *print-escape*. Значение *print-length* может игнори- роваться, а глубину печати принтер отслеживает сам. Y L i s p 2.0 ---------------------------------- Дополнительные возможности системы ---------------------------------- В данном файле перечисляются наиболее существенные расширения, включен- ные в систему YLisp 2.0, дополнительные переменные и функции, не специ- фицированные в стандарте [CLTL], диалоговые средства, которые обеспечи- вают удобный интерфейс и отладку программ. Свертка-развертка (rolling) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Свертка образа Лисп-среды (rolling out) есть копирование (дамп) текуще- го содержимого основных областей памяти интерпретатора: списковых яче- ек, ячеек символов и кучи - в файл на диске. Развертка образа Лисп-сре- ды (rolling in) есть восстановление содержимого памяти интерпретатора из файла свертки. Традиционно, в качестве расширения файла свертки используется ".ROL". Помимо указанных областей, в этом .ROL-файле сохраняются параметры ин- терпретатора: размеры регионов, цвет окон, значения некоторых режимов и т.п. Механизм свертки-развертки позволяет осуществить быстрый рестарт без загрузки исходных файлов, а также используется при вызове подпро- цесса (spawn). Ниже описываются встроенные примитивы, обеспечивающие пользователю непосредственный контроль к перечисленным средствам. - Специальная переменная *roll-pathname* всегда связана с именем пути ROL-файла, с которым была выполненa последняя операция свертки или развертки. - Функцию rollin вызывает развертку файла, указанного в качестве аргу- мента. - Функция rollout осуществляет свертку текущего образа Лисп-среды в файл на диске. Создание подпроцесса (spawn) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Система YLisp предоставляет возможность выполнения любой программы (подпроцесса) без выхода из среды интерпретатора. Это осуществляется обращением к функции spawn, которая выгружает текущую Лисп-среду во временный файл, освобождает выделенную под Лисп-структуры память и за- пускает под DOS указанную в качестве аргумента программу. Редактор ~~~~~~~~ Система YLisp допускает использование любого внешнего DOS-редактора, который вызывается в режиме подпроцесса (с помощью spawn). Путь выпол- няемого файла этого редактора должен быть помещен в качестве значения специальной переменной *editor-pathname*. Установить значение этой пе- ременной необходимо для правильной работы встроенной функции ed и дру- гих компонентов системы, например, отладчика. Сохранить установку для последующих сеансов можно вызовом функции rollout. Символьный отладчик (break-loop debugger) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Система программирования YLisp 2.0 имеет достаточно мощный отладчик, который позволяет - просматривать стек вызовов, перемещаясь по нему вверх и вниз, - просматривать значения параметров функций (встроенных и определя- емых), локальных переменных (как лексических, так и специальных), - редактировать формы, находящиеся в стеке, - редактировать определения функций и макросов, - модифицировать значения переменных и параметров, включая ключевые, - оценить любую форму так, словно это делается на верхнем уровне. Выход из отладчика возможен как в точку вызова, так и следующими двумя способами: 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* (оно запоминается в файле свертки) и автоматически загружает все исходные файлы, которые были изменены позже сохраненной даты. Таблицы клавиш (keymaps) ~~~~~~~~~~~~~~~~~~~~~~~~ Таблица клавиш содержит информацию о назначении клавиатуры, которое действует в конкретной среде работы, или конкретном диалоге, системы. В YLisp эти таблицы реализуются ассоциативными списками, в которых зна- ки, представляющие клавиши (возможны аккорды, задаваемые битами Control, Alt или Shift), связываются с функциями без аргументов (точ- нее, объектами типа function). В системе предусмотрены следующие гло- бальные переменные, имеющие в качестве значений таблицы клавиш. *keymap* Таблица клавиш верхнего уровня интерпретатора. *break-keymap* Таблица клавиш, предопределяющая действия в среде пре- рывания. *step-keymap* Назначение клавиш при пошаговом оценивании (step). *debug-keymap* Назначение клавиш, действующих в сеансе отладчика. Изменить назначение клавиатуры, действующее в том или ином режиме, до- бавить или переопределить реакцию системы на нажатие определенной кла- виши можно с помощью макроса defkey. ЗАКЛЮЧЕНИЕ: Чего бы хотелось в YLisp 2.1, 3.0, ... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Основной задачей будущего автор считает разработку версии, работающей под Microsoft Windows 3.1 или NT, со следующими возможностями: - использование большого объема памяти; - оконный интерфейс и система меню для более удобного выбора парамет- ров интерпретатора; - система документирования, доведенная до гипертекстовой оболочки, полностью русифицированную справочную систему по встроенным примити- вам языков Коммон Лисп и CLOS (похоже, не очень актуально); - переориентация на консервативный алгоритм сборки мусора для облегче- ния стыковки с программными модулями, написанными на других языках, - компилятор в Си или чистый машинный код (??!); Автор выражает готовность к любым контактам в сферах Лисп-культуры и искусственного интеллекта, будет благодарен каждому, кто может оказать посильное содействие в усовершенствовании YLisp-интерпретатора или в его приложении к конкретным предметным областям. Пожалуйста, подробнее информируйте меня о всех замеченных ошибках и отклонениях, чтобы я мог их исправить. ДОПОЛНЕНИЕ И ПОПРАВКИ ОТ 15.01.2010 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Скорректировны условия применения - теперь это freeware. Поскольку времена изменились, автор готов к доработкам только на коммерческой основе. За последними версиями для Windows и с пожеланиями обращайтесь к Арсению Слободюку, http://www.ich.dvo.ru/~nmr/ylisp/