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