This guide provides instructions on setting up and using a partial Prolog compiler within the SWI-Prolog environment on Linux.
The compiler is designed to transpile Prolog code into C executables, for a very small subset of the Prolog language - enough to demonstrate unification and backtracking. This was built to demonstrate code running in both directions (append.pl
) and a program with multiple solutions using heavy backtracking (nqueens.pl
).
- SWI-Prolog
- GNU Make
- GCC compatible C Compiler:
clang
(generates the fastest code) orgcc
Before starting, you need to install the dcg4pt
package from within SWI-Prolog:
?- pack_install(dcg4pt).
Having dcg4pt
properly installed and working is essential before attempting to install or use additional tools like plammar
.
In order to ensure compatibility with newer versions of SWI-Prolog, you may need to edit the dcg4pt.pl
file:
-
Open the
dcg4pt.pl
file for editing:<EDITOR> ~/.local/share/swi-prolog/pack/dcg4pt/prolog/dcg4pt.pl
-
Locate the two spots where an unquoted comma
(,)
is used. Replace the unquoted comma with a quoted one(',')
to make the code compatible with SWI-Prolog. If you have difficulty finding them, continue the setup and come back and fix it when it breaks. -
Save the file and exit the editor.
After making the necessary edits to dcg4pt
, you can now proceed to install plammar
from within SWI-prolog:
?- pack_install(plammar).
Start by launching SWI-Prolog with your custom files:
This command loads the parser.pl
and compiler.pl
files, which are required for the compilation process.
swipl -l parser.pl -l compiler.pl
To compile a Prolog file to C, use the compile/2
predicate. It takes two arguments: the file name and a test query as a string.
Example:
?- compile(file("nqueens.pl"), string("queens(4, Q).")).
true.
You can modify the file and query string as needed for different predicates. Here are some sample queries:
% Sample queries
compile(file("append.pl"),string("append([1,2],[3,4],X).")).
compile(file("append.pl"),string("append([1,2],X,[1,2,3,4]).")).
compile(file("append.pl"),string("append(X,[1],[2]).")).
compile(file("append.pl"),string("append(X,[3,4],[1,2,3,4]).")).
compile(file("append.pl"),string("append(X,Y,[1,2,3,4]).")).
compile(file("nqueens.pl"),string("queens(1,Q).")).
compile(file("nqueens.pl"),string("range(1,4,X).")).
compile(file("nqueens.pl"),string("queens_aux([1],[],Q).")).
compile(file("nqueens.pl"),string("selectx(X,[1],Y).")).
compile(file("nqueens.pl"),string("selectx(X,[1],Y).")).
compile(file("selectx.pl"),string("selectx(X,[1,2,3,4],Y).")).
compile(file("selectx.pl"),string("selecty(X,[1,2,3,4],Y).")).
compile(file("nqueens.pl"),string("queens(4,Q).")).
The compilation process generates C files named PrologGenerated.h
which contains some macros, and PrologGenerated.c
which contains the translated code.
To inspect the generated file and compile it, run:
cat PrologGenerated.c
make
Once compiled, run the generated binary to see the output of your Prolog queries:
./test
If you want to use a debugger like gdb, or want to track down an error, it is possible to build and run a debug version:
make debug
./test.debug
To generate an execution trace, just change:
trace_mode :- fail.
to
trace_mode.
on about line 55 of compiler.pl
, then reload and rerun the transpiler, make the binary and run it.
The word size for integers and indicies such as variables, list entries and trail entries can be set to 16, 32 or 64 bits. To change this, set the value inside word_size
on about line 57 of compiler.pl
:
word_size(32).