УДК 681.3: 681.51: 007.52 Программно-инструментальный комплекс автоматизации программирования
Казаков А.И., Обухов Л.И
Киевская лаборатория искусственного интеллекта (КЛИИ), г. Киев
В данной статье мы представляем программно-инструментальный комплекс автоматизации программирования. Описан компонентный состав комплекса. Дано описание ряда базовых компонент.
Введение
Комплекс автоматизации программирования (АП) состоит из следующих основных компонент:
- обеспечение языка Cprolog;
- обеспечение конструктивной логики Велиар-2;
- файл-менеджер Fmgr;
- текстовый редактор Fedit;
- обеспечение языка Perl-6;
- обеспечение языка Lisp-13;
- обеспечение языка Common-Lisp;
- обеспечение языка CLIPS;
- обеспечение одноключевой иерархической базы BTIO;
- обеспечение базы BerkeleyDB;
- обеспечение связи с С-компиляторами.
Все компоненты интегрированы между собой, в частности файл-менеджер, текстовый редактор и обеспечение языков могут использовать возможности базы BTIO. Все компоненты имеют связь со всеми другими. Пользователь может перестраивать интерфейс с компонентами в соответствии со своими привычками. Опишем возможности первых четырех базовых компонент комплекса автоматизации программирования.
Система Prolog
Система обеспечения Prolog состоит из модуля интерпретатора CProlog, вызываемого из текстового редактора Fedit.
В качестве основы для своей системы нами использовался интерпретатор Фернандо Перейры [1]. В процессе разработки были сделаны столь многочисленные и весьма существенные изменения и дополнения, что систему пришлось переименовать в систему Велиар. Но важно подчеркнуть, что у нашей системы сохранилась совместимость с т.н. Эдинбургским синтаксисом, который в настоящее время является стандартом. Отметим, что такие системы, как Turbo-Prolog, PDC-Prolog и Visual Prolog не удовлетворяют Эдинбургскому синтаксису, поэтому, как наши, так и другие широко известные программы и методики не будут работать в этих системах.
Система Велиар-2
Для обеспечения конструктивной логики была создана программная среда Велиар-2. В качестве основы был взят интерпретатор Перейры и существенно переработан. Перечислим наиболее важные дополнения и улучшения к интерпретатору Перейры:
— удален интерактивный консольный режим, вместо него за основу принят файловый интерфейс, то есть входная программа находится во входном файле, а результаты выводятся в выходной файл.
— допустимы русифицированные имена и переменные.
— исправлено несоответствие при работе с вещественными числами.
— увеличены размеры захвата памяти со 100кб до 10 Мгб.
— удалена интерактивная консольная отладка, в качестве отладчика выступает наш вариант метаинтерпретатора O’Keef [5].
— символы @ и # переведены в статус малой буквы, что удобно для пометки особых идентификаторов.
— изменена политика относительно неразрешенных ссылок-имен предикатов. Частая ошибка программирования – неправильная буква в имени. Интерпретатор Перейры трактует такой предикат как новый и ситуация остается допустимой, но на этапе выполнения выдается отказ, который обычно приводит к цепочке возвратов. Новая политика состоит в том, что неразрешенные имена предикатов используются как допустимые вперед. Их тела могут быть написаны позже, а разрешением на выдачу диагностического сообщения об этом факте можно управлять.
— введено расширение синтаксиса. Наряду с записью call(F) может использоваться запись F, для вызова предиката, являющегося значением переменной F, которая к моменту обращения должна быть связана с определенным предикатом. Если она остается свободной переменной, то выдается сообщение об ошибке. Это т.н. “голые вызовы” нулевой арности. В дальнейшем было введено расширение синтаксиса, вплоть до обращений вида F(X,Y), где на месте главного функтора может стоять переменная. Ядро системы конвертирует эту запись в apply2(F,X,Y).
Такая подстановка теперь производится не только для выполняемых предикатов, но и для структур. Это т.н. “голые предикаты”.
— введен и реализован механизм “автозагрузки” (AUTOLOAD), впервые появившийся в LISP. Это средство приспособлено для больших и очень больших программных систем, которые могут насчитывать сотни тысяч процедур. Проблема в том, что обычная стратегия загрузки необходимых программе ресурсов использует специальные системные команды для предварительной загрузки библиотек процедур. При работе с ЕЯ–текстами нам потребуется около 80.000 семантических процедур, связанных с отдельными словами и, следовательно:
– понадобится слишком много библиотек;
– загрузка библиотек будет длиться слишком долго;
– библиотеки займут слишком много оперативной памяти.
Идея автозагрузки состоит в том, чтобы на системном уровне реализовать динамическую подзагрузку необходимого предиката в момент первого обращения к нему. Все предикаты следует расположить в одноключевой иерархической базе данных типа BTIO и динамически загружать предикат по его имени как ключу. В базе BTIO может находиться более миллиона записей-предикатов. Динамическая автозагрузка решает вышеуказанные три проблемы:
- будут загружаться только необходимые предикаты, а их число определяется “деревом реализации” предикатов, входящих в запрос. В случае обработки ЕЯ-текста, это означает, что сначала будут автозагружены предикаты, отвечающие отдельным словам предложений, затем все предикаты, которые находятся в их телах реализации, затем все подчиненные им предикаты и т.д. рекурсивно. Это можно считать аналогом системы “ассоциаций”. Вместе с механизмом автозагрузки будет выдаваться и сообщение о неразрешенной ссылке, если в базе нужный предикат не будет найден.
В настоящее время еще существует некоторая трудность, связанная с арностью, а именно, в записи, отвечающей имени предиката, необходимо хранить все одноименные предикаты с различными арностями.
— разработана методика пополнения ядра интерпретатора системными предикатами, в частности, добавлены системные предикаты загрузки и сохранения записей в базу BTIO. С другой стороны удалены системные предикаты по работе с дисковыми файлами для того, чтобы меньше ориентировать Prolog-систему на несвойственную для нее работу по системному администрированию [3].
— добавлен новый системный предикат вывода на печать всех предков
текущей цели в виде списка, от ближайшей цели к самой верхней.
— добавлен системный предикат морфологической интерполяции для работы с произвольными, т.н. «открытыми», текстами на русском языке.
С использованием базы на 500.000 словоформ, для любого слова, даже не входящего в эту базу, записанного кириллицей, находится ближайшая словоформа из базы, по метрике близости, например, по совпадению максимального числа букв, справа налево.
Дальнейшие усовершенствования производились уже на уровне
Системной Библиотеки:
— полностью изменен главный интерпретатор-препроцессор и добавлен в него блок, обеспечивающий автозагрузку.
— введено расширение синтаксиса под названием “звездочки Михальского”: если в записи fun(X,Y,Z) один левый аргумент является выходным, то то же самое можно записать в более понятном виде *X = fun(Y,Z). Очевидно, один выходной аргумент в предикате является функциональным, а сам предикат можно трактовать как функцию. Если предикат по смыслу используется как функция, то это можно подчеркнуть с помощью специального обозначения. Если два аргумента выходных, то можно записать так:
(X,Y) = fun(Z).
— реализовано мощное препроцессорное средство макросов. Основные идеи заимствованы из LISP. Макрос – есть выражение на Прологе, которое работает в два этапа. Первый этап выполняется при начальном препроцессировании всей программы. В этот момент макрос “расширяется”, процедура макроса занимается тем, что по переданным аргументам генерирует лишь текст будущего предиката и вставляет его вместо макроса. Полученная процедура будет активизирована уже на втором этапе выполнения, если до нее дойдет точка управления. Через макросы реализованы предикаты второго уровня Ли Наиша, такие как map, foldr и filter. Введен новый макрос под именем for, который позволяет единым выражением записать то, что при других средствах требовало прямой или косвенной рекурсии. Таким образом, макрос for берет на себя все формы рекурсии, а не только “остаточную”.
- — оператор Перейры –> для простой записи процедур разбора DCG-грамматик [2] дополнен операторами < –– и <-*–, которые делают более сложные вещи, такие как автоматическое формирование выходных аргументов и сохранение информации об активном образце при разборе.
- — специальная процедура, под названием “красивая печать”, позволяет для любого предиката выполнить его “декомпиляцию”, то есть вывести из внутреннего представления в памяти во внешнее, с красивыми отступами и именами переменных. Такая операция необходима, например, для автосохранения предикатов из оперативной памяти на диск.
- — сделан еще один шаг, приближающий синтаксис Пролога к функциональному – реализована “функциональная звездочка Михальского”. Она позволяет более кратко записать следующий фрагмент процедуры Пролога: fun(S,X1), p(S,Y). Краткая запись имеет вид: p(*fun(X1),Y). В отличие от стандарта использования аргументов только для унификации, в такой записи “функционального аргумента” предикат выполняется так, как если бы fun была функцией и ее значение после вычисления подставлено на место аргумента в предикат p(). Средствами Пролога эти действия выполняются через введение дополнительной вспомогательной переменной.
Речь не идет о том, чтобы сделать синтаксис Пролога функциональным, а о том, чтобы иметь возможность чередовать функциональный стиль с предикатным там, где это необходимо.
— введено понятие “канонического представления” процедур и создана
мета-процедура, которая может переводить кластер одноименных клозов в каноническое представление.
— стала близка к окончательному решению одна из ключевых проблем в логическом программировании – проблема реализации отрицания в Прологе. Реализован т.н. оператор “конструктивного отрицания”, обозначаемый как ^. Конструктивное отрицание является метаинтерпретатором, который анализирует все дерево реализации отрицаемого предиката, меняет по закону дистрибутивности ‘;’ на ‘,’ и обратно ‘,’ на ‘;’ и реализует закон двойного отрицания, а перед листьевыми и системными предикатами выполняет уже известный оператор not. Идея “конструктивного отрицания” обладает свойством “схемы аксиом”, то есть требует особой дисциплины написания для каждой процедуры и ее “негативного варианта”. Теперь, процедура “конструктивного отрицания” при не обнаружении явной формы для негативной процедуры, моделирует ее создание через конструктивное отрицание позитивной формы.
— реализован механизм поддержки “списков свойств предикатов”, подобный механизм впервые появился в LISP. Идея в том, что к каждой процедуре должен быть привязан некоторый фрейм, в котором можно было бы хранить свойства процедуры, распределенные по ключам или позиционно. Другие процедуры могут эти свойства использовать и изменять. Мониторы должны иметь возможность перед вызовом процедур, по их свойствам, заранее принять решение: а стоит ли вообще данную процедуру вызывать? С другой стороны, административные мониторы базы процедур могут проверять поле частотности использования процедур и удалять редко используемые процедуры из актуальной базы. Некоторую функцию могут выполнять сразу несколько процедур, поэтому желательно уметь выбрать среди них лучшую для данного случая. Здесь также естественно привлекаются свойства процедур. Данный механизм создания и использования «информационных тел» процедур является одним из ключевых при построении системы автоматического программирования, которая должна создавать программы на основе ЕЯ-текстов технических заданий для их разработки, посредством метаинтерпретирования.
Поэтому, весьма важной частью системы являются метаинтерпретаторы. Приведем текст метаинтерпретатора – «Пролог на Прологе», созданного на основе замечательной программы O’Keefe [5], текст которой, нами переработан и упрощен за счет использования макроса for и канонического представления, то есть представления с заменой одноименных клозов внутренними дизъюнкциями:
фОР_ТРАСС(A,D) :-
( A=(X,Y), фОР_ТРАСС(X,D), фОР_ТРАСС(Y,D)
; ( tab(D), п(‘”Call” ‘,A), fail
; D1 is D+2,
for`((A,D1),_#1,(A,D),
( clause(A,Bd), integer(Bd),!, A
; clause(A,Bd),
for`((Bd,D), _#2,(Bd,D), (
for`((Bd,D,Afc,Hc), _#4,(Bd0,D,Afc,Hc),
( Bd0=(A,B), !,
for`((A,B,D,Afc,Hc,_#4), _#5,(Bd1,Bd2,D,Afc,Hc,_#4),
( Bd1=!, Bd2=Afc, Hc=yes, !
; Bd1=(A,B), !, _#5(A, (B,Bd2),D,Afc,Hc,_#4)
; Bd1=(A;B), _#5(A, Bd2, D,Afc,Hc,_#4)
; Bd1=(A;B), !, _#5(B, Bd2, D,Afc,Hc,_#4)
; Bd1=true, !, _#4(Bd2, D,Afc,Hc)
; фОР_ТРАСС(Bd1,D), _#4(Bd2, D,Afc,Hc)
))
; Bd0=!, Afc=true, Hc=yes,!
; Bd0=(A;B), _#4(A,D,Afc,Hc)
; Bd0=(A;B),!, _#4(B,D,Afc,Hc)
; Bd0=true, Afc=true, Hc=no, !
; Afc=true, Hc=no, фОР_ТРАСС(Bd0,D)
)),
( Hc = yes, !, tab(D), п(‘”cut” !’), _#2(Afc,D)
; Hc = no
)))
)),
( tab(D), п(‘”Exit” ‘,A), fail
; true
; tab(D), п(‘”Redo” ‘,A), fail
)
; tab(D), п(‘”Fail” ‘,A), fail
) ).
Данный метаинтерпретатор используется в среде Велиар-2 для решения следующих задач:
— отладка текстов программ на Прологе;
— входной анализ и приведение текстов из открытого множества ЕЯ-текстов к представлению текстов в формате малой грамматики;
— входной анализ и приведение выражений в других логических системах: фуззи-логики, модальные логики, деонтические логики и других системах, т.е.
к представлению в формате конструктивной логики Пролога.
Текстовый редактор Fedit
Текстовый редактор программиста Fedit позволяет редактировать текстовые файлы с числом строк до 900.000 и с длиной до 160 символов (общий объем до 14 Мгб – для многих нужд этого вполне достаточно).
В реализации использовалась концепция прямоугольного буфера в отличие от AVL-деревьев строк, как в других текстовых редакторах типа MultiEdit или текстовом редакторе в Perl.
Редактор Fedit интегрирован с компонентой обеспечения Perl, так что можно писать скрипты по обработке текстовых массивов непосредственно как расширение функций текстового редактора. Такой текстовый редактор становится рабочей лошадкой программиста – от его возможностей существенно зависит производительность труда. Укажем, хотя бы, на такой пустяк как автоматическое запоминание позиции курсора в последних 50 редактируемых файлах в течение данного дня. Редактирование файла, как правило, начинается не с первой позиции, а с той позиции, которая была оставлена при редактировании этого файла в предыдущем сеансе редактирования. После привыкания к этому и другим полезным свойствам, редакторы, не обладающие такими возможностями, кажутся уже “неудобными”, например, Far, MultiEdit или Word – конечно, с точки зрения программиста.
Перечислим некоторые встроенные средства редактора.
— Накопительный приватный и стандартный системный клипборд
— Автогенерация и проигрывание любых локальных клавишных макросов, за это отвечают всего две клавиши – серый плюс и серый минус. Это средство автоматизации во всех тех случаях, когда нужны многократно повторяющиеся группы операций, а таковых при редактировании – всегда много.
— Контекстная “умная” справка, по клавише F1 при этом контекст курсора используется как аргумент с показом в окне средств, связанных со справкой. Эта же клавиша в начале английского слова через базу BTIO получает статью из англо-русского словаря Мюллера. При программировании в Си очень удобна контекстная справка по функции из Win32.hlp
— Применена идея “виртуальной русификации” при программировании в С/С++. Недоступность исходных текстов компилятора Visual Studio приводит к невозможности создания в программах на Си идентификаторов на русском языке (такая возможность появилась только в С#). Это необходимо в парадигме концептуального программирования. Для реализации указанной возможности была использована функциональность текстового редактора. А это делает текст намного более понимаемым, самодокументируемым и доступным для обработки другими лингвистическими модулями.
— Вставка-скроллирование в тексте BMP-картинок и JPG по методу открытых якорей. Дескриптор картинки с ее именем файла не скрывается, а может находиться прямо в тексте и оформлен как Рис.'<имя-файла>’. Образцом является сочетание “Рис.’”, при этом картинка, из указанного файла или из базы BTIO, будет вставлена правее и выше якоря. Позицию относительно якоря можно настраивать.
— Аналогично вставляется векторная графика, а рукописный текст и векторные рисунки могут создаваться пером на планшете в самом редакторе.
— Поддерживается интерфейс с Perl. Аналогичный интерфейс используется для формирования текстовых блоков-программ для запуска программ в Прологе
— Быстрое сравнение файлов по двум окнам. Работа в двух окнах с одним и тем же файлом.
— Встроенная система контроля версий типа CVS. Некоторое отличие от стандарта UNIX состоит в том, что не требуется запускать специальные программы архивации. Архивация автоматически выполняется при сохранеии текста, а разархивация – автоматически при загрузке текста.
Файл-менеджер Fmgr
Fmgr представляет собой окно с отображением каталогов и имеет
функциональность, ориентированную на потребности программиста:
— файл-менеджер Fmgr интегрирован с обеспечением баз BTIO, если файл имеет расширение .wad, то его просмотр приводит к имитации каталоговой структуры, подсвечиваемой красным цветом. Каталог представляет собой иерархию ключей записей, называемых микро-файлами;
— в данном файл-менеджере Fmgr реализовано множество полезных достижений в области интерфейса с файлами. Создана система по имитации файлового интерфейса с базой данных BerkeleyDB;
В сочетании с большой емкостью текстового редактора сотни мелких текстовых файлов быстро превращаются в один произвольно большой файл, в котором возможны все средства быстрой навигации и контекстных изменений. На этой же основе, после помещения всего проекта в один файл, можно применять встроенную в файл-менеджер систему контроля версий CVS.
Заключение
Задача автоматизации программирования (АП) может пониматься как в узком, так и в широком смысле. Мы описали ряд компонент комплекса АП, среди них есть средства обеспечивающие АП как в узком, так и в широком смысле, вплоть до уровня понимания естественно-языковых текстов, как текстов технических заданий для их непосредственного программирования и исполнения.
В совокупности, описанные компоненты, вместе с остальными компонентами комплекса АП, позволяют его считать средой для автоматизации программирования нового типа с неограниченными возможностями по его развитию.
Литература
- Warren D., Pereira L. M. and Pereira F. Prolog – the language and its implementation compared with LISP // Proc. Symposium on AI Programming Languages / SIGPLAN Notices, Vol 12, No. 8 and SIGART Newsletter. – 1977. No. 64., pp 109-115.
- Pereira F.C.N., Warren D.H.D. Definite clause grammars for language analysis – a survey of the formalism and a comparison with augmented “transition networks” // Artificial Intelligence. – 1980. Vol. 13, pp 231-278.
- Sterling L., Shapiro E.Y. The art of Prolog: advanced, programming techniques // M.I.T. Press. – 1986.
- Pereira F.C.N., Shieber S.M. Prolog and Natural-Language Analysis // CSLI Lecture Notes / Stanford, CA. – 1987. N10, pp. 286.
- O’Keefe R.A. The Craft of PROLOG // MIT Press. – 1990. 410 pp.