char *un_quote();
char *ns[3] = {"Nothing","Number","String"};
extern int gle_debug;
/*---------------------------------------------------------------------------*/
#include "all.h"

#include <math.h>
int add_strvar(char *pcode,int *plen,int i);
int token_norm(void);
int token_space(void);

#define true (!false)
#define false 0
#define tok(n)  tk[n]
#define abort goto fatal_err
/*---------------------------------------------------------------------------*/
/* bin = 10..29, binstr = 30..49, fn= 60...139, userfn=200..nnn */
#define stack_bin(i,p) 	stack_op(pcode,plen,stk,stkp,&nstk,i-10+(last_typ*20),p+curpri)
#define stack_fn(i) 	stack_op(pcode,plen,stk,stkp,&nstk,i,10+curpri)
#define dbg if ((gle_debug & 4)>0)
/*---------------------------------------------------------------------------*/
/* Input is token array, and pointer to current point, output is pcode */

/* typedef struct op_key (*OPKEY)[100];  */
/* typedef char (*(*TOKENS)[500]); */

int zpolish(TOKENS tk,int *ntok,int *curtok,char *pcode,int *plen,int *rtype);
polish(char *expr,char *pcode,int *plen,int *rtype)
{
static char inbuff[200];
static char *tk[500];
static char tkbuff[500];
static int ntk,ct;
char *space_str=" ";
	static char buff[50];
	static int start_token;
	double xxx;
	int idx,ret,np,*plist,saveplen,term_bracket;
	int curpri=0;
	int i,j,v,p,savelen,isa_string,not_string,last_typ;
	int nstk=0,stk[50],stkp[50];	/* stack for operators */
	int unary=1;		/* binary or unary operation expected */
	int ln;			/* length of current token */
	char *cts;		/* current token */
	/* last_typ, 1=number,2=string */

	*plen = 0;
	if (tk[400]==NULL) for (i=0;i<500;i++) tk[i] = space_str;
	isa_string = false;
	not_string = false;
	if (*rtype==1) not_string = true;
	/* if (*rtype==2) isa_string = true; */
	*plen = *plen*4;	/* change into byte count */
	if (*rtype>0) term_bracket = true;
	last_typ = *rtype;
	saveplen = *plen;

	add_i(pcode,plen,1);	/* expression follows */
	savelen = *plen;	/* Used to set acutal length at end */
	add_i(pcode,plen,0);	/* Length of expression */
	dbg gprint("====Start of expression {%s} \n",expr);
	if (strlen(expr)==0) {gprint("Zero length expression\n"); return;}
	if (!start_token) {
		ntk = 0; ct=1;
		token_norm();
		token(expr,tk,&ntk,tkbuff);
		token_space();
	}
	for (;;) {
	  cts = tok(ct);
	  dbg gprint("First word token=%d via (1=unary %d) cts {%s} %d \n "
		,ct,unary,cts,strlen(cts));
	  ln = strlen(cts);
 	  switch (unary) {
	  case 1:  /* a unary operator, or function, or number or variable */
		if (ln==1 && (*cts=='E')) goto notnumber;
		if (ln==1 && (*cts=='-')) goto notnumber;
		if (isnumber(cts))  {
evalagain:	        dbg gprint("Found number {%s}\n",cts);
			if (lastchar(cts,'E'))  {
				strcpy(buff,cts);
				strcat(buff,tok(++ct));
				if (*tok(ct)=='-') {
					strcat(buff,tok(++ct));
				}
				tok(ct) = buff;
				cts = tok(ct);
				goto evalagain;
			}
			xxx = atof(cts);
			add_f(pcode,plen,xxx);
			if (last_typ==2) gprint("Expecting string {%s} \n",cts);
			last_typ = 1;
			unary=2; break;
		}
notnumber:	/* NOT a number, Is it a built in function */
		/* int idx,ret,np,*plist; */
		find_un(cts,&idx,&ret,&np,&plist);	/* 1,2 = +,- */
		if (idx>63) {
		  dbg gprint("Found built in function \n");
			if (*tok(++ct)!='(') {
				gprint("Expecting left bracket after functsion name");
				abort;
			}
			{
			 char fcode[400];
			 char *fp;
			 int flen,vtype,nparam=0;
			 if (*tok(ct+1)!=')') {
			   while (*tok(ct)!=')') {
				nparam++;
				vtype = *(plist+nparam-1);
				flen = 0;
				(ct)++;
				start_token = true;
				polish("xx",fcode,&flen,&vtype);
				start_token = false;
				flen = flen * 4;
				if (nparam>np) {gprint("Too many paramters got=%d want=%d \n",nparam,np);abort;}
				if (vtype==0) abort;
				add_pcode(pcode,plen,fcode,&flen);
			   }
			 } else {
				ct++;
			 }
			}
			if (last_typ==(3-ret)) {
				gprint("Function of wrong type Expecting {%s} \n",ns[ret]);
				abort;
			}
			last_typ = ret;
			add_fn(pcode,plen,idx);
			unary = 2; break;
		} else if (idx>0) {
			stack_fn(idx);
			unary=1; break;
		}

		 /* Is it a user-defined function, identical code too above. */
		  sub_find(cts,&idx,&ret,&np,&plist);	/* 1,2 = +,- */
		  if (idx>0) {
		  dbg gprint("Found user function \n");
			if (*tok(++ct)!='(') {
				gprint("Expecting left bracket after function name");
				abort;
			}
			{
			char fcode[400];
			char *fp;
			int flen,nnn,vtype,nparam=0;
			if (*tok(ct+1)!=')') {
			 while (*tok(ct)!=')') {
				ct++;
				nparam++;
				vtype = *(plist+nparam-1);
				nnn = *(plist+nparam);
				flen = 0;
				start_token = true;
				polish("xx",fcode,&flen,&vtype);
				start_token = false;
				flen = flen * 4;
				if (nparam>np) {gprint("Too many U paramters got=%d want=%d \n",nparam,np);abort;}
				if (vtype==0) abort;
				add_pcode(pcode,plen,fcode,&flen);
			  }
			 } else {
				ct++;
			 }
			}
			if (last_typ==(3-ret)) {
				gprint("Function of wrong type Expecting {%s} \n",ns[ret]);
				abort;
			}
			if (ret>0 && ret<3) last_typ = ret;
			add_fn(pcode,plen,idx+200);
			unary = 2; break;
		} else if (idx>0) {
			stack_fn(idx);
			unary=1; break;
		}


		/* Is it a 'known' variable */
		var_find(cts,&v,&ret);
		if (v>=0) {
			dbg gprint("Found variable %d \n",v);
			if (last_typ==(3-ret)) {
				gprint("Expecting {%s} \n",ns[last_typ]);
				abort;
			}
			last_typ=ret;
			if (ret==2) add_strvar(pcode,plen,v);
			else add_var(pcode,plen,v);
			unary=2; break;
		}
		/* Is it a atring */
		if (*cts=='"') {
		  dbg gprint("Found string \n");
			if (last_typ==1) {
				gprint("Expecting number {%s} \n",cts);
				abort;
			}
			last_typ = 2;
			add_string(pcode,plen,un_quote(cts));	/* remove quotes */
			unary = 2; break;
		}
		if (*cts=='(') { curpri = curpri + 100; break; }
		if (*cts==')') {
			if (curpri>0) {
				curpri = curpri - 100;
				unary = 2; break;
			}
			gprint("Too many right brackets found in exp \n");

		}
		/* must be unquoted string, unless a binary operator
		was found, in which case it is an undelcared variable */
		if (not_string) {
			dbg gprint("Found un-initialized variable {%s} /n",cts);
			var_add(cts,&v,&ret);
			last_typ=ret;
			add_var(pcode,plen,v) ;
			unary=2;
			break;
		}
		last_typ = 2;
		dbg printf("Unquoted string (%s) \n",cts);
		add_string(pcode,plen,un_quote(cts));	/* remove quotes */
		isa_string = true;
		unary = 2; break;
		isa_string = true;
		add_string(pcode,plen,cts);
		unary = 2;  /* Expecting end of expression next !! */
		break;
	  case 2:  /* a binary operator, or space, or end of line */
		if (ct>ntk || *cts==' ' || *cts==',' ) {
			goto end_expression;
		}
		if (*cts==')' && curpri==0) {
			goto end_expression;
		}
/* MIGHT (gives error with a$ = b$+c$) */
		if (isa_string) {
			gprint("Expression contained unquoted string\n");
			abort;
		}

		not_string = true;
		/* Binary operators, +,-,*,/,^,<,>,<=,>=,.and.,.or. */
		switch (*cts) {
		  case '+' : v = 1; p=2; break;
		  case '-' : v = 2; p=2; break;
		  case '*' : v = 3; p=3; break;
		  case '/' : v = 4; p=3; break;
		  case '^' : v = 5; p=4; break;
		  case '=' : v = 6; p=1; break;
		  case '<' : v = 7; p=1;
			if (*tok(ct+1)=='=') {v=8;++ct;} break;
		  case '>' : v = 9;p=1;
			if (*tok(ct+1)=='=') {v=10;++ct;} break;
		  case '.' : p=1;
			if (strcmp(cts,".AND.")) {v=11;} break;
			if (strcmp(cts,".OR.")) {v=12;} break;
	 	  default : v = 0 ; break;
		}
		if (v>0) {
			if (last_typ<1 || last_typ > 3) last_typ = 1;
			stack_bin(v,p);
			dbg gprint("Found binary operator \n");
			unary=1; break;
		}
		if (*cts==')') {
			if (curpri>0) {
				curpri = curpri - 100;
				unary = 2; break;
			}
			if (term_bracket!=true) {
				gprint("Too many right brackets, expecting binary operator \n");
				abort;
			}
			goto end_expression;
		}
	  }
	  if (++ct>ntk) { goto end_expression; }
/*	gprint("Next token is {%s} \n",tok(ct)); */
	}
end_expression:
	if (*tok(ct)==' ') (ct)++;
	dbg gprint("Got expression , curtok=%d {%s} \n",ct,tok(ct));
	*rtype = last_typ;
	  dbg gprint("Found END OF EXPRESSION \n");
	if (!start_token) if (curpri!=0) {gprint("Missing right brackets");}
	/* Pop everything off the stack */
	for (i=nstk;i>0;i--) {
		dbg gprint("Adding left over operators  I = %d  op=%d \n",i,stk[i]);
		add_i(pcode,plen,stk[i]);
	}
	* ((long *) (pcode+savelen)) = (*plen - savelen)/4-1;  /* Set length of expression */
	*plen = *plen/4;	/* change back to int count */
return;
fatal_err:
	gprint("Aborting expression parsing. \n");
	*plen = saveplen;
	*rtype = 0;
}

