Richard Meyer							March 31st 1993






			Calling Wild-LIFE from C.
			=========================




1- Description:
---------------

This command string-based interface provides a small but powerful means of
calling the Wild-LIFE interpreter from within C programs.

Routines are provided to:
	- state facts,
	- issue queries,
	- recover results,
	- extract data from psi-terms,
	- manipulate the current query status of Wild-LIFE:
		- generate more solutions,
		- reset the system.

The interface behave in pretty much the same way as the top-level of the
Wild-LIFE interpreter, so being familiar with the interpreter (and needless to
say, the LIFE programming language) is necessary, but this also makes the
interface very easy to use.

No means are provided to build psi-terms directly other than through successive
queries.



2- A simple example: "Hello World":
-----------------------------------

	#include "c_life.h"

	main(int argc, char *argv[])
	{
	  WFInit(argc,argv);
	  WFProve("write(\042Hello World!!\042)?");
	}


compile with:
	> cc -o hello hello.c c_life.a -lm -lX11
and execute:
	> hello
	Hello World!!
	>



3- Summary of functions and prototypes:
---------------------------------------

- Initialize Wild-LIFE
	void WFInit(int argc,char *argv[])

- Submit a query:
	int WFInput(char *query);

- Get a variable's value:
	PsiTerm WFGetVar(char *name);

- Get the type of a psi-term:
	char *WFType(PsiTerm psi);

- Get the value of a psi-term if it's a double:
	double WFGetDouble(PsiTerm psi, int *ok);

- Get the value of a psi-term if it's a string:
	char *WFGetString(PsiTerm psi, int *ok);

- Count the features of a psi-term:
	int WFFeatureCount(PsiTerm psi);

- Get the value of a feature:
	PsiTerm WFGetFeature(PsiTerm psi, char *featureName);

- Get all the feature names as a NULL-terminated array of strings:
	char **WFFeatures(PsiTerm psi);

- Prove a goal and report an error on failure:
	WFProve(char *goal);

This is a macro defined as:

	#define WFProve(A) { if(!WFInput(A)) \
	  fprintf(stderr,"%s failed (%s, line %d)\n",A,__FILE__,__LINE__); }

Warning: In case of failure it could cause its argument to be re-evaluated.



4- Memory management:
---------------------

As LIFE is a non-deterministic programming language, it is best to view it as a
task running in parallel that one is communicating with and whose state may be
very different from the calling C program.

Wild-LIFE uses its own memory management scheme (with garbage collection). At
each call to 'WFInput' the interpreter changes state, and may completely re-map
its memory layout, thus rendering obsolete any C variables pointing into the
LIFE memory space.

An example of dangerous programming:

	PsiTerm a;
	double n;
	WFProve("A=123?");
	a=WFGetVar("A");
	WFProve("B=fact(A)?"); /* Might cause a call to the GC */
	n=WFGetDouble(a,NULL); /* Random results - might even crash */

However, thanks to the garbage collector, it is not necessary for the C program
to worry about freeing memory in the LIFE space (in fact, doing so would
corrupt the integrity of the system). Currently the only function requiring the
C programmer to free memory is 'WFGetFeatures' which allocates an string array
of strings in LIFE space. The string array has to be freed (NOT the strings
within it).



5- An exhaustive example:
-------------------------

The following example displays the correct (and short-cut) use of all the
current features of the interface. Read it carefully as some of these are not
documented elsewhere.

The program generates the following output:

	> cc -g -o demo demo.c /udir/rmeyer/LIFE/MODULE/c_life.a -lm -lX11
	> demo
	Welcome to Wild-LIFE!!
	WFInput succeeded and there may be more answers
	true=false? failed (demo.c, line 51)
	C=4
	1
	2
	3
	4
	; failed (demo.c, line 69)
	6
	7
	message(three+four,equals => 7)
	The type of A is user#message
	A has 2 features
	sum=7
	the first feature is: 'three+four'
	feature 1 => built_in#string
	feature equals => built_in#int
	Linking X library...
	ok
	% here it runs the 'queens' program...


