# include "opihi.h"
# define VERBOSE 0

int evaluate_stack (StackVar *stack, int *Nstack) {
  
  int i, j, Nvar, Nout, status;
  StackVar tmp_stack;
  Nout = Nvar = 0;

  init_stack (&tmp_stack);

  if (*Nstack == 1) {
    if (stack[0].type == 'S') {
      S_unary (&tmp_stack, &stack[0], "=");
      move_stack (&stack[0], &tmp_stack);
      return (TRUE);
    }
    if (stack[0].type == 'V') {
      V_unary (&tmp_stack, &stack[0], "=");
      move_stack (&stack[0], &tmp_stack);
      return (TRUE);
    }
    if (stack[0].type == 'M') {
      M_unary (&tmp_stack, &stack[0], "=");
      move_stack (&stack[0], &tmp_stack);
      return (TRUE);
    }
    fprintf (stderr, "syntax error!\n");
    free (tmp_stack.name);
    return (FALSE);
  }      
    
  for (i = 0; i < *Nstack; i++) {

    if (VERBOSE) {
      fprintf (stderr, "%d: ", i);
      for (j = 0; j < *Nstack; j++) {
	fprintf (stderr, "%s ", stack[j].name);
      }
      if (*Nstack > 0) fprintf (stderr, "\n");
      fprintf (stderr, "%d: ", i);
      for (j = 0; j < *Nstack; j++) {
	fprintf (stderr, "%d ", stack[j].type);
      }
      if (*Nstack > 0) fprintf (stderr, "\n");
    }

    /***** binary operators *****/
    if ((stack[i].type == 3) || (stack[i].type == 4) || (stack[i].type == 5) || (stack[i].type == 6)) {

      if (i < 2) {  /* need two variables to operate on */
	fprintf (stderr, "syntax error\n");
	free (tmp_stack.name); 
	return (FALSE);
      }
      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
	status = VV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
	status = VS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
	status = SV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "V", 1)) 
	status = MV_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "V", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
	status = VM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
	status = MM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "M", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
	status = MS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "M", 1)) 
	status = SM_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 2].type, "S", 1) && !strncasecmp (&stack[i - 1].type, "S", 1)) 
	status = SS_binary (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name);
      if (!status) {
	free (tmp_stack.name);
	return (FALSE);
      }
      move_stack (&stack[i-2], &tmp_stack);
      delete_stack (&stack[i-1], 2);
      for (j = i + 1; j < *Nstack; j++) {
	copy_stack (&stack[j - 2], &stack[j]);
      }
      *Nstack -= 2;
      i -= 2;
      init_stack (&tmp_stack);
      continue;
    }

    /***** unary operators **/
    if (stack[i].type == 7) {

      if (i < 1) {  /* need one variable to operate on */
	fprintf (stderr, "syntax error\n");
	free (tmp_stack.name);
	return (FALSE);
      }
      
      if (!strncasecmp (&stack[i - 1].type, "M", 1)) 
	M_unary (&tmp_stack, &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 1].type, "V", 1)) 
	V_unary (&tmp_stack, &stack[i - 1], stack[i].name);
      if (!strncasecmp (&stack[i - 1].type, "S", 1)) 
	S_unary (&tmp_stack, &stack[i - 1], stack[i].name);

      move_stack (&stack[i-1], &tmp_stack);
      delete_stack (&stack[i], 1);
      for (j = i + 1; j < *Nstack; j++) {
	copy_stack (&stack[j - 1], &stack[j]);
      }
      init_stack (&tmp_stack);
      *Nstack -= 1;
      i -= 1;
      continue;
    } 
  }
  free (tmp_stack.name);

  if (*Nstack > 1) {
    fprintf (stderr, "syntax error\n");
    return (FALSE);
  }
  return (TRUE);
}

/* copy data to new stack variable */
void copy_stack (StackVar *stack1, StackVar *stack2) {
  stack1[0].name   = stack2[0].name  ;
  stack1[0].type   = stack2[0].type  ;
  stack1[0].ptr    = stack2[0].ptr   ;
  stack1[0].buffer = stack2[0].buffer;
  stack1[0].vector = stack2[0].vector;
  stack1[0].Float  = stack2[0].Float ;
  if (!strncasecmp (&stack1[0].type, "S", 1)) {
    stack1[0].ptr    = &stack1[0].Float;
  }
}

/* replace data with new stack variable */
void move_stack (StackVar *stack1, StackVar *stack2) {
  if (stack1[0].name != (char *) NULL) 
    free (stack1[0].name);
  copy_stack (stack1, stack2);
}

/* delete name and data */
void clean_stack (StackVar *stack, int Nstack) {

  int i;

  for (i = 0; i < Nstack; i++) {
    if (IsBufferPtr (stack[i].buffer) && (stack[i].type == 'm')) {
      if (VERBOSE) fprintf (stderr, "free %s (buff) (%x)\n", stack[i].name, (int) stack[i].buffer);
      free (stack[i].buffer[0].header.buffer);
      free (stack[i].buffer[0].matrix.buffer);
      free (stack[i].buffer);
      stack[i].buffer = NULL;
    }	
    if (IsVectorPtr (stack[i].vector) && (stack[i].type == 'v')) {
      if (VERBOSE) fprintf (stderr, "free %s (vect) (%x)\n", stack[i].name, (int) stack[i].vector);
      free (stack[i].vector[0].elements);
      free (stack[i].vector);
      stack[i].vector = NULL;
    }	
    if (VERBOSE) fprintf (stderr, "free %s (name) (%d) (%x)\n", stack[i].name, i, (int) stack[i].name);
    free (stack[i].name);
    stack[i].name = NULL;
  }

}

/* delete name only, not data */
void delete_stack (StackVar *stack, int Nstack) {
  int i;
  for (i = 0; i < Nstack; i++) {
    free (stack[i].name);
  }
}

void init_stack (StackVar *stack) {
  stack[0].buffer = NULL;
  stack[0].vector = NULL;
  stack[0].name = strncreate ("tmp", NCHARS);
}
