/************************************************************************
 *                  expr.c                                              *
 ************************************************************************/
/*         Routines for handling Expressions                            *
 ************************************************************************
 *   Part of the project : BASCY  Version 1.0                           *
 *   Copyright (C) 2001 - S. Narasimhan, No.11, Sathya Nagar,           *
 *                        MADURAI-625018. INDIA                         *
 *                       email: narasimhan_s_@hotmail.com               *
 ************************************************************************
 * This program is free software; you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published by *
 * the Free Software Foundation; either version 2 of the License, or    *
 * (at your option) any later version.                                  *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,      *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 * GNU General Public License for more details.                         *
 *                                                                      *
 * You should have received a copy of the GNU General Public License    *
 * along with this program; if not, write to the Free Software          *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                      *
 ************************************************************************/
#include <string.h>
#include "basic.h"
#define   MAXSTRLEN   256
#define   STACKSIZE   128
extern unsigned int lincount;
extern FILE *fin, *fout, *ftmp, *ffun;
extern char word[], exprstr[], indent[];
extern struct symbol symtab[];
String  stack[STACKSIZE];
String  inexp[MAXSTRLEN], postexp[MAXSTRLEN];
unsigned typstack[STACKSIZE], typin[MAXSTRLEN],typost[MAXSTRLEN]; 
unsigned int lenin, lenpost;
int emptystack = TRUE;
int ptr = 0; /* stack pointer */
char Zero[2] = "0" ;
double str2num(char *s) /*convert the numeric str.s into number */
{
  int c, sign;
  double val, power;
  while((c=*s++) == ' '||c=='\t')
     ;
  sign = 1;
  if(c=='+'|| c=='-') { sign=(c=='+')?1:-1; c=*s++;}
  for(val=0; c >= '0' && c <= '9' ; c=*s++)
     val = 10 * val + c - '0';
  power = 1;
  if(c == '.') {
    for(c=*s++;c >= '0' && c <= '9' ; c=*s++){
       power *= 10;
       val = 10 * val + c - '0';
    }
  }
  return(sign * val / power);
} /* end of str2num() */
int expr(void)
/* Parses for the lexical unit of expression */
/*
 * On return exprstr contains the expression and it returns
 * the type of the expression */
{
     int i,  exprtype;
     int brackount = 0;
     /*Read the complete expression and break into separate tokens */
     int tokndx = 0;
     do{
        do{
                i = lex();
                if(i == '(') brackount++;
                if(i == ')') brackount--;
                inexp[tokndx] = emalloc(strlen(word) + 1);
                if(inexp[tokndx] == 0) return -1;
                strcpy(inexp[tokndx], word);
                typin[tokndx] = i;
                tokndx++;
        } while (i == UNOP || i == BINOP || i == '=' || i == LE ||
           i == LT || i == GT || i == GE || i == NE || i == NUMVAR ||
           i == STRVAR || i == NUMBER || i == STRING || i == '(' ||
           i == ')'|| i == BUILTIN || i == UDF || i == NUMARR || i == STRARR);
        if(i != ',' || brackount == 0)
          /* May be an argument for builtin or Array Subscript*/
          break;
      }while(TRUE);
      if(brackount != 0) {
          error(238);
          return -1;
      }
        tokndx--; /* Now, tokndx contains the num. of tokens in the expr*/
        lenin = tokndx;
        /* Convert NIL arg. builtin into builtin with 1 dummy arg. */
        if(makearg() < 0) return -1;
        exprtype = ValidExpr();
        if(exprtype < 0) return exprtype;
        if(un2binop() < 0) return -1;
        if(intopost() < 0) return -1;
        exprtype = post2in();
        if(exprtype < 0) return -1;
        freemem();
        if(exprtype == NUMBER || exprtype == NUMVAR)
            return NUMVAR;
        else { /* it is String Var/ literal */
            if(libcode("LEN") < 0)  /* instal the  code for len */
                return -1;          /* builtin function */
            return STRVAR; /* word contains the token following the <expr> */
        }
} /* end of expr() */
int ValidExpr(void)
/* Validates the expression 'inexp'
 * Returns -100 if the expression is NULL expr.,
 * -1 if it is an invalid expression,
 * Returns 0 if valid expression */
{
        int i = 0;
        int brackount = 0;
        int prvtoken = -1; /* Indicates the start of expression */
        int sign = ' ';
        int typ;
        do {
          typ = typin[i];
          i++;
          switch(typ) {
		 case UNOP   : if(!((prvtoken == -1) || (prvtoken == ')') ||
                                   (prvtoken == NUMBER) || (prvtoken == NUMVAR) ||
                                   (prvtoken == STRING) || (prvtoken == STRVAR) ||
                                   (prvtoken == ',') ||
                                   (prvtoken == '('))) {
                                        error(250);
                                        return -1;
                                }
                               sign = inexp[i-1][0]; /* word[0]; */
                               if(((prvtoken == STRING) ||
                                   (prvtoken == STRVAR)) &&
                                   (sign != '+')) {
                                        error(239);
                                        return -1;
                                }
                               prvtoken = typ;
                               break;
                 case BINOP  : if(!((prvtoken == ')') || (prvtoken == NUMBER) ||
                                   (prvtoken == NUMVAR)|| (prvtoken == STRVAR))) {
                                        error(250);
                                        return -1;
                                }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 case '='  : 
                 case LE  :  
                 case LT  :  
                 case GT  :  
                 case GE  :  
                 case NE  :  
                             if(!((prvtoken == ')') ||
                                (prvtoken == NUMBER) || (prvtoken == NUMVAR) ||
                                (prvtoken == STRING) || (prvtoken == STRVAR))) { 
                                        error(250);
                                        return -1;
                             }
                             prvtoken = typ;
                             break;
                 case NUMVAR : 
                               if(!((prvtoken == -1) || (prvtoken == UNOP) ||
                                  (prvtoken == BINOP) || (prvtoken == '(') ||
                                  (prvtoken == ',') ||
                                  (prvtoken == '=') || (prvtoken == NE) ||
                                  (prvtoken == GT) || (prvtoken == GE) ||
                                  (prvtoken == LT) || (prvtoken == LE))) {
                                  error(250);
                                  return -1;
                               }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 case STRVAR : 
                               if(!((prvtoken == -1) || (prvtoken == '(') ||
                                   (sign == '+')||  (prvtoken == ',') ||
                                  (prvtoken == '=') || (prvtoken == NE) ||
                                  (prvtoken == GT) || (prvtoken == GE) ||
                                  (prvtoken == LT) || (prvtoken == LE))) {
                                  error(250);
                                  return -1;
                               }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 case NUMBER : 
                               if(!((prvtoken == -1) || (prvtoken == UNOP) ||
                                  (prvtoken == BINOP) || (prvtoken == '(')||
                                  (prvtoken == ',') ||
                                  (prvtoken == '=') || (prvtoken == NE) ||
                                  (prvtoken == GT) || (prvtoken == GE) ||
                                  (prvtoken == LT) || (prvtoken == LE))) {
                                  error(250);
                                  return -1;
                               }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 case STRING :
                               if(!((prvtoken == -1) || (prvtoken == '(') ||
                                   (sign == '+') || (prvtoken == ',') ||
                                  (prvtoken == '=') || (prvtoken == NE) ||
                                  (prvtoken == GT) || (prvtoken == GE) ||
                                  (prvtoken == LT) || (prvtoken == LE))) {
                                  error(250);
                                  return -1;
                               }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 case '(' : if(!((prvtoken == UNOP) || (prvtoken == BINOP) ||
                                (prvtoken == '(') || (prvtoken == -1)||
                                (prvtoken == ',') ||
                                (prvtoken == '=') || (prvtoken == NE) ||
                                (prvtoken == GT) || (prvtoken == GE) ||
                                (prvtoken == BUILTIN) || (prvtoken == UDF) ||
                                (prvtoken == LT) || (prvtoken == LE) ||
                                (prvtoken == NUMARR) || (prvtoken == STRARR))) {
                                  error(250);
                                  return -1;
                             }
                             brackount++;
                             sign = ' ';
                             prvtoken = typ;
                             break;
                 case ')' : if(!((prvtoken == NUMBER) || (prvtoken == NUMVAR) ||
                                (prvtoken == BUILTIN) ||
                                (prvtoken == STRING) || (prvtoken == STRVAR) ||
                                (prvtoken == ')'))) {
                                  error(250);
                                  return -1;
                             }
                             if(brackount > 0)
                                brackount--;
                             else {
                                error(238);
                                return -1;
                             }
                             sign = ' ';
                             prvtoken = typ;
                             break;
                 case ','  : if(!((prvtoken == NUMBER) || (prvtoken == NUMVAR) ||
                                  (prvtoken == STRING) || (prvtoken == STRVAR) ||
                                  (prvtoken == ')'))){
                                  error(250); return -1;
                             }
                             sign = ' ';
                             prvtoken = typ;
                             break;
                 case NUMARR  :
                 case STRARR  :
                 case UDF     :
                 case BUILTIN : if(!((prvtoken == UNOP) || (prvtoken == BINOP) ||
                                  (prvtoken == '(') || (prvtoken == -1) ||
                                  (prvtoken == ',') ||
                                  (prvtoken == '=') || (prvtoken == NE) ||
                                  (prvtoken == GT) || (prvtoken == GE) ||
                                  (prvtoken == LT) || (prvtoken == LE))) {
                                  error(250);
                                  return -1;
                               }
                               sign = ' ';
                               prvtoken = typ;
                               break;
                 default :   if(prvtoken == -1) return -100; /* NULL expr.*/
                             if(!((prvtoken == NUMBER) || (prvtoken == NUMVAR) ||
                                (prvtoken == STRING) || (prvtoken == STRVAR) ||
                                (prvtoken == ')'))) {
                                  error(232);
                                  return -1;
                             }
                             if(brackount != 0) {
                                error(238);
                                return -1;
                             }
          }  /* switch */
        } while(i<=lenin); 
        return 0;
} /* end of ValidExpr() */
int intopost(void)
/* Converts the Infix expression 'inexp' into Polish Postfix expression
 * 'postexp' */
{
        String curtok ;
        String stacktok ;
        unsigned curtyp, stacktyp;
        int i,k, stackpreclow, matchfound;
        i = k = 0;
        emptystack = TRUE;
        do {
                curtok = strdup(inexp[i]);
                if(curtok == NULL) {error(249); return -1;}
                curtyp = typin[i];
                switch(curtyp) {
                  case '(' : if(push(curtok,curtyp) < 0) return -1;
                             break;
                  case ')' : do {
                                if((stacktok = pop(&stacktyp)) == 0) return -1;
                                if(stacktyp == '(')
                                   matchfound = TRUE;
                                else {
                                   postexp[k] = strdup(stacktok);
                                   if(postexp[k] == NULL) {error(249); return -1;}
                                   typost[k] = stacktyp;
                                   k++;
                                   matchfound = FALSE;
                                }
                              } while (!(matchfound  || emptystack ));
                              break;
                  case ',' : do {
                                if((stacktok = pop(&stacktyp)) == 0) return -1;
                                if(stacktyp == '(')
                                   matchfound = TRUE;
                                else {
                                   postexp[k] = strdup(stacktok);
                                   if(postexp[k] == NULL) {error(249); return -1;}
                                   typost[k] = stacktyp;
                                   k++;
                                   matchfound = FALSE;
                                }
                              } while (!(matchfound  || emptystack ));
                              if(matchfound)
                                 if(push("(",'(') < 0) return -1;
                              postexp[k] = strdup(curtok);
                              if(postexp[k] == NULL) {error(249); return -1;}
                              typost[k] = curtyp;
                              k++;
                              break;
                  case '='   :
                  case NE    :
                  case LE    :
                  case LT    :
                  case GE    :
                  case GT    :
                  case UNOP  :
                  case BINOP :
                  case BUILTIN :
                  case UDF   :
                  case NUMARR:
                  case STRARR:
                             if(emptystack){
                                if(push(curtok,curtyp) < 0) return -1;
                             }
                             else {
                                do {
                                   if((stacktok = pop(&stacktyp)) == 0) return -1;
                                   if (precedence(stacktok) >= precedence(curtok)) {
                                      postexp[k] = strdup(stacktok);
                                      if(postexp[k] == NULL) {error(249); return -1;}
                                      typost[k] = stacktyp;
                                      k++;
                                      stackpreclow = FALSE;
                                   }
                                   else
                                      stackpreclow = TRUE;
                                }while (!(stackpreclow || emptystack));
                                if(stackpreclow == FALSE){
                                        if(push(curtok,curtyp) < 0) return -1;
                                }
                                else {
                                        if(push(stacktok,stacktyp) < 0) return -1;
                                        if(push(curtok,curtyp) < 0) return -1;
                                }
                             }
                             break;
                  default :  postexp[k] = strdup(curtok);
                             if(postexp[k] == NULL) {error(249); return -1;}
                             typost[k] = curtyp;
                             k++;
                } /*switch */
                /* End of scan of one token of inexp */
                i++;
          } while(i < lenin);
              /* End of parsing of expression */
              /* Now take out all the operators left in the stack */
          while(emptystack == FALSE) {
              if((stacktok = pop(&stacktyp)) == 0) return -1;
              postexp[k] = strdup(stacktok);
              if(postexp[k] == NULL) {error(249); return -1; }
              typost[k] = stacktyp;
              k++;
          }
          lenpost = k; /* No. of tokens in the postfix expression */
          return 0;
} /* end of intopost() */
int precedence(char *s)
{
        if(strcmp(s,")") == 0)
                return(1);
        if(strcmp(s,"(") == 0)
                return(2);
        if(strcmp(s,"OR") == 0)
                return(3);
        if(strcmp(s,"AND") == 0)
                return(4);
        if(strcmp(s,"NOT") == 0)
                return(5);
        if(strcmp(s,"=") == 0)
                return(6);
        if(strcmp(s,"!=") == 0)
                return(6);
        if(strcmp(s,"<") == 0)
                return(7);
        if(strcmp(s,"<=") == 0)
                return(7);
        if(strcmp(s, ">") == 0)
                return(7);
        if(strcmp(s,">=") == 0)
                return(7);
        if(strcmp(s,"+") == 0 || strcmp(s,"-") == 0)
                return(8);
        if(strcmp(s,"*") == 0 || strcmp(s,"/") == 0 ||
           strcmp(s,"\\") == 0 || strcmp(s,"MOD") == 0)
                return(9);
        if(strcmp(s,"^") == 0)
                return(10);
        else {
                int t, typ;
                t = lookup(s);
                typ = symtab[t].type;
                if(typ == BUILTIN || typ == UDF || typ == NUMARR || typ==STRARR)
                        return(11);
                else {
                        error(226);
                        exit(1);
                }
        }
} /* end of precedence */
int push(String s, unsigned typ)
/* Pushes the token-string 's' of lexical type 'typ' on the stack,
 * typstack respectively */
{
        if(ptr < STACKSIZE) {
                emptystack = FALSE;
                stack[ptr] = strdup(s); 
                if(stack[ptr] == NULL) {error(249); return -1;}
                typstack[ptr] = typ;
                ptr++;
                return 0;
        }
        else {
                error(230);
                return -1;
        }
} /* push */
String pop(unsigned *typ)
/* Pops the string 's' of lexical type 'typ' from the top of stack,
 * typstack respectively and returns the popped string*/
{
        String s;
        if(ptr > 0) {
                --ptr;
                s = strdup(stack[ptr]);
                if(s == NULL) {error(249); return 0;}
                *typ = typstack[ptr];
                free(stack[ptr]); 
                if(ptr == 0)
                      emptystack = TRUE;
                else
                      emptystack = FALSE;
                return s;
        }
        else {
                error(250);
                return 0;
        }
} /* pop */
int post2in(void)
/* Convert the Polish Post-fix expression 'postexp' into infix
 * expression
 * On return, 'exprstr' contains the Converted infix expression
 * The type of the resultant expression is returned */
{
        String curtok ;
        String termA, termB;
        unsigned i,typeA, typeB,curtyp;
        strcpy(exprstr, "");
        for (i = 0; i < lenpost; i++) {
           curtok = strdup(postexp[i]);
           if(curtok == NULL) {error(249); return -1;} 
           curtyp = typost[i];
           switch(curtyp) {
              case '='  : strcpy(curtok, "==");
              case NE   :
              case LT   :
              case LE   :
              case GT   :
              case GE   : strcpy(exprstr,"");
                          termB = pop(&typeB);
                          termA = pop(&typeA);
                          if(termA == 0 || termB == 0) return -1;
                          if(VTest1(typeA,typeB) < 0) return -1;
                          if(typeA == STRING || typeA == STRVAR) {
                             strcat(exprstr,"strcmp(");
                             if(typeA == STRING)
                               strcat(exprstr,"\"");
                             strcat(exprstr, termA);
                             if(typeA == STRING)
                               strcat(exprstr,"\"");
                             strcat(exprstr, ",");
                             if(typeB == STRING)
                               strcat(exprstr,"\"");
                             strcat(exprstr, termB);
                             if(typeB == STRING)
                               strcat(exprstr,"\"");
                             strcat(exprstr,")");
                             strcat(exprstr,curtok);
                             strcat(exprstr,"0");
                           }
                           else {
                             ParenCover(termA);
                             strcat(exprstr,curtok);
                             ParenCover(termB);
                          }
                          if(strlen(exprstr) > MAXWORDLEN-50) {
                                error(230); return -1;
                          }
                          free(termA); free(termB);
                          typeA = NUMVAR;
                          if(push(exprstr, typeA) < 0) return -1;
                          break;
              case UNOP   :
              case BINOP  : 
                            if(oprprc(curtok) < 0)
                                return -1;
                            break;
              case NUMARR :
              case STRARR : if(ArrHandler(curtok) < 0)
                               return -1;
                            break;
              case UDF    : if(udf(curtok) < 0)
                              return -1;
                            break;
              case BUILTIN : if(bltin(curtok) < 0)
                                return -1;
                             break;
              case ','    : 
              case NUMBER :
                            if(push(curtok,curtyp) < 0) return -1;
                            break;
              case STRING :
                            if(push(curtok,curtyp) < 0) return -1;
                            break;
              case NUMVAR : {
                                int s;
                                s = lookup(curtok);
                                if(s<0 || symtab[s].u.ival == 0){
                                  fprintf(fout,"\ndouble %s = 0.0;",curtok);
                                  fflush(fout);
                                  if(s<0)
                                     if(instal(curtok,curtyp,lincount) < 0) {
                                        error(248); return -1;
                                     }
                                 }
                            }
                            if(push(curtok,curtyp) < 0) return -1;
                            break;
              case STRVAR : {
                                int s;
                                s = lookup(curtok);
                                if(s<0 || symtab[s].u.ival == 0) {
                                   if(s<0) {
                                      if(instal(curtok,curtyp,lincount) < 0) {
                                        error(248); return -1;
                                      }
                                   }
                                   strvarconv(curtok);
                                   fprintf(fout,"\nchar %s[MAXSTRLEN+1]=\"\";", curtok);
                                   fflush(fout);
                                }
                               else
                                 strvarconv(curtok);
                            }
                            if(push(curtok,curtyp) < 0) return -1;
                            break;
          } /*switch*/
          free(curtok);
        } /* for */
        termA = pop(&typeA);
        if(termA == 0) return -1;
        i = typeA;  /*Contains the type of expression */
        if(typeA == STRING){
            fprintf(ftmp,"\n%sstrcpy(_tmp_,\"%s\");",indent,termA);
            fflush(ftmp);
            i = STRVAR;
        }
        if(typeA == STRVAR && strcmp(termA,"_tmp_") != 0){
            fprintf(ftmp,"\n%sstrcpy(_tmp_,%s);",indent,termA);
            fflush(ftmp);
        }
        strcpy(exprstr, termA);
        free(termA);
        return(i);
} /* main */
int VTest1(unsigned typeA, unsigned typeB)
/* Tests operand-types - typeA and typeB for type mismatch
 * If there is type mismatch error, returns -1
 */
{
        if((typeA == STRING || typeA == STRVAR) &&
           (typeB == NUMBER || typeB == NUMVAR)) {
                error(13);
                return -1;
        }
        if((typeA == NUMBER || typeA == NUMVAR) &&
           (typeB == STRING || typeB == STRVAR)) {
                error(13);
                return -1;
        }
        return 0;
} /*end of VTest1() */
void ParenCover(String op)
/* Covers the Operand expression - 'op' with parantheses & writes the result
 * in the string 'exprstr'
 */
{
        if(strlen(op) > 1)
                strcat(exprstr,"(");
        strcat(exprstr, op);
        if(strlen(op) > 1)
                strcat(exprstr,")");
}
int oprprc(String s)
/* Central Despatch routine to handle the operator 's' */
{
        char c;
        c = s[0];
        switch(c) {
          case '+'  : return(plus());
          case '-'  : return(sub());
          case '*'  : return(mul());
          case '/'  : return(div());
          case '\\'  : return(idiv());
          case '^'  : return(power());
        } /* switch */
        if(strcmp(s,"MOD") == 0)
                return(mod());
        if(strcmp(s,"NOT") == 0)
                return(not());
        if(strcmp(s, "OR") == 0)
                return(or());
        if(strcmp(s,"AND") == 0)
                return(and());
} /* end of oprprc() */
int plus(void)
/*Handles the operator '+'  */
{
        String d1, d2;
        unsigned  type1, type2, otyp;
        strcpy(exprstr,"");
        d2 = pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(VTest1(type1,type2) < 0) return -1;
        if(type1 == STRING) 
          fprintf(ftmp,"\n%sif((LEN(\"%s\")+",indent, d1);
        if(type1 == STRVAR)
            fprintf(ftmp,"\n%sif((LEN(%s)+",indent, d1);
        if(type2 == STRING)
          fprintf(ftmp,"LEN(\"%s\")) > MAXSTRLEN){", d2);
        if(type2 == STRVAR)
          fprintf(ftmp,"LEN(%s)) > MAXSTRLEN){", d2);
        if(type1 == STRING || type1 == STRVAR) {
          fflush(ftmp);
          fprintf(ftmp,"\n%s   fprintf(stderr,\"\\nString Too Big\");",indent);
          fflush(ftmp);
          fprintf(ftmp,"\n%s   exit(1);}",indent);
          fflush(ftmp);
          if(strcmp(d1,"_tmp_") != 0){
              if(type1 == STRVAR)
                 fprintf(ftmp,"\n%sstrcat(_tmp_,%s);",indent,d1);
              else
                 fprintf(ftmp,"\n%sstrcat(_tmp_,\"%s\");",indent,d1);
          }
          if(type2 == STRVAR)
             fprintf(ftmp,"\n%sstrcat(_tmp_,%s);",indent,d2);
          if(type2 == STRING)
             fprintf(ftmp,"\n%sstrcat(_tmp_,\"%s\");",indent,d2);
          fprintf(ftmp,"\n%sstrcpy(_tmp1_,_tmp_);",indent);
          fprintf(ftmp,"\n%sstrcpy(_tmp_,\"\");",indent);
          fflush(ftmp);
          strcpy(exprstr,"_tmp1_");
          otyp = STRVAR;
        }
        else if(type2 == NUMBER && str2num(d2) == 0) { /* d1 + 0 */
           ParenCover(d1);
        }
        else {
          ParenCover(d1);
          strcat(exprstr,"+");
          ParenCover(d2);
          otyp = NUMVAR;
        }
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
           error(230);  return -1;
        }
        if(push(exprstr,otyp) < 0) return -1;
        return 0;
} /* end of plus() */
int sub(void)
/* Handles the operator '-'  */
{
        String d1,d2;
        unsigned  type1, type2, otyp;
        otyp = NUMVAR;
        strcpy(exprstr,"");
        d2 = pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        if(type1 == NUMBER && type2 == NUMBER &&
           (str2num(d1) - str2num(d2)) == 0.0) { /* d1 - d2 = 0 */
                strcat(exprstr,"0");
                otyp = NUMBER;
        }
        else if(type2 == NUMBER && str2num(d2) == 0.0) { /*d1 - 0 */
               ParenCover(d1);
        }
        else {
             ParenCover(d1);
             strcat(exprstr,"-");
             ParenCover(d2);
        }
           free(d1); free(d2);
           if(strlen(exprstr) > MAXWORDLEN-50) {
              error(230);  return -1;
           }
           if(push(exprstr, otyp) < 0) return -1;
           return 0;
} /* end of sub() */
int mul(void)
/* Handles the Operator '*'  */
{
        String d1, d2;
        unsigned type1, type2, otyp, zeroval;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        otyp = NUMVAR;
        zeroval = FALSE;
        if(type1 == NUMBER && str2num(d1) == 0)
             zeroval = TRUE;
        if(type2 == NUMBER && str2num(d2) == 0)
             zeroval = TRUE;
        if(zeroval) {
           strcat(exprstr,"0");
           otyp = NUMBER;
        }
        else {
          ParenCover(d1);
          strcat(exprstr,"*");
          ParenCover(d2);
        }
           free(d1); free(d2);
           if(strlen(exprstr) > MAXWORDLEN-50) {
              error(230);  return -1;
           }
           if(push(exprstr,otyp) < 0) return -1;
           return 0;
} /* end of mul() */
int div(void)
/* Handles the operator '/'   */
{
        String d1, d2;
        unsigned type1, type2, otyp;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        otyp = NUMVAR;
        if(type2 == NUMBER && str2num(d2) == 0) {
          error(228);  /* Division by zero */
          return -1;
        }
        if(type1 == NUMBER && str2num(d1) == 0){ /* division into 0 */
          strcat(exprstr,"0");
          otyp = NUMBER;
        }
        else {
          ParenCover(d1);
          strcat(exprstr,"/");
          ParenCover(d2);
        }
           free(d1); free(d2);
           if(strlen(exprstr) > MAXWORDLEN-50) {
              error(230);  return -1;
           }
           if(push(exprstr, otyp) < 0) return -1;
           return 0;
} /* end of div() */
int idiv(void)
/* Handles the operator '\' */
{
        String d1, d2;
        unsigned type1, type2, otyp;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        otyp = NUMVAR;
        if(type2 == NUMBER && str2num(d2) == 0) {
          error(228);  /* Division by zero */
          return -1;
        }
        if(type1 == NUMBER && str2num(d1) == 0){ /* division into 0 */
          strcat(exprstr,"0");
          otyp = NUMBER;
        }
        else {
          if(libcode("idiv") < 0)  return -1;
          strcat(exprstr,"idiv(");
          if(type1 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d1);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d1);
          }
          strcat(exprstr,",");
          if(type2 == NUMVAR) {
             strcat(exprstr,"(double)");
             ParenCover(d2);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d2);
          }
          strcat(exprstr,")");
        }
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
            error(230);  return -1;
        }
        if(push(exprstr,otyp) < 0) return -1;
        return 0;
} /* end of idiv() */
int mod(void)
/* Handles the operator 'mod'  */
{
        String d1, d2;
        unsigned type1, type2, otyp;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        otyp = NUMVAR;
        if(type2 == NUMBER && str2num(d2) == 0) {
          error(228);  /* Division by zero */
          return -1;
        }
        if(type1 == NUMBER && str2num(d1) == 0){ /* division into 0 */
          strcat(exprstr,"0");
          otyp = NUMBER;
        }
        else {
          if(libcode("idiv") < 0)  return -1;
          strcat(exprstr,"mod(");
          if(type1 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d1);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d1);
          }
          strcat(exprstr,",");
          if(type2 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d2);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d2);
          }
          strcat(exprstr,")");
        }
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
            error(230);  return -1;
        }
        if(push(exprstr, otyp) < 0) return -1;
        return 0;
} /* end of mod() */
int power(void)
/* Handles the operator '^' (exponentiation) - 'd1^d2' */
{
        String d1, d2;
        unsigned type1, type2, otyp;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(type1==STRING || type1 == STRVAR || type2 == STRING ||
           type2 == STRVAR) {
           error(13); return -1;
        }
        otyp = NUMVAR;
        if(type1 == NUMBER && type2 == NUMBER &&
           str2num(d1) == 0.0 && str2num(d2) <= 0.0){  /* 0 ^ 0 or 0 ^ -ve */
                error(227); return -1;
        }
        if(type1 == NUMBER && type2 == NUMBER && str2num(d1) == 0.0){
          /* 0 ^ +ve */
          strcat(exprstr,"0");
          otyp = NUMBER;
        }
        else {
          if(libcode("power") < 0)  return -1;
          strcat(exprstr,"power(");
          if(type1 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d1);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d1);
          }
          strcat(exprstr,",");
          if(type2 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d2);
          }
          else {
             strcat(exprstr,"(double)");
             strcat(exprstr,d2);
          }
          strcat(exprstr,")");
        }
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
            error(230);  return -1;
        }
        if(push(exprstr, otyp) < 0) return -1;
        return 0;
} /* end of power() */
int or(void)
/* Handles the operator 'OR' */
{
        String d1, d2;
        unsigned type1, type2;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(VTest1(type1,type2) < 0) return -1;
        ParenCover(d1);
        strcat(exprstr,"||");
        ParenCover(d2);
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
           error(230);  return -1;
        }
        if(push(exprstr,NUMVAR) < 0) return -1;
        return 0;
} /* end of or() */
int and(void)
/* Handles the operator 'AND' */
{
        String d1, d2;
        unsigned type1, type2;
        strcpy(exprstr,"");
        d2=pop(&type2); d1 = pop(&type1);
        if(d2 == 0 || d1 == 0)
           return -1;
        if(VTest1(type1,type2) < 0) return -1;
        ParenCover(d1);
        strcat(exprstr,"&&");
        ParenCover(d2);
        free(d1); free(d2);
        if(strlen(exprstr) > MAXWORDLEN-50) {
           error(230);  return -1;
        }
        if(push(exprstr, NUMVAR) < 0) return -1;
        return 0;
} /* end of and() */
int not(void)
/* Handles the operator 'NOT' */
{
        String d1;
        unsigned type1;
        strcpy(exprstr,"");
        d1 = pop(&type1);
        if(d1 == 0)
           return -1;
        if(type1 == STRING || type1 == STRVAR) {
           error(13); return -1;
        }
        strcat(exprstr,"!");
        ParenCover(d1);
        free(d1);
        if(strlen(exprstr) > MAXWORDLEN-50) {
           error(230);  return -1;
        }
        if(push(exprstr, NUMVAR) < 0) return -1;
        return 0;
} /* end of not() */
void freemem(void)
/* Frees memory allocated for strings held in the arrays 'inexp' &
 * 'postexp */
{
    int m;
    for (m = 0; m < lenin; m++)
       free(inexp[m]);
    for (m = 0; m < lenpost; m++)
       free(postexp[m]);
}
int un2binop(void)
/* Converts the Unary operators '+' and '-' into Binary operators
 * Method-> Whenever a unary '+' or '-' is found in the infix expr.
 * 'inexp' , a token '0' is inserted before it.
 * On return, the array 'inexp' contains the Converted infix expr.
 */
{
    unsigned start = TRUE;
    unsigned prvtoken = '\0';
    int i = 0;
    while(i < lenin) {
        if(i > 0)
           start = FALSE;
        if(typin[i] != UNOP) {
          prvtoken = typin[i];
          i++;
          continue;
        }
        if(strcmp(inexp[i],"+") == 0 || strcmp(inexp[i],"-") == 0) {
          if(start || prvtoken == '(') {
            /* Means, it is Unary '+' or'-'.
             * Move all the tokens in 'inexp'
             * from position i up by 1 slot */
            if(moveup(i) < 0) return -1;
            /* Now place a constant '0' in the current slot
             * so that the expr. '-d1' becomes '0-d1' */
            inexp[i] = strdup(Zero);
            if(inexp[i] == NULL) {error(249); return -1; }
            typin[i] = NUMBER;
            i++;
          }
        }
        prvtoken = typin[i];
        i++;
    } /* end while */
    return 0;
} /* end un2binop */
int moveup(int i)
/* Move the tokens in the array 'inexp' from position i
 * up by 1 slot and adjust 'lenin' accordingly
 */
{
    int j;
    if(i >= MAXSTRLEN) { error(230); return -1; }
    for(j = lenin; j >= i; j--) {
       inexp[j+1] = inexp[j];
       typin[j+1] = typin[j];
    }
    lenin++;
    return 0;
} /* end - moveup */
int makearg(void)
/* In case of Builtins with no arguments, an argument is inserted per force
 * The entire array 'inexp' is scanned for nil argument Builtins
 * and inserts the dummy arg. string '(1)' immediately after the name of Builtin
 * On return , the array 'inexp' contains the adjusted expression */
{
   int i;
   i = 0;
   while(i < lenin) {
     if(typin[i] == BUILTIN && typin[i+1] != '('){
       if(strcmp(inexp[i],"RND") == 0 || strcmp(inexp[i],"DATE$") == 0 ||
          strcmp(inexp[i],"TIME$") == 0 || strcmp(inexp[i],"TIMER") == 0 ||
          strcmp(inexp[i],"FREEFILE") == 0) {
         int j;
         for(j = 0; j < 3; j++){
           i++;
           if(moveup(i) < 0) return -1;
         }
         inexp[i] = strdup(")");
         typin[i] = ')';
         inexp[i-1] = strdup("1");
         typin[i-1] = NUMBER;
         inexp[i-2] = strdup("(");
         typin[i-2] = '(';
       } /* End - If */
     } /* End - If */
     i++;
   } /* End - while */
   return 0;
} /* End - makearg */
int bltin(char *s)
/* Handles only single argument Builtin functions */
/* The multiple argument Builtin functions are re-directed to
 * the function 'ebltin'.
/* 's' contains the name of the Builtin function */
{
        String d1;
        unsigned type1, bltintyp, otyp;
        if(strcmp(s,"LEFT$") == 0 || strcmp(s,"RIGHT$") == 0 ||
           strcmp(s, "MID$") == 0 || strcmp(s,"STRING$") == 0 ||
           strcmp(s,"INSTR") == 0 || strcmp(s,"DOW") == 0) {
              return(ebltin(s));
        }
        strcpy(exprstr,"");
        otyp = NUMVAR;
        d1 = pop(&type1);
        if(d1 == 0)
           return -1;
        libcode(s);
        if(strcmp(s,"ENVIRON$") == 0) {
           if(type1 == STRING || type1 == STRVAR)
               strcpy(s,"EnvS$"); /* ENVIRON$(<string-exp>) */
           else
               strcpy(s,"EnvN$"); /* ENVIRON$(<numeric-exp>) */
        }
        if(strcmp(s,"EOF") == 0)
           strcpy(s,"eof");
        if(strcmp(s,"LEN") == 0 || strcmp(s,"ASC") == 0 ||
           strcmp(s,"VAL") == 0 || strcmp(s,"RTRIM$") == 0 ||
	   strcmp(s,"LTRIM$") == 0||strcmp(s,"UCASE$") == 0 ||
           strcmp(s,"TRIM$") == 0 ||strcmp(s,"EnvS$") == 0 ||
           strcmp(s,"LCASE$") == 0){ /* If LEN | ASC| VAL| EnvS$
                                      * LTRIM$|LCASE$|UCASE$ library function,
                                   * Arg. should be STRING/ STRVAR */
           if(type1 == NUMBER || type1 == NUMVAR){
               error(13); return -1;
           }
        }
        else if(type1 == STRING || type1 == STRVAR) {
           error(13); return -1;
        }
        bltintyp = ((s[strlen(s) - 1] =='$') ? STRING : NUMBER);
        if(bltintyp == STRING) {
           strvarconv(s); otyp = STRVAR;
        }
        strcat(exprstr,s);
        strcat(exprstr,"(");
        if(type1 == NUMVAR){
           strcat(exprstr,"(double)");
           ParenCover(d1);
        }
        else if(type1 == NUMBER){
           strcat(exprstr,"(double)");
           strcat(exprstr,d1);
        }
        else if(type1 == STRING) { /* Bracket it with double quote */
           strcat(exprstr,"\"");
           strcat(exprstr,d1);
           strcat(exprstr,"\"");
        }
        else  /* It is String Variable*/
           strcat(exprstr,d1);
        strcat(exprstr,")");
        if(!emptystack){
            d1 = pop(&type1);
            if(d1 == 0) return -1;
            if(type1 == ',') {
               strcpy(word, s);
               error(217); return -1;
            }
            else push(d1,type1);
        }
	free(d1);
        if(strlen(exprstr) > MAXWORDLEN-50) {
            error(230);  return -1;
        }
        if(push(exprstr, otyp) < 0) return -1;
        return 0;
} /* end of bltin() */
int ebltin(char *s)
/* Handles the translation of multiple argument Builtin functions
 * 's' contains the name of the function */
{
        String t;
        unsigned otyp;
        t = strdup(s);
        strcpy(exprstr,"");
        if(libcode(s) < 0) return -1;
        strvarconv(s);
        strcat(exprstr,s);
        strcat(exprstr,"(");
        if(strcmp(s,"LEFT_") == 0 || strcmp(s,"RIGHT_") == 0) {
          String d1,d2;
          unsigned type1,type2;
          otyp = STRVAR;
          d2 = pop(&type2); /* 2nd argument */
          if(d2 == 0) return -1;
	  if(emptystack){
             strcpy(word, t);
             error(217); return -1;
          }
          if(pop(&type1) == 0) return -1; /* The arg. separator ',' expected*/
          if(type1 != ',') {
             strcpy(word, t);
             error(217); return -1;
          }
          d1 = pop(&type1); /* 1st argument */
          if(d1 == 0) return -1;
          if(!emptystack){
            String d1;
            unsigned type1;
            d1 = pop(&type1);
            if(d1 == 0) return -1;
            if(type1 == ',') {
               strcpy(word, t);
               error(217); return -1;
            }
            else push(d1,type1);
            free(d1);
          }
	  if(type1 != STRVAR && type1 != STRING){
            strcpy(word, d1);
            error(13); return -1;
          }
	  if(type2 != NUMVAR && type2 != NUMBER){
            strcpy(word, d2);
            error(13); return -1;
          }
          if(type1 == STRING)
            strcat(exprstr,"\"");
          strcat(exprstr,d1);
          if(type1 == STRING)
            strcat(exprstr,"\"");
          strcat(exprstr,",");
          if(type2 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d2);
          }
          else { /* It should be NUMBER */
             strcat(exprstr,"(double)");
             strcat(exprstr,d2);
          }
        free(d1); free(d2);
        } /* End - LEFT_ | RIGHT_ */
        if(strcmp(s,"STRING_") == 0){
          String d1,d2;
          unsigned type1,type2;
          otyp = STRVAR;
          d2 = pop(&type2); /* 2nd argument */
          if(d2 == 0) return -1;
	  if(emptystack){
             strcpy(word, t);
             error(217); return -1;
          }
          if(pop(&type1) == 0) return -1; /* The arg. separator ',' expected*/
          if(type1 != ',') {
             strcpy(word, t);
             error(217); return -1;
          }
          d1 = pop(&type1); /* 1st argument */
          if(d1 == 0) return -1;
          if(!emptystack){
            String d1;
            unsigned type1;
            d1 = pop(&type1);
            if(d1 == 0) return -1;
            if(type1 == ',') {
               strcpy(word, t);
               error(217); return -1;
            }
            else push(d1,type1);
            free(d1);
          }
          if(type1 != NUMVAR && type1 != NUMBER){
            strcpy(word, d1);
            error(13); return -1;
          }
          if(type1 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d1);
          }
          else { /* It should be NUMBER */
             strcat(exprstr,"(double)");
             strcat(exprstr,d1);
          }
          strcat(exprstr,",(double)");
          if(type2 == STRING) {
            char temp[2];
            temp[0] = d2[0];
            temp[1] = '\0';
            strcat(exprstr,"'");
            strcat(exprstr, temp);
            strcat(exprstr,"'");
          }
          if(type2 == STRVAR) {
             strcat(exprstr,"(*");
             strcat(exprstr, d2);
             strcat(exprstr,")");
          }
          if(type2 == NUMVAR){
             strcat(exprstr,"(double)");
             ParenCover(d2);
          }
          if(type2 == NUMBER) { 
             strcat(exprstr,"(double)");
             strcat(exprstr,d2);
          }
        free(d1); free(d2);
        } /* End - STRING_ */
        if(strcmp(s,"DOW") == 0) {
           String d1,d[3];
           int i;
           unsigned type1, type[3];
           otyp = NUMVAR;
           for(i = 2; i >= 0; i--) {
             if(emptystack){
                strcpy(word, t);
                error(217); return -1;
             }
	     d[i] = pop(&type[i]);
             if(type[i] != NUMBER && type[i] != NUMVAR) {
               strcpy(word,d[i]);
               error(13); return -1;
             }
             if(i > 0) {
                if(!emptystack) {
                  d1 = pop(&type1);
                  if(type1 != ','){
                    strcpy(word, t);
                    error(217); return -1;
                  } /*End -if */
                }/* End - if */
             } /* End - if */   
             else { /* i == 0 */
                if(!emptystack) {
                  d1 = pop(&type1);
                  if(type1 == ','){
                    strcpy(word, t);
                    error(217); return -1;
                  } /*End -if */
                  else {
                    push(d1,type1); free(d1);
                  }/* End - else */
                }/*End - if */
             } /*End - else */
           } /* End - For */
           for(i = 0; i < 3; i++){
             if(type[i] == NUMVAR) {
               strcat(exprstr,"(double)");
               ParenCover(d[i]);
             }
             else { /* It should be NUMBER */
               strcat(exprstr,"(double)");
               strcat(exprstr,d[i]);
             }
             if(i < 2)
               strcat(exprstr,",");
             free(d[i]);
           } /* End - For */
        } /* End - DOW */
        if(strcmp(s,"MID_") == 0) {
          String d1,d2,d3;
          unsigned type1,type2,type3,argcount;
          otyp = STRVAR;
          d3 = pop(&type3); /* 3rd argument */
          if(d3 == 0) return -1;
	  if(emptystack){
             strcpy(word, t);
             error(217); return -1;
          }
          if(pop(&type1) == 0) return -1; /* The arg. separator ',' expected*/
          if(type1 != ',') {
             strcpy(word, t);
             error(217); return -1;
          }
          d2 = pop(&type2); /* 2nd argument */
          if(d2 == 0) return -1;
          if(emptystack)
             argcount = 2;
          else{
             d1 = pop(&type1);
             if(d1 == 0) return -1; 
             if(type1 != ',') {
                push(d1,type1);
                free(d1);
                argcount = 2;
             }
             else{
                d1 = pop(&type1);
                if(d1 == 0) return -1; 
                argcount = 3;
                if(!emptystack){
                   String d1;
                   unsigned type1;
                   d1 = pop(&type1);
                   if(d1 == 0) return -1;
                   if(type1 == ',') {
                      strcpy(word, t);
                      error(217); return -1;
                   }
                   else push(d1,type1);
                   free(d1);
                }
             }
          }
          if(type3 == STRING || type3 == STRVAR) {
            strcpy(word,d3);
            error(13); return -1;
          }
          if(type3 != NUMBER && type3 != NUMVAR) {
            strcpy(word,d3);
            error(252); return -1;
          }
          if(argcount == 2){
            if(type2 == NUMBER || type2 == NUMVAR){
               strcpy(word,d2);
               error(13); return -1;
            }
            if(type2 != STRING && type2 != STRVAR) {
              strcpy(word,d2);
              error(252); return -1;
            }
            if(type2 == STRING)
               strcat(exprstr,"\"");
            strcat(exprstr,d2);
            if(type2 == STRING)
               strcat(exprstr,"\"");
            strcat(exprstr,",");
            if(type3 == NUMVAR){
               strcat(exprstr,"(double)");
               ParenCover(d3);
            }
            else { /* It should be NUMBER */
               strcat(exprstr,"(double)");
               strcat(exprstr,d3);
            }
            strcat(exprstr,",(double)MAXSTRLEN");
            free(d2); free(d3);
          } /* End of code for arg.count = 2 */
          if(argcount == 3){
             if(type1 == NUMBER || type1 == NUMVAR){
               strcpy(word,d1);
               error(13); return -1;
             }
             if(type1 != STRVAR && type1 != STRING){
               strcpy(word, d1);
               error(252); return -1;
             }
             if(type2 == STRING || type2 == STRVAR){
               strcpy(word,d2);
               error(13); return -1;
             }
             if(type2 != NUMVAR && type2 != NUMBER){
               strcpy(word, d2);
               error(252); return -1;
             }
             if(type1 == STRING)
               strcat(exprstr,"\"");
             strcat(exprstr,d1);
             if(type1 == STRING)
               strcat(exprstr,"\"");
             strcat(exprstr,",");
             if(type2 == NUMVAR){
               strcat(exprstr,"(double)");
               ParenCover(d2);
             }
             else { /* It should be NUMBER */
                strcat(exprstr,"(double)");
                strcat(exprstr,d2);
             }
             strcat(exprstr,",");
             if(type3 == NUMVAR){
               strcat(exprstr,"(double)");
               ParenCover(d3);
             }
             else { /* It should be NUMBER */
                strcat(exprstr,"(double)");
                strcat(exprstr,d3);
             }
             free(d1); free(d2);free(d3);
          } /* End of code for argcount = 3 */
        } /* End - MID_ */
        if(strcmp(s,"INSTR") == 0) {
          String d1,d2,d3;
          unsigned type1,type2,type3,argcount;
          otyp = NUMVAR;
          d3 = pop(&type3); /* 3rd argument */
          if(d3 == 0) return -1;
	  if(emptystack){
             strcpy(word, t);
             error(217); return -1;
          }
          if(pop(&type1) == 0) return -1; /* The arg. separator ',' expected*/
          if(type1 != ',') {
             strcpy(word, t);
             error(217); return -1;
          }
          d2 = pop(&type2); /* 2nd argument */
          if(d2 == 0) return -1;
          if(emptystack)
             argcount = 2;
          else{
             d1 = pop(&type1);
             if(d1 == 0) return -1; 
             if(type1 != ',') {
                push(d1,type1);
                free(d1);
                argcount = 2;
             }
             else{
                d1 = pop(&type1);
                if(d1 == 0) return -1; 
                argcount = 3;
                if(!emptystack){
                   String d1;
                   unsigned type1;
                   d1 = pop(&type1);
                   if(d1 == 0) return -1;
                   if(type1 == ',') {
                      strcpy(word, t);
                      error(217); return -1;
                   }
                   else push(d1,type1);
                   free(d1);
                }
             }
          }
          if(type3 == NUMBER || type3 == NUMVAR) {
            strcpy(word,d3);
            error(13); return -1;
          }
          if(type3 != STRING && type3 != STRVAR) {
            strcpy(word,d3);
            error(252); return -1;
          }
          if(type2 == NUMBER || type2 == NUMVAR){
             strcpy(word,d2);
             error(13); return -1;
          }
          if(type2 != STRING && type2 != STRVAR) {
            strcpy(word,d2);
            error(252); return -1;
          }
          if(argcount == 2)
            strcat(exprstr,"(double) 1");
          if(argcount == 3){
             if(type1 == STRING || type1 == STRVAR){
               strcpy(word,d1);
               error(13); return -1;
             }
             if(type1 != NUMVAR && type1 != NUMBER){
               strcpy(word, d1);
               error(252); return -1;
             }
             if(type1 == NUMVAR){
               strcat(exprstr,"(double)");
               ParenCover(d1);
             }
             else { /* It should be NUMBER */
                strcat(exprstr,"(double)");
                strcat(exprstr,d1);
             }
          } /* End of code specific for arg.count = 3 */
          /* Code common for argcount = 2 as well as 3 */
          strcat(exprstr,",");
          if(type2 == STRING)
             strcat(exprstr,"\"");
          strcat(exprstr,d2);
          if(type2 == STRING)
             strcat(exprstr,"\"");
          strcat(exprstr,",");
          if(type3 == STRING)
             strcat(exprstr,"\"");
          strcat(exprstr,d3);
          if(type3 == STRING)
             strcat(exprstr,"\"");
          if(argcount == 3)
            free(d1);
          free(d2);free(d3);
        } /* End - INSTR */
        strcat(exprstr,")");
        if(strlen(exprstr) > MAXWORDLEN-50) {
            error(230);  return -1;
        }
        if(push(exprstr, otyp) < 0) return -1;
        free(t);
        return 0;
} /* End - ebltin() */

