Class Diagrams
Below are a series of class diagrams describing the architecture of the Projog project. The diagrams start with implementations of Term
, the low-level building blocks used to construct Prolog clauses, and finishes with ProjogConsole
, the console based application.
Terms
Terms are the building blocks used to construct Prolog programs and queries.

Implementations of the Term interface.
Atom
- Atoms are constant; their values cannot be changed after they are created. Atoms have no arguments.Structure
- Compound terms are represented in Projog by theStructure
implementation of theTerm
interface.Structure
objects consist of otherTerm
objects representing the compound term's arguments. As an argument of aStructure
can be anotherStructure
it is possible to use it to represent complex tree data structures. (Example of the "composite" design pattern.)List
- Represents Prolog lists - a specific type of compound term that has two arguments (a head and a tail).EmptyList
- Represents a list that contains no elements.Variable
- Has aTerm
member variable which provides a reference to the value theVariable
is currently instantiated to. When aVariable
is instantiated to anotherTerm
it delegates any method calls to it. To client code, aVariable
behaves just like theTerm
it is currently instantiated to. Over its lifetime aVariable
can be instantiated to a number of otherTerm
instances. (Example of the "state" design pattern.)Numeric
- Projog provides two number types -IntegerNumber
andDecimalFraction
both of which implement theNumeric
interface. TheIntegerNumber
class represents numbers using along
primitive and theDecimalFraction
class represents numbers using adouble
primitive.
Prolog Syntax Parser
ProjogSourceReader
populates a KnowledgeBase
with clauses constructed by a SentenceParser
from Prolog syntax contained in a text file.
SentenceParser
transforms Prolog syntax into Term
objects. SentenceParser
can parse pre-, post- and in-fix operands e.g. "p([X|Y], Z) :- Z < X+1, p(Y, X).
". SentenceParser
uses TokenParser
to retrieve Token
objects representing individual numbers, predicate names and seperators, etc. TokenParser
constructs the Token
objects from characters read from CharacterParser
.
CharacterParser
uses a java.io.BufferedReader
to read characters from a stream. CharacterParser
keeps track of the current line and column number being parsed - this is useful for producing descriptive messages when an error occurs during parsing. Errors are propagated up using a ParserException
- which takes a CharacterParser
as a constructor argument.

Structure of the classes used to parse Prolog code.
Built-in Predicates
Projog provides a number of built-in predicates. Built-in predicates are functionality that is implemented in Java rather than constructed from Prolog code. Built-in predicates make it possible to provide a convenient and efficient way of doing standard tasks - including functionality that is not possible using only pure Prolog syntax. New built-in predicates can be easily developed by Java developers and "plugged-in" to Projog - obeying the open/closed principle. See Adding Extra Functionality to Prolog Using Java.
A projog-bootstrap.pl file, containing Prolog syntax, is used to initialise new Projog instances. This mechanism promotes flexibility as the configuration of built-in predicates can be controlled without altering any Java code.
User Defined Predicates
User defined predicates are generated at runtime as a result of parsing Prolog code. User defined predicates can be static or dynamic. Unlike static predicates, dynamic predicates can have clauses added or removed after they are first defined.
DynamicUserDefinedPredicateFactory
is used to represent dynamic perdicates. StaticUserDefinedPredicateFactory
is used to represent static perdicates. For performance reasons StaticUserDefinedPredicateFactory
delegates to specialised implementations of PredicateFactory
. If a user-defined predicate is suitable for term indexing (a similar concept to indexing of relational detabases) then IndexablePredicateFactory
is used. If a user-defined predicate is tail-recursive then InterpretedTailRecursivePredicate
is used.

Implementations of the UserDefinedPredicateFactory interface.
Arithmetic Operators
Projog supports the common arithmetic operations. As with built-in predicates, new arithmetic operations can be easily developed by Java developers and "plugged-in" to Projog. See Adding New Arithmetic Operators to Prolog.

Implementations of the ArithmeticOperator interface.
Knowledge Base
KnowledgeBase
is the central object that connects the various components of an instance of the "core" inference engine.

The KnowledgeBase class and the components it is associated with.
Predicates
- A repository of user defined predicates (specified using Prolog syntax) and built-in predicates (implemented in Java).ArithmeticOperators
- A repository of arithmetic operators.FileHandles
- A repository of file handles used by predicates for reading and writing to files.ProjogListeners
- A repository ofProjogListener
objects that clients can register to recieve notifications of events.SpyPoints
- A repository ofSpyPoint
objects. Supports the debugging of Prolog queries.TermFormatter
- Used to produceString
representations ofTerm
instances.Operands
- A repository of operators used in the parsing and formatting of Prolog syntax. Prolog allows functors (names of predicates) to be defined as "operators". The use of operators allows syntax to be easier to read.ProjogProperties
- Used for configuration. Currently only used to provide the location of the bootstrap file.
Java API to Prolog inference engine
The Projog
class provides a single high-level entry point for Java applications to interface with an instance of a Prolog inference engine. By shielding client code from the low-level implementation of the "core" inference engine Projog
reduces coupling and makes the subsystem easier to use. (Example of the "facade" design pattern.)
The mechanism for evaluating Prolog queries is similar to Java's JDBC API used to query relational databases. QueryStatement
is similar to java.sql.PreparedStatement
. QueryResult
is similar to java.sql.ResultSet
. See Using Prolog in Java Applications.

The Projog API for calling Prolog from Java.
Console Application
The ProjogConsole
application allows Prolog developers to interact with the inference engine via a read-evaluate-print loop (REPL). ProjogConsole
uses a Projog
instance as a facade to the "core" inference engine. ProjogConsole
registers a LoggingProjogListener
so it can receive SpyPointEvent
objects in order to provide feedback to the user.

Structure of the console based application.