Quintus
Prolog Manual
As outlined in {manual(a-2)}, a constellation of new features greatly extends the relationship between Quintus Prolog code and foreign lang code. It is now possible to embed Prolog code in a program written in another language without restrictions. Clearly, the first requirement for embedding Prolog code freely in foreign code is to be able to call Prolog from foreign code and vice versa. C calling Prolog is a major new feature of Release 3 and is discussed in {manual(i-4)}. A further requirement is that all types of data structures can be passed between Prolog and the foreign code. Previously it was not possible to pass compound Prolog terms between Prolog and foreign code. In addition there were serious limitations on passing mathematical data. Release 3 adds
With these new features, Quintus Prolog fulfills the full data passing requir The foreign language interface is now fully bidirectional. This in itself is not sufficient for embeddability in a strong sense. The Prolog portions of the application must in addition be well-behaved. That is, they must not make any assumptions about how the operating system will handle such matters as memory and input/output operations. This is where the embedding layer of Quintus Prolog comes in.
In many cases, the embedding layer will be transparent to the application developer. It provides a full set of default functions for interaction between Prolog and the host operating system. Frequently all you will need to do is use the extended FLI and let the defaults provided by Quintus Prolog take care of the operating system requirements concerning memory management and I/O. However, Prolog no longer insists on controlling memory management and input/output operations, should this be impossible or undesirable in your application. These default interfaces are fully user redefinable. Memory management: Quintus Prolog Release 3 does not have any restrictions on the underlying memory. This is a crucial aspect of embeddability. Any good Prolog implementation will start up with the minimum amount of memory necessary and expand and shrink depending on the memory needed to execute each goal. In previous releases of Quintus Prolog (as well as most other Prolog implementations) all the memory which Prolog used had to be contiguous. So it was possible that if some foreign component of the application allocated memory from the top, it would disable Prolog from growing any further. With Release 3, Quintus Prolog runs on discontiguous memory. Therefore Prolog can share the process' address space with memory allocated to Prolog interspersed with memory allocated by other components of the application. The user can replace Quintus Prolog's low level memory management functions. This is essential if the user has an application which would like to take care of all memory management and does not want Prolog to directly make system calls to the OS to allocate memory. This makes it easy to link Prolog with other components that have more rigid restrictions about its memory allocation. (Discussed further in {manual(i-2-2-2)}). Input/Output: The user can create, access and manipulate Prolog I/O streams from foreign code. This provides a unified way of performing I/O from Prolog as well as foreign code. It also gives the user the ability to have I/O streams to sockets, pipes or even windows. Graphical user interfaces have become a natural Prolog component of an application. The low level I/O functions can also be replaced. This is essential if the user has a large application and wants to take care of all I/O without any direct calls from Prolog to the OS to perform I/O. This is elaborated in {manual(i-2-2-3)}.
To understand the motivation for the new "embeddability" layer, contrast the model of foreign language interface which previously held with the new model.
The Old Model: Under the one-directional foreign language interface, it was necessary to write a 'main' program in Prolog. The foreign language interface was able to call foreign code from this 'main'. There were basically two components, the Prolog Main, and the Foreign Program. The foreign program itself could have all sorts of components. However, from the point where the foreign code began, no more Prolog code could be inserted. For instance, if you wanted to add a Prolog component to Module C of the program, it would be necessary to restructure the program to enable control to return to the Prolog 'main', where the new Prolog code could be called, and then reinvoke the foreign code in Module C. Another limitation of the old foreign interface was the possibility of conflicts between the foreign code called by the user's Prolog code and the foreign code used by the Quintus Prolog kernel. For example, the Quintus Pro required total control of all memory allocation to ensure that the Prolog memory areas were contiguous. Therefore the users code could not use the system call sbrk() to allocate memory, but had to use the malloc() function provided with Quintus Prolog. Now, however, the foreign functions used by the Quintus Prolog kernel forms t Embedding Layer and it is possible for the user to redefine these functions to conform to the requirements of his foreign code.
The New Model: The Embedding Layer contains C functions which establish defaults for memory management and I/O. The user can redefine any of these modules so as to prevent conflicts between the application's C calls and the C calls made by the Quintus Prolog kernel.
The next three sections describe the major areas of Prolog which can be redefined to facilitate the embedding of Prolog code in foreign language applications:
Consider the details presented in these sections in the context of this overview of the process of creating a program with a Prolog component:
qld -Dd component.qof prog.o -o BigApplication
You may also want to link in QUI in order to be able to use the debugger, as described in {manual(e-2)}. The process of linking QUI into an application is discussed in {manual(h-1-9)}.
Quintus Prolog provides defaults for interfacing the operating system. If customization is necessary in this area, a user must completely redefine, not just extend, the supplied functions.
NOTE: The default OS interface functions which can be redefined all have names beginning with the prefix "QU_". The QU_ functions are like hooks in the sense that they provide you with a place to insert code which changes Prolog's behavior. However, we do not include Prolog hooks such as message_hook/3 in this discussion because the point of embedding is to call Prolog code from foreign programs. The Prolog hooks are used independently of embedding.
Normally, when building an executable with qld the Quintus main() routine is linked in to the executable, which initializes the Prolog environment and calls QP_toplevel. QP_toplevel() will either:
However, you are not limited to using this default main(). You can define your main() and have Prolog as a function call. This should be done if the Prolog component(s) of your application are such that they may not be called in a given run of the program. In that case, you would not want to initialize Prolog unless it became necessary. An example of this sort of case is a program written in C which utilizes menus. The end user can select a number of options. One of these options involves further decision making, and runs an expert system written in Prolog. If the user doesn't happen to select this menu option on a given occasion, there is no reason to use the resources involved in initializing Prolog. So you would write a main which is dependent upon this menu selection. Once the user selects this option and thus starts up Prolog, however, subsequent invocations will recognize that Prolog is already initialized and will not do it again. Another situation where it makes sense to "redefine" main() is where you already have a large application written in C or some other foreign language and you wish to extend it with a module written in Prolog without having to rewrite the top level of the existing program. If you choose to use a different main(), you should be aware that the default Quintus main() provides certain functionality, which will have to be included in the user-supplied main():
The built-in function QP_initialize() takes care of these tasks. An example of a user-supplied main can be found in the reference page for QP_initialize(). The QP_* functions require that Prolog is initialized for memory management, etc. Thus, whenever main() is redefined, it will be necessary to call QP_initialize(). There is no harm in calling this routine more than once. So people writing portions of large projects can safely assume Prolog isn't initialized, and call QP_initialize(). An example of defining your own main is given in the reference page for QP_initialize().
Release 3 of Quintus Prolog makes it possible to run Prolog as an embedded system. In terms of memory management this means that Prolog does not assume full control of the address space or that all its memory is going to be contiguous. This makes it possible to share the same address space between Prolog and other applications. The memory used by Prolog can be interspersed with the memory used by the application into which Prolog is embedded. With Release 3 all of Prolog's sophisticated memory management can be built on top of a primitive layer which users can replace with their own functions. Such replacement is only required when the application in which the Prolog code is embedded demands full control of the address space and memory allocation. In general it is not necessary or even advantageous to do this. The embedding layer of memory management comprises three primitive functions: QU_alloc_init_mem(), QU_alloc_mem() and QU_free_mem(). The system has a default implementation of these functions based on the Unix call sbrk(). If Prolog is to become part of an embedded package which would like to provide its own memory management routines then the user can redefine these functions and statically link it with the Prolog system. (Static linking is discussed in {manual(STATIC-LINKING)}.) If the user does not provide these functions, the Quintus-supplied functions (in libqp.a) will be used by default. This layer is responsible for allocating memory to Prolog and freeing memory back to the Operating System. Prolog calls the functions QU_alloc_mem() and QU_free_mem() for these purposes. QU_init_mem() is called the first time Prolog makes a call to allocate memory. If the user redefines these functions the redefinition should meet the specifications for these functions mentioned in the reference pages. An example of defining your own memory management routines is given in the reference page for QU_alloc_mem(). This layer is also responsible for the environment variables PROLOGINCSIZE and PROLOGMAXSIZE, which are available for customizing the Quintus-supplied default memory management routines. The user can set PROLOGINCSIZE to set the least amount by which Prolog should expand each time. The user can set PROLOGMAXSIZE to limit the maximum memory used by Prolog. The Prolog system top level supplied by Quintus automatically cleans up Prolog memory each time it returns to top level. However, when Prolog is called directly from a foreign function the Quintus top level (or a user-defined equivalent) need not be used. If nothing else is done (such as calling trimcore/0 in the Prolog code), when a Prolog query returns, the memory allocated to Prolog will stay expanded to whatever was required to compute the previous solutions. In the case where it is more convenient to call a C function than a Prolog built-in, QP_trimcore() is provided to explicitly clean up Prolog memory. It has the same effect as trimcore/0. Like trimcore/0 it should be used judiciously, as overuse can result in unnecessary time being spent in memory expansion and contraction. However, when Prolog is to be dormant for a period, or as much free memory as possible is desired, QP_trimcore() can be quite useful.
Prolog streams are designed by default to be channels for I/O operations to a file or a terminal. User defined streams enable these operations to be performed on other types of object: notably, windows or a network channel. The embedding input/output functions create the default Prolog streams and provide the user with the default parameters for creating a user-defined stream. It is possible to change these defaults. However, in general it is not necessary or even advantageous to do this. Such replacement is only required when the application in which the Prolog code is embedded demands full control of the I/O system and does not want Prolog to make direct calls to the operating systen to perform I/O. One instance of such usage is to embed a Prolog program within an application which uses a graphical window-oriented user interface. The embedding layer for input/output contains four functions:
Details of each function can be found in the individual reference pages. Any of these functions can be supplied in linking a Prolog system through qld. If any function is not supplied, the default version of that function is linked in. A number of C macros and functions are provided in quintus.h and libqp.a to access and manipulate Prolog streams where it is more convenient to access them from C rather than calling a Prolog builtin. For example, QP_getc() will get a character from a Prolog stream in the same way as get0/2. These macros and functions are listed in {manual(i-5-8)}.
Detailed information is found in the reference pages for the following:
contact: product
support sales information