NAME
Inline::CLIPS - Perl interface to run CLIPS programs
SYNOPSIS
use Inline::CLIPS;
my $clips = Inline::CLIPS->new;
my $result = $clips->run_program(q{
(deftemplate animal (slot name) (slot class))
(deffacts initial (animal (name "penguin") (class bird)))
(defrule print-animal
(animal (name ?n) (class ?c))
=>
(printout t ?n " is a " ?c crlf))
}, '(run)');
print $result->{stdout};
warn $result->{stderr} if $result->{stderr};
exit $result->{status};
DESCRIPTION
Inline::CLIPS provides a small Perl API for executing CLIPS programs by wrapping a CLIPS executable. It does not embed a CLIPS engine; instead it writes a temporary .clp file and invokes the CLIPS interpreter with that file. The captured output, errors, and exit status are returned as a plain hash reference.
The module discovers the CLIPS executable in the following order:
The
executableargument passed tonew.The
INLINE_CLIPS_EXECUTABLEenvironment variable.A command named
clipsfound in$PATH.The binary directory reported by
Alien::CLIPS, if installed.
INSTALLATION
Installing the Perl module
The distribution follows the standard ExtUtils::MakeMaker build process:
perl Makefile.PL
make
make test
make install
Making CLIPS available to Perl
Inline::CLIPS needs a working CLIPS executable. You can make one available in any of these ways.
Option 1: Use a system CLIPS on $PATH
Install CLIPS from your operating system package manager, or build CLIPS from source and copy the clips binary into a directory on your $PATH. Once clips is executable and discoverable, Inline::CLIPS will find it automatically.
# Verify CLIPS is visible
which clips
clips -v
Option 2: Set INLINE_CLIPS_EXECUTABLE
If CLIPS is installed in a non-standard location, set the environment variable to the absolute path of the executable:
export INLINE_CLIPS_EXECUTABLE=/opt/clips/6.4.2/clips
perl my_script.pl
You can also set this in your Perl code before constructing the object:
$ENV{INLINE_CLIPS_EXECUTABLE} = '/opt/clips/6.4.2/clips';
my $clips = Inline::CLIPS->new;
Option 3: Use Alien::CLIPS
If this distribution is installed with its companion module Alien::CLIPS, the module will fall back to a CLIPS binary discovered through the Alien infrastructure. Alien::CLIPS can locate a system CLIPS installation or, when no system copy is found, build CLIPS from the FuzzyCLIPS source repository:
L<https://github.com/jtrujil43/FuzzyCLIPS>
Verifying the installation
use Inline::CLIPS;
my $clips = Inline::CLIPS->new;
die "CLIPS executable not found\n" unless $clips->executable;
my $result = $clips->run_program(q{
(printout t "CLIPS is available" crlf)
}, '(exit)');
print $result->{stdout};
METHODS
new(%args)
Constructor. Accepts the following optional arguments:
executable-
Path to the CLIPS executable. If omitted, the executable is discovered using the rules in "INSTALLATION".
library-
Path to the CLIPS shared library. This is exposed for callers that need to know where CLIPS libraries live; it is not used directly by the executable wrapper.
my $clips = Inline::CLIPS->new(
executable => '/usr/local/bin/clips',
);
executable
Returns the resolved path to the CLIPS executable, or the empty string if none was found.
my $path = $clips->executable;
library
Returns the resolved path to the CLIPS shared library, or the empty string if none was found. The library is resolved from the library constructor argument, the INLINE_CLIPS_LIB environment variable, or Alien::CLIPS.
my $lib = $clips->library;
run_program($program, @commands)
Executes an inline CLIPS program. The $program string is written to a temporary .clp file followed by (reset), each command in @commands, and finally (exit). Returns a hash reference:
{
status => 0, # CLIPS exit status
stdout => "...", # everything printed to STDOUT
stderr => "...", # everything printed to STDERR
}
my $result = $clips->run_program(q{
(deffacts numbers (number 1) (number 2) (number 3))
(defrule sum-numbers
(number ?n)
=>
(printout t "number: " ?n crlf))
}, '(reset)', '(run)');
run_file($file)
Executes an existing CLIPS source file. The file must exist and be readable. The CLIPS interpreter is invoked as clips -f2 $file.
my $result = $clips->run_file('src/main.clp');
This is useful for projects that already keep their rules, templates, and facts in separate .clp files. See "Running a real process-flow-check project" for a complete example.
ENVIRONMENT
INLINE_CLIPS_EXECUTABLE-
Full path to the CLIPS executable. Overrides the
$PATHsearch and theAlien::CLIPSfallback. INLINE_CLIPS_LIB-
Full path to the CLIPS shared library. Used by
library(). INLINE_CLIPS_BIN-
Directory containing the CLIPS binary. Consulted by
Alien::CLIPSwhen no system executable is found. ALIEN_CLIPS_LIB,ALIEN_CLIPS_BIN-
Fallback variables read by
Alien::CLIPS.
EXAMPLES
Basic inline program
use Inline::CLIPS;
my $clips = Inline::CLIPS->new;
my $result = $clips->run_program(q{
(deftemplate animal (slot name) (slot class))
(deffacts seed
(animal (name "penguin") (class bird))
(animal (name "salmon") (class fish)))
(defrule describe-animal
(animal (name ?n) (class ?c))
=>
(printout t ?n " is a " ?c crlf))
}, '(run)');
print $result->{stdout};
Running a real process-flow-check project
Suppose you have the process-flow-check CLIPS project at /home/jovan/devel/Clips_code/process-flow-check. It defines templates for flow-step, tool-capability, and violation, loads rules from src/core/*.clp, and provides a check-flow deffunction in src/io/run-validation.clp. You can drive that project from Perl with run_file or with a self-contained inline program.
Using run_file with the project loader
use Inline::CLIPS;
my $clips = Inline::CLIPS->new;
my $project_dir = '/home/jovan/devel/Clips_code/process-flow-check';
# CLIPS file paths are relative to its current directory, so run from there.
chdir $project_dir or die "Cannot chdir: $!";
my $result = $clips->run_file('src/main.clp');
print $result->{stdout};
warn $result->{stderr} if $result->{stderr};
Using an inline copy of the same rules
The project checks semiconductor-style process flows. The CLIPS snippet below is a self-contained, simplified version of the real rules that validates a short photolithography and poly-etch flow.
use Inline::CLIPS;
my $clips = Inline::CLIPS->new;
my $result = $clips->run_program(
q{
(deftemplate flow-step
(slot step-id (type INTEGER))
(slot step-name)
(slot layer)
(slot tool-id)
(slot recipe-id)
(slot queue-time-min (type INTEGER))
(slot max-wait-min (type INTEGER))
(slot rework-allowed (allowed-values TRUE FALSE))
(slot prev-step-id (type INTEGER) (default -1)))
(deftemplate tool-capability
(slot tool-id)
(slot allowed-layers)
(multislot allowed-recipes))
(deftemplate violation
(slot code)
(slot message)
(slot step-id)
(slot severity (allowed-values info warning error)))
(deffacts reference-capabilities
(tool-capability (tool-id CT-01) (allowed-layers PHOTO)
(allowed-recipes CT-PR-193))
(tool-capability (tool-id EX-05) (allowed-layers PHOTO)
(allowed-recipes EX-193-NA13))
(tool-capability (tool-id DEV-02) (allowed-layers PHOTO)
(allowed-recipes DEV-TMAH))
(tool-capability (tool-id INS-01) (allowed-layers PHOTO)
(allowed-recipes INS-BF))
(tool-capability (tool-id ETCH-07) (allowed-layers POLY)
(allowed-recipes ETCH-Cl2-BCl3)))
(defrule check-tool-layer
(flow-step (step-id ?id) (layer ?layer) (tool-id ?tool))
(tool-capability (tool-id ?tool) (allowed-layers ?allowed))
(test (neq ?layer ?allowed))
=>
(assert (violation (code CONS-001)
(message "Tool not qualified for layer")
(step-id ?id)
(severity error))))
(defrule check-queue-time
(flow-step (step-id ?id) (queue-time-min ?q) (max-wait-min ?m))
(test (> ?q ?m))
=>
(assert (violation (code TIME-001)
(message "Queue time exceeds maximum wait")
(step-id ?id)
(severity error))))
(deffunction print-report ()
(bind ?errs (find-all-facts ((?v violation)) TRUE))
(if (eq (length$ ?errs) 0)
then
(printout t "No violations found." crlf)
else
(printout t "Violations:" crlf)
(foreach ?vf ?errs
(printout t "[" (fact-slot-value ?vf code) "] @ step "
(fact-slot-value ?vf step-id) " — "
(fact-slot-value ?vf message) crlf))))
(deffacts current-flow
(flow-step (step-id 10) (step-name Coat) (layer PHOTO)
(tool-id CT-01) (recipe-id CT-PR-193)
(queue-time-min 10) (max-wait-min 60) (rework-allowed FALSE)
(prev-step-id -1))
(flow-step (step-id 20) (step-name Expose) (layer PHOTO)
(tool-id EX-05) (recipe-id EX-193-NA13)
(queue-time-min 12) (max-wait-min 60) (rework-allowed FALSE)
(prev-step-id 10))
(flow-step (step-id 30) (step-name Develop) (layer PHOTO)
(tool-id DEV-02) (recipe-id DEV-TMAH)
(queue-time-min 8) (max-wait-min 45) (rework-allowed FALSE)
(prev-step-id 20))
(flow-step (step-id 40) (step-name Inspect) (layer PHOTO)
(tool-id INS-01) (recipe-id INS-BF)
(queue-time-min 5) (max-wait-min 30) (rework-allowed TRUE)
(prev-step-id 30))
(flow-step (step-id 50) (step-name Etch) (layer POLY)
(tool-id ETCH-07) (recipe-id ETCH-Cl2-BCl3)
(queue-time-min 15) (max-wait-min 120) (rework-allowed FALSE)
(prev-step-id 40)))
},
'(reset)',
'(run)',
'(print-report)',
);
print $result->{stdout};
warn $result->{stderr} if $result->{stderr};
exit $result->{status};
DIAGNOSTICS
CLIPS executable is not available; set INLINE_CLIPS_EXECUTABLE or install CLIPS/Alien::CLIPS-
Thrown by
run_fileandrun_programwhen no CLIPS executable could be discovered. Follow the steps in "INSTALLATION". program text is required-
run_programwas called without a program string. file path is required/CLIPS file not found: ...-
run_filewas called with a missing, empty, or non-existent file path.
SEE ALSO
- Alien::CLIPS
-
Companion Alien module that can locate or build CLIPS.
- CLIPS home page
- FuzzyCLIPS source used by the Alien fallback
AUTHOR
Inline-CLIPS contributors.
LICENSE
This library is free software; you may redistribute it and/or modify it under the same terms as Perl itself.