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.plfile 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.plTo 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
makeOnce compiled, run the generated binary to see the output of your Prolog queries:
./testIf 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.debugTo 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).