int udf(char *s)
/* Handles the translation of the User Defined Function in string 's' */
{
   int argnum;
   unsigned otyp, kount,atyp[MAXARG], t1;
   String  a[MAXARG], d1, t;
   FUNCTION *fp;
   t = strdup(s);
   if(t[strlen(t)-1] == '$'){  /* It is a string Function */
      t[strlen(t)-1] = '_';    /* Convert the name as per C- syntax */
      otyp = STRVAR;
   }
   else
      otyp = NUMVAR;
   fp = FunSearch(s);
   if(fp == 0) return -1;
   kount = fp->ArgCount;
   argnum = kount - 1;
   while(1 == 1) {
      a[argnum] = pop(&atyp[argnum]);  /* Get the n-th argument from stack */
      if(a[argnum] == 0) return -1;
      if(VTest1(atyp[argnum],fp->ArgType[argnum]) < 0) return -1;
      if(emptystack){
         if(argnum > 0){
            strcpy(word,s);
            error(217); return -1; /*Arg. count mis-match */
         }
         else
           break;
      }
      d1 = pop(&t1);  /* Previous datum should be arg. separator(,) */
      if(d1 == 0) return -1;
      if((t1 != ',' && argnum > 0) || (t1 == ',' && argnum == 0)) {
          strcpy(word,s);
          error(217); return -1; /*Arg. count mis-match */
      }
      if(t1 == ',')   /* There are more arguments */
         argnum--;    /* So, continue the loop */
      else {          /* The arguments are over */
         push(d1,t1);
         free(d1);
         break;      /* So, quit the loop */
      }
   } /* End - while */
   /* Code Generation Part */
   strcpy(exprstr,t);
   strcat(exprstr,"(");
   for(argnum = 0; argnum < kount; argnum++){
      switch(atyp[argnum]) {
         case NUMBER :  strcat(exprstr,"(double)");
                        strcat(exprstr,a[argnum]);
                        break;
         case NUMVAR :  strcat(exprstr,"(double)");
                        ParenCover(a[argnum]);
                        break;
         case STRING :  strcat(exprstr,"\"");
                        strcat(exprstr,a[argnum]);
                        strcat(exprstr,"\"");
                        break;
         case STRVAR :  strcat(exprstr,a[argnum]);
      } /* end - switch */
      if((kount - argnum) > 1)
	 strcat(exprstr,",");
   } /* End - for */
   strcat(exprstr,")");
   if(strlen(exprstr) > MAXWORDLEN-50) {
      error(230);  return -1;
   }
   if(push(exprstr, otyp) < 0) return -1;
   free(t);
   return 0;
} /* End - udf */

