GNU PROLOG


A Native Prolog Compiler with Constraint Solving over Finite Domains

Edition 1.8, for GNU Prolog version 1.3.0
5th January, 2007
by Daniel Diaz






Copyright (C) 1999-2007 Daniel Diaz

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.




Contents

1  Acknowledgements

I would like to thank the department of computing science at the university of Paris 1 for allowing me the time and freedom necessary to achieve this project.

I am grateful to the members of the Loco project at INRIA Rocquencourt for their encouragement. Their involvement in this work led to useful feedback and exchange.

I would particularly like to thank Jonathan Hodgson for the time and effort he put into the proofreading of this manual. His suggestions, both regarding ISO technical aspects as well as the language in which it was expressed, proved invaluable.

The on-line HTML version of this document was created using HEVEA developed by Luc Maranget who kindly devoted so much of his time extending the capabilities of HEVEA in order to handle such a sizeable manual.

Jean-Christophe Aude kindly improved the visual aspect of both the illustrations and the GNU Prolog web pages.

Thanks to Richard A. O'Keefe for his advice regarding the implementation of some Prolog built-in predicates and for suggesting me the in-place installation feature.

Many thanks to the following contributors: Many thanks to all those people at GNU who helped me to finalize the GNU Prolog project.

Finally, I would like to thank everybody who tested preliminary releases and helped me to put the finishing touches to this system.

2  Introduction

GNU Prolog [5] is a free Prolog compiler with constraint solving over finite domains developed by Daniel Diaz. For recent information about GNU Prolog please consult the GNU Prolog page.

GNU Prolog is a Prolog compiler based on the Warren Abstract Machine (WAM) [9, 1]. It first compiles a Prolog program to a WAM file which is then translated to a low-level machine independent language called mini-assembly specifically designed for GNU Prolog. The resulting file is then translated to the assembly language of the target machine (from which an object is obtained). This allows GNU Prolog to produce a native stand alone executable from a Prolog source (similarly to what does a C compiler from a C program). The main advantage of this compilation scheme is to produce native code and to be fast. Another interesting feature is that executables are small. Indeed, the code of most unused built-in predicates is not included in the executables at link-time.

A lot of work has been devoted to the ISO compatibility. Indeed, GNU Prolog is very close to the ISO standard for Prolog [6].

GNU Prolog also offers various extensions very useful in practice (global variables, OS interface, sockets,...). In particular, GNU Prolog contains an efficient constraint solver over Finite Domains (FD). This opens contraint logic pogramming to the user combining the power of constraint programming to the declarativity of logic programming. The key feature of the GNU Prolog solver is the use of a single (low-level) primitive to define all (high-level) FD constraints. There are many advantages of this approach: constraints can be compiled, the user can define his own constraints (in terms of the primitive), the solver is open and extensible (as opposed to black-box solvers like CHIP),...Moreover, the GNU Prolog solver is rather efficient, often more than commercial solvers.

GNU Prolog is inspired from two systems developed by the same author: Here are some features of GNU Prolog:

3  Using GNU Prolog

3.1  Introduction

GNU Prolog offers two ways to execute a Prolog program: Running a program under the interactive interpreter allows the user to list it and to make full use of the debugger on it (section 4). Compiling a program to native code makes it possible to obtain a stand alone executable, with a reduced size and optimized for speed. Running a Prolog program compiled to native-code is around 3-5 times faster than running it under the interpreter. However, it is not possible to make full use of the debugger on a program compiled to native-code. Nor is it possible to list the program. In general, it is preferable to run a program under the interpreter for debugging and then use the native-code compiler to produce an autonomous executable. It is also possible to combine these two modes by producing an executable that contains some parts of the program (e.g. already debugged predicates whose execution-time speed is crucial) and interpreting the other parts under this executable. In that case, the executable has the same facilities as the GNU Prolog interpreter but also integrates the native-code predicates. This way to define a new enriched interpreter is detailed later (section 3.4.5).

3.2  The GNU Prolog interactive interpreter

3.2.1  Starting/exiting the interactive interpreter

GNU Prolog offers a classical Prolog interactive interpreter also called top-level. It allows the user to execute queries, to consult Prolog programs, to list them, to execute them and to debug them. The top-level can be invoked using the following command:
% gprolog [OPTION]...    (the % symbol is the operating system shell prompt)
Options:
–init-goal GOAL execute GOAL before top_level/0
–entry-goal GOAL execute GOAL inside top_level/0
–query-goal GOAL execute GOAL as a query for top_level/0
–help print a help and exit
–version print version number and exit
do not parse the rest of the command-line

The main role of the gprolog command is to execute the top-level itself, i.e. to execute the built-in predicate top_level/0 (section 7.18.1) which will produce something like:

GNU Prolog 1.2.9
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?-
The top-level is ready to execute your queries as explained in the next section.

