Реферат: Использование Prolog совместно с другими ЯП
Реферат: Использование Prolog совместно с другими ЯП
Использование Prolog совместно с другими ЯП.
Понятие Dll.
Вспомним процесс
программирования в DOS. Преобразование исходного текста
в машинный код включал в себя 2 процесса: компиляцию и линковку. Во время
линковки в код программы помещались не только объявления функций и процедур, но
и их полный код.
В многозадачной среде подобный
подход был бы весьма расточителен, так как огромное количество функций,
отвечающих за прорисовку элементов пользовательского интерфейса, за обращение к
системным ресурсам и т.п. дублировались в каждой программе. В качестве решения
возникшей проблемы была предложена концепция динамической компоновки (см. рис.
1).
рис 1.
DLL
(библиотека динамической связи) – файл, выступающий в качестве коллективной
библиотеки предикатов, которые могут быть использованы одновременно в
нескольких приложениях. Prolog способен генерировать DLL, включать DLL статически и
загружать динамически.
Вызов в программе на VP
процедур и функций на других языках.
Прежде чем вызвать процедуры и функции на других языках
их нужно объявить как внешний предикат, упомянув, что он осуществляется на
другом языке. При этом необходимо знать количество и порядок входных
параметров:
GLOBAL PREDICATES
procedure add(integer A, integer B,
integer C) – (i,i,o) language pascal
Замечание: обратите внимание, что в VP явно указывается язык процедуры
Передача
входных/выходных параметров и возвращение значений.
Размер входных параметров определен однозначно и
зависит только от объявленного типа. Выходной параметр – 32 битный указатель на
область памяти, где хранится выходное значение.
Следует отметить, что функции на Pascal
не могут возвращать значения в формате чисел с плавающей точкой, а функции C - структуры (но могут, конечно, возвращать указатели на
них).
Многочисленные
декларации.
Предикат VP может иметь
различные комбинации входных/выходных параметров, и для каждой из них
необходима отдельная процедура. Идентификаторы, используемые в Prolog должны совпадать с идентификаторами в библиотеке + суффикс
_X, где X – целое число
(порядковый номер процедуры, нумерация начинается с 0). Если существует только
один вариант, то суффикс отсутствует. Рассмотрим пример:
GLOBAL PREDICATES
subtraction(integer, integer, integer) –
(i,i,o), (i,o,i), (o,i,i), (i,i,i) language C
change(integer, integer) – (i,o)
language C
GOAL
subtraction(2,2,X), write(“2-2=”,X),
nl,
subtraction(2,Y,5), write(“2-5=”,Y),
nl,
subtraction(Z,5,4), write(“5-4=”,X),
nl,
subtraction(2,2,5), write(“2-2 равно 5”), nl,
change(5, Ch), write(Ch).
Модуль, связываемый с
этой программой должен содержать процедуры:
subtraction_0 (int x, int y, int
*z)
{*z=x-y;}
subtraction_1 (int x,
int *y, int z)
{*y=x-z;}
subtraction_2 (int *x, int y, int z)
{*x=y-z;}
subtraction_3 (int x,
int y, int z)
{if ((x-y)!=z)RUN_Fail();}
change(int a, int *b)
{*b=a;}
Примечание: если процедура написана на языке C, то параметры заносятся в стек в обратном порядке (после
возврата значений указатель автоматически корректируется VP),
в противном случае, параметры заносятся в стек в нормальном порядке (см.
таблицу 1).
Форматы объектных
файлов в Win32.
Под Win32 используется 2
формата объектных файлов: OMF (объектно-модульный
формат – используется, например, Borland C++ ) и COFF
(Общий объектно-файловый формат, используется, например, Visual C++ ).
1. При
использовании файла в формате OMF имя предиката должно
совпадать с именем функции.
2. При
использовании файла в формате COFF, к имени предиката
добавляется знак подчеркивания, и после символа @ указывается количество байт,
добавленных в стек (например, если предикат name имеет
2 целых аргумента, то он должен быть объявлен как _name@8 (см. таблицу 1)).
Установка указателя
на стек.
Существует два способа установки указателя на стек: при
объявлении функции и при ее вызове. Так сложилось, что Pascal
устанавливает указатель при объявлении функции, а С – при вызове (см. таблицу
1).
|
Конвертирует имена в
верхний регистр. |
Порядок аргументов
прямой. |
Устанавливает
указатель на стек при объявлении. |
Необходимость
конвертировать имена в формат COFF. |
C |
- |
- |
- |
|
pascal |
+ |
+ |
+ |
|
stdcall |
|
+ |
- |
+ |
syscall |
|
+ |
+ |
- |
Таблица 1: вызов
модулей из VP.
Неавтоматическое обозначение внешних предикатов.
Идентификатор процедуры или
функции в VP не обязательно должен совпадать с
идентификатором во внешнем модуле. В этом случае объявление такого предиката
имеет вид:
GLOBAL PREDICATES
add(integer, integer, integer) – (i,o) language c as “_myadd@12”
Эквивалентность типов.
Большинство простых типов
переменных в VP имеют эквиваленты в других языках
программирования, однако размер резервируемой для них памяти может не совпадать
(см. таблицу 2).
Тип переменной |
Размер (Win32). |
char, byte |
1 байт |
short, word |
2 байт |
long, dword |
4 байт |
unsigned, integer |
4 байт |
Real |
8 байт |
Ref |
4 байт |
Таблица 2: размер
переменных в VP.
Обработка списков.
Ниже приведен пример
программы, преобразующей список в массив, и затем вновь возвращающей данные в
список.
Программа ListToArray
на языке С преобразует список целых чисел в массив, записывает в стек элементы
массива и возвращает количество элементов (массив и количество элементов
передаются в программу как параметры).
Преобразование списка проходит
в 2 этапа:
1.
Просматривается список и находится количество элементов в нем.
2.
Целые числа из списка заносятся в массив, состоящий из известного
количества элементов.
/* Program
lstar_p.pro */
project "lstar"
global domains
ilist = integer*
global predicates
inclist(ilist,ilist) - (i,o) language c
goal
inclist([1,2,3,4,5,6,7],L), write(L).
/* Program
lstar_c.c */
#define listfno 1
#define nilfno 2
typedef unsigned char BYTE;
void *MEM_AllocGStack(unsigned);
typedef struct ilist {
BYTE Functor;
int Value;
struct ilist *Next;
} INTLIST;
int ListToArray(INTLIST *List,int **ResultArray)
{
INTLIST *SaveList = List;
int *Array, len;
register int *ArrP;
register int i;
/*
количество элементов в списке */
i = 0;
while ( List->Functor == listfno ) {
i++;
List = List->Next;
}
len = i;
Array = MEM_AllocGStack(i*sizeof(int));
ArrP = Array;
/*
перемещение элементов списка в массив */
List = SaveList;
while ( i != 0 ) {
*ArrP++ = List->Value;
List = List->Next;
i--;
}
*ResultArray = Array;
return(len);
}
void ArrayToList(register int
*ArrP,register int n,
register INTLIST **ListPP)
{
while ( n != 0 ) {
*ListPP = MEM_AllocGStack(sizeof(INTLIST));
(*ListPP)->Functor = listfno;
(*ListPP)->Value = *ArrP++;
ListPP = &(*ListPP)->Next;
n--;
}
*ListPP = MEM_AllocGStack(sizeof((*ListPP)->Functor));
/* конец списка */
(*ListPP)->Functor = nilfno;
}
void inclist(INTLIST *InList,INTLIST **OutList)
{
register int *ArrP, i, len;
int *Array;
len = ListToArray(InList,&Array);
ArrP = Array;
for ( i = 0; i < len; i++)
++*ArrP++;
ArrayToList(Array,len,OutList);
}
Вызов предикатов VP.
VP
способен не только вызывать предикаты, но и предоставлять их другим программам.
Ниже приведен пример вызова предиката prowin_msg
из программы на С:
/* Program hello_p.pro */
global predicates
char prowin_msg(string) - (i) language c
hello_c - language c
clauses
prowin_msg(S,C) :-
write(S," (press any key)"), readchar(C).
goal
prowin_msg("Hello from PDC Prolog"),
hello_c.
/* Program
hello_c.c */
char prowin_msg(char *);
void hello_c()
{
while ( prowin_msg("Hello
from C (press 'C')") != 'C' )
;
}
2003 Pechenkin
pechenkin@pochtamt.ru
www.cs.vsu.ru/~pechenkin
|