topheader Welcome 3.133.152.95 @ xps.scios.ch on Fri Apr 19 0:10:23 UTC 2024
 
topheader
 

Section 5   Creating a CLIPS Run time Program

5.1 Compiling the Constructs

This section describes the procedure for creating a CLIPS run time module. A run time program compiles all of the constructs (defrule, deffacts, deftemplate, etc.) into a single executable and reduces the size of the executable image. A run-time program will not run any faster than a program loaded using the load or bload commands. The constructs-to-c command used to generate a run-time program creates files containing the C data structures that would dynamically be allocated if the load; or bload command was used. With the exception of some initialization routines, the constructs-to-c command does not generate any executable code. The primary benefits of creating a run-time program are: applications can be delivered as a single executable file; loading constructs as part of an executable is faster than loading them from an text or binary file; the CLIPS portion of the run-time program is smaller because the code needed to parse constructs can be discarded; and less memory is required to represent your program’s constructs since memory for them is statically rather than dynamically allocated.


Creating a run time module can be achieved with the following steps:


1) Start CLIPS and load in all of the constructs that will constitute a run time module. Call the constructs to c command using the following syntax:


(constructs to c <file name> <id> [<max-elements>])


where <file name> is a string or a symbol, <id> is an integer, and the optional argument <max-elements> is also an integer. For example, if the construct file loaded was named “expert.clp”, the conversion command might be


(constructs to c exp 1)


This command would store the converted constructs in several output files (“exp1_1.c”, “exp1_2.c”, … , “exp7_1.c”) and use a module id of 1 for this collection of constructs. The use of the module id will be discussed in greater detail later. Once the con­version is complete, exit CLIPS. For large systems, this output may be very large (> 200K). It is possible to limit the size of the generated files by using the <max elements> argument. This argument indicates the maximum number of structures which may be placed in a single array stored in a file. Where possible, if this number is exceeded new files will be created to store additional information. This feature is useful for compilers that may place a limitation on the size of a file that may be compiled.


Note that the .c extension is added by CLIPS. When giving the file name prefix, users should consider the maximum number of characters their system allows in a file name. For example, under MS DOS, only eight characters are allowed in the file name. For very large systems, it is possible for CLIPS to add up to 5 characters to the file name prefix. Therefore, for system which allow only 8 character file names, the prefix should be no more than 3 characters.


Constraint information associated with constructs is not saved to the C files generated by the constructs-to-c command unless dynamic constraint checking is enabled (using the set-dynamic-constraint-checking command).


The constructs to c command is not available in the standard CLIPS distribution executable. Users wishing to create a run-time program must recompile CLIPS to include this capability (see section 2.2 for information on tailoring CLIPS and the CONSTRUCT_COMPILER setup flag).


2) Set the RUN_TIME setup flag in the setup.h header file to 1 and compile all of the c files just generated.


3) Modify the main.c module for embedded operation. Unless the user has other specific uses, the argc and argv arguments to the main function should be elimi­nated. The function InitializeEnvironment should not be called. Also do not call the CommandLoop or RerouteStdin functions which are normally called from the main function of a command line version of CLIPS. Do not define any functions in the UserFunctions function. The function UserFunctions is not called during initialization. All of the function definitions have already been compiled in the 'C' constructs code. In order for your run-time program to be loaded, a function must be called to initialize the constructs module. This function is defined in the 'C' constructs code, and its name is dependent upon the id used when translating the constructs to 'C' code. The name of the function is InitCImage_<id> where <id> is the integer used as the construct module <id>. In the example above, the function name would be InitCImage_1. The return value of this function is a pointer to an environment (see section 9) which was created and initialized to contain your run-time program. This initialization steps probably would be followed by any user initialization, then by a reset and run. Finally, when you are finished with a run-time module, you can call DestroyEnvironment to remove it. An example main.c file would be


#include <stdio.h>
#include “clips.h”

main()
{

void *theEnv;


theEnv = InitCImage_1();


• /* Any user Initialization */

EnvReset(theEnv);

EnvRun(theEnv,-1);


• /* Any other code */

DestroyEnvironment(theEnv);
}