To quit the top-level type the end-of-file key sequence (Ctl-D) or its term representation: end_of_file. It is also possible to use the built-in predicate halt/0 (section 7.18.1).

However, before entering the top-level itself, the command-line is processed to treat all known options (those listed above). All unrecognized arguments are collected together to form the argument list which will be available using argument_value/2 (section 7.27.2) or argument_list/1 (section 7.27.3). The option stops the parsing of the command-line, all remainding options are collected into the argument list.

Several options are provided to execute a goal before entering the interaction with the user: The above order is thus the order in which each kind of goal (init, entry, query) is executed. If there are several goals of a same kind they are executed in the oder of appearance. Thus, all init goals are executed (in the order of appearance) before all entry goals and all entry goals are executed before all query goals.

Each GOAL is passed as a shell argument (i.e. one shell string) and should not contain a terminal dot. Example: –init-goal 'write(hello), nl' under a sh-like. To be executed, a GOAL is transformed into a term using read_term_from_atom(Goal, Term, [end_of_term(eof)]). Respecting both the syntax of shell strings and of Prolog can be heavy. For instance, passing a backslash character \ can be difficult since it introduces an escape sequence both in sh and inside Prolog quoted atoms. The use of back quotes can then be useful since, by default, no escape sequence is processed inside back quotes (this behavior can be controlled using the back_quotes Prolog flag (section 7.22.1)).

Since the Prolog argument list is created when the whole command-line is parsed, if a –init-goal option uses argument_value/2 or argument_list/1 it will obtained the original command-line arguments (i.e. including all recognized arguments).

Here is an example of using execution goal options:
% gprolog –init-goal 'write(before), nl' –entry-goal 'write(inside), nl'
–query-goal 'append([a,b],[c,d],X)'
will produce the following:

before
GNU Prolog 1.2.9
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
inside
| ?- append([a,b],[c,d],X).

X = [a,b,c,d]

yes
| ?-

3.2.2  The interactive interpreter read-execute-write loop

The GNU Prolog top-level is built on a classical read-execute-write loop that also allows for re-executions (when the query is not deterministic) as follows: Here is an example of execution of a query (“find the lists X and Y such that the concatenation of X and Y is [a,b]”):
| ?- append(X,Y,[a,b,c]).
 
X = []
Y = [a,b,c] ? ;    (here the user presses ; to compute another solution)
 
X = [a]
Y = [b,c] ? a    (here the user presses a to compute all remaining solutions)
 
X = [a,b]
Y = [c]    (here the user is not asked and the next solution is computed)
 
X = [a,b,c]
Y = []    (here the user is not asked and the next solution is computed)
 
no    (no more solution)
In some cases the top-level can detect that the current solution is the last one (no more alternatives remaining). In such a case it does not display the ? symbol (and does not ask the user). Example:
| ?- (X=1 ; X=2).
 
X = 1 ? ;    (here the user presses ; to compute another solution)
 
X = 2    (here the user is not prompted since there are no more alternatives)
 
yes
The user can stop the execution even if there are more alternatives by typing RETURN.
| ?- (X=1 ; X=2).
 
X = 1 ?    (here the user presses RETURN to stop the execution)
 
yes
The top-level tries to display the values of the variables of the query in a readable manner. For instance, when a variable is bound to a query variable, the name of this variable appears. When a variable is a singleton an underscore symbol _ is displayed (_ is a generic name for a singleton variable, it is also called an anonymous variable). Other variables are bound to new brand variable names. When a query variable name X appears as the value of another query variable Y it is because X is itself not instantiated otherwise the value of X is displayed. In such a case, nothing is output for X itself (since it is a variable). Example:
| ?- X=f(A,B,_,A), A=k.
 
A = k    (the value of A is displayed also in f/3 for X)
X = f(k,B,_,k)    (since B is a variable which is also a part of X, B is not displayed)
| ?- functor(T,f,3), arg(1,T,X), arg(3,T,X).
 
T = f(X,_,X)    (the 1st and 3rd args are equal to X, the 2nd is an anonymous variable)
| ?- read_from_atom('k(X,Y,X).',T).
 
T = k(A,_,A)    (the 1st and 3rd args are unified, a new variable name A is introduced)
The top-level uses variable binding predicates (section 7.5). To display the value of a variable, the top-level calls write_term/3 with the following option list: [quoted(true),numbervars(false), namevars(true)] (section 7.14.6). A term of the form '$VARNAME'(Name) where Name is an atom is displayed as a variable name while a term of the form '$VAR'(N) where N is an integer is displayed as a normal compound term (such a term could be output as a variable name by write_term/3). Example:
| ?- X='$VARNAME'('Y'), Y='$VAR'(1).
 
X = Y    (the term '$VARNAME'('Y') is displayed as Y)
Y = '$VAR'(1)    (the term '$VAR'(1) is displayed as is)
| ?- X=Y, Y='$VAR'(1).
 