/*------------------------------------------------------------------*/
/* append fcode to pcode */
add_pcode(char *pcode,int *plen,char *fcode,int *flen)
{
	char *p;
	p = pcode + *plen;
	memcpy(p,fcode,*flen);
	*plen = *plen + *flen;
}
add_i(char *pcode,int *plen,long i)
{
	long *p;
	p = (long *) (pcode + *plen);
	*p = i;
	*plen += 4;
}
add_f(char *pcode,int *plen,double f)
{
	union { double d ; long l[2]; short s[4]; } both;
	both.d = f;
	add_i(pcode,plen,2);
	add_i(pcode,plen,both.l[0]);
	add_i(pcode,plen,both.l[1]);
}
add_var(char *pcode,int *plen,int i)
{
	add_i(pcode,plen,3);
	add_i(pcode,plen,i);
}
add_strvar(char *pcode,int *plen,int i)
{
	add_i(pcode,plen,4);
	add_i(pcode,plen,i);
}
add_fn(char *pcode, int *plen, int i)
{
	add_i(pcode,plen,i);
	dbg gprint(" add Function %d \n",i);
}
add_string(char *pcode, int *plen, char *s)
{
	char *p;
	int sl;
	dbg gprint("adding string {%s} \n",s);
	add_i(pcode,plen,5);
	sl = strlen(s)+1;
	p = pcode + *plen;
	sl = ((sl + 3) & 0xfffc);
 	strncpy(p,s,sl);
	*plen = *plen + sl;
}
/*------------------------------------------------------------------*/
/* Remove the quotes from a string and return a modified pointer */
char *un_quote(char *cts)
{
	int i,j;
	i = strlen(cts);
	if (*cts=='"') {
		*(cts+i-1) = 0;
		cts = cts + 1;
	}
	return cts;
}
/*------------------------------------------------------------------*/
stack_op(char *pcode, int *plen, int stk[]
	, int stkp[], int *nstk,  int i, int p)
{
	dbg gprint("Stack oper %d priority %d \n",i,p);
	while (p<=stkp[*nstk] &&(*nstk)>0) {
		dbg gprint("ADDING oper stack = %d  oper=%d \n",*nstk,stk[(*nstk)]);
		add_i(pcode,plen,stk[(*nstk)--]);
	}
	stk[++(*nstk)] = i;
	stkp[*nstk] = p;
}
isnumber(char *s)
{
	while (*s!='\0') {
		if (isdigit(*s) || *s=='.' || *s=='E' ) s++;
		else  return false;
	}
	return true;
}
lastchar(char *s, char c)
{
	while (*s!='\0') {s++;}
	return *(--s)==c;
}