UserFunctions()
{

/* UserFunctions is not called for a run-time version. */

}


4) Recompile all of the CLIPS source code (the RUN_TIME flag should still be 1). This causes several modifications in the CLIPS code. The run time CLIPS module does not have the capability to load new constructs. Do NOT change any other compiler flags! Because of the time involved in recompiling CLIPS, it may be appropriate to recompile the run time version of CLIPS into a separate library from the full ver­sion of CLIPS.


5) Link all regular CLIPS modules together with any user defined function modules and the 'C' construct modules. Make sure that any user-defined functions have global scope. Do not place the construct modules within a library for the purposes of linking (the regular CLIPS modules, however, can be placed in a library). Some linkers (most notably the VAX VMS linker) will not correctly resolve references to global data that is stored in a module consisting only of global data.


6) The run time module which includes user constructs is now ready to run.


Note that individual constructs may not be added or removed in a run time environment. Because of this, the load function is not available for use in run-time programs. The clear command will also not remove any constructs (although it will clear facts and instances). Use calls to the InitCImage­_… functions to clear the environment and replace it with a new set of constructs. In addition, the eval and build functions do not work in a run time environment.


Since new constructs can’t be added, a run-time program can’t dynamically load a deffacts or definstances construct. To dynamically load facts and/or instances in a run-time program, the CLIPS load-facts and load-instances functions or the C LoadFacts and LoadInstances functions should be used in place of deffacts and definstances constructs.


Important Note

In prior versions of CLIPS, it was possible to switch between different images by calling the InitCImage function of the desired run-time program while execution was halted. This mechanism is no longer available. Each call to separate InitCImage functions creates a unique environment into which the run-time program is loaded. You can thus switch between various runtime programs by using the environment API to specify which environment is the target of a command. Also note that only the first call to a given InitCImage function will create an environment containing the specified run-time program. Subsequent calls have no effect and a value of NULL is returned by the function. Once the DestroyEnvironment function has been called to remove an environment created by an InitCImage call, there is no way to reload the run time program.


Section 6   Combining CLIPS with Languages Other Than C

CLIPS is developed in C and is most easily combined with user functions written in C. However, other languages can be used for user defined functions, and CLIPS even may be embedded within a program written in another language. Users wishing to embed CLIPS with Ada should consider using CLIPS/Ada (see the CLIPS/Ada Advanced Programming Guide).

6.1 Introduction

This section will describe how to combine CLIPS with Ada or FORTRAN routines. Specific code examples will be used to illustrate the con­cepts. The code used in these examples is valid for VAX VMS systems which have the DEC C compiler, the DEC FORTRAN compiler, and the DEC Ada compiler.


Three basic capabilities are needed for complete language mixing.


• A program in another language may be used as the main program.


• The C access functions to CLIPS can be called from the other language and have parameters passed to them.


• Functions written in the other language can be called by CLIPS and have parameters passed to them.


The integration of CLIPS (and C) with other languages requires an understanding of how each language passes parameters between routines. In general, interface functions will be needed to pass parameters from C to another language and from another language to C. The basic concepts of mixed language parameter passing are the same regardless of the language or machine. However, since every machine and op­erating system passes parameters differently, specific details (and code) may differ from machine to machine. To improve usability and to minimize the amount of recoding needed for each ma­chine, interface packages can be developed which allow user routines to call the standard CLIPS embedded command functions. The details of passing information from external routines to CLIPS generally are handled inside of the interface package. To pass parameters from CLIPS to an external routine, users will have to write inter­face functions. Example interface packages for VMS FORTRAN and VMS Ada to selected CLIPS functions are listed in appendix A. Section 6.9 will discuss how to construct an interface package for other machines/compilers.

6.2 Ada and FORTRAN Interface Package Function List

The Ada and FORTRAN interface packages in appendix A provide many of the embedded CLIPS commands discussed in section 4 of this manual. Each function in the interface package prepends an x to the beginning of the corresponding C function name. A list of the C functions and their FORTRAN or Ada corollaries which are provided in the interface packages listed in the appendices appears below.


| C Function | Ada/FORTRAN Function |