X = '$VAR'(1)
Y = '$VAR'(1)
In the first example, X is explicitly bound to '$VARNAME'('Y') by the query so the top-level displays Y as the value of X. Y is unified with '$VAR'(1) so the top-level displays it as a normal compound term. It should be clear that X is not bound to Y (whereas it is in the second query). This behavior should be kept in mind when doing variable binding operations.

Finally, the top-level computes the user-time (section 7.24.2) taken by a query and displays it when it is significant. Example:
| ?- retractall(p(_)), assertz(p(0)),
     repeat,
        retract(p(X)),
        Y is X + 1,
        assertz(p(Y)),
        X = 1000, !.
 
X = 1000
Y = 1001
 
(180 ms) yes    (the query took 180ms of user time)

3.2.3  Consulting a Prolog program

The top-level allows the user to consult Prolog source files. Consulted predicates can be listed, executed and debugged (while predicates compiled to native-code cannot). For more information about the difference between a native-code predicate and a consulted predicate refer to the introduction of this section (section 3.1) and to the part devoted to the compiler (section 3.4.1).

To consult a program use the built-in predicate consult/1 (section 7.23.1). The argument of this predicate is a Prolog file name or user to specify the terminal. This allows the user to directly input the predicates from the terminal. In that case the input shall be terminated by the end-of-file key sequence (Ctl-D) or its term representation: end_of_file. A shorthand for consult(FILE) is [FILE]. Example:
| ?- [user].
{compiling user for byte code...}
even(0).
even(s(s(X))):-
        even(X).
     (here the user presses Ctl-D to end the input)
{user compiled, 3 lines read - 350 bytes written, 1180 ms}
 
| ?- even(X).
 
X = 0 ? ;    (here the user presses ; to compute another solution)
 
X = s(s(0)) ? ;    (here the user presses ; to compute another solution)
 
X = s(s(s(s(0)))) ?    (here the user presses RETURN to stop the execution)
 
yes
| ?- listing.
 
even(0).
even(s(s(A))) :-
        even(A).
When consult/1 (section 7.23.1) is invoked on a Prolog file it first runs the GNU Prolog compiler (section 3.4) as a child process to generate a temporary WAM file for byte-code. If the compilation fails a message is displayed and nothing is loaded. If the compilation succeeds, the produced file is loaded into memory using load/1 (section 7.23.2). Namely, the byte-code of each predicate is loaded. When a predicate P is loaded if there is a previous definition for P it is removed (i.e. all clauses defining P are erased). We say that P is redefined. Note that only consulted predicates can be redefined. If P is a native-code predicate, trying to redefine it will produce an error at load-time: the predicate redefinition will be ignored and the following message displayed:
native code procedure P cannot be redefined
Finally, an existing predicate will not be removed if it is not re-loaded. This means that if a predicate P is loaded when consulting the file F, and if later the definition of P is removed from the file F, consulting F again will not remove the previously loaded definition of P from the memory.

Consulted predicates can be debugged using the Prolog debugger. Use the debugger predicate trace/0 or debug/0 (section 4.3.1) to activate the debugger.

3.2.4  Interrupting a query

Under the top-level it is possible to interrupt the execution of a query by typing the interruption key (Ctl-C). This can be used to abort a query, to stop an infinite loop, to activate the debugger,...When an interruption occurs the top-level displays the following message: Prolog interruption (h for help) ? The user can then type one of the following commands:
Command Name Description
a abort abort the current execution. Same as abort/0 (section 7.18.1)
e exit quit the current Prolog process. Same as halt/0 (section 7.18.1)
b break invoke a recursive top-level. Same as break/0 (section 7.18.1)
c continue resume the execution
t trace start the debugger using trace/0 (section 4.3.1)
d debug start the debugger using debug/0 (section 4.3.1)
h or ? help display a summary of available commands

3.2.5  The line editor

The line editor (linedit) allows the user to build/update the current input line using a variety of commands. This facility is available if the linedit part of GNU Prolog has been installed. linedit is implicitly called by any built-in predicate reading from a terminal (e.g. get_char/1, read/1,...). This is the case when the top-level reads a query.

Bindings: each command of linedit is activated using a key. For some commands another key is also available to invoke the command (on some terminals this other key may not work properly while the primary key always works). Here is the list of available commands:
Key Alternate key Description
Ctl-B go to the previous character
Ctl-F go to the next character
Esc-B Ctl-← go to the previous word
Esc-F Ctl-→ go to the next word
Ctl-A Home go to the beginning of the line
Ctl-E End go to the end of the line
Ctl-H Backspace delete the previous character
Ctl-D Delete delete the current character
Ctl-U Ctl-Home delete from beginning of the line to the current character
Ctl-K Ctl-End delete from the current character to the end of the line
Esc-L   lower case the next word
Esc-U   upper case the next word
Esc-C   capitalize the next word
Ctl-T   exchange last two characters
Ctl-V Insert switch on/off the insert/replace mode
Ctl-I Tab complete word (twice displays all possible completions)
Esc-Ctl-I Esc-Tab insert spaces to emulate a tabulation
Ctl-space   mark beginning of the selection
Esc-W   copy (from the begin selection mark to the current character)
Ctl-W   cut (from the begin selection mark to the current character)
Ctl-Y   paste
Ctl-P recall previous history line
Ctl-N recall next history line
Esc-P   recall previous history line beginning with the current prefix
Esc-N   recall next history line beginning with the current prefix
Esc-< Page Up recall first history line
Esc-> Page Down recall last history line
Ctl-C   generate an interrupt signal (section 3.2.4)
Ctl-D   generate an end-of-file character (at the begin of the line)
RETURN   validate a line
Esc-?   display a summary of available commands