int ArrHandler(char *s)
/* Handles the translation of Array variable in string 's' */
{
   int dimnum;
   unsigned otyp, kount,subtyp[MAXDIM], t1;
   String  subval[MAXDIM], d1, t;
   ARRAY *ap;
   t = strdup(s);
   if(t[strlen(t)-1] == '$'){  /* It is a string Array */
      t[strlen(t)-1] = '_';    /* Convert the name as per C- syntax */
      otyp = STRVAR;
   }
   else
      otyp = NUMVAR;
   ap = ArrSearch(s);
   if(ap == 0) return -1;
   kount = ap->DimCount;
   dimnum = kount - 1;
   while(1 == 1) {
      subval[dimnum] = pop(&subtyp[dimnum]); /* Get the n-th subscript from stack */
      if(subval[dimnum] == 0) return -1;
      if(subtyp[dimnum] == STRING || subtyp[dimnum] == STRVAR){
         strcpy(word, subval[dimnum]);
         error(13); return -1;
      }
      if(emptystack){
         if(dimnum > 0){
            strcpy(word,s);
            error(209); return -1; /*Wrong no. of dimensions*/
         }
         else
           break;
      }
      d1 = pop(&t1);  /* Previous datum should be subscip. separator(,) */
      if(d1 == 0) return -1;
      if((t1 != ',' && dimnum > 0) || (t1 == ',' && dimnum == 0)) {
          strcpy(word,s);
          error(209); return -1; /*wrong no. of dimensions*/
      }
      if(t1 == ',')   /* There are more dimensions */
         dimnum--;    /* So, continue the loop */
      else {          /* The subscripts are over */
         push(d1,t1);
         free(d1);
         break;      /* So, quit the loop */
      }
   } /* End - while */
   /* Code Generation Part */
   strcpy(exprstr,t);
   strcat(exprstr,"[");
   for(dimnum = 0; dimnum < kount; dimnum++){
      strcat(exprstr,"(int)(0.5+");
      strcat(exprstr,subval[dimnum]);
      strcat(exprstr,")]");
      if((kount - dimnum) > 1)
         strcat(exprstr,"[");
   } /* End - for */
   if(strlen(exprstr) > MAXWORDLEN-50) {
      error(230);  return -1;
   }
   if(push(exprstr, otyp) < 0) return -1;
   free(t);
   return 0;
} /* End - ArrHandler */

