/* runtime.c - (c) 1998 Peter Selinger - Version 1.3 */

#include <stdio.h>

int verbose=0;

/* issues a runtime error and aborts execution. */
void runtimeerr(char *s) {
  fprintf(stderr, "Runtime Error: %s.\n", s);
  exit(1);
}

/* converts an integer to a string. */
char *int2str(int n) {
  char *str;
  if ((str=(char *) calloc(15,sizeof(char)))==NULL)
    runtimeerr("out of memory");
  sprintf(str, "%d", n);
  return str;
}

/* writes the string s to standard output. */
void output(char *s) {
  printf(verbose ? "Output: %s\n\n" : "%s\n", s);
}

/* allocates n consecutive words on the heap and returns a pointer to them. */
void **alloc(int n) {
  void **pt;
  if ((pt=(void **) calloc(n,sizeof(void *)))==NULL)
    runtimeerr("out of memory");
  return pt;
}

#define MAXSTACK 100
void *stack[MAXSTACK];
int sp=0;

/* tests whether the stack is empty. */
int stackempty() {
  return sp==0;
}

/* returns the current size of the stack. */
int stackheight() {
  return sp;
}

/* pop data from the stack. */
void *pop() {
  if (sp<=0)
    runtimeerr("stack underflow");
  return stack[--sp];
}

/* push data to the stack. */
void push(void *x) {
  if (sp>=MAXSTACK)
    runtimeerr("stack overflow");
  stack[sp++]=x;
}

/* gets the n-th element from the stack, where n=0 is the topmost element. */
void *getstack(int n) {
  if (n<0 || n>=sp)
    runtimeerr("illegal stack read access");
  return stack[sp-1-n];
}

/* sets the n-th element of the stack to x. */
void modifystack(int n,void *x) {
  if (n<0 || n>=sp)
    runtimeerr("illegal stack write access");
  stack[sp-1-n]=x;
}

/* creates a new stack closure from the current stack, resets the stack, and
returns a pointer to the new closure. */
void **savestack() { 
  void **tmp;
  int i;

  /* build stack closure */
  tmp=alloc(sp+1);
  tmp[0]=(void *)sp;
  for (i=0; i<sp; i++)
    tmp[i+1]=stack[i];
  if (verbose)
    printf("New stack closure: %x\n\n", tmp);

  /* erase old stack */
  sp=0;
  return tmp;
}

/* restores the stack from the stack closure found at addr. */
void loadstack(void **addr) {
  int i;

  sp=(int)addr[0];
  if (sp<0 || sp>MAXSTACK)
    runtimeerr("bad stack closure");
  for (i=0; i<sp; i++)
    stack[i]=addr[i+1];
}

void printstack() {
  int i;

  for (i=sp-1; i>=0; i--)
    printf("%d%s", stack[i], (i==0)?"":", ");
  printf("\n\n");
}

char *myname;

void usage(int ec) {
  fprintf(stderr, "Usage: %s [-verbose]\n", myname);
  exit(ec);
}

char *compiled();

/* reads the command-line arguments and calls the compiled function. */
int main(int argc, char *argv[]) {
  char *p, *result;

  /* read command line */
  myname=*argv;
  ++argv, --argc;

  while (argc > 0) {
    p = *argv;
    ++argv, --argc;
    if (p[0] == '-') {           /* '-x' must be an option */
      p++;                       /* strip off the - */
      switch(p[0]) {
      case 'v':                  /* -v verbose */
        verbose=1;
        break;
      default:
        usage(1);
        break;
      }
    } else {
      usage(1);
    }
  }

  result=compiled();
  if (verbose)
    printf("Result: ");
  printf("%s\n", result);

  return 0;
}