The program: "demo.c"

/* Example C program calling Wild-LIFE */
#include "/udir/rmeyer/LIFE/MODULE/c_life.h"



main(argc,argv)

     int argc;
     char *argv[];

{
  int ans;
  
  PsiTerm a;
  PsiTerm sum;
  char **features;
  int i;
  double value;
  int ok;
  

  
  /*** Initialize Wild-LIFE ***/
  WFInit(argc,argv); /* Currently doesn't really use the arguments */


  
  /*** Submit a query ***/
  /* \042 is a quote sign (") */
  ans=WFInput("write(\042Welcome to Wild-LIFE!!\042),nl?");
  
  /* Deal with Wild-LIFE response */
  switch(ans) {

  case WFno:
    printf("WFInput failed\n");
    break;
    
  case WFyes :
    printf("WFInput succeeded\n");
    break;

  case WFmore:
    printf("WFInput succeeded and there may be more answers\n");
    break;
  }


  
  /*** This MACRO displays an error message if the query fails ***/
  WFProve("true=false?");


  
  /*** Solve a simple constraint ***/
  WFProve("A=B+C?");
  WFProve("B=1?");
  WFProve("A=5?");
  WFProve("write('C=',C),nl?");
  WFProve(".");


  
  /*** Back-track over 4 solutions ***/
  WFProve("A={1;2;3;4},write(A),nl?");
  WFProve(";");
  WFProve(";");
  WFProve(";");
  WFProve(";"); /* No more at this point */

  
  
  /*** Back-track over only the first 2 solutions ***/
  WFProve("A={6;7;8},write(A),nl?");
  WFProve(";");
  WFProve("."); /* Return to top level */


  
  /*** Build a psi-term and query it ***/
  WFProve("A=message(\042three+four\042,equals => 3+4),write(A),nl?");

  /* Read the variable 'A' */
  a=WFGetVar("A");
  if(!a) { /* Error checking, here for demonstration only */
    fprintf(stderr,"Couldn't read variable 'A'\n");
    exit(1);
  }

  /* Print the type of 'A' */
  printf("The type of A is %s\n",WFType(a));

  /* Get the number of features of 'A' */
  printf("A has %d features\n",WFFeatureCount(a));

  /* Get the feature 'equals' */
  sum=WFGetFeature(a,"equals");
  if(!sum) { /* Error checking, here for demonstration only */
    fprintf(stderr,"Couldn't read feature 'equals'\n");
    exit(1);
  }

  /* Get the value of 'sum' */
  value=WFGetDouble(sum,&ok);
  if(!ok) { /* Error checking, here for demonstration only */
    fprintf(stderr,"'sum' is not a real number\n");
    exit(1);
  }
  printf("sum=%lg\n",value);

  /* Get the first feature */
  /* You can use NULL in WFGetDouble and WFGetString if you are sure the
     psi-term effectively contains a value of the correct type. */
  printf("the first feature is: '%s'\n",
	 WFGetString(WFGetFeature(a,"1"),NULL));
  
  /* Get the features as a NULL terminated string array */
  features=WFFeatures(a);
  if(features) {
    for(i=0;features[i];i++) {
      printf("feature %s => %s\n",
	     features[i],
	     WFType(WFGetFeature(a,features[i])));
    }
    free(features); /* Recommended */
  }
  else { /* Error checking, here for demonstration only */
    fprintf(stderr,"'A' has no features\n");
    exit(1);
  }
  
  
  /* Run the queens program */
  WFProve("link_x?");
  WFProve("write(ok),nl?");
  WFProve("load(\042/udir/dumant/NolistDemos/queens.lf\042)?");
  WFProve("queens?");

  /* Loop over each solution */
  do {
    sleep(1);
    printf("retrying\n");
    ans=WFInput(";");
    printf("ans=%d\n",ans);
  } while(ans);
}