InitializeEnvironment xInitializeEnvironment
Reset xReset
Load xLoad
Run xRun
Facts xFacts
Watch xWatch
Unwatch xUnwatch
AssertString xAssertString
Retract xRetract
PrintRouter xPrintRouter
FindDefrule xFindDefrule
Undefrule xUndefrule


The arguments to these functions are the same as described in section 4, however, the corresponding data type in either Ada or FORTRAN should be passed as a parameter. For example, when using Ada, the function xLoad should be passed an Ada string, not a C string (the function xLoad will perform the conversion). FORTRAN function names defined above do not follow ANSI 77 name standards. The VMS FORTRAN implementation described in this section allows long function names.

6.3 Embedded CLIPS   Using an External Main Program

Any program may be used as the main program for embedded CLIPS application;s. The main program works essentially the same as in C.

Example Ada Main Program

with CLIPS; use CLIPS;


with TEXT_IO; use TEXT_IO;


procedure MAIN is


File_Name : string (1..50);

File_Open_Status : integer;

Rules_Fired : integer;


begin


xInitializeEnvironment;


File_Name (1..7) := “mab.clp”;

– Load rules

File_Open_Status := xLoad (File_Name);


if File_Open_Status = 1 then

xReset;

Rules_Fired := xRun (-1);

