home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
pd3.lzh
/
SBPROLOG2.2
/
DOC
/
sbprolog_doc.me
next >
Wrap
Text File
|
1991-08-10
|
146KB
|
4,507 lines
.ds f. init
.nr _0 \n(c.
.\" Setup for thesis.
.\" This file should be modified to keep up with the standard
.\" for a doctoral thesis at Berkeley. Other macros which may
.\" be useful for a thesis are defined here.
.\" @(#)thesis.me 2.1 8/18/80
.
.\" This version is updated to reflect the ridiculous margin requirements of
.\" the graduate school at Stony Brook.
.\" It also has comments supplied by PKH to allow for easier upgrading in the
.\" future.
.
.
.if n .if \n(_o \
.po 1.00i \" nroff with page offset, reset to 1.5 inches
.if t .po 0.85i \" want 1.5 Canon and Troff loose .25
.ll 6.5i \" for precise 1.5 margins right and left
.if n .if 1n=0.1i \
. ll 8.8i \" for nroff and pica, line has even # of char
.lt 7.5i \" pageno close as possible to 1" off rt edge
.if n .ls 2 \" double space for nroff (was orig. for both)
.
.\" time to reset some "PARAMETRIC INITIALIZATIONS"
.
.ie t \
\{\
. \" for troff and Canon printer--fudges
.nr hm 5i/12 \" page number offset 5/12{8} inch top{8}
.nr tm 1.00i \" margins 1.00{1.5} inches top{1.5}
.nr bm 1.00i \" and 1.00{1.5} bottom{1.5}
.nr fm 5i/12 \" page number offset 5/12{8} inch bottom{8}
. \" nullify cut mark macro for canon
.rm @m
.\}
.el \
\{\
.nr hm 5i/12 \" page number offset 5/12{8} inch top{8}
.nr tm 1.00i \" margins 1.00{1.5} inches top{1.5}
.nr bm 1.00i \" and 1.00{1.5} bottom{1.5}
.nr fm 5i/12 \" page number offset 5/12{8} inch bottom{8}
.\}
.if t \
\{\
.nr pp 11 \" set pointsize
.nr sp 11 \" set header pointsize
.vs 16 \" line spacing 1-1/2 [12=single @ 10 points]
.nr $r \n(.v/\n(.s \" ratio of vert space to point size
.nr $R \n($r \" same, but for another use
.nr fp 10
.\}
.de IP
.ip \\$1 \\$2
..
.de LP
.lp
..
.de SH
.sp
.ti \\n(.iu
.if \\n(1T .sp
.ne 3.1
.ft B
..
.EQ
.nr 99 \n(.s
.nr 98 \n(.f
.ps 10
.ft 2
.ps 11
.ps \n(99
.ft \n(98
.EN
.de $0
\\*(st
.(x c
.if '\\$3'1' \
.if '\\$3'2' \ \ \
.if '\\$3'3' \ \ \ \ \ \
.if '\\$3'4'\ \ \ \ \ \ \ \ \
.if '\\$3'5'\ \ \ \ \ \ \ \ \ \ \ \
\\$2
.if !'\\$3'' :\
\\$1 \\fR
.)x \\n%
..
.de $1
.ds co " \\fB
.ds st \\fR
.br
..
.de $2
.ds co "
.ds st \\fR
.br
..
.de $3
.ds co " \\fB
.ds st \\fR
.br
..
.de $4
.ds co " \\fB
.ds st \\fR
.br
..
\" .de lf
\" Figure \\n($1.\\n+(fn\\$1
\" .ds \\$4 Figure \\n($1.\\n(fn
\" .ie '\\$3'p' \{\
\" .nr % +1 \}
\" .el \{\
\" .ie '\\$3'n' \{\\}
\" .el \{\
\" .(z
\" .sp \\$3
\" .ce 100
\" \\$2
\" Figure \\n($1.\\n(fn
\" .ce 0
\" .)z \} \}
\" .(x f
\" Figure \\n($1.\\n(fn
\" \\$2
\" .)x \\n%
\" ..
.ds f. sec0.t
.tp
.nr pp 11
.nr $r 10
.fo ''''
.EQ
.nr 99 \n(.s
.nr 98 \n(.f
.ps 11
.ft 2
.ps 11
.ps \n(99
.ft \n(98
.EN
.pp
\ \ \
\ \
.(l
\
\
.ce 20
\fBThe SB-Prolog System, Version 2.2
.sp
A User Manual\fR
edited by
\fISaumya K. Debray\fR
.sp
from material by
.sp
\fIDavid Scott Warren
Suzanne Dietrich\fR
SUNY at Stony Brook
.sp
\fIFernando Pereira\fR
SRI International
.sp 3
\fIMarch 1987\fR
.sp 2
Department of Computer Science
University of Arizona
Tucson, AZ 85721
.)l
.ce 0
.fo ''%'' \" page number on middle of bottom
.bp
.pp
\ \ \
\ \
.(l
\
\
\
\
.ce 20
\fBThe SB-Prolog System, Version 2.2
.sp
A User Manual\fR
.)l
.ce 0
.sp 3
.lp
\fBAbstract\fR: SB-Prolog is a public-domain Prolog system for Unix\(dg
based systems originally developed at SUNY, Stony Brook. The core of
the system is an emulator, written in C for portability, of a Prolog
virtual machine that is an extension of the Warren Abstract Machine.
The remainder of the system, including the translator from
Prolog to the virtual machine instructions, is written in Prolog.
Parts of this
manual, specifically the sections on Prolog syntax and descriptions of some
of the builtins, are based on the C-Prolog User Manual by Fernando Pereira.
.(f
\(dg Unix is a trademark of AT&T.
.)f
.fo ''%'' \" page number on middle of bottom
.bp
.ds f. sec1.t
.lp
.bp
.lp
.sh 1 "Introduction"
.pp
SB-Prolog is a public domain Prolog system based on an extension of the Warren
Abstract Machine\**.
.(f
\** D. H. D. Warren, ``An Abstract Prolog Instruction Set'',
Tech. Note 309, SRI International, 1983.
.)f
The WAM simulator is written in C to enhance
portability. Prolog source programs can be compiled into \fIbyte code\fR
files, which contain encodings of WAM instructions and are
interpreted by the simulator. Programs can also be interpreted via \fIconsult\fR.
.pp
SB-Prolog offers several features that are not found on most Prolog systems
currently available. These include: compilation to object files; dynamic
loading of predicates; provision for generating executable code on the
global stack, which can be later be reclaimed; an \fIextension table\fR
facility that permits memoization of relations. Other features include
full integration between compiled and interpreted code, and a facility for the
definition and expansion of macros that is fully compatible with the runtime system.
.pp
The following features are absent: we expect to
incorporate them in future versions.
.ip \(de
A ``listing'' feature, which produces a listing of clauses in the system
database.
.ip \(de
A garbage collector for the global stack.
.ip \(de
The \fIrecord\fR/\fIrecorded\fR/\fIerase\fR and
the \fIcurrent_\|atom\fR/\fIcurrent_\|functor\fR/\fIcurrent_\|predicate\fR
facilities of C-Prolog.
.pp
In addition, it should be mentioned that while interpreted and compiled code
behave similarly in almost all cases, there are a few cases that we are aware
of where they behave differently:
.np
In cuts buried within \fIif-then-else\fRs (\->): such cuts are treated as
``hard'' cuts in interpreted code (i.e. cuts away alternative clauses as well), but
as ``soft'' cuts in compiled code (i.e. cuts as far back as the head of the
clause, but does not cut away alternative clauses).
.np
In the evaluation of arithmetic expressions involving compound subexpressions created dynamically: in compiled code,
this cannot be handled using \fBis\fR/2, and must be handled using
\fBeval\fR/2 (see the section on Arithmetic predicates), while in interpreted code either
\fBis\fR/2 or \fBeval\fR/2 is acceptable.
.bp
.ds f. sec2.t
.sh 1 "Getting Started"
.pp
This section is intended to give a broad overview of the SB-Prolog system,
so as to enable the new user to begin using the system with a minimum of
delay. Many of the topics touched on here are covered in greater depth
in later sections.
.sh 2 "The Dynamic Loader Search Path"
.pp
In SB-Prolog, it is not necessary for the user to load all the
predicates necessary to execute a program. Instead, if an undefined predicate \fIfoo\fR is encountered during execution, the
system searches the user's directories in the order specified by
the environment variable SIMPATH until it finds a directory containing a file \fIfoo\fR
whose name is that of the undefined predicate. It then dynamically loads and
links the file \fIfoo\fR (which is expected to be a byte code file
defining the predicate \fIfoo\fR), and continues with execution; if no such file can be found, an error message is given and execution fails.
This feature makes it unnecessary for the user to have to explicitly
link in all the predicates that might be necessary in a
program: instead, only those files are loaded which are necessary to have the
program execute. This can significantly reduce the memory requirements of
programs.
.pp
The key to this dynamic search-and-load behaviour is the SIMPATH environment
variable, which specifies the order in which directories are to be searched.
It may be set by adding the following line to the user's .\fIcshrc\fR file:
.(l
setenv SIMPATH \fIpath\fR
.)l
where \fIpath\fR is a sequence of directory names separated by colons:
.(l
\fIdir\fR\*<1\*>:\fIdir\fR\*<2\*>: ... :\fIdir\*<n\*>\fR
.)l
and \fIdir\*<i\*>\fR are \fIfull path names\fR to the respective
directories.
For example, executing the command
.(l
setenv SIMPATH .:$HOME/prolog/modlib:$HOME/prolog/lib
.)l
sets the search order for undefined predicates to the following: first, the
directory in which the program is executing is searched; if the appropriate file is not found in this
directory, the directories searched are, in order, ~/prolog/modlib and
~/prolog/lib. If the appropriate file is not found in any
of these directories, the system gives an error message and execution fails.
.pp
The beginning user is advised to include the system directories (listed in
the next section) in his SIMPATH, in order to be able to access the system
libraries (see below).
.sh 2 "System Directories"
.pp
There are four basic system directories: cmplib, lib, modlib and sim.
\fIcmplib\fR contains the Prolog to byte code translator;
\fIlib\fR and \fImodlib\fR contain library routines. The \fIsrc\fR
subdirectory in each of these contains the corresponding Prolog source programs. The
directory \fIsim\fR contains the simulator, the subdirectory \fIbuiltin\fR
contains code for the builtin predicates of the system.
.pp
It is recommended that the beginning user include the system directories in
his SIMPATH, by setting SIMPATH to
.(l C
.\|:\|\fISBP\fR/modlib\|:\|\fISBP\fR/lib\|:\|\fISBP\fR/cmplib
.)l
where \fISBP\fR denotes the path to the root of the SB-Prolog system directories.
.sh 2 "Invoking the Simulator"
.pp
The simulator is invoked by the command
.(l
sbprolog\fIbc_\|\^file\fR
.)l
where \fIbc_\|\^file\fR is a byte code file resulting from the compilation of a
Prolog program. In almost all cases, the user will wish to interact with the
SB-Prolog \fIquery evaluator\fR, in which case \fIbc_\|file\fR will be
\fI$readloop\fR, and the command will be
.(l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 " sbprolog
.ps 11
.ft 2
.ds 12 "\s-5\b'\(sl\e'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 " path
.ps 11
.ft 2
.ds 12 "\s-5\b'\e\(sl'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "/\\\\$\$\readloop
.ps \n(99
.ft \n(98
\*(11
.)l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "where
.ps 11
.ft 2
.ds 12 "\s-5\b'\(sl\e'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "\fIpath\fR
.ps 11
.ft 2
.ds 12 "\s-5\b'\e\(sl'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 " is the path to the directory containing the
.ps \n(99
.ft \n(98
\*(11
command interpreter \fI$readloop\fR. This directory, typically, is \fImodlib\fR
(see Section 2.2 above).
.pp
The command interpreter reads in a query typed in by the user, evaluates it and
prints the answer(s), repeating this until it encounters an end-of-file
(the standard end-of-file character on the system, e.g. ctrl-D), or the user types
in \fIend_\|of_\|file\fR or \fIhalt\fR.
.pp
The user should ensure that the the directory containing the executable file \fIsim\fR
(typically, the system directory \fIsim\fR: see Section 2.2
above) is included in the shell variable \fIpath\fR; if not, the full path
to the simulator will have to be specified.
.pp
In general, the simulator may be invoked with a variety of options, as
follows:
.(l
sbprolog\-\fIoptions\fR \fIbc_\|\^file\fR
or
sbprolog \-\fIoption\fR\*<1\*> \-\fIoption\fR\*<2\*> ... \-\fIoption\*<n\*>\fR \fIbc_\|\^file\fR
.)l
The options recognized by the simulator are described in Section 4.2.
.pp
When called with a byte code file \fIbc_\|\^file\fR, the simulator begins
execution with the first clause in that file. The first clause in such a
file, therefore, should be a clause without any arguments in the head
(otherwise, the simulator will attempt to dereference argument pointers
in the head
that are really pointing into deep space, and usually come to a sad end).
If the user is executing a file in this manner rather than using the
command interpreter, he should also be careful to include the undefined
predicate handler `_\|\fI$undefined_\|pred\fR'/1, which is normally defined
in the file \fImodlib/$init_\|sys.P\fR.
.(x b
(L) _\|$undefined_\|pred/1
.)x
.sh 2 "Executing Programs"
.pp
There are two ways of executing a program: a source file may be compiled
into a byte-code file, which can then be loaded and executed; or, the source file may be
interpreted via \fIconsult\fR. The system supports full integration of compiled and
interpreted code, so that some predicates of a program may be compiled, while
others may be interpreted. However, the unit of compilation or consulting
remains the file. The remainder of this section describes each of these procedures in
more detail.
.sh 3 "Compiling Programs"
.pp
The compiler is invoked through the Prolog predicate \fIcompile\fR. It translates Prolog
source programs into byte code that can then be executed on the simulator.
.(x b
(L) compile/1
.)x
.(x b
(L) compile/2
.)x
.(x b
(L) compile/3
.)x
.(x b
(L) compile/4
.)x
The compiler may be invoked as follows:
.(l
| ?- compile(\fIInFile\fR [, \fIOutFile\fR ] [, \fIOptionsList\fR ]).
or
| ?- compile(\fIInFile\fR, \fIOutFile\fR, \fIOptionsList\fR, \fIPredList\fR).
.)l
where optional parameters are enclosed in brackets.
\fIInFile\fR is the name of the input (i.e. source) file; \fIOutFile\fR is the
name of the output file (i.e. byte code) file; \fIOptionsList\fR is a list of compiler options,
and \fIPredList\fR is a list of terms \fIP\fR/\fIN\fR denoting the
predicates defined in \fIInFile\fR, where \fIP\fR is a predicate name and \fIN\fR
its arity.
.pp
The input and output file names must be Prolog atoms, i.e. either
begin with a lower case letter and consist only of letters, digits,
dollar signs and underscores; or, be enclosed within single quotes.
If the output file name is not specified, it defaults to
\fIInFile\fB.out\fR. The list of options, if specified, is
a Prolog list, i.e. a term of the form
.(l
[ \fIoption\fR\*<1\*>, \fIoption\fR\*<2\*>, ..., \fIoption\*<n\*>\fR ].
.)l
If left unspecified, it defaults to the empty list [\^].
\fIPredList\fR, if specified, is usually given as an uninstantiated
variable; its principal use is for setting trace points on the predicates in the file (see Sections 6 and 8).
Notice that \fIPredList\fR can only appear in \fIcompile\fR/4.
.pp
A list of compiler options appears in Section 8.3.
.sh 3 "Loading Byte Code Files"
.lp
Byte code files may be loaded into the simulator using the
predicate \fIload\fR:
.(l
| ?- load(\fIByteCode_\|File\fR).
.)l
where \fIByteCode_\|File\fR is a Prolog atom (see Section 3.1) that is the name of a byte code
file.
.(x b
(B) load/1
.)x
.pp
The \fIload\fR predicate invokes the dynamic loader, which carries out a search according to
the sequence specified by the environment variable SIMPATH (see Section
2.1). It is therefore not necessary to always specify the full path name to the file to be
loaded.
.pp
Byte code files may be concatenated together to produce other byte code files. Thus,
for example, if \fIfoo1\fR and \fIfoo2\fR are byte code files resulting
from the compilation of two Prolog source programs, then the file \fIfoo\fR,
obtained by executing the shell command
.(l
cat foo1 foo2 > foo
.)l
is a byte code file as well, and may be loaded and executed. In this case,
loading and executing the file \fIfoo\fR would give the same result as
loading \fIfoo1\fR and \fIfoo2\fR separately, which in turn would be the same as
concatenating the original source files and compiling this larger file. This
makes it easier to compile large programs: one need only break them into smaller
pieces, compile the individual pieces, and concatenate the resulting byte code files together.
.sh 3 "Consulting Programs"
.pp
Instead of compiling a file to generate a byte code file which then has to be loaded,
a program may be executed interpretively by ``consulting'' the corresponding
source file:
.(x b
(L) consult/1
.)x
.(x b
(L) consult/2
.)x
.(l
| ?- consult(\fISourceFile\fR [, \fIOptionList\fR ] ).
or
| ?- consult(\fISourceFile\fR, \fIOptionList\fR, \fIPredList\fR).
.)l
where \fISourceFile\fR is a Prolog atom which is the name of a file
containing a Prolog source program; \fIOptionList\fR is a list of options
to consult; and \fIPredList\fR is a list of terms \fIP\fR/\fIN\fR, where \fIP\fR is a
predicate name and \fIN\fR its arity, specifying which predicates have been consulted
from \fISourceFile\fR; its principal use is for setting trace points
on the predicates in the file (see Section 6). Notice that \fIPredList\fR can only appear in \fIconsult\fR/3.
.pp
At this point, the options recognized for \fIconsult\fR are
the following:
.lp
\fBfirst\fR
.ip
If on, causes each clause read in to be added as the first clause of
the database (so that effectively, the clauses appear in the reverse
order as in the source file). Default: off.
.lp
\fBindex\fR
.ip
If on, causes an index to be generated on the first argument of each
predicate. Default: off.
.ip \fBindex(N)\fR
If on, causes an index to be generated on the N\*[th\*] argument of each
predicate. Default: off.
.ip \fBq\fR
``quick''. If on, invokes a consultation algorithm that is simpler and
more efficient than
the general one. However, the code generated with the simpler algorithm
may not be correct if there are repeated variables within compound terms
in the body of the clause, e.g. in
.(l
p(X) :\- q([X, X]).
.)l
Default: off.
.ip \fBt\fR
``trace''. Causes a trace point to be set on any predicate in the current
file that does not already have a trace point set.
.ip \fBv\fR
``verbose''. Causes information regarding which predicates have been
consulted to be printed out. Default: off.
.lp
In addition to the above, the options specified for the macro expander
are also recognized (see Section 10)).
.pp
It is important to note that SB-Prolog's \fIconsult\fR predicate is similar
to that of Quintus Prolog, and behaves like C-Prolog's \fIreconsult\fR.
This means that if a predicate is defined across two or more files,
consulting them will result in only the clauses in the file consulted last
being used.
.sh 2 "Execution Directives"
.pp
Execution directives may be specified to \fIcompile\fR and \fIconsult\fR through :\-/1. If, in the read
phase of \fIcompile\fR or \fIconsult\fR, a term with principal
functor :\-/1 is read in, this term is executed directly via \fIcall\fR/1.
This enables the user to dynamically modify the environment, e.g. via
\fIop\fR declarations (see Section 3.2), \fIassert\fRs etc.
.(x b
(P) :\-/1
.)x
.pp
A point to note is that if the environment is modified as a result of an execution
directive, the modifications are visible only in that environment. This
means that consulted code, which runs in the environment in which
the source program is read in (and which is modified by such execution directives) feel the effects of such
execution directives. However, byte code resulting from compilation, which,
in general, executes in an environment different from that in which the
source was compiled, does not inherit the effects of such directives. Thus,
an \fIop\fR declaration can be used in a source file to change the syntax and
allow the remainder of the program to be parsed according to the modified
syntax; however, these modifications will not, in general, manifest themselves
if the byte code is executed in another environment. Of course, if the byte code
is loaded into the same environment as that in which the source program was
compiled, e.g. through
.(l
| ?- compile(foo, bar), load(bar).
.)l
the effects of execution directives will continue to be felt.
.sh 1 "Syntax"
.pp
.sh 2 "Terms"
.pp
The syntax of SB-Prolog is by and large compatible with that of
C-Prolog.
The data objects of the language are called \fIterm\fPs.
A term is either a \fIconstant\fP, a \fIvariable\fP or a \fIcompound term\fP.
Constants can be \fIintegers\fR or \fIatoms\fR.
The symbol for an atom must begin with a lower case letter or the dollar
sign $, and consist of any number of letters, digits, underscores
and dollar signs; if it contains any character other than these, it must be
enclosed within single quotes.\**
.(f
\** Users are advised against using symbols beginning with `$' or `_\|$',
however, in order to minimize the possibility of conflicts with symbols
internal to the system.
.)f
As in other programming languages, constants are definite elementary objects.
.pp
Variables are distinguished by an initial capital letter or by
the initial character \*(lq\(ul\|\*(rq, for example
.(l
X Value A A1 \(ul\|3 \(ul\|RESULT \(ul\|result
.)l
If a variable is only referred to once, it does not need to be named
and may be written as an \fIanonymous\fP variable, indicated by the
underline character \*(lq\(ul\|\*(rq.
.pp
A variable should be thought of as standing for some definite but
unidentified object.
A variable is not simply a writeable
storage location as in most programming languages; rather it is a
local name for some data object, cf. the variable of pure LISP and
constant declarations in Pascal.
.pp
The structured data objects of the language are the compound terms. A
compound term comprises a \fIfunctor\fP (called the \fIprincipal\fP functor of
the term) and a sequence of one or more terms called \fIarguments\fP.
A functor is characterised by its \fIname\fP, which is an atom, and its
\fIarity\fP or number of arguments.
For example the compound term whose functor is
named `point' of arity 3, with arguments X, Y and Z, is written
.(l
point(X,Y,Z)
.)l
An atom is considered to be a functor of arity 0.
.pp
A functor or predicate symbol is uniquely identified by its name and arity
(in other words, it is possible for different symbols having different
arities to share the same name). A functor or predicate symbol \fIp\fR
with arity \fIn\fR is usually written \fIp\fR/\fIn\fR.
.pp
One may think of a functor as a record type and the
arguments of a compound term as the fields of a record. Compound
terms are usefully pictured as trees. For example, the term
.(l
s(np(john),vp(v(likes),np(mary)))
.)l
would be pictured as the structure
.(b C
s
/ \e
np vp
| / \e
john v np
| |
likes mary
.)b
.pp
Sometimes it is convenient to write certain functors as \fIoperators\fP
\*- 2-ary functors may be declared as \fIinfix\fP operators and 1-ary functors
as \fIprefix\fP or \fIpostfix\fP operators.
Thus it is possible to write
.(l
X+Y (P;Q) X<Y +X P;
.)l
as optional alternatives to
.(l
+(X,Y) ;(P,Q) <(X,Y) +(X) ;(P)
.)l
Operators are described fully in the next section.
.pp
\fIList\fPs form an important class of data structures in Prolog.
They are essentially the same as the lists of LISP:
a list either is the atom
[],
representing the empty list, or is a compound term with functor `.'/2
and two arguments which are respectively the head and tail of the
list. Thus a list of the first three natural numbers is the
structure
.(b C
.
/ \e
1 .
/ \e
2 .
/ \e
3 []
.)b
which could be written, using the standard syntax, as
.(l
\&.(1,.(2,.(3,[])))
.)l
but which is normally written, in a special list notation, as
[1,2,3].
The special list notation in the case when the tail of a list is a
variable is exemplified by
.(l
[X|L] [a,b|L]
.)l
representing
.(b C
. .
/ \e / \e
X L a .
/ \e
b L
.)b
respectively.
.pp
Note that this list syntax is only syntactic sugar for terms of the form
\&`.'(\(ul\|,\(ul\|) and does not provide any new facilities that were not
available otherwise.
.pp
For convenience, a further notational variant is allowed for
lists of integers which correspond to ASCII character codes. Lists
written in this notation are called \fIstring\fPs.
For example,
.(l
"Prolog"
.)l
represents exactly the same list as
.(l
[80,114,111,108,111,103]
.)l
.sh 2 "Operators"
.pp
Operators in Prolog are simply a notational convenience.
For example, the expression
.(l
2 + 1
.)l
could also be written +(2,1).
It should be noticed that this expression represents the structure
.(b C
+
/ \e
2 1
.)b
and not the number 3.
The addition would only be performed if the structure was passed as an
argument to an appropriate procedure (such as \fBeval\fP/2 \- see Section 5.2).
.pp
The Prolog syntax caters for operators of three main kinds \-
\fIinfix\fR, \fIprefix\fR and \fIpostfix\fR.
An infix operator appears between its two arguments, while a prefix operator
precedes its single argument and a postfix operator is written after its
single argument.
.pp
Each operator has a \fIprecedence\fP, which is a
number from 1 to 1200. The precedence is used to disambiguate
expressions where the structure of the term denoted is not made
explicit through parenthesization. The general rule
is that the operator with the
\fIhighest\fP precedence is the principal functor. Thus if `+' has a
higher precedence than `/', then ``a+b/c'' and ``a+(b/c)''
are equivalent and denote the term \*(lq+(a,/(b,c))\*(rq.
Note that the infix
form of the term \*(lq/(+(a,b),c)\*(rq must be written with explicit
parentheses, ``(a+b)/c''.
.pp
If there are two operators in the subexpression having the same
highest precedence, the ambiguity must be resolved from the \fItypes\fP of
the operators. The possible types for an infix operator are
.(l
xfx xfy yfx
.)l
With an operator of type `xfx', it is a requirement that both of the
two subexpressions which are the arguments of the operator must be of
\fIlower\fR precedence than the operator itself, i.e. their principal
functors must be of lower precedence, unless the subexpression is
explicitly bracketed (which gives it zero precedence). With an
operator of type `xfy', only the first or left-hand subexpression must
be of lower precedence; the second can be of the \fIsame\fP precedence as
the main operator; and vice versa for an operator of type `yfx'.
.pp
For example, if the operators `+' and `\-' both have type `yfx'
and are of the same precedence, then the expression
``a\-b+c'' is valid, and means ``(a\-b)+c'', i.e. ``+(\-(a,b),c)''.
Note that the expression would be invalid if the operators had type
\&`xfx', and would mean ``a\-(b+c)'', i.e. ``\-(a,+(b,c))'',
if the types were both `xfy'.
.pp
The possible types for a prefix operator are
.(l
fx fy
.)l
and for a postfix operator they are
.(l
xf yf
.)l
The meaning of the types should be clear by analogy with those for
infix operators. As an example, if `not' were declared as a prefix
operator of type `fy', then
.(l
not not P
.)l
would be a permissible way to write \*(lqnot(not(P))\*(rq. If the type were
\&`fx', the preceding expression would not be legal, although
.(l
not P
.)l
would still be a permissible form for \*(lqnot(P)\*(rq.
.pp
In SB-Prolog, a functor named \fIname\fP is declared as an
operator of type \fItype\fP and precedence \fIprecedence\fP by calling
the evaluable predicate \fBop\fP:
.(l
| ?- op(\fIprecedence\fP,\fItype\fP,\fIname\fP).
.)l
.(x b
(L) op/3
.)x
The argument \fIname\fP can also be a list of names of operators of the same
type and precedence.
.pp
It is possible to have more than one operator of the same name,
so long as they are of different kinds, i.e. infix, prefix or postfix.
An operator of any kind may be redefined by a new declaration of the
same kind. This applies equally to operators which are provided as
\fIstandard\fP in SB-Prolog, namely:
.(l
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if n .nr #~ 0.6n
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.fc
.nr 33 \n(.s
.rm 80 81 82 83
.nr 80 0
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w\&
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w:\- op(
.if \n(80<\n(38 .nr 80 \n(38
.80
.rm 80
.nr 81 0
.nr 38 \w1200,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w1200,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w1198,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w1100,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w1050,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w1000,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w900,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w700,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w\&
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w661,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w500,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w500,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w400,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w300,
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w200,
.if \n(81<\n(38 .nr 81 \n(38
.81
.rm 81
.nr 82 0
.nr 38 \wxfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfy,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfy,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfy,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wfy,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \w\&
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfy,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wyfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wyfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfx,
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wxfy,
.if \n(82<\n(38 .nr 82 \n(38
.82
.rm 82
.nr 83 0
.nr 38 \w[ :\-, --> ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ :\-, ?- ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ ::\- ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ ; ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ \-> ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ ',' ]). /* See note below */
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ not, \e+, spy, nospy ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 ".nr 38 \w[ =, is, =.., ==, \e==,
.ps 11
.ft 2
.ds 12 "<\f1,\fP
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ">,
.ps 11
.ft 2
.ds 12 "\(eq<\f1,\fP
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ">=,
.ps \n(99
.ft \n(98
\*(11
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w =:=, =\e=, <, >, =<, >= ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ `.' ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ +, \-, /\e, \e/ ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ +, \- ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ *, /, //, <<, >> ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ mod ]).
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w[ ^ ]).
.if \n(83<\n(38 .nr 83 \n(38
.83
.rm 83
.nr 38 1n
.nr 79 0
.nr 40 \n(79+(0*\n(38)
.nr 80 +\n(40
.nr 41 \n(80+(3*\n(38)
.nr 81 +\n(41
.nr 42 \n(81+(3*\n(38)
.nr 82 +\n(42
.nr 43 \n(82+(3*\n(38)
.nr 83 +\n(43
.nr TW \n(83
.if t .if (\n(TW+\n(.o)>7.65i .tm Table at line 549 file sec2.t is too wide - \n(TW units
.fc
.nr #T 0-1
.nr #a 0-1
.eo
.de T#
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.ls
..
.ec
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1200,\h'|\n(42u'xfx,\h'|\n(43u'[ :\-, --> ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1200,\h'|\n(42u'fx,\h'|\n(43u'[ :\-, ?- ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1198,\h'|\n(42u'xfx,\h'|\n(43u'[ ::\- ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1100,\h'|\n(42u'xfy,\h'|\n(43u'[ ; ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1050,\h'|\n(42u'xfy,\h'|\n(43u'[ \-> ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'1000,\h'|\n(42u'xfy,\h'|\n(43u'[ ',' ]). /* See note below */
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'900,\h'|\n(42u'fy,\h'|\n(43u'[ not, \e+, spy, nospy ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "\&\h'|\n(40u':\- op(\h'|\n(41u'700,\h'|\n(42u'xfx,\h'|\n(43u'[ =, is, =.., ==, \e==,
.ps 11
.ft 2
.ds 12 "<\f1,\fP
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ">,
.ps 11
.ft 2
.ds 12 "\(eq<\f1,\fP
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ">=,
.ps \n(99
.ft \n(98
\*(11
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'\&\h'|\n(41u'\&\h'|\n(42u'\&\h'|\n(43u' =:=, =\e=, <, >, =<, >= ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'661,\h'|\n(42u'xfy,\h'|\n(43u'[ `.' ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'500,\h'|\n(42u'yfx,\h'|\n(43u'[ +, \-, /\e, \e/ ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'500,\h'|\n(42u'fx,\h'|\n(43u'[ +, \- ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'400,\h'|\n(42u'yfx,\h'|\n(43u'[ *, /, //, <<, >> ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'300,\h'|\n(42u'xfx,\h'|\n(43u'[ mod ]).
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u':\- op(\h'|\n(41u'200,\h'|\n(42u'xfy,\h'|\n(43u'[ ^ ]).
.fc
.nr T. 1
.T# 1
.35
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-17
.)l
.pp
Operator declarations are most usefully placed in directives at the top
of your program files. In this case the directive should be a command as
shown above. Another common method of organisation is to have one file
just containing commands to declare all the necessary operators. This file
is then always consulted first.
.pp
Note that a comma written literally as a punctuation character
can be used as though it were an infix operator of precedence 1000 and
type `xfy':
.(l
X,Y ','(X,Y)
.)l
represent the same compound term. But note that a comma written as a
quoted atom is \fInot\fP a standard operator.
.pp
Note also that the arguments of a compound term written in
standard syntax must be expressions of precedence \fIbelow\fP 1000. Thus it
is necessary to parenthesize the expression \*(lqP :\- Q\*(rq in
.(l
assert((P :\- Q))
.)l
The following syntax restrictions serve to
remove potential ambiguity associated with prefix operators.
.ip -
In a term written in standard syntax, the principal functor and
its following \*(lq(\*(rq must \fInot\fP be separated by any whitespace. Thus
.(l
point (X,Y,Z)
.)l
is invalid syntax (unless \fIpoint\fR were declared as a prefix operator).
.ip -
If the argument of a prefix operator starts with a \*(lq(\*(rq, this \*(lq(\*(rq
must be separated from the operator by at least one space or other
non-printable character. Thus
.(l
:\-(p;q),r.
.)l
(where `:\-' is the prefix operator) is invalid syntax, and must be written as
.(l
:\- (p;q),r.
.)l
.ip -
If a prefix operator is written without an argument, as an
ordinary atom, the atom is treated as an expression of the same
precedence as the prefix operator, and must therefore be bracketed
where necessary. Thus the brackets are necessary in
.(l
X = (?-)
.)l
.sh 1 "SB-Prolog: Operational Semantics"
.sh 2 "Standard Execution Behaviour"
.pp
The normal execution behaviour of SB-Prolog follows the usual left to right
order of literals within a clause, and the textual top to bottom order of
clauses for a predicate. This corresponds to a depth first search of the
leftmost SLD-tree for the program and the given query. Unification without
occurs check is used, and execution backtracks to the most recent choice
point when unification fails.
.sh 2 "Cuts and If-Then-Else"
.pp
This standard execution behaviour of SB-Prolog can be changed using
constructs like \fIcut\fR (`!') and \fIif-then-else\fR (\^`\->'\^). In
SB-Prolog, cuts are usually treated as \fIhard\fR, i.e. discard choice points
of all the literals to the left of the cut in the clause containing the cut
being executed, and also the choice point for the parent predicate, i.e.
any remaining clauses for the predicate containing the cut being executed.
There are some situations, however, where the scope of a cut is restricted
to be smaller than this. Restrictions apply under the following conditions:
.np
The cut occurs in a term which has been constructed at runtime and called
through \fIcall\fR/1, e.g. in
.(l C
..., X = (p(Y), !, q(Y)), ..., call(X), ...
.)l
In this case, the scope of the cut is restricted to be within the \fIcall\fR,
unless one of the following cases also apply and serve to restrict its
scope further.
.np
The cut occurs in a negated goal, or within the scope of an if-then-else.
In these cases, the scope of the cut is restricted to be within the
negation or the if-then-else.
.lp
In cases involving nested occurrences of these situations, the scope of the
cut is restricted to that for the deepest such nested construct, i.e. most
restricted. For example, in the construct
.(l C
..., not( (p(X) \-> not( (q(X), (r(X) \-> s(X) ; (t(X), !, u(X)))) )) ), ...
.)l
the scope of the cut is restricted to the inner if-then-else, and does not
affect any choice point that may have been set up for q(X).
.pp
The behaviour of the \fIif-then-else\fR operator `\->' is as follows: when
executing the goal
.(l C
\fIP\fR \-> \fIQ\fR ; \fIR\fR
.)l
if \fIP\fR succeeds, then any alternatives for \fIP\fR are discarded and \fIQ\fR
is tried, while if \fIP\fR fails then \fIR\fR is tried. Thus, \-> may be
thought of as
.(l
\fIP\fR \-> \fIQ\fR ; \fIR\fR :\- \fIP\fR, !, \fIQ\fR.
\fIP\fR \-> \fIQ\fR ; \fIR\fR :\- \fIR\fR.
.)l
The scoping of cuts within if-then-elses is consistent with this
conceptualization.
.sh 2 "Unification of Floating Point Numbers"
.pp
As far as unification is concerned, no type distinction is made between
integers and floating point numbers, and no explicit type conversion is necessary
when unifying an integer with a float. However, due to the finite precision
representation of floating point numbers and cumulative round-off errors in
floating point arithmetic, comparisons involving floating point numbers may
not always give the expected results. An effort is made to minimize surprises
by considering two numbers \fIx\fR and \fIy\fR (at least one of which is a float)
to be unifiable if |\^|\^\fIx\fR\^| \- |\^\fIy\fR\^|\^|/\fImin\fR(|\^\fIx\fR\^|, |\^\fIy\fR\^|)
to be less than 10\*[\-5\*]. However, this does not guarantee
immunity against round-off errors. For the same reason, users are warned
that indexing on predicate arguments (see Section 13) may not give the
expected results if floating point numbers are involved.
.sh 1 "Evaluable Predicates"
.pp
This section describes (most of) the evaluable predicates provided by
SB-Prolog. These can be divided into three classes: \fIinline\fR
predicates, \fIbuiltin\fR predicates and \fIlibrary\fR predicates.
.pp
Inline predicates represent ``primitive'' operations in the WAM.
Calls to inline predicates are compiled into a sequence of WAM
instructions in-line, i.e. without actually making a call to the predicate. Thus, for
example, relational predicates (>/2, >=/2, etc.) compile to, essentially, a
subtraction and a conditional branch. Inline predicates cannot be redefined by the
user. Table 1 lists the SB-Prolog inline predicates.
.(z
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if n .nr #~ 0.6n
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.fc
.nr 33 \n(.s
.rm 80 81 82 83
.nr 80 0
.nr 38 \w=/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w>/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w>>/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w\\/1
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w`_\|$call'/1
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \whalt/0
.if \n(80<\n(38 .nr 80 \n(38
.80
.rm 80
.nr 81 0
.nr 38 \w</2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w/\e/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w=:=/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w`_\|\|$savecp'/1
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \wnonvar/1
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \wtrue/0
.if \n(81<\n(38 .nr 81 \n(38
.81
.rm 81
.nr 82 0
.nr 38 \w=</2
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \w`\e/'/2
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \w=\e=/2
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \w`_\|\|$cutto'/1
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wvar/1
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \w
.if \n(82<\n(38 .nr 82 \n(38
.82
.rm 82
.nr 83 0
.nr 38 \w>=/2
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w<</2
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \wis/2
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \w`_\|\|$builtin'/1
.if \n(83<\n(38 .nr 83 \n(38
.nr 38 \wfail/0
.if \n(83<\n(38 .nr 83 \n(38
.83
.rm 83
.nr 38 0+\n(80+\n(81+\n(82+\n(83
.nr 38 \n(.l-\n(.i-\n(38
.nr 38 \n(38/9
.if \n(38<1n .nr 38 1n
.nr 79 0
.nr 40 \n(79+(0*\n(38)
.nr 80 +\n(40
.nr 41 \n(80+(3*\n(38)
.nr 81 +\n(41
.nr 42 \n(81+(3*\n(38)
.nr 82 +\n(42
.nr 43 \n(82+(3*\n(38)
.nr 83 +\n(43
.nr TW \n(83
.if t .if (\n(TW+\n(.o)>7.65i .tm Table at line 695 file sec2.t is too wide - \n(TW units
.nr #I \n(.i
.in +(\n(.lu-\n(TWu-\n(.iu)/2u
.fc
.nr #T 0-1
.nr #a 0-1
.eo
.de T#
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.ls
..
.ec
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'=/2\h'|\n(41u'</2\h'|\n(42u'=</2\h'|\n(43u'>=/2
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'>/2\h'|\n(41u'/\e/2\h'|\n(42u'`\e/'/2\h'|\n(43u'<</2
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'>>/2\h'|\n(41u'=:=/2\h'|\n(42u'=\e=/2\h'|\n(43u'is/2
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'\\/1\h'|\n(41u'`_\|\|$savecp'/1\h'|\n(42u'`_\|\|$cutto'/1\h'|\n(43u'`_\|\|$builtin'/1
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'`_\|$call'/1\h'|\n(41u'nonvar/1\h'|\n(42u'var/1\h'|\n(43u'fail/0
.ta \n(80u \n(81u \n(82u \n(83u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'halt/0\h'|\n(41u'true/0\h'|\n(42u' \h'|\n(43u'
.fc
.nr T. 1
.T# 1
.in \n(#Iu
.35
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-9
.sp
.ce
Table 1: Inline Predicates of SB-Prolog
.sp 2
.)z
.pp
Unlike inline predicates, builtin predicates are implemented by C
functions in the simulator, and accessed via the inline predicate
`\fI_\|\|$builtin\fR'/1.
Thus, if a builtin predicate \fIfoo\fR/3 was defined
as builtin number 38, there would be a definition in the system
of the form
.(l
foo(X,Y,Z) :\- '_\|\|$builtin'(38).
.)l
.pp
In effect, a builtin is simply a segment of code in a large case
(i.e. \fIswitch\fR) statement. Each builtin is identified internally by an
integer, referred to as its ``builtin number'', associated with it. The code for a builtin with
builtin number \fIk\fR corresponds to the \fIk\*[th.\*]\fR case in the switch
statement.
SB-Prolog limits the total number of builtins to 256.
.pp
Builtins, unlike inline predicates, can be redefined by the user. For example, the
predicate \fIfoo\fR/3 above can be redefined simply by compiling the new definition into a
directory such that during dynamic loading, the new definition would be
encountered first and loaded.
.pp
A list of the builtins currently provided is listed in Appendix 1.
Section 7.4 describes the procedure to be followed in order to define new
builtin predicates.
.pp
Like builtin predicates, library predicates may also be redefined by the
user. The essential difference between builtin and library predicates is
that whereas the former are coded into the simulator in C, the latter are
written in Prolog.
.sh 2 "Input and Output"
.pp
Input and output are done with respect to the current input and output
streams. These can be set, reset or checked using the file handling
predicates described below. The default input and output streams are
denoted by \fBuser\fR, and refer to the user's terminal.
.sh 3 "File Handling"
.ip \fBsee\fR(\fIF\fR\|)
\fIF\fR becomes the current input stream. \fIF\fR must be instantiated to
an atom at the time of the call.
.(x b
(B) see/1
.)x
.ip \fBseeing\fR(\fIF\fR\|)
\fIF\fR is unified with the name of the current input file.
.ip \fBseen\fR
Closes the current input stream.
.(x b
(B) seen
.)x
.ip \fBtell\fR(\fIF\fR\^)
\fIF\fR becomes the current output stream. \fIF\fR must be instantiated to
an atom at the time of the call.
.(x b
(B) tell/1
.)x
.ip \fBtelling\fR(\fIF\fR\^)
\fIF\fR is unified with the name of the current output file.
.(x b
(B) telling/1
.)x
.lp
\fBtold\fR
.ip
Closes the current output stream.
.(x b
(B) told/0
.)x
.ip \fB$exists\fR(\fIF\fR\^)
Succeeds if file \fIF\fR exists.
.(x b
(B) $exists/1
.)x
.sh 3 "Term I/O"
.ip \fBread\fR(\fIX\fR\^)
The
next term, delimited by a full stop (i.e. a \*(lq.\*(rq followed by a carriage-return
or a space), is read from the current input stream and
unified with \fIX\fP. The syntax of the term must accord with current
operator declarations. If a call \fBread\fP(\fIX\fP) causes the end of the
current input stream to be reached, \fIX\fP is unified with the atom
\&`end\(ul\|of\(ul\|file'. Further calls to \fBread\fP for the same stream will then
cause an error failure.
.(x b
(L) read/1
.)x
.ip \fBwrite\fP(\fIX\fP)
The
term \fIX\fP is written to the current output stream according to
operator declarations in force.
.(x b
(L) write/1
.)x
.ip \fBdisplay\fP(\fIX\fP)
.(x b
(L) display/1
.)x
The
term \fIX\fP is displayed on the terminal in standard parenthesised
prefix notation.
.ip \fBwriteq\fP(\fITerm\fP)
Similar
to \fBwrite\fP(\fITerm\fP), but the names of atoms and functors
are quoted where necessary to make the result acceptable as input to \fBread\fP.
.(x b
(L) writeq/1
.)x
.ip \fBprint\fP(\fITerm\fP)
Prints out the term \fITerm\fR onto the user's terminal.
.(x b
(L) print/1
.)x
.ip \fBwritename\fR(\fITerm\fR\^)
.(x b
(B) writename/1
.)x
If \fITerm\fR is an uninstantiated variable, its name, which
looks a lot like an address in memory, is written out; otherwise, the
principal functor of \fITerm\fR is written out.
.ip \fBwriteqname\fR(\fITerm\fR)
.(x b
(B) writeqname/1
.)x
As for \fBwritename\fR, but the names are quoted where necessary.
.sh 3 "Character I/O"
.ip \fBnl\fP
A new line is started on the current output stream.
.(x b
(B) nl/0
.)x
.ip \fBget0\fP(\fIN\fP)
\fIN\fP
is the ASCII code of the next character from the current input
stream. If the current input stream reaches its end of file,
a \-1 is returned (however, unlike in C-Prolog, the input stream is not closed on encountering
end-of-file).
.(x b
(B) get0/1
.)x
.ip \fBget\fP(\fIN\fP)
\fIN\fP is the ASCII code of the next non-blank printable character
from the current input stream. It has the same behaviour as \fBget0\fP
on end of file.
.(x b
(B) get/1
.)x
.ip \fBput\fP(\fIN\fP)
ASCII character code \fIN\fP is output to the current output stream.
\fIN\fP must be an integer.
.(x b
(B) put/1
.)x
.ip \fBtab\fP(\fIN\fP)
\fIN\fP
spaces are output to the current output stream. \fIN\fP
must be an integer.
.(x b
(B) tab/1
.)x
.sh 2 "Arithmetic"
.pp
Arithmetic is performed by evaluable predicates which take as
arguments \fIarithmetic expressions\fP and \fIevaluate\fP them.
An arithmetic expression is a term built from \fIevaluable functors\fP,
numbers and variables.
At the time of evaluation, each variable in an arithmetic
expression must be bound to a number or
to an arithmetic expression.
Each evaluable functor stands for an arithmetic operation.
.pp
The
evaluable functors are as follows, where \fIX\fP and \fIY\fP are
arithmetic expressions.
.ip \fIX\fP\ +\ \fIY\fP
addition.
.ip \fIX\fP\ \-\ \fIY\fP
subtraction.
.ip \fIX\fP\ *\ \fIY\fP
multiplication.
.ip \fIX\fP\ /\ \fIY\fP
division.\** Amounts to integer division if both \fIX\fR and \fIY\fR are
integers.
.(f
\** The ``integer division'' operator `//' of C-Prolog is not supported;
it can be faked using \fIfloor\fR/2 if necessary.
.)f
.ip \fIX\fP\ mod\ \fIY\fP
\fIX\fP (integer) modulo \fIY\fP.
.ip \-\fIX\fP
unary minus.
.ip \fIX\fP\ /\e\ \fIY\fP
integer bitwise conjunction.
.ip \fIX\fP\ \e/\ \fIY\fP
integer bitwise disjunction.
.ip \fIX\fP\ <<\ \fIY\fP
integer bitwise left shift of \fIX\fP by \fIY\fP places.
.ip \fIX\fP\ >>\ \fIY\fP
integer bitwise right shift of \fIX\fP by \fIY\fP places.
.ip \e\fIX\fP
integer bitwise negation.
.pp
As far as unification is concerned, no type distinction is made between
integers and floating point numbers, and no explicit type conversion is necessary
when unifying an integer with a float. However, due to the finite precision
representation of floating point numbers and cumulative round-off errors in
floating point arithmetic, comparisons involving floating point numbers may
not always give the expected results. An effort is made to minimize surprises
by considering two numbers \fIx\fR and \fIy\fR (at least one of which is a float)
to be unifiable if |\fIx\fR \- \fIy\fR|/\fImin\fR(|\fIx\fR|, |\fIy\fR|)
to be less than 10\*[\-5\*]. The user should note, however, that this does
not guarantee immunity against round-off errors.
.pp
The arithmetic evaluable predicates are as follows, where \fIX\fP and
\fIY\fP stand for arithmetic expressions, and \fIZ\fP for some term.
Note that this means that \fBis\fP only evaluates one of its arguments
as an arithmetic expression (the right-hand side one),
whereas all the comparison
predicates evaluate both their arguments.
.lp
\fIZ\fP \fBis\fP \fIX\fP
.(x b
(I) is/2
.)x
.ip
Arithmetic
expression \fIX\fP is evaluated and the result,
is unified with
\fIZ\fP. Fails if \fIX\fP is not an arithmetic expression. One point to note is
that in compiled code, the current implementation of \fBis\fR/2 cannot
handle compound expressions created dynamically: these have to be handled using \fBeval\fR/2. Thus, for example, the goals
.(l C
..., X = Y + Z, Y = 3, Z = 2, W is X, ...
.)l
would fail, whereas
.(l C
..., X = Y + Z, Y = 3, Z = 2, eval(X,W), ...
.)l
could succeed.
.ip \fBeval\fR(\fIE\fR,\ \fIX\fR\^)
.(x b
(L) eval/2
.)x
Evaluates the arithmetic expression \fIE\fR and unifies the result with the term
\fIX\fR. Fails if \fIE\fR is not an arithmetic expression. The principal difference between \fBeval\fR/2 and \fBis\fR/2 is that in compiled code,
\fBis\fR/2 cannot handle arithmetic expressions that are compound
terms constructed at runtime, but \fBeval\fR/2 can. On the other hand,
\fBis\fR/2 is more efficient for the evaluation of static arithmetic expressions (i.
e. expressions that do not have compound subterms created at runtime).
Another difference is that while \fBis\fR/2 is an inline predicate,
\fBeval\fR/2 is not; thus, \fBis\fR/2 cannot be redefined by the user,
but \fBeval\fR/2 can.
.lp
\fIX\fP \fB=:=\fP \fIY\fP
.(x b
(I) =:=/2
.)x
.ip
The values of \fIX\fP and \fIY\fP are equal. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fIX\fP \fB=\\=\fP \fIY\fP
.ip
.(x b
(I) =\e=/2
.)x
The values of \fIX\fP and \fIY\fP are not equal. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fIX\fP\fB < \fP\fIY\fP
.(x b
(I) </2
.)x
.ip
The
value of \fIX\fP is less than the value of \fIY\fP. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fIX\fP\fB > \fP\fIY\fP
.(x b
(I) >/2
.)x
.ip
The
value of \fIX\fP is greater than the value of \fIY\fP. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fIX\fP\fB =<\fP \fIY\fP
.(x b
(I) =</2
.)x
.ip
The
value of \fIX\fP is less than or equal to the value of \fIY\fP. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fIX\fP\fB >=\fP \fIY\fP
.(x b
(I) >=/2
.)x
.ip
The
value of \fIX\fP is greater than or equal to the value of \fIY\fP. If either \fIX\fR or \fIY\fR
involve compound subexpressions that are created at runtime, they should first be evaluated
using \fBeval\fR/2.
.lp
\fBfloor\fR(\fIX\fR, \fIY\fR\^)
.(x b
(B) floor/2
.)x
.ip
If \fIX\fR is a floating point number in the call and \fIY\fR is free,
then \fIY\fR is instantiated to the largest integer whose absolute value
is not greater than the absolute value of \fIX\fR; if \fIX\fR is
uninstantiated in the call and \fIY\fR is an integer, then \fIX\fR is instantiated to
the smallest float not less than \fIY\fR.
.lp
\fBfloatc\fR(\fIF\fR, \fIM\fR, \fIE\fR\^)
.(x b
(B) floatc/3
.)x
.ip
If \fIF\fR is a number while \fIM\fR and \fIE\fR are uninstantiated in the call, then
\fIM\fR is instantiated to a float \fIm\fR (of magnitude less than 1), and \fIE\fR to an
integer \fIn\fR, such that
.(l C
\fIF\fR = \fIm\fR * 2\*[\fIn\fR\*].
.)l
If \fIF\fR is uninstantiated in the call while \fIM\fR is a float and \fIE\fR
an integer, then \fIF\fR becomes instantiated to \fIM\fR * 2\*[\fIE\fR\*].
.lp
\fBexp\fR(\fIX\fR, \fIY\fR\^)
.(x b
(B) exp/2
.)x
.ip
If \fIX\fR is instantiated to a number and \fIY\fR is uninstantiated in the call, then \fIY\fR
is instantiated to \fIe\*[X\*]\fR (where \fIe\fR = 2.71828...); if \fIX\fR
is uninstantiated in the call while \fIY\fR is instantiated to a positive
number, then \fIX\fR is instantiated to \fIlog\*<e\*>\fR(\fIY\fR\^).
.lp
\fBsquare\fR(\fIX\fR, \fIY\fR\^)
.(x b
(B) square/2
.)x
.ip
If \fIX\fR is instantiated to a number while \fIY\fR is uninstantiated in
the call, then \fIY\fR becomes instantiated to \fIX\fR\^\*[2\*]; if \fIX\fR
is uninstantiated in the call while \fIY\fR is instantiated to a positive number, then
\fIX\fR becomes instantiated to the positive square root of \fIY\fR (if \fIY\fR
is negative in the call, \fIX\fR becomes instantiated to 0.0).
.lp
\fBsin\fR(\fIX\fR, \fIY\fR\^)
.(x b
(B) sin/2
.)x
.ip
If \fIX\fR is instantiated to a number (representing an angle in radians)
and \fIY\fR is uninstantiated in the call, then \fIY\fR becomes
instantiated to \fIsin\fR(\fIX\fR\^) (the user should check the magnitude
of \fIX\fR to make sure that the result is meaningful). If \fIY\fR is
instantiated to a number between \-\(*p/2 and \(*p/2 and \fIX\fR is
uninstantiated in the call, then \fIX\fR becomes instantiated to
\fIsin\fR\*[\-1\*](\fIY\fR\^).
.lp
.sh 2 "Convenience"
.ip \fIP\fP\ \fB,\fP\ \fIQ\fP
\fIP\fP and then \fIQ\fP.
.(x b
(I) `,'/2
.)x
.ip \fIP\fP\ \fB;\fP\ \fIQ\fP
\fIP\fP or \fIQ\fP.
.(x b
(I) `;'/2
.)x
.lp \fBtrue\fP
.ip
Always succeeds.
.(x b
(I) true/0
.)x
.ip \fIX\fP\ \fB=\fP\ \fIY\fP
Defined as if by the clause \*(lq Z=Z \*(rq, i.e. \fIX\fP and \fIY\fP are unified.
.(x b
(I) =/2
.)x
.sh 2 "Extra Control"
.ip \fB!\fP
Cut (discard) all choice points made since
the parent goal started execution. (The scope of cut in different contexts is discussed in Section 4.2).
.(x b
(P) !/0
.)x
.ip \fBnot\fP\ \fIP\fP
If
the goal \fIP\fP has a solution, fail, otherwise succeed. It is
defined as if by
.(l
not(P) :\- P, !, fail.
not(\(ul\|\|).
.)l
.(x b
(P) not/1
.)x
.ip \fIP\fP\ \fB\->\fP\ \fIQ\fP\ \fB;\fP\ \fIR\fP
Analogous to
\*(lqif \fIP\fP then \fIQ\fP else \fIR\fP\*(rq
i.e. defined as if by
.(l
P \-> Q ; R :\- P, !, Q.
P \-> Q ; R :\- R.
.)l
.ip \fIP\fP\ \fB\->\fP\ \fIQ\fP
When
occurring other than as one of the alternatives of a
disjunction, is equivalent to
.(l
\fIP\fP \-> \fIQ\fP ; fail.
.)l
.(x b
(P) \->/2
.)x
.ip \fBrepeat\fP
Generates an infinite sequence of backtracking choices. It
is defined by the clauses:
.(l
repeat.
repeat :\- repeat.
.)l
.(x b
(L) repeat/0
.)x
.ip \fBfail\fP
Always fails.
.(x b
(I) fail/0
.)x
.sh 2 "Meta-Logical"
.ip \fBvar\fP(\fIX\fP\^)
Tests whether \fIX\fP is currently instantiated to a variable.
.(x b
(I) var/1
.)x
.ip \fBnonvar\fP(\fIX\fP\^)
Tests whether \fIX\fP is currently instantiated to a non-variable term.
.(x b
(I) nonvar/1
.)x
.ip \fBatom\fP(\fIX\fP\^)
.(x b
(B) atom/1
.)x
Checks
that \fIX\fP is currently instantiated to an atom (i.e. a
non-variable term of arity 0, other than a number).
.ip \fBinteger\fP(\fIX\fP\^)
Checks that \fIX\fP is currently instantiated to an integer.
.(x b
(B) integer/1
.)x
.lp
\fBreal\fR(\fIX\fR\^)
.(x b
(B) real/1
.)x
.ip
Checks that \fIX\fP is currently instantiated to a floating point number..
.)x
.ip \fBnumber\fP(\fIX\fP\^)
Checks that \fIX\fP is currently instantiated to a number, i.e. that it is
either an integer or a real.
.(x b
(B) number/1
.)x
.ip \fBatomic\fP(\fIX\fP\^)
Checks that \fIX\fP is currently instantiated to an atom or number.
.(x b
(B) atomic/1
.)x
.lp
\fBstructure\fR(\fIX\fR\^)
.(x b
(B) structure/1
.)x
.ip
Checks that \fIX\fP is currently instantiated to a compound term, i.e. to a
nonvariable term that is not atomic.
.ip \fBfunctor\fP(\fIT\fP,\fIF\fP,\fIN\fP\^)
The
principal functor of term \fIT\fP has name \fIF\fP and arity
\fIN\fP, where \fIF\fP
is either an atom or, provided \fIN\fP is 0, a number.
Initially,
either \fIT\fP must be instantiated to a non-variable, or \fIF\fP and
\fIN\fP must
be instantiated to, respectively, either an atom and a
non-negative integer or an integer and 0. If these conditions are
not satisfied, an error message is given. In the case where \fIT\fP is
initially instantiated to a variable, the result of the call is
to instantiate \fIT\fP to the most general term having the principal
functor indicated.
.(x b
(L) functor/3
.)x
.ip \fBarg\fP(\fII\fP,\fIT\fP,\fIX\fP\^)
Initially, \fII\fP must be instantiated to a positive integer and
\fIT\fP to
a compound term. The result of the call is to unify \fIX\fP with the
\fII\fPth argument of term \fIT\fP. (The arguments are numbered
from 1
upwards.) If the initial conditions are not satisfied or \fII\fP is out
of range, the call merely fails.
.(x b
(B) arg/3
.)x
.ip \fIX\fP\ \fB=..\fP\ \fIY\fP
\fIY\fP is a list whose head is the atom corresponding to the principal
functor of \fIX\fP and whose tail is the argument list of that functor
in \fIX\fP. E.g.
.(x b
(L) =../2
.)x
.(l
product(0,N,N\-1) =.. [product,0,N,N\-1]
N\-1 =.. [\-,N,1]
product =.. [product]
.)l
If \fIX\fP is instantiated to a variable, then \fIY\fP must be instantiated
either to a list of determinate length whose head is an atom, or to a list of
length 1 whose head is a number.
.ip \fBname\fP(\fIX\fP,\fIL\fP)
If \fIX\fP is an atom or a number then \fIL\fP is a list of the
ASCII codes of the characters comprising the name of \fIX\fP. E.g.
.(x b
(B) name/2
.)x
.(l
name(product,[112,114,111,100,117,99,116])
.)l
i.e. name(product,"product").
.lp
If \fIX\fP is instantiated to a variable, \fIL\fP must be instantiated
to a list of ASCII character codes. E.g.
.(l
| ?- name(X,[104,101,108,108,111])).
X = hello
| ?- name(X,"hello").
X = hello
.)l
.ip \fBcall\fP(\fIX\fP\^)
If \fIX\fR is a nonvariable term in the program text, then it is executed exactly as if \fIX\fR appeared in the program
text instead of \fIcall\fR(\fIX\fR\^), e.g.
.(x b
(P) call/1
.)x
.(l
..., p(a), call( (q(X), r(Y)) ), s(X), ...
.)l
is equivalent to
.(l
..., p(a), q(X), r(Y), s(X), ...
.)l
However, if X is a variable in the program text, then if at runtime
\fIX\fP is instantiated to a term which would be acceptable as the body
of a clause, the goal \fBcall\fP(\fIX\fP) is executed as if that
term appeared textually in place of the \fBcall\fP(\fIX\fP), \fIexcept that\fR
any cut (`!') occurring in \fIX\fP will remove only those choice points
in \fIX\fP.
If \fIX\fP is not instantiated as
described above, an error message is printed and \fBcall\fP fails.
.ip \fIX\fP
(where
\fIX\fP is a variable) Exactly the same as \fBcall\fP(\fIX\fP). However, we prefer the
explicit usage of \fIcall\fR/1 as good programming practice, and the use of a
top level variable subgoal elicits a warning from the compiler.
.lp
\fBconlength\fR(\fIC\fR,\fIL\fR\^)
.ip
Succeeds if the length of the print name of the constant
\fIC\fR (which can be an atom, buffer or integer), in bytes, is \fIL\fR.
.(x b
(B) conlength/2
.)x
If \fIC\fR is a buffer (see Section 5.8), it
is the length of the buffer; if \fIC\fR is an integer, it is the
length of the decimal representation of that integer, i.e., the
number of bytes that a $\fIwritename\fR will use.
.sh 2 "Sets"
.pp
When there are many solutions to a problem, and when all those solutions are
required to be collected together, this can be achieved by repeatedly
backtracking and gradually building up a list of the solutions. The following
evaluable predicates are provided to automate this process.
.ip \fBsetof\fP(\fIX\fP,\fIP\fP,\fIS\fP)
Read this as \*(lq\fIS\fP is the set of all instances of \fIX\fP such that
\fIP\fP is
provable''. If \fIP\fR is not provable, \fBsetof\fP(\fIX\fP,\fIP\fP,\fIS\fP)
succeeds with \fIS\fR instantiated to the empty list [\^].
.(x b
(L) setof/3
.)x
The term \fIP\fP specifies a
goal or goals as in \fBcall\fP(\fIP\fP).
\fIS\fP is a set of terms represented as a
list of those terms, without duplicates, in the standard order for
terms (see Section 5.7).
If there are uninstantiated variables in \fIP\fP which do not also appear
in \fIX\fP, then a call to this evaluable predicate may backtrack,
generating alternative values for \fIS\fP corresponding to different
instantiations of the free variables of \fIP\fP. Variables occurring in \fIP\fP will not be treated as free if they are
explicitly bound within \fIP\fP by an existential quantifier. An
existential quantification is written:
.(l
\fIY\fP^\fIQ\fP
.)l
meaning \*(lqthere exists a \fIY\fP such that \fIQ\fP is true\*(rq,
where \fIY\fP is some Prolog term (usually, a variable, or tuple or list of
variables).
.ip \fBbagof\fP(\fIX\fP,\fIP\fP,\fIBag\fP)
This is the same as \fBsetof\fP except that the list (or
alternative lists) returned will not be ordered, and may contain
duplicates. If \fIP\fR is unsatisfiable, \fIbagof\fR succeeds binding
\fIBag\fR to the empty list.
.(x b
(L) bagof/3
.)x
The effect of this relaxation is to save considerable
time and space in execution.
.ip \fBfindall\fR(\fIX\fR,\fIP\fR,\fIL\fR)
Similar to \fIbagof\fR/3, except that variables in \fIP\fR that do not occur in \fIX\fR are
treated as local, and alternative lists are not returned for different bindings of such
variables. The list \fIL\fR is, in general, unordered, and may contain duplicates. If \fIP\fR
is unsatisfiable, \fIfindall\fR succeeds binding \fIS\fR to the empty list.
.lp
\fIX\fP\fB^\fP\fIP\fP
.ip
The system recognises this as meaning \*(lqthere exists an \fIX\fP such
that \fIP\fP is true\*(rq, and treats it as equivalent to \fBcall\fP(\fIP\fP).
The use of this explicit existential
quantifier outside the \fBsetof\fP and \fBbagof\fP
constructs is superfluous.
.sh 2 "Comparison of Terms"
.pp
These evaluable predicates are meta-logical. They treat uninstantiated
variables as objects with values which may be compared, and they never
instantiate those variables. They should \fInot\fP be used when what you really want
is arithmetic comparison (Section 5.2) or unification.
.pp
The predicates make reference to a standard total ordering of terms, which is
as follows:
.ip \(de
variables, in a standard order (roughly, oldest first \- the order is
\fInot\fP related to the names of variables);
.ip \(de
numbers, from \-\*(lqinfinity\*(rq to +\*(lqinfinity\*(rq;
.ip \(de
atoms, in alphabetical (i.e. ASCII) order;
.ip \(de
complex terms, ordered first by arity, then by the name of principal
functor, then by the arguments (in left-to-right order).
.pp
For example, here is a list of terms in the standard order:
.(l
[ X, \-9, 1, fie, foe, fum, X = Y, fie(0,2), fie(1,1) ]
.)l
These are the basic predicates for comparison of arbitrary terms:
.lp
\fIX\fP \fB==\fP \fIY\fP
.ip
Tests if the terms currently instantiating \fIX\fP and \fIY\fP
are literally
identical (in particular, variables in equivalent positions in the
two terms must be identical).
.(x b
(B) ==/2
.)x
For example, the question
.(l
| ?- X == Y.
.)l
fails (answers \*(lqno\*(rq) because \fIX\fP and \fIY\fP
are distinct uninstantiated
variables. However, the question
.(l
| ?- X = Y, X == Y.
.)l
succeeds because the first goal unifies the two variables (see page 42).
.lp
\fIX\fP \fB\e==\fP \fIY\fP
.ip
Tests if the terms currently instantiating \fIX\fP and \fIY\fP are
not literally identical.
.(x b
(B) \e==/2
.)x
.EQ
.nr 99 \n(.s
.nr 98 \n(.f
.ps 11
.ft 2
.ps \n(99
.ft \n(98
.EN
.lp
\fIT1\fP \fB@<\fP \fIT2\fP
.ip
Term \fIT1\fP is before term \fIT2\fP in the standard order.
.(x b
(B) @</2
.)x
.lp
\fIT1\fP \fB@>\fP \fIT2\fP
.ip
Term \fIT1\fP is after term \fIT2\fP in the standard order.
.(x b
(B) @>/2
.)x
.lp
\fIT1\fP \fB@=<\fP \fIT2\fP
.ip
Term \fIT1\fP is not after term \fIT2\fP in the standard order.
.(x b
(B) @=</2
.)x
.lp
\fIT1\fP \fB@>=\fP \fIT2\fP
.ip
Term \fIT1\fP is not before term \fIT2\fP in the standard order.
.(x b
(B) @>=/2
.)x
.sp
.lp
Some further predicates involving comparison of terms are:
.lp
\fBcompare\fP(\fIOp\fP,\fIT1\fP,\fIT2\fP)
.ip
The result of comparing terms \fIT1\fP and \fIT2\fP is \fIOp\fP,
where the possible
values for \fIOp\fP are:
.(l
\&`=' if \fIT1\fP is identical to \fIT2\fP,
\&`<' if \fIT1\fP is before \fIT2\fP in the standard order,
\&`>' if \fIT1\fP is after \fIT2\fP in the standard order.
.)l
Thus \fBcompare\fP(=,\fIT1\fP,\fIT2\fP) is equivalent to
\fIT1\fP \fB==\fP \fIT2\fP.
.(x b
(B) compare/3
.)x
.lp
\fBsort\fP(\fIL1\fP,\fIL2\fP)
.ip
The elements of the list \fIL1\fP are sorted into the standard order, and
any identical (i.e. `==') elements are merged, yielding the list
\fIL2\fP.
.(x b
(L) sort/2
.)x
.EQ
.nr 99 \n(.s
.nr 98 \n(.f
.ps 11
.ft 2
.ps \n(99
.ft \n(98
.EN
.sh 2 "Buffers"
.pp
SB-Prolog supports the concept of buffers. A buffer is actually a
constant and the characters that make up the buffer is the name of
the constant. However, the
symbol table entry for a buffer is not hashed and thus is not added to
the obj-list, so two different buffers will never unify.
Buffers can be allocated either in permanent space or
on the heap. Buffers in permanent space stay there forever; buffers
on the heap are deallocated when the ``allocate buffer'' goal is
backtracked over.
.pp
A buffer allocated on the heap can either be a simple buffer, or it
can be allocated as a subbuffer of another buffer already on the
heap. A subbuffer will be deallocated when its superbuffer is
deallocated.
.pp
There are occasions when it is not known, in advance, exactly how much
space will be required and so how big a buffer should be allocated.
Sometimes this problem can be overcome by allocating a large buffer
and then, after using as much as is needed, returning the rest of the
buffer to the system. This can be done, but only under \fIvery\fR limited
circumstances: a buffer is allocated from the end of the permanent space,
the top of the heap, or from the next available space in the superbuffer;
if no more space has been used beyond the end of the buffer, a tail
portion of the buffer can be returned to the system. This operation
is called ``trimming'' the buffer.
.pp
The following is a list of library predicates for buffer management
(predicates whose names begin with `$' are low-level routines intended only
for serious hackers willing to put up with little or no protection):
.sp
.ip \fBalloc_\|perm\fR(\fISize\fR,\ \fIBuff\fR)
Allocates a buffer with a length \fISize\fR in the permanent (i.e. program) area. \fISize\fR must be bound to
a number. On successful return, \fIBuff\fR will be bound to the allocated buffer.
.(x b
(L) alloc_\|perm/2
.)x
The buffer, being in the permanent area, is never de-allocated.
.ip \fBalloc_\|heap\fR(\fISize\fR,\ \fIBuff\fR)
Allocates a buffer of size \fISize\fR on the heap and binds \fIBuff\fR to
it. Since it is on the heap, it will be deallocated on backtracking.
.(x b
(L) alloc_\|heap/2
.)x
.lp
\fB$alloc_\|buff\fR(\fISize\fR,\fIBuff\fR,\fIType\fR,\fISupbuff\fR,\fIRetcode\fR)
.ip
Allocates a buffer. \fISize\fR is the length (in bytes) of the buffer to
allocate;
.(x b
(L) $alloc_\|heap/5
.)x
\fIBuff\fR is the buffer allocated, and should be unbound at
the time of the call; \fIType\fR indicates where to allocate the
buffer: a value of 0 indicates that the buffer is to be allocated
in permanent space, 1 that it should be on the heap, and 2 indicates
that it should be allocated from a larger heap buffer; \fISupbuff\fR is
the larger buffer to allocate a subbuffer out of, and is only looked at
if the value of \fIType\fR is 2; \fIRetcode\fR is the return code: a
value of 0 indicates that the buffer has been allocated, while a value
of 1 indicates that the buffer could not be allocated due to lack of
space. The arguments \fISize\fR, \fIType\fR, and \fISupbuff\fR (if
\fIType\fR = 2) are input arguments, and should be bound at the time
of the call; \fIBuff\fR and \fIRetcode\fR are output
arguments, and should be unbound at the time of the call.
.ip \fBtrimbuff\fR(\fIType\fR,\ \fIBuff\fR,\ \fINewlen\fR)
This allows (in some very restricted circumstances) the changing of
the size of a buffer. \fIType\fR is 0 if the buffer is permanent, 1 if the buffer
is on the heap. \fIBuff\fR is the buffer.
.(x b
(L) trimbuff/3
.)x
\fINewlen\fR is an integer: the size (which
should be smaller than the original length of the buffer) to make
the buffer. If the buffer is at the top of the heap (if heap buffer) or the
end of the program area (if permanent) then the heap-top (or program area top)
will be readjusted down. The length of the buffer will be modified to
\fINewlen\fR. This is (obviously) a very low-level
primitive and is for hackers only to implement grungy stuff.
.lp
\fB$trim_\|buff\fR(\fISize\fR,\fIBuff\fR,\fIType\fR,\fISupbuff\fR\^)
.ip
Trims the buffer \fIBuff\fR (possibly contained in superbuffer
\fISupbuff\fR) of type \fIType\fR to \fISize\fR bytes.
.(x b
(L) $trim_\|buff/4
.)x
The value of
\fIType\fR indicates where the buffer is located: a value of 0 denotes a buffer in permanent
space, a value of 1 a buffer on the heap, and a value of 2 a buffer within
another buffer (the superbuffer).
All the arguments are input arguments,
and should be instantiated at the time of call (with the possible exception
of \fISupbuff\fR, which is looked at only if \fIType\fR is 2).
The internal length of the buffer \fIBuff\fR is changed to
\fISize\fR.
.lp
\fBconlength\fR(\fIConstant\fR,\fILength\fR\^)
.ip
Succeeds if the length of the print name of the constant
\fIConstant\fR (which can be an atom, buffer
or integer), in bytes, is \fILength\fR.
If \fIConstant\fR is a buffer, it
is the length of the buffer; if \fIConstant\fR is an integer, it is the
length of the decimal representation of that integer, i.e., the
number of bytes that a $\fIwritename\fR will use.
.sh 2 "Modification of the Program"
.pp
The predicates defined in this section allow modification of the program
as it is actually running.
Clauses can be added to the program (\fIasserted\fP) or removed from the program
(\fIretracted\fP).
At the lowest level, the system supports the asserting of clauses with upto
one literal in the body. It
does this by allocating a buffer and compiling code for the clause into
that buffer. Such a buffer is called a ``clause reference'' (\fIclref\fR\|).
The clref is then added to a chain of clrefs. The chain of clrefs
has a header, which is a small buffer called a ``predicate reference''
(\fIprref\fR\|), which contains pointers to the beginning and end of its
chain of clrefs. Clause references are quite similar to ``database references'' of C-Prolog, and can be called.
.pp
A prref is normally associated with a predicate symbol and contains
the clauses that have been asserted for that symbol. However, prrefs
can be constructed and clrefs added to them, and such clauses can be
called, all without associating that prref with any particular predicate
symbol. A predicate symbol that has an associated
prref is called a ``dynamic'' predicate (other predicate types are
``compiled'' and ``undefined'').
.pp
There are options as to where clrefs are allocated and how they are
linked to a chain of clrefs associated with a prref. A clref can
either be allocated in permanent space (the normal arrangement) or as
a sub-buffer of a superbuffer on the heap. When adding a clref to a
prref chain, it can be be added at the beginning of the chain or at
the end of the chain. In addition, one of the argument positions can
be used to index, so that subsequent retrievals will try to index on
that position.
.sp
.lp
\fBassert\fP(\fIC\fP)
.(x b
(L) assert/1
.)x
.ip
The
current instance of \fIC\fP is interpreted as a clause and is added
to the program (with new private variables
replacing any uninstantiated variables), at the end of the list of
clauses for that predicate.
\fIC\fP must be instantiated to a non-variable.
.lp
\fBassert\fR(\fIC\fR, \fIOpts\fR)
.(x b
(L) assert/2
.)x
.ip
As for \fIassert\fR/1, with \fIOpts\fR a list of options. The options
currently recognized are:
.lp
\fBfirst\fR
.ip
If on, causes the asserted clause to be added as the first clause of
the database. Default: off.
.lp
\fBindex\fR
.ip
If on, causes an index to be generated on the first argument of the
clause. Default: off.
.lp
\fBindex(N)\fR
.ip
If on, causes an index to be generated on the N\*[th\*] argument of the
clause. Default: off.
.lp
\fBq\fR
.ip
``quick''. If on, invokes an assertion algorithm that is simpler and
more efficient than
the general one. However, the code generated with the simpler algorithm
may not be correct if there are repeated variables within compound terms
in the body of the clause, e.g. in
.(l
p(X) :\- q([X, X]).
.)l
Default: off.
.lp
\fBasserti\fR(\fIC\fR,\fIN\fR\^)
.(x b
(L) asserti/2
.)x
.ip
The current instance of \fIC\fR, interpreted as a clause, is asserted to
the program with an index on its \fIN\^\*[th\*]\fR argument. If \fIN\fR is
zero, no index is created.
.lp
\fBasserta\fR(\fIC\fR\^)
.(x b
(L) asserta/1
.)x
.ip
Similar to \fBassert\fR(\fIC\fR\^), except that the new clause becomes the
\fIfirst\fR clause of the procedure concerned.
.lp
\fBasserta\fR(\fIC\fR, \fIRef\fR\^)
.(x b
(L) asserta/2
.)x
.ip
Similar to \fBasserta\fR(\fIC\fR\^), but also unifies \fIRef\fR with the
clause reference of the clause asserted.
.lp
\fBassertz\fR(\fIC\fR\^)
.(x b
(L) assertz/1
.)x
.ip
Similar to \fBassert\fR(\fIC\fR\^), except that the new clause becomes the
\fIlast\fR clause of the procedure concerned.
.lp
\fBassertz\fR(\fIC\fR, \fIRef\fR\^)
.(x b
(L) assertz/2
.)x
.ip
Similar to \fBassertz\fR(\fIC\fR\^), but also unifies \fIRef\fR with the
clause reference of the clause asserted.
.lp
\fBassert_\|union\fR(\fIP\fR, \fIQ\fR)
.ip
The clauses for \fIQ\fR are added to the clauses for \fIP\fR.
.(x b
(L) assert_\|union/2
.)x
For example, the call
.(l
| ?- assert_\|union(p(X,Y),q(X,Y)).
.)l
has the effect of adding the rule
.(l
p(X,Y) :\- q(X,Y).
.)l
as the last rule defining \fIp\fR/2. If \fIP\fR is not defined, it results
in the call to \fIQ\fR being the only clause for \fIP\fR.
The variables in the arguments to
\fIassert_\^union\fR/2 are not significant, e.g. the above would have been
equivalent to
.(l
| ?- assert_\|union(p(Y,X),q(X,Y)).
or
| ?- assert_\|union(p(_\|,_\|),q(_\|,_\|)).
.)l
However, the arities of the two predicates involved must match, e.g.
even though the goal
.(l
| ?- assert_\|union(p(X,Y), r(X,Y,Z)).
.)l
will succeed, the predicate \fIp\fR/2 will not in any way depend on the
clauses for \fIr\fR/3.
.lp
\fBassert\fR(\fIClause\fR,\fIAZ\fR,\fIIndex\fR,\fIClref\fR\^)
.ip
Asserts a clause to a predicate. \fIClause\fR is the clause to assert.
.(x b
(L) assert/4
.)x
\fIAZ\fR is 0 for insertion as the first clause, 1 for insertion as the last clause.
\fIIndex\fR is the number of the argument on which to index (0 for
no indexing). \fIClref\fR is returned as the clause reference of
the fact newly asserted. If the main functor symbol of \fIClause\fR has
been declared (by \fI$assertf_\|alloc_\|t\fR/2, see below) to have its
clauses on the heap, the clref will be allocated there. If the predicate
symbol of \fIClause\fR is undefined, it will be initialized and \fIClause\fR
added. If the predicate symbol has compiled clauses, it is first
converted to be dynamic (see \fIsymtype\fR/2, Section 5.10) by adding a special clref that calls the
compiled clauses. \fIFact\fR, \fIAZ\fR and \fIIndex\fR are input arguments,
and should be instantiated at the time of call; \fIClref\fR is an output
argument, and should be uninstantiated at the time of call.
.lp
\fBretract\fP(\fIHead\fP\^)
.ip
The first clause in the program whose head matches \fIHead\fP is erased.
This predicate may be used in a non-deterministic fashion, i.e. it will
successively backtrack to retract clauses whose heads match \fIHead\fR.
.(x b
(L) retract/1
.)x
\fIHead\fP must be initially instantiated to a non-variable.
.lp
\fBabolish\fP(\fIP\fP)
.ip
Completely
remove all clauses for the procedure with head \fIP\fP (which should be
a term).
.(x b
(L) abolish/1
.)x
For example, the goal
.(l
| ?- abolish( p(_\|, _\|, _\|) ).
.)l
removes all clauses for the predicate \fIp\fR/3.
.lp
\fBabolish\fR(\fIP\fR, \fIN\fR\^)
.ip
Completely remove all clauses for the predicate \fIP\fR (which should be an
atom) with arity \fIN\fR (which should be an integer).
.(x b
(L) abolish/2
.)x
.lp
\fBcall_\^ref\fR(\fICall\fR, \fIRef\fR)
.(x b
(L) call_\|ref/2
.)x
.ip
Calls the predicate whose database reference (prref) is \fIRef\fR, using the
literal \fICall\fR as the call. This is similar to
\fBcall_\|ref\fR(\fICall\fR, \fIRef\fR, 0).
.lp
\fBcall_\^ref\fR(\fICall\fR, \fIRef\fR, \fITr\fR\^)
.(x b
(L) call_\|ref/3
.)x
.ip
Calls the predicate whose database reference (prref) is \fIRef\fR, using the
literal \fICall\fR as the call. \fITr\fR must be either 0 or 1: if \fITr\fR
is 0 then the call \fICall\fR is made assuming the ``trust'' optimization
will be made; if \fITr\fR is 1 then the ``trust'' optimization is not used,
so that any new fact added
before final failure will be seen by \fICall\fR. (Also, this currently
does not take advantage of any indexing that might have been constructed,
while \fI$db_\|call_\|prref\fR does.) \fICall\fR, \fIRef\fR and \fITr\fR
are all input arguments, and should be instantiated at the time of call.
.sp
.lp
The basic library predicates that support the manipulation of
prrefs and clrefs are as follows:
.lp
\fB$db_\|new_\|prref\fR(\fIPrref\fR,\fIWhere\fR,\fISupbuff\fR\^)
.ip
Creates an empty Prref, i.e. one with no facts in it.
.(x b
(L) $db_\|new_\|prref/3
.)x
If called, it will simply fail. \fIWhere\fR
indicates where the prref should be allocated: a value of
0 indicates the permanent area, while a value of 2 indicates that
it is to be allocated as a subbuffer. \fISupbuff\fR is the superbuffer
from which to allocate \fIPrref\fR if \fIWhere\fR is 2. \fIWhere\fR
should be instantiated at the time of call, while \fIPrref\fR should be
uninstantiated; in addition, if \fIWhere\fR is 2, \fISupbuff\fR
should be instantiated at the time of call.
.lp
\fB$db_\|assert_\|fact\fR(\fIFact\fR,\fIPrref\fR,\fIAZ\fR,\fIIndex\fR,\fIClref\fR,\fIWhere\fR,\fISupbuff\fR)
.ip
\fIFact\fR is a fact to be asserted; \fIPrref\fR is a predicate
reference to which to add the asserted fact;
.(x b
(L) $db_\|assert_\|fact/5
.)x
\fIAZ\fR is either 0,
indicating the fact should be inserted as the first clause in \fIPrref\fR,
or 1, indicating it should be inserted as the last; \fIIndex\fR is 0
if no index is to be built, or \fIn\fR if an index on the \fIn\fR\*[th\*]
argument of the fact is to be used. (Asserting at the beginning of the
chain with indexing is not yet supported.) \fIWhere\fR indicates where
the clref is to be allocated: a value of 0 indicates that it should be
in the permanent area, while a value of 2 indicates that it should be
allocated
as a subbuffer of \fISupbuff\fR. \fIClref\fR is returned and
it is the clause reference of the asserted fact. \fIFact\fR, \fIPrref\fR, \fIAZ\fR,
\fIIndex\fR and \fIWhere\fR are input arguments, and should be instantiated at the
time of call; in addition, if \fIWhere\fR is 2, then \fISupbuff\fR should also
be instantiated. \fIClref\fR is an output argument, and should be uninstantiated at the
time of call.
.lp
\fB$db_\|add_\|clref\fR(\fIFact\fR,\fIPrref\fR,\fIAZ\fR,\fIIndex\fR,\fIClref\fR,\fIWhere\fR,\fISupbuff\fR\^)
.ip
Adds the clref \fIClref\fR to the prref \fIPrref\fR.
.(x b
(L) $db_\|add_\|clref/7
.)x
\fIFact\fR is the fact that has been compiled into \fIClref\fR
(used only to get the arity and for indexing). The other parameters
are as for \fI$db_\|assert_\|fact\fR/7.
.lp
\fB$db_\|call_\|prref\fR(\fICall\fR,\fIPrref\fR)
.ip
Calls the prref \fIPrref\fR using the literal \fICall\fR as the call.
.(x b
(L) $db_\|call_\|prref/2
.)x
The call is done by simply branching to the first
clause. New facts added to \fIPrref\fR after the last fact has been retrieved
by \fICall\fR, but before \fICall\fR is failed through, will \fInot\fR
be used. Both \fICall\fR and \fIPrref\fR are
input arguments, and should be instantiated at the time of call.
.lp
\fB$db_\|call_\|prref_\|s\fR(\fICall\fR,\fIPrref\fR)
.ip
This also calls the prref \fIPrref\fR using \fICall\fR as the call.
.(x b
(L) $db_\|call_\|prref_\|s/2
.)x
The difference from \fI$db_\|call_\|prref\fR is that this does not use
the ``trust'' optimization, so that any new fact added
before final failure will be seen by \fICall\fR. (Also, this currently
does not take advantage of any indexing that might have been constructed,
while \fI$db_\|call_\|prref\fR does.) Both \fICall\fR and \fIPrref\fR are
input arguments, and should be instantiated at the time of call.
.lp
\fB$db_\|get_\|clauses\fR(\fIPrref\fR,\fIClref\fR,\fIDir\fR)
.ip
This returns, nondeterministically, all the clause references \fIClref\fR
for clauses asserted to prref \fIPrref\fR.
.(x b
(L) $db_\|get_\|clauses/3
.)x
If \fIDir\fR is 0, then the
first clref on the list is returned first; if \fIDir\fR is 1, then they
are returned in reverse order. \fIPrref\fR and \fIDir\fR are input
arguments, and should be instantiated at the time of call; \fIClref\fR
is an output argument, and should be uninstantiated at the time of call.
.lp
\fB$db_\|kill_\|clause\fR(\fIClref\fR\^)
.ip
This predicate retracts the fact referenced by clref \fIClref\fR.
.(x b
(L) $db_\|kill_\|clause/1
.)x
It does this by simply making the first instruction of the clause
a \fIfail\fR instruction. This means that this clause will fail
whenever it is called in the future, no matter how it is accessed.
\fIClref\fR should be instantiated at the time of call.
.sh 2 "Environmental"
.lp
\fBop\fR(\fIpriority\fR, \fItype\fR, \fIname\fR\^)
.ip
Treat \fIname\fR as an operator of the stated \fItype\fR and \fIpriority\fR (see
Section 3.2). \fIname\fR may also be a list of names, in which all are to
be treated as operators of the stated \fItype\fR and \fIpriority\fR.
.lp
\fBbreak\fR
.(x b
(L) break/0
.)x
.ip
Causes the current execution to be suspended at the next procedure call.
Then the message ``[ Break (level 1) ]'' is displayed. The interpreter is
then ready to accept input as though it was at the top level (except that
at break level \fIn\fR > 0, the prompt is ``\fIn\fR: ?- ''). If another
call of \fBbreak\fR is encountered, it moves up to level 2, and so on. To
close the break and resume the execution which was suspended, type the
\s-2END-OF-INPUT\s+2 character. Execution will be resumed at the procedure
call where it had been suspended. Alternatively, the suspended execution
can be aborted by calling the evaluable predicate \fBabort\fR, which
causes a return to the top level.
.lp
\fBabort\fR
.(x b
(B) abort/0
.)x
.ip
Aborts the current execution, taking you back to top level.
.lp
\fBsave\fR(\fIF\fR\^)
.(x b
(B) save/1
.)x
.ip
The system saves the current state of the system into file \fIF\fR.
.lp
\fBrestore\fR(\fIF\fR\^)
.(x b
(B) restore/1
.)x
.ip
The system restores the saved state in file \fIF\fR to be the current state.
One restriction imposed by the current system is that various system parameters
(e.g. stack sizes, permanent space, heap space, etc.) of the saved state
have to be the same as that of the current invocation. Thus, it is not
possible to save a state from an invocation where 50000 words of permanent
space had been allocated, and then restore the same state in an invocation
with 100000 words of permanent space.
.lp
\fBcputime\fR(\fIX\fR)
.ip
Unifies \fIX\fR with the time elapsed, in milliseconds, since
the system was started up.
.(x b
(B) cputime/1
.)x
.lp
\fB$getenv\fR(\fIVar\fR,\fIVal\fR\^)
.ip
\fIVal\fR is unified with the value of the Unix environment variable \fIVar\fR.
.(x b
(L) $getenv/2
.)x
.lp
\fBstatistics\fR
.ip
Prints out the current allocations and amounts of space used for each of
the four main areas: the permanent area, the local stack, the global stack
and the trail stack.
.(x b
(B) statistics/0
.)x
Does not work well unless the simulator has been called
with the -\fBs\fR option (see Section 7.2).
.lp
\fBsymtype\fR(\fIT\fR,\fIN\fR\^)
.ip
Unifies \fIN\fR with the ``internal type'' of the principal functor of the term \fIT\fR,
which must be instantiated at the time of the call.
.(x b
(B) symtype/2
.)x
\fIN\fR is bound to 0 if
\fIT\fR does not have an entry point defined (i.e. cannot be executed);
to 1 if the principal functor of \fIT\fR is ``dynamic'', i.e. has asserted code; to 2
if the principal functor for \fIT\fR is a compiled predicate; and
3 if \fIT\fR denotes a buffer. Thus, for example, if the predicate \fIp\fR/2
is a compiled predicate which has been loaded into the system, the goal
.(l
| ?- symtype(p(_\|,_\|), X).
.)l
will succeed binding X to 2; on the other hand, the goal
.(l
| ?- assert(q(a,b,c)), symtype(q(_\|,_\|,_\|), X).
.)l
will succeed binding X to 1.
.lp
\fBsystem\fR(\fICall\fR)
.ip
Calls the operating system with the atom \fICall\fR as argument.
.(x b
(B) system/1
.)x
For example, the call
.(l
| ?- system('ls').
.)l
will produce a directory listing. Since \fIsystem\fR/1 is executed by
forking off a shell process, it cannot be used, for example, to change the working
directory of the simulator.
.lp
\fBsyscall\fR(\fIN\fR,\fIArgs\fR,\fIRes\fR)
.ip
Executes the Unix system call number \fIN\fR with
arguments \fIArgs\fR, and returns the result in \fIRes\fR.
.(x b
(B) syscall/3
.)x
\fIN\fR is an integer, and \fIArgs\fR a Prolog
list of the arguments to the system call. For example, to execute the system call
``\fIcreat\fR(\fIFile\fR,\fIMode\fR)'', knowing that the syscall number for
the Unix command \fIcreat\fR(2) is 8, we execute the goal
.(l
| ?- syscall(8, [\fIFile\fR, \fIMode\fR], \fIDes\fR).
.)l
where \fIDes\fR is the file descriptor returned by \fIcreat\fR. The syscall numbers
for some Unix system calls are given in Table 2.
.(z
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if n .nr #~ 0.6n
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.fc
.nr 33 \n(.s
.rm 80 81 82 83
.nr 80 0
.nr 38 \wexit
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wread
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wopen
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wcreat
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wunlink
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wchmod
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \waccess
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wwait
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wconnect
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wsend
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wbind
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wlisten
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wsendmsg
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wrecvfrom
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wsocketpair
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wrmdir
.if \n(80<\n(38 .nr 80 \n(38
.80
.rm 80
.nr 81 0
.nr 31 0
.nr 32 0
.nr 38 \w1
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w3
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w5
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w8
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w10
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w15
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w33
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w84
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w98
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w101
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w104
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w106
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w114
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w125
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w135
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w137
.if \n(31<\n(38 .nr 31 \n(38
.81
.rm 81
.nr 61 \n(31
.nr 38 \n(61+\n(32
.if \n(38>\n(81 .nr 81 \n(38
.if \n(38<\n(81 .nr 61 +(\n(81-\n(38)/2
.nr 82 0
.nr 38 \wfork
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wwrite
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wclose
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wlink
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wchdir
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wlseek
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wkill
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wsocket
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \waccept
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wrecv
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wsetsockopt
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wrecvmsg
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wgetsockopt
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wsendto
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wmkdir
.if \n(82<\n(38 .nr 82 \n(38
.nr 38 \wgetsockname
.if \n(82<\n(38 .nr 82 \n(38
.82
.rm 82
.nr 83 0
.nr 31 0
.nr 32 0
.nr 38 \w2
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w4
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w6
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w9
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w12
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w19
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w37
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w97
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w99
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w102
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w105
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w113
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w118
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w133
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w136
.if \n(31<\n(38 .nr 31 \n(38
.nr 38 \w150
.if \n(31<\n(38 .nr 31 \n(38
.83
.rm 83
.nr 63 \n(31
.nr 38 \n(63+\n(32
.if \n(38>\n(83 .nr 83 \n(38
.if \n(38<\n(83 .nr 63 +(\n(83-\n(38)/2
.nr 38 0
.if \n(80>\n(38 .nr 38 \n(80
.if \n(82>\n(38 .nr 38 \n(82
.nr 80 \n(38
.nr 82 \n(38
.nr 38 0+\n(80+\n(81+\n(82+\n(83
.nr 38 \n(.l-\n(.i-\n(38
.nr 38 \n(38/11
.if \n(38<1n .nr 38 1n
.nr 79 0
.nr 40 \n(79+(1*\n(38)
.nr 80 +\n(40
.nr 41 \n(80+(3*\n(38)
.nr 81 +\n(41
.nr 61 +\n(41
.nr 42 \n(81+(3*\n(38)
.nr 82 +\n(42
.nr 43 \n(82+(3*\n(38)
.nr 83 +\n(43
.nr 63 +\n(43
.nr TW \n(83
.nr TW +1*\n(38
.if t .if (\n(TW+\n(.o)>7.65i .tm Table at line 1969 file sec2.t is too wide - \n(TW units
.ne 16v+0p
.nr #I \n(.i
.in +(\n(.lu-\n(TWu-\n(.iu)/2u
.fc
.nr #T 0-1
.nr #a 0-1
.nr #a 0-1
.eo
.de T#
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.if \n(#T>=0 .nr #a \n(#T
.if \n(T. .vs \n(.vu-\n(.sp
.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.if \n(T. .vs
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'(|\n(42u+|\n(81u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'
.ls
..
.ec
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.mk #a
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'exit\h'|\n(41u'1\h'|\n(42u'fork\h'|\n(43u'2
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'read\h'|\n(41u'3\h'|\n(42u'write\h'|\n(43u'4
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'open\h'|\n(41u'5\h'|\n(42u'close\h'|\n(43u'6
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'creat\h'|\n(41u'8\h'|\n(42u'link\h'|\n(43u'9
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'unlink\h'|\n(41u'10\h'|\n(42u'chdir\h'|\n(43u'12
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'chmod\h'|\n(41u'15\h'|\n(42u'lseek\h'|\n(43u'19
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'access\h'|\n(41u'33\h'|\n(42u'kill\h'|\n(43u'37
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'wait\h'|\n(41u'84\h'|\n(42u'socket\h'|\n(43u'97
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'connect\h'|\n(41u'98\h'|\n(42u'accept\h'|\n(43u'99
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'send\h'|\n(41u'101\h'|\n(42u'recv\h'|\n(43u'102
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'bind\h'|\n(41u'104\h'|\n(42u'setsockopt\h'|\n(43u'105
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'listen\h'|\n(41u'106\h'|\n(42u'recvmsg\h'|\n(43u'113
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'sendmsg\h'|\n(41u'114\h'|\n(42u'getsockopt\h'|\n(43u'118
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'recvfrom\h'|\n(41u'125\h'|\n(42u'sendto\h'|\n(43u'133
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'socketpair\h'|\n(41u'135\h'|\n(42u'mkdir\h'|\n(43u'136
.ta \n(80u \n(61u \n(82u \n(63u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'rmdir\h'|\n(41u'137\h'|\n(42u'getsockname\h'|\n(43u'150
.fc
.nr T. 1
.T# 1
.in \n(#Iu
.35
.nr #a 0
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-19
.sp
.ce
Table 2: Some Syscall Numbers for Unix Systems Calls
.sp 2
.)z
.sh 2 "Global Values"
.pp
SB-Prolog has some primitives that permit the programmer to manipulate global
values. These are provided primarily as an efficiency hack, and needless to say, should
be used with a great deal of care.
.lp
\fBglobalset\fR(\fITerm\fR)
.ip
Allows the user to save a global value.
.(x b
(L) globalset/1
.)x
\fITerm\fR must be bound
to a compound term, say \fIp\fR(\fIV\fR\^). \fIV\fR must be a number or
a constant or a variable.
If \fIV\fR is a number or a constant, the effect of \fIglobalset\fR(\fIp\fR(\fIV\fR\^)) can be
described as:
.(l
retract(p(_\|)), assert(p(V)).
.)l
I.e., \fIp\fR is a predicate that when called will, from now on (until some other
change by \fIglobalset\fR/1), deterministically return \fIV\fR.
If \fIV\fR is a variable, the effect is to make \fIV\fR a global variable whose value is
accessible by calling \fIp\fR. For example, executing
``\fIglobalset\fR(\fIp\fR(\fIX\fR\^))'' makes \fIX\fR a global
variable. \fIX\fR can be set by unification with some other term.
On backtracking, \fIX\fR will be restored to its earlier value.
.lp
\fBgennum\fR(\fINewnum\fR)
.ip
gennum/1 sets its argument to a new integer every time it is invoked.
.(x b
(L) gennum/1
.)x
.lp
\fBgensym\fR(\fIC\fR,\fINewsym\fR)
.ip
gensym/2 sets its second argument to an atom whose name is made by
concatenating the name of the atom \fIC\fR to the current gennum number.
.(x b
(L) gensym/2
.)x
This new constant is bound to \fINewsym\fR. For example, if the current
\fIgennum\fR number is 37, then the call
.(l
| ?- gensym(aaa,X)
.)l
will succeed binding \fIX\fR to the atom `aaa37'.
.ds f. sec3.t
.sh 1 "Debugging"
.sh 2 "High Level Tracing"
.pp
The preferred method of tracing execution is through the predicate
\fItrace\fR/1.
.(x b
(L) trace/1
.)x
This predicate takes as argument a term \fIP\fR/\fIN\fR, where
\fIP\fR is a predicate name and \fIN\fR its arity, and sets a ``trace
point'' on the corresponding predicate; it can also be given a
list of such terms, in which case a trace point is set on each member of the list.
For example, executing
.(l
| ?- trace(pred1/2), trace([pred2/3, pred3/2]).
.)l
sets trace points on predicates \fIpred1\fR/2, \fIpred2\fR/3 and
\fIpred3\fR/2.
Only those predicates are traced that have trace points set on them.
.pp
If all the predicates in a file are to be traced, it is usually convenient to use the
\fIPredList\fR parameter of \fIcompile\fR/4 or \fIconsult\fR/3, e.g.:
.(l
| ?- compile(foo, 'foo.out', [t,v], Preds), load('foo.out'), trace(Preds).
or
| ?- consult(foo, [v], Preds), trace(Preds).
.)l
Notice that in the first case, the \fBt\fR compiler option (see Section 8.3)
should be specified in
order to turn off certain assembler optimizations and facilitate tracing.
In the second case, the same effect may be achieved by specifying the
\fBt\fR option to \fIconsult\fR.
.pp
The trace points set on predicates may be overwritten by loading byte code
files via \fIload\fR/1, and in this case it may be necessary to explicitly
set trace points again on the loaded predicates. This does not happen with
\fIconsult\fR: predicates that were being traced continue to have trace points
set after consulting.
.pp
The tracing facilities of SB-Prolog are in many ways very similar to those of
C-Prolog. However, leashing is not supported, and only those predicates
can be traced which have had trace points
set on them through \fItrace\fR/1. This makes \fItrace\fR/1 and \fIspy\fR/1
very similar: essentially, trace amounts to two levels of spy points.
In SB-Prolog, tracing occurs at \fICall\fR (i.e. entry to a predicate),
successful \fIExit\fR from a clause, and \fIFailure\fR of the entire call. The tracing options available during debugging are the following:
.ip \fBc\fR,\ \s-2NEWLINE\s+2:\ Creep
Causes the system to single-step to the next port (i.e. either the entry to a traced
predicate called by the executed clause, or the success or failure exit from that
clause).
.ip \fBa\fR:\ Abort
Causes execution to abort and control to return to the top level interpreter.
.ip \fBb\fR:\ Break
Calls the evaluable predicate \fIbreak\fR, thus invoking recursively
a new incarnation of the system interpreter. The
command prompt at break level \fIn\fR is
.(l
\fIn\fR: ?-
.)l
The user may return to the previous break level by entering the system end-of-file character (e.g. ctrl-D), or
typing in the atom \fIend_\^of_\^file\fR; or to the top level interpreter by typing in \fIabort\fR.
.ip \fBf\fR:\ Fail
Causes execution to fail, thus transferring control to the Fail port of the current execution.
.ip \fBh\fR:\ Help
Displays the table of debugging options.
.ip \fBl\fR:\ Leap
Causes the system to resume running the program, only stopping when a spy-point
is reached or the program terminates. This allows the user to follow the execution at a higher level than
exhaustive tracing.
.ip \fBn\fR:\ Nodebug
Turns off debug mode.
.ip \fBq\fR:\ Quasi-skip
This is like Skip except that it does not mask out spy points.
.ip \fBr\fR:\ Retry\ (fail)
Transfers to the Call port of the current goal. Note, however, that side effects, such as
database modifications etc., are not undone.
.ip \fBs\fR:\ Skip
Causes tracing to be turned off for the entire execution of the procedure. Thus,
nothing is seen until control comes back to that procedure, either at the Success or the Failure port.
.sp
.lp
Other predicates that are useful in debugging are:
.sp
.ip \fBuntrace\fR(\fIPreds\fR)
.(x b
(L) untrace/1
.)x
where Preds is a term \fIP\fR/\fIN\fR, where \fIP\fR is a predicate name and \fIN\fR its arity,
or a list of such terms. Turns off tracing on the specified predicates.
\fIPreds\fR must be instantiated at the time of the call.
.ip \fBspy\fR(\fIPreds\fR)
.(x b
(L) spy/1
.)x
where Preds is a term \fIP\fR/\fIN\fR, where \fIP\fR is a predicate name and \fIN\fR its arity,
or a list of such terms. Sets spy points on the specified predicates.
\fIPreds\fR must be instantiated at the time of the call.
.ip \fBnospy\fR(\fBPreds\fR)
.(x b
(L) nospy/1
.)x
where Preds is a term \fIP\fR/\fIN\fR, where \fIP\fR is a predicate name and \fIN\fR its arity,
or a list of such terms. Removes spy points on the specified predicates.
\fIPreds\fR must be instantiated at the time of the call.
.ip \fBdebug\fR
Turns on debugging mode. This causes subsequent execution of predicates with trace or spy
points to be traced, and is a no-op if there are no such predicates.
.(x b
(L) debug/0
.)x
The predicates \fItrace\fR/1 and \fIspy\fR/1 cause debugging mode to be turned on automatically.
.ip \fBnodebug\fR
Turns off debugging mode. This causes trace and spy points to be ignored.
.(x b
(L) nodebug/0
.)x
.ip \fBdebugging\fR
Displays information about whether debug mode is on or not, and lists
predicates that have trace points or spy points set on them.
.(x b
(L) debugging/0
.)x
.ip \fBtracepreds\fR(\fIL\fR\|)
Binds \fIL\fR to a list of terms \fIP\fR/\fIN\fR where the predicate
\fIP\fR of arity \fIN\fR has a trace point set on it.
.(x b
(L) tracepreds/1
.)x
.ip \fBspypreds\fR(\fIL\fR\|)
Binds \fIL\fR to a list of terms \fIP\fR/\fIN\fR where the predicate
\fIP\fR of arity \fIN\fR has a spy point set on it.
.(x b
(L) spypreds/1
.)x
.sp
.pp
There is one known bug in the package: attempts to set trace points, via
\fItrace\fR/1, on system and library predicates that are used by the trace
package can cause bizarre behaviour.
.sh 2 "Low Level Tracing"
.pp
SB-Prolog also provides a facility for low level tracing of execution. This can
be activated by invoking the simulator with the \-T option, or through the
predicate \fItrace\fR/0. It causes trace information to be printed out at every
call (including those to system trap handlers). The volume of such trace information can very become large very
quickly, so this method of tracing is not recommended in general.
.(x b
(L) trace/0
.)x
.pp
Low level tracing may be turned off using the predicate \fIuntrace\fR/0.
.(x b
(L) untrace/0
.)x
.ds f. sec4.t
.sh 1 "The Simulator"
.pp
The simulator resides in the SB-Prolog system directory \fIsim\fR. The following
sections describe various aspects of the simulator.
.sh 2 "Invoking the Simulator"
.pp
The simulator is invoked by the command
.(l
sbprolog \fIbc_\^file\fR
.)l
where \fIbc_\^file\fR is a byte code file resulting from the compilation of a
Prolog program. In almost all cases, the user will wish to interact with the
SB-Prolog \fIquery evaluator\fR, in which case \fIbc_\|file\fR will be
\fI$readloop\fR, and the command will be
.(l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 " sbprolog
.ps 11
.ft 2
.ds 12 "\s-5\b'\(sl\e'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 " path
.ps 11
.ft 2
.ds 12 "\s-5\b'\e\(sl'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "/\\\\$\$\readloop
.ps \n(99
.ft \n(98
\*(11
.)l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "where
.ps 11
.ft 2
.ds 12 "\s-5\b'\(sl\e'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "\fIpath\fR
.ps 11
.ft 2
.ds 12 "\s-5\b'\e\(sl'\s0
.ds 12 \x'0'\f2\s11\*(12\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 " is the path to the directory containing the
.ps \n(99
.ft \n(98
\*(11
command interpreter \fI$readloop\fR. This directory, typically, is the
system directory \fImodlib\fR.
.pp
The command interpreter reads in a query typed in by the user, evaluates it and
prints the answer(s), repeating this until it encounters an end-of-file
(the standard end-of-file character on the system, e.g. ctrl-D), or the user types
in \fIend_\|of_\|file\fR or \fIhalt\fR.
.pp
The user should ensure that the the directory containing the executable file \fIsim\fR
(typically, the system directory \fIsim\fR) is included in the shell variable
\fIpath\fR; if not, the full path to the simulator will have to be specified.
.pp
In general, the simulator may be invoked with a variety of options, as
follows:
.(l
sbprolog \-\fIoptions\fR \fIbc_\^file\fR
or
sbprolog \-\fIoption\fR\*<1\*> \-\fIoption\fR\*<2\*> ... \-\fIoption\*<n\*>\fR \fIbc_\^file\fR
.)l
The options recognized by the simulator are described below.
.pp
When called with a byte code file \fIbc_\^file\fR, the simulator begins
execution with the first clause in that file. The first clause in such a
file, therefore, should be a clause without any arguments in the head
(otherwise, the simulator will attempt to dereference argument pointers
in the head
that are really pointing into deep space, and usually come to a sad end).
If the user is executing a file in this manner rather than using the
command interpreter, he should also be careful to include the undefined
predicate handler `_\|\fI$undefined_\|pred\fR'/1, which is normally defined
in the file \fImodlib/$init_\|sys.P\fR.
.sh 2 "Simulator Options"
.lp
The following is a list of options recognized by the simulator.
.ip \fBT\fR
Generates a trace at entry to each called routine.
.ip \fBd\fR
Produces a disassembled dump of \fIbc_\|file\fR into a file named
`dump.pil' and exits.
.ip \fBn\fR
Adds machine addresses when producing trace and dump.
.ip \fBs\fR
Maintains information for the builtin \fIstatistics\fR/0. Default: off.
.ip \fBm\fR\ \fIsize\fR
Allocates \fIsize\fR words (4 bytes) of space to the local stack and heap
together. Default: 100000.
.ip \fBp\fR\ \fIsize\fR
Allocates \fIsize\fR words of space to the program area. Default: 100000.
.ip \fBb\fR\ \fIsize\fR
Allocates \fIsize\fR words of space to the trail stack. Default: \fIm\fR/5,
where \fIm\fR is the amount of space allocated to the local stack and heap
together. This parameter, if specified, must follow the -m parameter.
.sp
.lp
As an example, the command
.(l
sbprolog -s -p 60000 -m 150000 \e$readloop
.)l
starts the simulator executing the command interpreter with 60000 bytes of
program space, 150000 bytes of local and global stack space and (by default)
30000 bytes of trail stack space; the \fIs\fR option also results in
statistics information being maintained.
.sh 2 "Interrupt Handling"
.pp
SB-Prolog provides a facility for exception
handling using user-definable interrupt handlers. This can be used both
for external interrupts, e.g. those generated from the keyboard by the user
or from signals other processes; or internal traps, e.g. those caused by stack overflows, encountering undefined predicates, etc.
For example, the ``undefined predicate'' interrupt is handled, by default, by the
predicate `\fI_\|$undefined_\|pred\fR'/1, which is defined in the file
\fImodlib/$init_\|sys.P\fR. The default action on encountering an undefined
predicate is to attempt to dynamically load a file whose name matches that of the
undefined predicate. However, the user may easily alter this behaviour by
redefining the undefined predicate handler.
.ds f. sec5.t
.sh 1 "The Compiler"
.lp
The compiler translates Prolog source files into byte-code object files. It is written
entirely in Prolog. The byte code for the compiler can be found in the
SB-Prolog system directory \fIcmplib\fR, with the source code resident in
\fIcmplib/src\fR.
.pp
Byte code files may be concatenated together to produce other byte code files. Thus,
for example, if \fIfoo1\fR and \fIfoo2\fR are byte code files resulting
from the compilation of two Prolog source programs, then the file \fIfoo\fR,
obtained by executing the shell command
.(l
cat foo1 foo2 > foo
.)l
is a byte code file as well, and may be loaded and executed. In this case,
loading and executing the file \fIfoo\fR would give the same result as
loading \fIfoo1\fR and \fIfoo2\fR separately, which in turn would be the same as
concatenating the original source files and compiling this larger file. This
makes it easier to compile large programs: one need only break them into smaller
pieces, compile the individual pieces, and concatenate the byte files together.
.pp
The following sections describe the various aspects of
the compiler in more detail.
.sh 2 "Structure of the Compiler"
.lp
The compilation of a Prolog program proceeds in four phases. In the first
phase, the source program is read in and passed through a preprocessor.
The output of the preprocessor is essentially another Prolog source
program. Next, this program is transformed into an internal representation
(essentially an annotated abstract syntax tree). The third phase
involves generating WAM ``assembly'' code and peephole optimization.
Finally, the WAM assembly code is processed by an assembler which generates
byte code.
.sh 2 "Invoking the Compiler"
.lp
The compiler is invoked through the Prolog predicate \fIcompile\fR:
.(l
| ?- compile(\fIInFile\fR [, \fIOutFile\fR ] [, \fIOptionsList\fR ]).
.)l
where optional parameters are enclosed in brackets.
\fIInFile\fR is the name of the input (i.e. source) file; \fIOutFile\fR is the
name of the output file (i.e. byte code) file; \fIOptionsList\fR is a list of compiler options (see
below).
.pp
The input and output file names must be Prolog atoms, i.e. either
begin with a lower case letter or dollar sign `$', and consist only of letters, digits,
and underscores; or, be enclosed within single quotes.
If the output file name is not specified, it defaults to
\fIInFile\fB.out\fR. The list of options, if specified, is
a Prolog list, i.e. a term of the form
.(l
[ \fIoption\fR\*<1\*>, \fIoption\fR\*<2\*>, ..., \fIoption\*<n\*>\fR ].
.)l
If left unspecified, it defaults to the empty list [\^].
.pp
In fact, the output file name and the options list may be specified in any order. Thus,
for example, the queries
.(l
| ?- compile('/usr/debray/foo', foo_\|out, [v]).
and
| ?- compile('/usr/debray/foo', [v], foo_\|out).
.)l
are equivalent, and specify that the Prolog source file
`\fI/usr/debray/foo\fR' is to be compiled in verbose mode (see ``Compiler
Options'' below), and that the byte code is to be generated into the file
\fIfoo_out\fR.
.pp
The \fIcompile\fR predicate may also be called with a fourth parameter:
.(l
| ?- compile(\fIInFile\fR, \fIOutFile\fR, \fIOptionsList\fR, \fIPredList\fR).
.)l
where \fIInFile\fR, \fIOutFile\fR and \fIOptionsList\fR are as before;
\fIcompile\fR/4 unifies \fIPredList\fR with a list of terms \fIP\fR/\fIN\fR denoting the
predicates defined in \fIInFile\fR, where \fIP\fR is a predicate name and \fIN\fR its arity.
\fIPredList\fR, if specified, is usually given as an uninstantiated
variable; its principal use is for setting trace points on the predicates in the file (see Section 6),
e.g. by executing
.(l
| ?- compile('/usr/debray/foo', foo_\|out, [v], L), load(foo_\|out), trace(L).
.)l
Notice that \fIPredList\fR can only appear in \fIcompile\fR/4.
.sh 2 "Compiler Options"
.lp
The following options are currently recognized by the compiler:
.ip \fBa\fR
Specifies that an ``assembler'' file is to be created. The name of the
assembler file is obtained by appending ``.asl'' to the source file name.
While the writing out of assembly code slows down the compilation process
to some extent, it allows the assembler to do a better job of optimizing
away indirect subroutine linkages (since in this case the assembler has
assembly code for the entire program to work with at once, not just a single
predicate). This results in code that is faster and more compact.
.ip \fBd\fR
Dumps expanded macros to the user (see Section 10).
.ip \fBe\fR
Expand macros (see Section 10).
.ip \fBi\fR
Specifies that indexes are to be generated. The pragma file (see Section 12) corresponding to
the source file is consulted for information regarding predicates which should have
indexes constructed, and the arguments on which indexes are to be
constructed.
.ip \fBt\fR
If specified, turns off assembler optimizations that eliminate indirect branches through the symbol table in
favour of direct branches. This is useful in debugging compiled code. It
is \fInecessary\fR if the extension table feature is to be used.
.ip \fBv\fR
If specified, compiles in ``verbose'' mode, which causes messages regarding progress
of compilation to be printed out.
.sh 2 "A Note on Coding for Efficiency"
.pp
The SB-Prolog system tends to favour programs that are relatively pure. Thus, for
example, \fIassert\fRs tend to be quite expensive, encouraging the user to avoid them
if possible. This section points out some syntactic constructs that lead to the generation
of efficient code. These involve (\fIi\fR\^) avoiding the creation of backtrack points; and (\fIii\fR\^)
minimizing data movement between registers.
Optimization of logic programs is an area of ongoing research,
and we expect to enhance the capabilities of the system further in future
versions.
.sh 3 "Avoiding Creation of Backtrack Points"
.pp
Since the creation of backtrack points is relatively expensive, program efficiency may
be improved substantially by using constructs that avoid the creation of backtrack points where possible.
The SB-Prolog compiler recognizes conditionals involving certain
complementary inline tests, and generates code that does not create
choice points for such cases.
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "Two inline tests \fIp\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ") and \fIq\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ") are complementary
.ps \n(99
.ft \n(98
\*(11
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "if and only if \fIp\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ") \(== \fInot\fR(\fIq\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ")).
.ps \n(99
.ft \n(98
\*(11
For example, the literals `\fIX\fR > \fIY\fR\^' and `\fIX\fR =< \fIY\fR\^'
are complementary. At this point, complementary tests are recognized as such only
if their argument tuples are identical. The inline predicates that are
treated in this manner, with their corresponding complementary literals,
are shown in Table 3.
.(z
.sp
.TS
.if \n+(b.=1 .nr d. \n(.c-\n(c.-1
.de 35
.ps \n(.s
.vs \n(.vu
.in \n(.iu
.if \n(.u .fi
.if \n(.j .ad
.if \n(.j=0 .na
..
.nf
.nr #~ 0
.if n .nr #~ 0.6n
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.fc
.nr 33 \n(.s
.rm 80 81
.nr 80 0
.nr 38 \w\fIInline Test
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w>/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w=</2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w>=/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w</2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w=:=/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \w=\e=/2
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wvar/1
.if \n(80<\n(38 .nr 80 \n(38
.nr 38 \wnonvar/1
.if \n(80<\n(38 .nr 80 \n(38
.80
.rm 80
.nr 81 0
.nr 38 \wComplementary Test\fR
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w=</2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w>/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w</2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w>=/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w=\e=/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \w=:=/2
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \wnonvar/1
.if \n(81<\n(38 .nr 81 \n(38
.nr 38 \wvar/1
.if \n(81<\n(38 .nr 81 \n(38
.81
.rm 81
.nr 38 0
.if \n(80>\n(38 .nr 38 \n(80
.if \n(81>\n(38 .nr 38 \n(81
.nr 80 \n(38
.nr 81 \n(38
.nr 38 1n
.nr 79 0
.nr 40 \n(79+(1*\n(38)
.nr 80 +\n(40
.nr 41 \n(80+(3*\n(38)
.nr 81 +\n(41
.nr TW \n(81
.nr TW +1*\n(38
.if t .if (\n(TW+\n(.o)>7.65i .tm Table at line 147 file sec5.t is too wide - \n(TW units
.ne 9v+0p
.nr #I \n(.i
.in +(\n(.lu-\n(TWu-\n(.iu)/2u
.fc
.nr #T 0-1
.nr #a 0-1
.nr #a 0-1
.eo
.de T#
.ds #d .d
.if \(ts\n(.z\(ts\(ts .ds #d nl
.mk ##
.nr ## -1v
.ls 1
.if \n(#T>=0 .nr #a \n(#T
.if \n(T. .vs \n(.vu-\n(.sp
.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.if \n(T. .vs
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'(|\n(41u+|\n(80u)/2u'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu'
.if \n(#a>=0 .sp -1
.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'
.ls
..
.ec
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.mk #a
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'\fIInline Test\h'|\n(41u'Complementary Test\fR
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'>/2\h'|\n(41u'=</2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'=</2\h'|\n(41u'>/2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'>=/2\h'|\n(41u'</2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'</2\h'|\n(41u'>=/2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'=:=/2\h'|\n(41u'=\e=/2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'=\e=/2\h'|\n(41u'=:=/2
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'var/1\h'|\n(41u'nonvar/1
.nr 36 \n(.v
.vs \n(.vu-\n(.sp
\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0
.vs \n(36u
.ta \n(80u \n(81u
.nr 31 \n(.f
.nr 35 1m
\&\h'|\n(40u'nonvar/1\h'|\n(41u'var/1
.fc
.nr T. 1
.T# 1
.in \n(#Iu
.35
.nr #a 0
.TE
.if \n-(b.=0 .nr c. \n(.c-\n(d.-13
.sp
.ce
Table 3: Complementary tests recognized by the compiler
.sp
.)z
The syntactic constructs recognized are:
.ip (\fIi\fR\^)
Disjuncts of the form
.(l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "\fIhead\fR :\- (( \fItest\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "), ... ) ; ( not(\fItest\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 ")), ...)).
.ps \n(99
.ft \n(98
\*(11
.)l
or
.(l
.nr 99 \n(.s
.nr 98 \n(.f
.rm 11
.as 11 "\fIhead\fR :\- (( \fItest\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "), ... ) ; ( \fIcomp_\|test\fR(
.ps 11
.ft 2
.ds 12 "X
.nr 12 \w'\s11\*(12'
.nr 10 0u
.if \n(ct>1 .nr 10 \n(10+\s11.25m\s0
.nr 14 \s11.1m\s0
.if \n(ct>1 .nr 14 \s11.15m\s0
.ds 13 \s11\v'.18m'\h'.05m'\l'\n(12u-.1m\(rn'\h'.05m'\v'-.18m'\s0
.nr 13 \w'\s11\*(13'
.as 12 \h'-\n(12u-\n(13u/2u+\n(14u'\v'0-\n(10u'\*(13\v'\n(10u'\h'-\n(13u+\n(12u/2u-\n(14u'
.ds 12 \x'0'\f2\s11\*(12\|\s\n(99\f\n(98
.as 11 \*(12
.ps \n(99
.ft \n(98
.as 11 "), ...)).
.ps \n(99
.ft \n(98
\*(11
.)l
where \fItest\fR is one of the inline tests in the table above, and
\fIcomp_\|test\fR the corresponding complementary test (note that the
arguments to \fItest\fR and \fIcomp_\|test\fR have to be identical).
.ip (\fIii\fR\^)
Conditionals of the form
.(l
\fIhead\fR :\- (\fItest\fR\*<1\*>\fB,\fR ... \fB,\fR \fItest\*<n\*>\fR) \-> \fITrue_\|Case\fR ; \fIFalse_\|Case\fR.
.)l
or
.(l
\fIhead\fR :\- (\fItest\fR\*<1\*>\fB;\fR ... \fB;\fR \fItest\*<n\*>\fR) \-> \fITrue_\|Case\fR ; \fIFalse_\|Case\fR.
.)l
where each \fItest\*<i\*>\fR is an inline test, as mentioned in the table
above.
.pp
The code generated for these cases involves a test and conditional branch, and no
choice point is created. We expect future versions of the translator to
recognize a wider class of complementary tests.
.pp
Notice that this discourages the use of explicit cuts. For example,
whereas a choice point will be created for
.(l
part(M,[E|L],U1,U2) :\-
((E =< M, !, U1 = [E|U1a], U2 = U2a) ;
(U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
.)l
no choice point will be created for either
.(l
part(M,[E|L],U1,U2) :\-
(E =< M \->
(U1 = [E|U1a], U2 = U2a) ;
(U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
.)l
or
.(l
part(M,[E|L],U1,U2) :\-
((E =< M, U1 = [E|U1a], U2 = U2a) ;
(E > M, U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
.)l
Thus, either of the two later versions will be more efficient than the version with the
explicit cut.
.sh 3 "Minimizing Data Movement Between Registers"
.pp
Data movement between registers for parameter passing may be minimized by leaving variables in
the same argument position wherever possible. Thus, the clause
.(l
p(X,Y) :\- p1(X,Y,0).
.)l
is preferable to
.(l
p(X,Y) :\- p1(0,X,Y).
.)l
because the first definition leaves the variables \fIX\fR and \fIY\fR
in the same argument positions (first and second, respectively), while the second definition does
not.
.sh 2 "Assembly"
.pp
The SB-Prolog assembler can be invoked by loading the compiler and using the
predicate \fI$asm\fR/3:
.(l
| ?- $asm(\fIInFile\fR, \fIOutFile\fR, \fIOptionsList\fR).
.)l
where \fIInFile\fR is a Prolog atom which is the name of a WAM assembly source file (e.g.
the ``.asl'' file generated when a Prolog program is compiled with the ``a'' option),
\fIOutFile\fR is an atom which is the name of the intended byte code file, and
\fIOptionsList\fR is a list of options. The options recognized by the
assembler are:
.ip \fBv\fR
``Verbose'' mode. Prints out information regarding progress of assembly.
.ip \fBt\fR
``Trace''. If specified, the assembler generates code to force procedure calls
to branch indirectly via the symbol table, instead of using a direct branch.
This is Useful for tracing compiled code. It is \fInecessary\fR if the extension table
feature is to be used.
.lp
The assembler is intended primarily to support the compiler, so the assembly language
syntax is quirky in places. The interested reader is advised to look at
the assembly files resulting from compilation with the ``a'' option for more on SB-Prolog assembler
syntax.
.ds f. sec6.t
.sh 1 "Modules"
.pp
To describe how modules (or maybe more properly, just libraries) are
currently supported in our system, we must describe the \fI_\|$undefined_\|pred\fR/1
interrupt handler. The system keeps a table of modules and routines that
are needed from each. When a predicate is found to be undefined, the table
is searched to see if it is defined by some module. If so, that module is
loaded (if it hasn't been previously loaded) and the association is made
between the routine name as defined in the module, and the routine name as
used by the invoker.
.pp
The table of modules and needed routines is:
.(l C
defined_\|mods(\fIModname\fR, [\fIpred\fR\*<1\*>/\fIarity\fR\*<1\*>, ..., \fIpred\*<n\*>\fR/\fIarity\*<n\*>\fR]).
.)l
where \fIModname\fR is the name of the module. The module exports \fIn\fR
predicate definitions. The first exported pred is of arity \fIarity\fR\*<\*>1,
and needs to be invoked by the name of \fIpred\fR\*<1\*>.
.pp
The table of modules that have already been loaded is given by
.(l
loaded_\|mods(\fIModname\fR).
.)l
A module is a file of predicate definitions, together with a fact defining a list
of predicates exported by that module, and a set of facts, each of which specifies, for some
other module, the predicates imported from that module. For example, consider a module
name `\fIp\fR'. It contains a single fact, named \fIp_\|export\fR, that is true of the
list of predicate/arity's that are exported. E.g.
.(l
p_\|export([p1/2, p2/4])
.)l
indicates that the module \fIp\fR exports the predicates \fIp1\fR/2 and \fIp2\fR/4.
For each module \fIm\fR which contains predicates needed by the module \fIp\fR, there
is a fact for \fIp_use\fR, describing what module is needed and the names of the
predicates defined there that are needed. For example, if module \fIp\fR needs
to import predicates \fIip1\fR/2 and \fIip2\fR/3 from module \fIq\fR, there would be a fact
.(l
p_\|use(q,[ip1/2, ip2/3])
.)l
where \fIq\fR is a module that exports two predicates: one 2-ary and one
3-ary. This list corresponds to the export list of module \fIq\fR.
.pp
The correspondence between the predicates in the export list of an exporting
module, and those in the import or \fIuse\fR list of a module which imports one or
more of them, is by position, i.e. the predicate names at the exporting and importing names may be different, and
the association between names in the two lists is by the position in the list. If the importing
module does not wish to import one or more of the predicates exported by the
exporting module, it may put an anonymous variable in the corresponding position in
its \fIuse\fR list. Thus, for example, if module \fIp\fR above had wished to import only
the predicate \fIip2\fR/3 from module \fIq\fR, the corresponding use fact would
be
.(l
p_\|use(q, [_\|\|, ip2/3]).
.)l
.pp
The initial set of predicates and the modules from which they are to be
loaded is set up by an initial call to \fI$prorc\fR/0 (see the SB-Prolog
system file \fImodlib/src/$prorc.P\fR).
This predicate makes initial calls to the predicate $define_\|mod which set up
the tables described above so that the use of standard predicates will cause
the correct modules to be loaded in the \fI_\|$undefined_\|pred\fR routine, and the
correct names to be used.
.ds f. sec7.t
.sh 1 "Macros"
.pp
SB-Prolog features a facility for the definition and expansion of macros that is fully compatible with
the runtime system. Its basic mechanism is a simple partial evaluator. It
is called by both \fIconsult\fR and \fIcompile\fR, so that macro expansion
occurs independently of whether the code is interpreted or compiled (but not when
asserted). Moreover, the macro definitions are retained as clauses at runtime, so
that invocation of macros via \fIcall\fR/1 at runtime (or from asserted clauses)
does not pose a problem. This means, however, that if the same macro is
used in many different files, it will be loaded more than once, thus leading to
wasetd space. This ought to be thought about and fixed.
.pp
The source for the macro expander is in the SB-Prolog system file
\fImodlib/src/$mac.P\fR.
.sh 2 "Defining Macros"
.pp
`Macros', or predicates to be evaluated at compile-time, are defined
by clauses of the form
.(l
Head ::\- Body
.)l
where facts have `true' as their body.
.(x b
(P) ::\-/2
.)x
The partial evaluator will expand any call to a
predicate defined by ::\-/2 that
unifies with the head of only one clause in ::\-/2. If a call unifies with the
head of more than one clause in ::\-/2, it will not be expanded
Notice that this is not a
fundamental restriction, since `;' is permitted in the body of a
clause. The partial evaluator also converts each definition of the form
.(l
Head ::\- Body.
.)l
to a clause of the form
.(l
Head :\- Body.
.)l
and adds this second clause to the other ``normal'' clauses that were read from
the file. This ensures that calls to the macro at runtime, e.g. through
\fIcall\fR/1 or from unexpanded calls in the program do not cause any
problems.
.pp
The partial evaluator is actually a Prolog interpreter written
`purely' in Prolog, i.e., variable assignments are explicitly
handled. This is necessary to be able to handle impure constructs
such as `var(X), X=a'. As a result this is a \fIvery slow\fR Prolog
evaluator.
.pp
Since naive partial evaluation can go into an infinite loop, SB-Prolog's
partial evaluator
maintains a depth-bound and will not expand recursive calls deeper
than that. The depth is determined by the globalset predicate
\fI$mac_\|depth\fR. The default value for \fI$mac_\|depth\fR
is 50 This can be changed to some other value \fIn\fR by executing
.(l
| ?- globalset($mac_\|depth(\fIn\fR)).
.)l.
.sh 2 "Macro Expander Options"
.lp
The following options are recognized by the macro expander:
.ip \fBd\fR
Dumps all clauses to the user after expansion. Useful for debugging.
.ip \fBe\fR
Expand macros. If omitted, the expander simply converts each ::\-/2 clause to a normal :\-/2 clause.
.ip \fBv\fR
``Verbose'' mode. Prints macros that are/are not being expanded.
.ds f. sec8.t
.sh 1 "Extension Tables"
.pp
Extension tables store the calls and answers for a predicate. If a
call has been made before, answers are retrieved from the extension
table instead of being recomputed. Extension tables provide a
caching mechanism for Prolog. In addition, extension tables affect
the termination characteristics of recursive programs. Some Prolog
programs, which are logically correct, enter an infinite loop due
to recursive predicates. An extension table saved on recursive
predicates can find all answers (provided the set of such answers is
finite) and terminate
for some logic programs for which Prolog's evaluation strategy
enters an infinite loop. Iterations over the extension table
execution strategy provides complete evaluation of queries over
function-free Horn clause programs.
.pp
To be able to use the simple extension table evaluation on a set of
predicates, the source file should either be consulted, or
compiled with the \fBt\fR option (the \fBt\fR option
keeps the assembler from optimizing subroutine linkage and allows
the extension table facility to intercept calls to predicates).
.pp
To use extension table execution, all predicates that are to be
saved in the extension table must be passed to \fIet\fR/1. For example,
.(l
| ?\- et([pred1/1, pred2/2]), et(pred3/2)
.)l
will set up ``ET-points'' for the for predicates \fIpred1\fR/1, \fIpred2\fR/2 and
\fIpred3\fR/2, which will cause extension tables for these predicates to be
maintained during execution. At the time of the call to \fIet\fR/1, these predicates
must be defined, either by having been loaded, or through \fIconsult\fR.
.pp
The predicate \fInoet\fR/1 takes a list of predicate/arity pairs for
which ET-points should be deleted. Notice that
once an ET-point has been set up for a predicate, it will be maintained
unless explicitly deleted via \fInoet\fR/1.
If the definition of a predicate which has an ET-point defined is to be updated,
the ET-point must first be deleted via \fInoet\fR/1.
The predicate can then be reloaded and a new ET-point established.
This is enforced by the failure of the goal ``et(P/N)'' if an
ET-point already exists for the argument predicate. In this case,
the following error message will be displayed:
.(l
*et* already defined for: P/N
.)l
.pp
There are, in fact, two extension table algorithms: a simple one, which
simply caches calls to predicates which have ET-points defined; and a
complete ET algorithm, which iterates the simple extension table algorithm until
no more answers can be found. The simple algorithm is more efficient than the
complete one; however, the simple algorithm is not complete for certain
especially nasty forms of mutual recursion, while the complete
algorithm is. To use the simple extension table algorithm,
predicates can simply be called as usual.
The complete extension table algorithm may be used via the query
.(l
| ?\- et_\|star(Query).
.)l
.lp
The extension table algorithm is intended for predicates that are ``essentially
pure'', and results are not guaranteed for code using impure code.
The extension table algorithm saves only those answers which are
not instances of what is already in the
table, and uses these answers if the current call is an instance of a call
already made. For example, if a call \fIp\fR(\fIX\fR, \fIY\fR\^), with
\fIX\fR and \fIY\fR uninstantiated, is encountered and inserted into the
extension table, then a subsequent call \fIp\fR(\fIX\fR, \fIb\fR) will be
computed using the answers for \fIp\fR(\fIX\fR, \fIY\fR\^) already in the
extension table. Notice that this might not work
if var/nonvar tests are used on the second argument
in the evaluation of \fIp\fR.
.pp
Another problem with using impure code is that if an ET predicate is cut
over, then the saved call implies that all answers for that predicate were
computed,
but there are only partial results in the ET because of the cut.
So on a subsequent call the incomplete extension table answers are used
when all answers are expected.
.(l
Example:
r(X,Y) :\- p(X,Y),q(Y,Z),!,fail.
| ?\- r(X,Y) ; p(X,Y).
.)l
.lp
Let p be an ET predicate whose evaluation yields many tuples.
In the evaluation of the query, r(X,Y) makes a call to p(X,Y).
Assuming that there is a tuple such that q(Y,Z) succeeds with the
first p tuple then the evaluation of p is cut over. The call to p(X,Y)
in the query uses the extension table because of the previous call
in the evaluation of r(X,Y). Only one answer is found, whereas the
relation p contains many tuples, so the computation is not complete.
Note that "cuts" used within the evaluation of an ET predicate are ok,
as long as they don't cut over the evaluation of another ET predicate.
The evaluation of the predicate that uses cuts does not cut over any et
processing (such as storing or retrieving answers) so that the tuples that
are computed are saved. In the following example, the ET is used to generate
prime numbers where an ET point is put on prime/1.
.(l
Example:
prime(I) :\- globalset(globalgenint(2)),fail. /* Generating Primes */
prime(I) :\- genint(I), not(div(I)).
div(I) :\- prime(X), 0 is I mod X.
genint(N) :\-
repeat,
globalgenint(N),
N1 is N+1,
globalset(globalgenint(N1)).
.)l
.lp
The following summarizes the library predicates supporting the extension
table facility:
.sp
.lp
\fBet\fR(\fIL\fR)
.ip
Sets up an ET-point on the predicates \fIL\fR, which causes calls and
anwers to these predicates to be saved in an ``extension table''.
.(x b
(L) et/1
.)x
\fIL\fR is either a term \fIPred\fR/\fIArity\fR, where \fIPred\fR is a predicate
symbol and \fIArity\fR its arity, or a set of such terms represented as a list.
\fIL\fR must be
instantiated, and the predicates specified in it defined, at the time of
the call to \fIet\fR/1. Gives error messages and fails if any of
the predicates in \fIL\fR is undefined, or if an ET-point
already exists on any of them; in this case, no ET-point
is set up on any of the predicates in \fIL\fR.
.lp
\fBet_\|\fBstar\fR(Goal\fR\^)
.ip
Invokes the complete extension table algorithm on the goal \fIGoal\fR.
.(x b
(L) et_\|star/1
.)x
.lp
\fIet_\^points\fR(\fIL\fR)
.ip
Unifies \fIL\fR with a list of predicates for which an ET-point is
defined. \fIL\fR is the empty list [] if there are no ET-points defined.
.(x b
(L) et_\^points/1
.)x
.lp
\fBnoet\fR(\fIL\fR)
.ip
Deletes ET-points on the predicates specified in \fIL\fR.
.(x b
(L) noet/1
.)x
\fIL\fR is either a term \fIP\fR/\fIN\fR, where \fIP\fR is the name of a
predicate and \fIN\fR its arity, or a set of such terms represented as a
list. Gives error messages and
fails if there is no ET-point on any of the predicates specified in
\fIL\fR. Deleting an ET-point for a predicate also removes the calls and
answers stored in the extension table for that predicate. The extension
tables for all predicates for which ET-points are defined may be deleted
using \fIet_\^points\fR/1 in cojnunction with \fInoet\fR/1.
\fIL\fR must be instantiated at the time of the call to \fInoet\fR/1.
.lp
\fBet_\|remove(\fIL\^)
.ip
Removes both calls and answers for the predicates specified in \fIL\fR. In
effect, this results in the extension table for these predicates to be set
to empty. \fIL\fR must be instantiated at the time of the call to
either a term \fIP\fR/\fIN\fR, where \fIP\fR is a
predicate with arity \fIN\fR, or a list of such terms. An error occurs if
any of the predicates in \fIL\fR does not have an ET-point set.
All extension tables can be emptied by using \fIet_\^points\fR/1 in
conjunction with \fIet_\^remove\fR/1.
.(x b
(L) et_\|remove/1
.)x
.lp
\fBet_\|answers\fR\^(\fIP\fR/\fIN\fR, \fITerm\fR\^)
.ip
Retrieves the answers stored in the extension table for the predicate \fIP\fR/\fIN\fR
in \fITerm\fR one at a time. \fITerm\fR is of the form
\fIP\fR(\fIt\fR\*<1\*>, ..., \fIt\*<N\*>\fR). An error results and
\fIet_\^answers\fR/2 fails if \fIP\fR/\fIN\fR is not fully specified (ground),
or if \fIP\fR/\fIN\fR does not have an ET-point set.
.lp
\fBet_\|calls\fR(\fIP/N\fR, \fITerm\fR\^)
.ip
Retrieves the calls stored in the extension table for the predicate \fIP/N\fR
in \fITerm\fR one at a time. \fITerm\fR is of the form
\fIP\fR(\fIt\fR\*<1\*>, ..., \fIt\*<N\*>\fR). An error results and
\fIet_\^calls\fR/2 fails if \fIP\fR/\fIN\fR is not fully specified (ground),
or if \fIP\fR/\fIN\fR does not have an ET-point set.
.(x b
(L) et_\|calls/2
.)x
.lp
.ds f. sec9.t
.sh 1 "Other Library Utilities"
.pp
The SB-Prolog library contains various other utilities, some of which are
listed below.
.lp
\fB$append\fR(\fIX\fR, \fIY\fR, \fIZ\fR)
.ip
Succeeds if list \fIZ\fR is the concatenation of lists \fIX\fR and \fIY\fR.
.(x b
(L) $append/3
.)x
.lp
\fB$member\fR(\fIX\fR, \fIL\fR)
.ip
Checks whether \fIX\fR unifies with any element of list \fIL\fR, succeeding more than
once if there are multiple such elements.
.(x b
(L) $member/2
.)x
.lp
\fB$memberchk\fR(\fIX\fR, \fIL\fR)
.ip
Similar to $\fImember\fR/2, except that $\fImemberchk\fR/2 is
deterministic, i.e. does not succeed more than once for any call.
.lp
\fB$reverse\fR(\fIL\fR, \fIR\fR)
.ip
Succeeds if \fIR\fR is the reverse of list \fIL\fR. If \fIL\fR is not a
fully determined list, i.e. if the tail of \fIL\fR is a variable, this
predicate can succeed arbitrarily many times.
.(x b
(L) $reverse/2
.)x
.lp
\fB$merge\fR(\fIX\fR, \fIY\fR, \fIZ\fR\^)
.ip
Succeeds if \fIZ\fR is the list resulting from ``merging'' lists
\fIX\fR and \fIY\fR, i.e. the elements of \fIX\fR together with any
element of \fIY\fR not occurring in \fIX\fR. If \fIX\fR or \fIY\fR contain
duplicates, \fIZ\fR may also contain duplicates.
.(x b
(L) $merge/3
.)x
.lp
\fB$absmember\fR(\fIX\fR, \fIL\fR\^)
.ip
Similar to \fI$member\fR/2, except that it checks for identity (through ==/2)
rather than unifiability (through =/2) of \fIX\fR with elements of \fIL\fR.
.(x b
(L) $absmember/2
.)x
.lp
\fB$nthmember\fR(\fIX\fR, \fIL\fR, \fIN\fR)
.ip
Succeeds if the \fIN\fR\*[th.\*] element of the list \fIL\fR unifies with
\fIX\fR. Fails if \fIN\fR is greater than the length of \fIL\fR. Either
\fIX\fR and \fIL\fR, or \fIL\fR and \fIN\fR, should be instantiated at the
time of the call.
.(x b
(L) $nthmember/3
.)x
.lp
\fB$member2\fR(\fIX\fR, \fIL\fR)
.ip
Checks whether \fIX\fR unifies with any of the actual elements of \fIL\fR.
The only difference between this and \fI$member\fR/2 is on lists with
a variable tail, e.g. [a, b, c | _ ]: while \fI$member\fR/2 would insert
\fIX\fR at the end of such a list if it did not find it, \fI$member2\fR/2
only checks for membership but does not insert it into the list if it is
not there.
.lp
.ds f. seca.t
.sh 1 "Pragma Files"
.pp
Users may specify pragma information about SB-Prolog programs in a file called the
\fIpragma file\fR for the program. The pragma file corresponding to a
Prolog source file \fIfoo\fR is a file \fIfoo.def\fR which is either in the
same directory as the source file, or is in a subdirectory \fIdefs\fR in the
directory containing the source file. In other words, relative to the
directory containing the source file \fIfoo\fR, the pragma file can be either
\fIfoo.def\fR or \fIdefs/foo.def\fR.
.pp
Pragma information in such a file is specified as a set of facts
\fIprag/3\fR. The first and second arguments are, respectively, the name and arity
of the predicate for which information is being specified. The third
argument is the pragma being specified, and can be either a term, or a list of
terms. Thus, for example, to specify that an index is to be created on the
first argument position for a predicate \fIbar\fR/3 in the file \fIfoo\fR, we would enter, in a file \fIfoo.def\fR, the fact ``prag(bar, 3, index)''
or ``prag(bar, 3, [index])''.
.pp
The pragma information that may be specified is limited, at this point, to
information about indexing. If an index is to be created on argument \fIn\fR
of a predicate, the corresponding pragma is a term ``index(\fIn\fR)''.
In the special case where \fIn\fR = 1, the pragma ``\fIindex\fR(1)''
may be abbreviated to ``\fIindex\fR''.
.sp
.lp
\fBAcknowledgements\fR
.pp
A large number of people were involved, at some time or another, with the
Logic Programming group at SUNY, Stony Brook, and deserve credit for
bringing the SB-Prolog system to its present form. The following names, in particular, ought
to be mentioned: David Scott Warren, Weidong Chen, Suzanne Dietrich,
Sanjay Manchanda, Jiyang Xu and David Znidarsic. The author is also
grateful to Fernando Pereira for permission to use material from the
C-Prolog manual for the descriptions of Prolog syntax and many of the builtins.
.ds f. secb.t
.nr % 53
junk
.bp
.uh "Appendix 1: Evaluable Predicates of SB-Prolog"
.sp
.pp
An entry of ``B'' indicates a builtin predicate, ``I'' an inline predicate,
and ``L'' a library predicate. A ``P'' indicates that the predicate is
handled by the preprocessor during compilation and/or consulting.
.sp
.2c
.lp
.xp b
.1c
.lp
.bp
.lp
.uh "Appendix 2: Adding Builtins to SB-Prolog"
.EQ
.nr 99 \n(.s
.nr 98 \n(.f
.ps 11
.ft 2
.ps \n(99
.ft \n(98
.EN
.pp
Adding a builtin involves writing the C code for the desired case and installing
it into the simulator. The files in the irectory \fIsim/builtin\fR
contain the C code for the builtin predicates supported by the system.
The following procedure is to be followed when adding a builtin to the system:
.sp
.lp
\fII. Installing C Code\fR:
.np
Go to the directory \fIsim/builtin\fR.
.np
Look at the \fB#define\fRs in the file \fIbuiltin.h\fR, and choose a number \fIN1\fR
(between 0 and 255) which is not in use to be the builtin number for the new builtin.
.np
Add to the file \fIbuiltin.h\fR the line
.(l
#define NEWBUILTIN \fIN1\fR
.)l
.np
The convention is that the code for builtin will be in a parameterless
procedure named \fIb_\|NEWBUILTIN\fR. Modify the file
\fIinit_\|\^branch.c\fR in the directory \fIsim/builtin\fR by adding these lines:
.(l
extern int b_\|NEWBUILTIN();
and
set_\|b_\|inst ( NEWBUILTIN, b_\|NEWBUILTIN );
.)l
in the appropriate places.
.np
The builtins are compiled together into one object file, \fIbuiltin\fR.
Update the file \fIMakefile\fR by appending the name of your object code file at the
end of the line ``OBJS = ... '' and insert the appropriate commands to compile
your C source file, e.g.:
.(l
OBJS = [ ... \fIother file names\fR ... ] newbuiltin.o
...
newbuiltin.o: $(HS)
cc $(CFLAGS) newbuiltin.c
.)l
.np
Execute the updated make file to create an updated object file \fIbuiltin\fR.
.np
Go to the directory \fIsim\fR and execute \fImake\fR to install the new file \fIbuiltin\fR.
.sp
.lp
\fIII. Installing Prolog Code\fR:
.pp
Assume that the builtin predicate to be added is \fInewbuiltin\fR/4. The
procedure for installing the Prolog code for this is as follows:
.np
Go to the SB-Prolog system directory \fIlib/src\fR, where the Prolog source for
the library routines is kept.
.np
Each builtin definition is of the form
.(l
pred( ... ) :\- '_\|$builtin'(\fIN\fR\^).
.)l
where \fIN\fR is an integer, the builtin number of \fIpred\fR.
.np
Create a Prolog source file \fInewbuiltin.P\fR (notice correspondence with
the name of the predicate being defined) containing the definition
.(l
newbuiltin(A,B,C,D) :\- '_\|$builtin'(\fIN1\fR\^).
.)l
where \fIN1\fR is the builtin number of the predicate \fInewbuiltin\fR,
obtained when installing the C code for the builtin (see above).
.np
Compile this Prolog predicate, using the simulator and the \fIcompile\fR
predicate, into a file \fInewbuiltin\fR (notice correspondence with the name of
the predicate being defined) in the SB-Prolog directory \fIlib\fR.
.sp
.fo ''''
.bp
.ce
\fBTABLE OF CONTENTS\fR
.sp
.xp c