Программирование и комп-ры

Использование Prolog совместно с другими ЯП

                Использование Prolog совместно с другими ЯП.

Понятие Dll.

   Вспомним процесс программирования в DOS. Преобразование исходного  текста
в машинный код включал в себя 2 процесса: компиляцию и  линковку.  Во  время
линковки  в  код  программы  помещались  не  только  объявления  функций   и
процедур, но и их полный код.
   В многозадачной среде подобный подход был  бы  весьма  расточителен,  так
как  огромное  количество  функций,  отвечающих  за   прорисовку   элементов
пользовательского интерфейса, за  обращение  к  системным  ресурсам  и  т.п.
дублировались в каждой программе.  В  качестве  решения  возникшей  проблемы
была предложена концепция динамической компоновки (см. рис. 1).

[pic]рис 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



смотреть на рефераты похожие на "Использование Prolog совместно с другими ЯП "