PUT (integer'IMAGE (Rules_Fired));

PUT_LINE (“ Rules Fired”);

else

PUT_LINE (“Unable to open rules file”);

end if;


end MAIN;

Example FORTRAN Main Program

PROGRAM MAIN

C

INTEGER xLoad, FILE_OPEN_STATUS

CHARACTER *8 FILE_NAME

INTEGER xRun, RULES_FIRED

C

CALL xInitializeEnvironment

C

FILE_NAME = 'mab.clp'

FILE_OPEN_STATUS = xLoad (FILE_NAME)


IF (FILE_OPEN_STATUS .EQ. 1) THEN

CALL xReset

RULES_FIRED = xRun (-1)

WRITE (6,100) RULES_FIRED

ELSE

WRITE (6,101)

END IF


100 FORMAT (I8,' RULES FIRED')

101 FORMAT (' UNABLE TO OPEN RULES FILE')

STOP

END


SUBROUTINE UserFunctions

RETURN

END

6.4 Asserting Facts into CLIPS

An external function may assert a fact into CLIPS by calling xAssertString. External functions also may retract a fact previously asserted from outside of CLIPS. Note that the parameter passed to xRetract must have been received from a call to xAssertString. Any other value will cause unpredictable results.

Ada Example

Fact_Pointer : integer;
Not_Previously_Retracted : boolean;

Fact_Pointer := xAssertString (“dummy hello”);
Not_Previously_Retracted := xRetract (Fact_Pointer);

FORTRAN Example

CHARACTER *20 FACT_STRING

INTEGER xAssertString, FACT_POINTER
INTEGER xRetract, NOT_PREVIOUSLY_RETRACTED

FACT_STRING = 'dummy hello'
FACT_POINTER = xAssertString (FACT_STRING)
NOT_PREVIOUSLY_RETRACTED = xRetract (FACT_POINTER)

6.5 Calling a Subroutine from CLIPS

Like any other user defined functions, subroutines written in other languages may be called from CLIPS. Depending on the language, the return value from the function call may or may not be useful. For example, most FORTRAN imple­mentations allow a return value from a function but not from a subroutine. In these in­stances, the subroutine may be called for side effect only. As with defined functions written in C, the user must create an entry in UserFunctions for the subroutine (see section 3.1;). An extern defi­nition also must appear in the same file as the UserFunctions function, defining the type of data that the function will return. If the function does not return a value (Ada procedures or FORTRAN subroutines), it should be defined as returning a void value. See section 3.1 for the allowed return values for user defined functions.

Ada Example

1:procedure DISPLAY is
2:   Standard Ada definitions and declarations
3:begin
4:  
5:   Any kind of normal Ada code may be used
6:  



7:  
8:end DISPLAY;

FORTRAN Example

subroutine display
C
C Any kind of normal FORTRAN code may be used
C



C
return
end

UserFunctions entry for either example

extern void display();

UserFunctions()
{
DefineFunction(“display”,'v',PTIF display,“display”);



/* Any other user-defined functions. */



}

6.6 Passing Arguments from CLIPS to an External Function

Arguments may be passed from CLIPS to an external function. CLIPS does not actually pass arguments to the function; instead arguments must be pulled from internal CLIPS buffers by using the functions described in section 3. Although the argument access functions could be called directly from Ada or FORTRAN, it probably is easier to write an interface function in C. CLIPS will call the C routine, which gathers the arguments and passes them in the proper manner to the external sub­program.


In this situation, the user must ensure argument compatibility. In particular, string vari­ables must be converted from C arrays to FORTRAN or Ada string descriptors. The actual code used in the interface routine for argument conversion will depend on the language. Examples are given below for Ada and FORTRAN. Each example assumes the subroutine is called as follows:


(dummy 3.7 “An example string”)

VMS Ada Example

Note the procedure definition in line 2 of the Ada routine. The numerical value is defined as an IN OUT type and the string as an IN. Also note the compiler PRAGMA on line 4 5. PRAGMA is DEC Ada specific, and a similar statement will be needed for other compil­ers. Following the Ada routine is an example of a C interface function that calls the Ada sub­routine. The C routine must convert a C string into an Ada string descriptor using the MakeStringDsc (see section 6.7 for more on string conversion) function as shown in line 16 of the C routine. Note that the C function passes the address of the numerical parameters to the Ada subprogram (line 16) and a pointer to a descrip­tor for the string parameter. Note also that the UserFunctions definition (lines 21 24) calls the dummy C routine, not the Ada pro­gram.


package DUMMY_PKG is
procedure DUMMY (Value : in out float ;
Name : in string);

(The following two lines are DEC Ada specific)

pragma EXPORT_PROCEDURE (DUMMY
PARAMETER_TYPES ⇒ (float,string));

end DUMMY_PKG;

   Ada interface to CLIPS internal functions, see Appendix A
with CLIPS_INTERNALS; use CLIPS_INTERNALS;


PACKAGE Dummy_PKG IS

package body DUMMY_PKG is

procedure DUMMY (Value : in out float ;
Name : in string) is

begin
   Value and Name may be used as normal Ada variables.

– Name should not be modified by this procedure since

– it has a direct pointer to a CLIPS C string.

end DUMMY;

end DUMMY_PKG;

C interface routine

#include <stdio.h>
#include “clips.h”


(The following two lines are VAX VMS specific)

#include <descrip.h>
struct dsc$descriptor_s *MakeStringDsc();

c_dummy()
{
double value;
char *name;
extern int dummy();

value = RtnDouble(1);
name = RtnLexeme(2);

dummy(&value, MakeStringDsc(name));

return(0);
}

UserFunctions()
{
DefineFunction(“dummy”, 'i', c_dummy, “c_dummy”);
}

VMS FORTRAN Example

The VMS FORTRAN routine looks very similar to the Ada routine and, in fact, uses the same C interface function listed for VMS Ada.


subroutine dummy(value, name)
C
REAL value
CHARACTER *80 name
C
C value and name may now be used as normal FORTRAN variables
C



C
return
end


Note that the previous two examples performed the string conversion in C, not in the language (Ada or FORTRAN) to which the string was being passed. On some machines, it may be easier to convert the string in the language (Ada or FORTRAN) to which the string is being passed rather than in the language (C) from which the string is being passed.

6.7 String Conversion

Much of the information that needs to be passed between CLIPS and another lan­guage typically is stored as strings. The storage of string variables can differ radically between languages. Both Ada and FOR­TRAN use a special (machine dependent) string descriptor for string data types, whereas C uses simple arrays. Because of this difference, special functions must be de­fined to convert FORTRAN or Ada strings to C strings and back. The implementation of these functions will be different for every lan­guage and computer. Typically, two functions are needed: one to convert an Ada or a FORTRAN string to a C string, and one to convert a C string to an Ada or a FORTRAN string descriptor. When converting C strings that have been provided by CLIPS to strings suitable for other languages, do not modify the original C string. The following table shows the string conversion routines provided in the interface packages in appendix A.


| Environment | Function to Convert TO a C string | Function to Convert FROM a C string |

VMS Ada ADA_TO_C_STRING MakeStringDsc
VMS FORTRAN CONVERT_TO_C_STRING MakeStringDsc


The interface package does all of the converting from Ada or FORTRAN strings to C strings. Users will have to convert from C when defining functions that are passed parameters from CLIPS. Appendix A.3 has a listing for a function that will convert C strings to Ada or FORTRAN character strings under VAX VMS.

6.8 Compiling and Linking

After all routines are defined, they must be compiled and linked to execute. The man­ner of compilation will depend on the machine on which the user is working. Two examples are given below: one for VMS Ada and one for VMS FORTRAN.

6.8.1 VMS Ada Version

1) Copy all of the CLIPS include files and Ada interface package to the user directory.