History: when a line is entered (i.e. terminated by RETURN), linedit records it in an internal list called history. It is later possible to recall history lines using appropriate commands (e.g. Ctl-P recall the last entered line) and to modify them as needed. It is also possible to recall a history line beginning with a given prefix. For instance to recall the previous line beginning with write simply type write followed by Esc-P. Another Esc-P will recall an earlier line beginning with write,...

Completion: another important feature of linedit is its completion facility. Indeed, linedit maintains a list of known words and uses it to complete the prefix of a word. Initially this list contains all predefined atoms and the atoms corresponding to available predicates. This list is dynamically updated when a new atom appears in the system (whether read at the top-level, created with a built-in predicate, associated with a new consulted predicate,...). When the completion key (Tab) is pressed linedit acts as follows: Example:
| ?- argu    (here the user presses Tab to complete the word)
| ?- argument_    (linedit completes argu with argument_ and emits a beep)
     (the user presses again Tab to see all possible completions)
argument_counter    (linedit shows 3 possible completions)
argument_list
argument_value
| ?- argument_    (linedit redisplays the input line)
 
| ?- argument_c    (to select argument_counter the user presses c and Tab)
| ?- argument_counter    (linedit completes with argument_counter)
Finally, linedit allows the user to check that (square/curly) brackets are well balanced. For this, when a close bracket symbol, i.e. ), ] or }, is typed, linedit determines the associated open bracket, i.e. (, [ or {, and temporarily repositions the cursor on it to show the match.

3.3  Adjusting the size of Prolog stacks

GNU Prolog uses several stacks to execute a Prolog program. Each stack has a static size and cannot be dynamically increased during the execution. For each stack there is a default size but the user can define a new size by setting an environment variable. When a GNU Prolog program is run it first consults these variables and if they are not defined uses the default sizes. The following table presents each stack of GNU Prolog with its default size and the name of its associated environment variable:
Stack Default Environment Description
name size (Kb) variable  
local 4096 LOCALSZ control stack (environments and choice-points)
global 8192 GLOBALSZ heap (compound terms)
trail 3072 TRAILSZ conditional bindings (bindings to undo at backtracking)
cstr 3072 CSTRSZ finite domain constraint stack (FD variables and constraints)

If the size of a stack is too small an overflow will occur during the execution. In that case GNU Prolog emits the following error message before stopping:
S stack overflow (size: N Kb, environment variable used: E)
where S is the name of the stack, N is the current stack size in Kb and E the name of the associated environment variable. When such a message occurs it is possible to (re)define the variable E with the new size. For instance to allocate 8192 Kb to the local stack under a Unix shell use:
LOCALSZ=8192; export LOCALS    (under sh or bash)
setenv LOCALSZ 8192    (under csh or tcsh)
This method allows the user to adjust the size of Prolog stacks. However, in some cases it is preferable not to allow the user to modify these sizes. For instance, when providing a stand alone executable whose behavior should be independent of the environment in which it is run. In that case the program should not consult environment variables and the programmer should be able to define new default stack sizes. The GNU Prolog compiler offers this facilities via several command-line options such as –local-size or –fixed-sizes (section 3.4.3).

Finally note that GNU Prolog stacks are virtually allocated (i.e. use virtual memory). This means that a physical memory page is allocated only when needed (i.e. when an attempt to read/write it occurs). Thus it is possible to define very large stacks. At the execution, only the needed amount of space will be physically allocated.

3.4  The GNU Prolog compiler

3.4.1  Different kinds of codes

One of the main advantages of GNU Prolog is its ability to produce stand alone executables. A Prolog program can be compiled to native code to give rise to a machine-dependent executable using the GNU Prolog compiler. However native-code predicates cannot be listed nor fully debugged. So there is an alternative to native-code compilation: byte-code compilation. By default the GNU Prolog compiler produces native-code but via a command-line option it can produce a file ready for byte-code loading. This is exactly what consult/1 does as was explained above (section 3.2.3). GNU Prolog also manages interpreted code using a Prolog interpreter written in Prolog. Obviously interpreted code is slower than byte-code but does not require the invocation of the GNU Prolog compiler. This interpreter is used each time a meta-call is needed as by call/1 (section 6.2.3). This also the case of dynamically asserted clauses. The following table summarizes these three kinds of codes:
Type Speed Debug ? For what
interpreted-code slow yes meta-call and dynamically asserted clauses
byte-code medium yes consulted predicates
native-code fast no compiled predicates

3.4.2  Compilation scheme

Native-code compilation: a Prolog source is compiled in several stages to produce an object file that is linked to the GNU Prolog libraries to produce an executable. The Prolog source is first compiled to obtain a WAM [9] file. For a detailed study of the WAM the interested reader can refer to “Warren's Abstract Machine: A Tutorial Reconstruction” [1]. The WAM file is translated to a machine-independent language specifically designed for GNU Prolog. This language is close to a (universal) assembly language and is based on a very reduced instruction set. For this reason this language is called mini-assembly (MA). The mini-assembly file is then mapped to the assembly language of the target machine. This assembly file is assembled to give rise to an object file which is then linked with the GNU Prolog libraries to provide an executable. The compiler also takes into account Finite Domain constraint definition files. It translates them to C and invoke the C compiler to obtain object files. The following figure presents this compilation scheme:



Obviously all intermediate stages are hidden to the user who simply invokes the compiler on his Prolog file(s) (plus other files: C,...) and obtains an executable. However, it is also possible to stop the compiler at any given stage. This can be useful, for instance, to see the WAM code produced (perhaps when learning the WAM). Finally it is possible to give any kind of file to the compiler which will insert it in the compilation chain at the stage corresponding to its type. The type of a file is determined using the suffix of its file name. The following table presents all recognized types/suffixes:
Suffix of the file Type of the file Handled by:
.pl, .pro Prolog source file pl2wam
.wam WAM source file wam2ma
.ma Mini-assembly source file ma2asm
.s Assembly source file the assembler
.c, .C, .CC, .cc, .cxx, .c++, .cpp C or C++ source file the C compiler
.fd Finite Domain constraint source file fd2c
any other suffix (.o, .a,...) any other type (object, library,...) the linker (C linker)

Byte-code compilation: the same compiler can be used to compile a source Prolog file for byte-code. In that case the Prolog to WAM compiler is invoked using a specific option and produces a WAM for byte-code source file (suffixed .wbc) that can be later loaded using load/1 (section 7.23.2). Note that this is exactly what consult/1 (section 7.23.1) does as explained above (section 3.2.3).

3.4.3  Using the compiler

The GNU Prolog compiler is a command-line compiler similar in spirit to a Unix C compiler like gcc. To invoke the compiler use the gplc command as follows:
% gplc [OPTION]... FILE...    (the % symbol is the operating system shell prompt)
The arguments of gplc are file names that are dispatched in the compilation scheme depending on the type determined from their suffix as was explained previously (section 3.4.2). All object files are then linked to produce an executable. Note however that GNU Prolog has no module facility (since there is not yet an ISO reference for Prolog modules) thus a predicate defined in a Prolog file is visible from any other predicate defined in any other file. GNU Prolog allows the user to split a big Prolog source into several files but does not offer any way to hide a predicate from others.

The simplest way to obtain an executable from a Prolog source file prog.pl is to use:
% gplc prog.pl
This will produce an native executable called prog which can be executed as follows:
% prog
However, there are several options that can be used to control the compilation:

General options:
-o FILE, –output FILE use FILE as the name of the output file
-W, –wam-for-native stop after producing WAM files(s)
-w, –wam-for-byte-code stop after producing WAM for byte-code file(s) (force –no-call-c)
-M, –mini-assembly stop after producing mini-assembly files(s)
-S, –assembly stop after producing assembly files (s)
-F, –fd-to-c stop after producing C files(s) from FD constraint definition file(s)
-c, –object stop after producing object files(s)
–temp-dir PATH use PATH as directory for temporary files
–no-del-temp do not delete temporary files
–no-decode-hexa do not decode hexadecimal predicate names
-v, –verbose print executed commands
-h, –help print a help and exit
–version print version number and exit

Prolog to WAM compiler options:
–pl-state FILE read FILE to set the initial Prolog state
–no-susp-warn do not show warnings for suspicious predicates
–no-singl-warn do not show warnings for named singleton variables
–no-redef-error no not show errors for built-in predicate redefinitions
–foreign-only only compile foreign/1-2 directives
–no-call-c do not allow the use of fd_tell, '$call_c',...
–no-inline do not inline predicates
–no-reorder do not reorder predicate arguments
–no-reg-opt do not optimize registers
–min-reg-opt minimally optimize registers
–no-opt-last-subterm do not optimize last subterm compilation
–fast-math use fast mathematical mode (assume integer arithmetics)
–keep-void-inst keep void WAM instructions in the output file
–compile-msg print a compile message
–statistics print statistics information

WAM to mini-assembly translator options:
–comment include comments in the output file

Mini-assembly to assembly translator options:
–comment include comments in the output file

C compiler options:
–c-compiler FILE use FILE as C compiler
-C OPTION pass OPTION to the C compiler

Assembler options:
-A OPTION pass OPTION to the assembler

Linker options:
–local-size N set default local stack size to N Kb
–global-size N set default global stack size to N Kb
–trail-size N set default trail stack size to N Kb
–cstr-size N set default constraint stack size to N Kb
–fixed-sizes do not consult environment variables at run-time (use default sizes)
–no-top-level do not link the top-level (force –no-debugger)
–no-debugger do not link the Prolog/WAM debugger
–min-pl-bips link only used Prolog built-in predicates
–min-fd-bips link only used FD solver built-in predicates
–min-bips shorthand for: –no-top-level –min-pl-bips –min-fd-bips
–min-size shorthand˛ for: –min-bips –strip
–no-fd-lib do not look for the FD library (maintenance only)
-s, –strip strip the executable
-L OPTION Pass OPTION to the linker

It is possible to only give the prefix of an option if there is no ambiguity.

The name of the output file is controlled via the -o FILE option. If present the output file produced will be named FILE. If not specified, the output file name depends on the last stage reached by the compiler. If the link is not done the output file name(s) is the input file name(s) with the suffix associated with the last stage. If the link is done, the name of the executable is the name (without suffix) of the first file name encountered in the command-line. Note that if the link is not done -o has no sense in the presence of multiple input file names. For this reason, several meta characters are available for substitution in FILE: By default the compiler runs in the native-code compilation scheme. To generate a WAM file for byte-code use the –wam-for-byte-code option. The resulting file can then be loaded using load/1 (section 7.23.2).

To execute the Prolog to WAM compiler in a given read environment (operator definitions, character conversion table,...) use –pl-state FILE. The state file should be produced by write_pl_state_file/1 (section 7.22.5).

By default the Prolog to WAM compiler inlines calls to some deterministic built-in predicates (e.g. arg/3 and functor/3). Namely a call to such a predicate will not yield a classical predicate call but a simple C function call (which is obviously faster). It is possible to avoid this using –no-inline.

Another optimization performed by the Prolog to WAM compiler is unification reordering. The arguments of a predicate are reordered to optimize unification. This can be deactivated using –no-reorder. The compiler also optimizes the unification/loading of nested compound terms. More precisely, the compiler emits optimized instructions when the last subterm of a compound term is itself a compound term (e.g. lists). This can be deactivated using –no-opt-last-subterm.

By default the Prolog to WAM compiler fully optimizes the allocation of registers to decrease both the number of instruction produced and the number of used registers. A good allocation will generate many void instructions that are removed from the produced file except if –keep-void-inst is specified. To prevent any optimization use –no-reg-opt while –min-reg-opt forces the compiler to only perform simple register optimizations.

The Prolog to WAM compiler emits an error when a control construct or a built-in predicate is redefined. This can be avoided using –no-redef-error. The compiler also emits warnings for suspicious predicate definitions like -/2 since this often corresponds to an earlier syntax error (e.g. - instead of _. This can be deactivated by specifying –no-susp-warn. Finally, the compiler warns when a singleton variable has a name (i.e. not the generic anonymous name _). This can be deactivated specifying –no-singl-warn.

Predicate names are encoded with an hexadecimal representation. This is explained in more detail later (section 3.4.6). By default the error messages from the linker (e.g. multiple definitions for a given predicate, reference to an undefined predicate,...) are filtered to replace any hexadecimal representation by the real predicate name. Specifying the –no-decode-hexa prevents gplc from filtering linker output messages and hexadecimal representations are then shown.

When producing an executable it is possible to specify default stack sizes (using STACK_NAME-size) and to prevent it from consulting environment variables (using –fixed-sizes) as was explained above (section 3.3). By default the produced executable will include the top-level, the Prolog/WAM debugger and all Prolog and FD built-in predicates. It is possible to avoid linking the top-level (section 3.2) by specifying –no-top-level. In this case, at least one initialization/1 directive (section 6.1.13) should be defined. The option –no-debugger does not link the debugger. To include only used built-in predicates that are actually used the options –no-pl-bips and/or –no-fd-bips can be specified. For the smallest executable all these options should be specified. This can be abbreviated by using the shorthand option –min-bips. By default, executables are not stripped, i.e. their symbol table is not removed. This table is only useful for the C debugger (e.g. when interfacing Prolog and C). To remove the symbol table (and then to reduce the size of the final executable) use –strip. Finally –min-size is a shortcut for –min-bips and –strip, i.e. the produced executable is as small as possible.

Example: compile and link two Prolog sources prog1.pl and prog2.pl. The resulting executable will be named prog1 (since -o is not specified):
% gplc prog1.pl prog2.pl
Example: compile the Prolog file prog.pl to study basic WAM code. The resulting file will be named prog.wam:
% gplc -W –no-inline –no-reorder –keep-void-inst prog.pl
Example: compile the Prolog file prog.pl and its C interface file utils.c to provide an autonomous executable called mycommand. The executable is not stripped to allow the use of the C debugger:
% gplc -o mycommand prog.pl utils.c
Example: detail all steps to compile the Prolog file prog.pl (the resulting executable is stripped). All intermediate files are produced (prog.wam, prog.ma, prog.s, prog.o and the executable prog):
% gplc -W prog.pl
% gplc -M --comment prog.wam
% gplc -S --comment prog.ma
% gplc -c prog.s
% gplc -o prog -s prog.o

3.4.4  Running an executable

In this section we explain what happens when running an executable produced by the GNU Prolog native-code compiler. The default main function first starts the Prolog engine. This function collects all linked objects (issued from the compilation of Prolog files) and initializes them. The initialization of a Prolog object file consists in adding to appropriate tables new atoms, new predicates and executing its system directives. A system directive is generated by the Prolog to WAM compiler to reflect a (user) directive executed at compile-time such as op/3 (section 6.1.10). Indeed, when the compiler encounters such a directive it immediately executes it and also generates a system directive to execute it at the start of the executable. When all system directives have been executed the Prolog engine executes all initialization directives defined with initialization/1 (section 6.1.13). If several initialization directives appear in the same file they are executed in the order of appearance. If several initialization directives appear in different files the order in which they are executed is machine-dependant. However, on most machines the order will be the reverse order in which the associated files have been linked (this is not true under native win32). When all initialization directives have been executed the default main function looks for the GNU Prolog top-level. If present (i.e. it has been linked) it is called otherwise the program simply ends. Note that if the top-level is not linked and if there is no initialization directive the program is useless since it simply ends without doing any work. The default main function detects such a behavior and emits a warning message.

Example: compile an empty file prog.pl without linking the top-level and execute it:
% gplc --no-top-level prog.pl
% prog
Warning: no initial goal executed
   use a directive :- initialization(Goal)
   or remove the link option --no-top-level (or --min-bips or --min-size)

3.4.5  Generating a new interactive interpreter

In this section we show how to define a new top-level extending the GNU Prolog interactive interpreter with new predicate definitions. The obtained top-level can then be considered as an enriched version of the basic GNU Prolog top-level (section 3.2). Indeed, each added predicate can be viewed as a predefined predicate just like any other built-in predicate. This can be achieved by compiling these predicates and including the top-level at link-time.

The real question is: why would we include some predicates in a new top-level instead of simply consulting them under the GNU Prolog top-level ? There are two reasons for this: To define a new top-level simply compile the set of desired predicates and linking them with the GNU Prolog top-level (this is the default) using gplc (section 3.4.3).

Example: let us define a new top-level called my_top_level including all predicates defined in prog.pl:
% gplc -o my_top_level prog.pl
By the way, note that if prog.pl is an empty Prolog file the previous command will simply create a new interactive interpreter similar to the GNU Prolog top-level.

Example: as before where some predicates of prog.pl call C functions defined in utils.c:
% gplc -o my_top_level prog.pl utils.c
In conclusion, defining a particular top-level is nothing else but a particular case of the native-code compilation. It is simple to do and very useful in practice.

3.4.6  The hexadecimal predicate name encoding

When the GNU Prolog compiler compiles a Prolog source to an object file it has to associate a symbol to each predicate name. However, the syntax of symbols is restricted to identifiers: string containing only letters, digits or underscore characters. On the other hand, predicate names (i.e. atoms) can contain any character with quotes if necessary (e.g. 'x+y=z' is a valid predicate name). The compiler has then to encode predicate names respecting the syntax of identifiers. To achieve this, GNU Prolog uses an hexadecimal representation where each predicate name is translated to a symbol beginning with an X followed by the hexadecimal notation of the code of each character of the name.

Example: 'x+y=z' will be encoded as X782B793D7A since 78 is the hexadecimal representation of the code of x, 2B of the code of +, etc.

Since Prolog allows the user to define several predicates with the same name but with a different arity GNU Prolog encodes predicate indicators (predicate name followed by the arity). The symbol associated with the predicate name is then followed by an underscore and by the decimal notation of the arity.

Example: 'x+y=z'/3 will be encoded as X782B793D7A_3.

So, from the mini-assembly stage, each predicate indicator is replaced by its hexadecimal encoding. The knowledge of this encoding is normally not of interest for the user, i.e. the Prolog programmer. For this reason the GNU Prolog compiler hides this encoding. When an error occurs on a predicate (undefined predicate, predicate with multiple definitions,...) the compiler has to decode the symbol associated with the predicate indicator. For this gplc filters each message emitted by the linker to locate and decode eventual predicate indicators. This filtering can be deactivated specifying –no-decode-hexa when invoking gplc (section 3.4.3).

This filter is provided as an utility that can be invoked using the hexgplc command as follows:
% hexgplc [OPTION]... FILE...    (the % symbol is the operating system shell prompt)
Options:
–encode encoding mode (default mode is decoding)
–relax decode also predicate names (not only predicate indicators)
–printf FORMAT pass encoded/decoded string to C printf(3) with FORMAT
–aux-father decode an auxiliary predicate as its father
–aux-father2 decode an auxiliary predicate as its father + auxiliary number
–cmd-line encode/decode each argument of the command-line
-H same as: –cmd-line –encode
-P same as: –cmd-line –relax
–help print a help and exit
–version print version number and exit

It is possible to give a prefix of an option if there is no ambiguity.

Without arguments hexgplc runs in decoding mode reading its standard input and decoding each symbol corresponding to a predicate indicator. To use hexgplc in the encoding mode the –encode option must be specified. By default hexgplc only decodes predicate indicators, this can be relaxed using –relax to also take into account simple predicate names (the arity can be omitted). It is possible to format the output of an encoded/decoded string using –printf FORMAT in that case each string S is passed to the C printf(3) function as printf(FORMAT,S).

Auxiliary predicates are generated by the Prolog to WAM compiler when simplifying some control constructs like ';'/2 present in the body of a clause. They are of the form '$NAME/ARITY_$auxN' where NAME/ARITY is the predicate indicator of the simplified (i.e. father) predicate and N is a sequential number (a predicate can give rise to several auxiliary predicates). It is possible to force hexgplc to decode an auxiliary predicate as its father predicate indicator using –aux-father or as its father predicate indicator followed by the sequential number using –aux-father2.

If no file is specified, hexgplc processes its standard input otherwise each file is treated sequentially. Specifying the –cmd-line option informs hexgplc that each argument is not a file name but a string that must be encoded (or decoded). This is useful to encode/decode a particular string. For this reason the option -H (encode to hexadecimal) and -P (decode to Prolog) are provided as shorthand. Then, to obtain the hexadecimal representation of a predicate P use:
% hexgplc -H P
Example:
% hexgplc -H 'x+y=z'
X782B793D7A

4  Debugging

4.1  Introduction

The GNU Prolog debugger provides information concerning the control flow of the program. The debugger can be fully used on consulted predicates (i.e. byte-code). For native compiled code only the calls/exits are traced, no internal behavior is shown. Under the debugger it is possible to exhaustively trace the execution or to set spy-points to only debug a specific part of the program. Spy-points allow the user to indicate on which predicates the debugger has to stop to allow the user to interact with it. The debugger uses the “procedure box control flow model”, also called the Byrd Box model since it is due to Lawrence Byrd.

4.2  The procedure box model

The procedure box model of Prolog execution provides a simple way to show the control flow. This model is very popular and has been adopted in many Prolog systems (e.g. SICStus Prolog, Quintus Prolog,...). A good introduction is the chapter 8 of “Programming in Prolog” of Clocksin & Mellish [2]. The debugger executes a program step by step tracing an invocation to a predicate (call) and the return from this predicate due to either a success (exit) or a failure (fail). When a failure occurs the execution backtracks to the last predicate with an alternative clause. The predicate is then re-invoked (redo). Another source of change of the control flow is due to exceptions. When an exception is raised from a predicate (exception) by throw/1 (section 6.2.4) the control is given back to the most recent predicate that has defined a handler to recover this exception using catch/3 (section 6.2.4). The procedure box model shows these different changes in the control flow, as illustrated here:



Each arrow corresponds to a port. An arrow to the box indicates that the control is given to this predicate while an arrow from the box indicates that the control is given back from the procedure. This model visualizes the control flow through these five ports and the connections between the boxes associated with subgoals. Finally, it should be clear that a box is associated with one invocation of a given predicate. In particular, a recursive predicate will give raise to a box for each invocation of the predicate with different entries/exits in the control flow. Since this might get confusing for the user, the debugger associates with each box a unique identifier (i.e. the invocation number).

4.3  Debugging predicates

4.3.1  Running and stopping the debugger

trace/0 activates the debugger. The next invocation of a predicate will be traced.

debug/0 activates the debugger. The next invocation of a predicate on which a spy-point has been set will be traced.

It is important to understand that the information associated with the control flow is only available when the debugger is on. For efficiency reasons, when the debugger is off the information concerning the control flow (i.e. the boxes) is not retained. So, if the debugger is activated in the middle of a computation (by a call to debug/0 or trace/0 in the program or after the interrupt key sequence (Ctl-C) by choosing trace or debug), information prior to this point is not available.

debugging/0: prints onto the terminal information about the current debugging state (whether the debugger is switched on, what are the leashed ports, spy-points defined,...).

notrace/0 or nodebug/0 switches the debugger off.

wam_debug/0 invokes the sub-debugger devoted to the WAM data structures (section 4.6). It can be also invoked using the W debugger command (section 4.5).

4.3.2  Leashing ports