How to return values or objects in CLIPS from a C function?
Hi. I am trying to combine CLIPS with C functions that I will then call from Swift. My idea is to pass commands as parameters to C functions, perform operations with CLIPS inside those C functions and then return results from those C functions to Swift. My first approach is this (apologies in advance for my lack of knowledge of CLIPS and certainly of C):
char * test_clips(char *command) {
CLIPSValue cv;
Environment *env;
StringBuilder *sb;
char *out = NULL;
env = CreateEnvironment();
sb = CreateStringBuilder(env, 1024);
// The file hello.clp must be in the same directory
// as the CLIPS executable or you must specify the
// full directory path as part of the file name.
//Load(env, "hello.clp");
//Reset(env);
//Run(env, -1);
Build(env, "(defrule hello => (println \"Hello World!\"))");
//Build(env, "(+ 3 4)");
Eval(env, "(reset)", &cv);
Eval(env, "(run)", &cv);
SBAppend(sb, cv.lexemeValue->contents);
if (cv.header->type == SYMBOL_TYPE) {
SBAppend(sb, cv.lexemeValue->contents);
} else {
SBAppend(sb, "No hay saludo!...");
}
out = SBCopy(sb);
SBDispose(sb);
DestroyEnvironment(env);
return out;
}
But when I execute this code it does not return the message, what am I doing wrong? Greetings.
I am trying to make calls from Swift to C functions with internal CLIPS statement passing own commands and that those functions return results the ones processed by CLIPS.
When you call Eval, the return value of the command/function you specify, is stored in CLIPSValue parameter you supply. In your code, the last Eval call executes the (run) command and stores the value in the variable cv. The (run) command has no return value, so there's nothing meaningful that's going to be stored in the variable cv. I'm sure there are some programming languages that are exceptions, but generally printing is a side effect of functions that print; what's printed is not used as the return value of the function. So there's nothing set up in CLIPS that grabs the output of println statements in rules and uses this as the return value of the run command.
I've added some sample code that shows two different mechanisms for transferring data out of CLIPS. One is adding a user defined function which you can use to call out from the actions of a rule. The other shows how you can pass information back by storing it in facts.
main.c:
#include "clips.h"
int main(
int argc,
char *argv[])
{
Environment *env;
CLIPSValue cv, sv;
env = CreateEnvironment();
Build(env,"(deftemplate message (slot value))");
Build(env,"(defrule hello => (myfun \"User Function Callout\"))");
Build(env,"(defrule goodbye => (assert (message (value \"Fact Slot Retrieval\"))))");
Eval(env,"(reset)",NULL);
Eval(env,"(run)",NULL);
Eval(env,"(find-all-facts ((?f message)) TRUE)",&cv);
if (cv.header->type == MULTIFIELD_TYPE)
{
for (size_t i = 0; i < cv.multifieldValue->length; i++)
{
if (cv.multifieldValue->contents[i].header->type == FACT_ADDRESS_TYPE)
{
Fact *theFact = cv.multifieldValue->contents[i].factValue;
FactSlotValue(env,theFact,"value",&sv);
if (sv.header->type == STRING_TYPE)
{ printf("%s\n",sv.lexemeValue->contents); }
}
}
}
DestroyEnvironment(env);
return -1;
}
userfunctions.c:
#include "clips.h"
void UserFunctions(Environment *);
void MyFunFunction(Environment *,UDFContext *,UDFValue *);
void UserFunctions(
Environment *env)
{
AddUDF(env,"myfun","v",1,1,"s",MyFunFunction,"MyFunFunction",NULL);
}
void MyFunFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UDFValue theArg;
const char *theString;
if (! UDFFirstArgument(context,STRING_BIT,&theArg))
{ return; }
theString = theArg.lexemeValue->contents;
printf("%s\n",theString);
}
Output:
User Function Callout
Fact Slot Retrieval