
/* $Id: qint.c,v 1.3 2004/01/14 21:52:38 agraef Exp $

   Poor man's Q interpreter -- illustrates the use of the C->Q interface.
   This program just invokes a Q script with args as given on the command line
   (no additional options are recognized), then reads expressions and prints
   the evaluated results. Compile with (e.g.):

   GCC> gcc -o qint qint.c -lqint

   MSVC> cl qint.c libqint.lib

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <qint.h>
#ifdef DMALLOC
#include <dmalloc.h>
#endif

/* Here's a contrived and silly example showing how to invoke an inlined
   script using qexeclx() and then perform some evaluations. To enable this
   code, just uncomment the corresponding line in the main program below. */

void test(void)
{
  int status;
  char *t;
  qexpr x;

  /* Our little hello world script. */
  char *script = "hello = writes \"Hello, world!\\n\";";

  /* Load the script into the interpreter, also pass arguments (the first
     argument is always the (fake) script name which becomes ARGS!0). */
  qexeclx(script, strlen(script), 2, "Hello!", "Hello world example.");

  /* Just for fun, print the arguments passed to the script. (We don't do any
     error checking, since there's not much that can go wrong here.) */
  t = qeval("ARGS", &status);
  printf("ARGS ==> %s\n", t);
  free(t);

  /* Evaluate the `hello' function from the script and print the result. */
  t = qeval("hello", &status);
  printf("hello ==> %s\n", t);
  free(t);

  /* The following piece of code shows how to use qevalx() to evaluate a
     (binary) expression object created with libqint's expression construction
     operations. By these means we don't have to mess around with textual
     representations. This is the preferred method if you want to build the
     input expression directly from corresponding C data, and/or if you have
     to analyze the result expression with the inspection operations in order
     to, e.g., translate the result back to some C structure. In this example
     we just check that the returned result is (), meaning that the
     interpreter successfully executed the call to the builtin writes
     function. */

  /* Construct the function application `writes "Hello, world #2!\n"' and
     evaluate it. Note that the string value *must* be allocated dynamically
     since it is taken over by the interpreter (and freed automatically
     together with the rest of the input expression when qevalx() is finished
     with it). */

  x = qevalx(qmkapp(qmksym(qsym(writes)),
		    qmkstr(strdup("Hello, world #2!\n"))),
	     &status);

  /* Check the result. */
  if (status)
    printf("evalx() returned error code %d: %s\n", status,
	   qstrerror(status));
  else if (qisvoid(x))
    printf("writes was executed successfully\n");
  else {
    t = qprint(x, &status);
    printf("writes returned some unexpected value: %s\n", t);
    free(t);
  }

  /* Get rid of the result. */
  qdispose(x);

}

#define BUFSIZE 1024

int main(int argc, char **argv)
{
  int status;
  char s[BUFSIZE], *t;

  /* Change to `1' to run the example above. */
#if 0
  test();
#endif

  /* The main program begins here. First load the script with args as given on
     the command line. */

  if ((status = qexecv(argv[1], argc-1, argv+1))) {
    char msg[1000];
    sprintf(msg, qstrerror(status), argv[1]);
    fprintf(stderr, "Error starting interpreter: %d: %s\n", status, msg);
    exit(1);
  }

  /* The read/eval/print loop. */

  printf("%s loaded, ready to rumble!\n", argv[1]?argv[1]:"empty script");
  printf("\nin>  "); fflush(stdout);

  while (fgets(s, BUFSIZE, stdin)) {
    int l = strlen(s);

    if (l > 0 && s[l-1] == '\n')
      s[l-1] = 0;

    t = qeval(s, &status);

    if (status)
      printf("err> %d: %s\n", status, qstrerror(status));
    if (t) {
      printf("out> %s\n", t);
      free(t);
    }
    printf("\nin>  "); fflush(stdout);

  }

  printf("\n");
  exit(0);

}