$copy [{CLIPS master directory}]*.h [{user directory}]

$copy [{CLIPS master directory}]*.ada [{user directory}]


2) Create an object file from the file holding the UserFunctions definition.


$cc usrfuncs.c


3) Set up the Ada library and compile the Ada routine(s).


$acs create library [{user directory}.adalib]

$acs set library [{user directory}.adalib]

$ada {Ada files, including the interface packages}


4) Export the Ada object code from the DEC ACS library.


$acs export/main {Ada files, including the interface package}


5) Define the link libraries and link all of the files together. Note that, prior to linking, each user must define the standard link libraries with the define lnk$library command. This usually is done once in the login.com file during login. This definition may be different for each VMS system.


$link/executable={exec name} {Ada files}, usrfuncs, [{CLIPS master di­rectory}] clipslib/library


This will create an embedded version of CLIPS using an Ada routine as the main pro­gram. To create a program that uses the CLIPS interface but calls Ada subprograms, modify step 4 to read


$acs export {user's Ada packages}


5) Copy the CLIPS main.c file from the CLIPS master directory and remove the UserFunctions definition from the CLIPS main.c routine. Then recompile


$cc main


6) Link with the following command:


$link/executable={exec name} {Ada files}, main, usrfuncs , [{CLIPS master directory}] clipslib/library

6.8.2 VMS FORTRAN Version

1) Copy all of the CLIPS include files to the user directory.


$copy [{CLIPS master directory}]*.h [{user directory}]


2) Create an object file from the file holding the UserFunctions definition.


$cc usrfuncs.c


3) Compile the FORTRAN routine(s).


$fortran {FORTRAN files}


4) Link all of the files together.


$link/executable={exec name} {FORTRAN files}, usrfuncs, [{CLIPS master directory}] clipslib/library, clipsforlib/library


Note that one of the FORTRAN programs must be a main program.

6.8.3 CLIPS Library

All of the previous examples assume a CLIPS library has been created on the user's ma­chine. A CLIPS library can be made with any standard object code library pro­gram and should include all of the CLIPS object code files except the main.c file. A library also may be made for the interface packages.

6.9 Building an Interface Package

To develop an interface package for CLIPS and FORTRAN, Ada, or any other lan­guage, the primary need is the string conversion routines. Once these have been developed, the rest of the interface package should look very similar to the examples shown in appendices A.1 to A.3. The majority of the conversion work should be done in the interface package. Note that if a CLIPS function takes no arguments then it is not necessary to write an interface function for it. For example, the function ListFacts takes no arguments and has no return value and can therefore be called directly (however, some languages, such as Ada, will require the function to be declared). The Ada listing in appendix A.1 use pragmas to map the C ListFacts function to the Ada xListFacts function (for consistency with the other functions which are proceeded by an x). The FORTRAN listings in appendix A include interface routines to function which do not require them as well. The functions listed in appendix A also directly mimic the equivalent C functions. That is, functions which return the integer 0 or 1 in C have the exact same value returned by their Ada and FORTRAN counterparts (rather than a boolean or logical value). It would normally be more useful to directly map these integers values into their boolean counterparts (TRUE or FALSE) in the other language.

 
 
clips/apg3.txt · Last modified: 2010/01/04 20:31 by admin
topheader
© 1998-2021, SciOS Scientific Operating Systems GmbH

Legal | Credits | Profile | Contact | Customer Login