(file) Return to thTestParse.c CVS log (file) (dir) Up to [HallC] / Analyzer / CTP

   1 saw   1.1 /*-----------------------------------------------------------------------------
   2            * Copyright (c) 1993 Southeastern Universities Research Association,
   3            *                    Continuous Electron Beam Accelerator Facility
   4            *
   5            * This software was developed under a United States Government license
   6            * described in the NOTICE file included as part of this distribution.
   7            *
   8            * Stephen A. Wood, 12000 Jefferson Ave., Newport News, VA 23606
   9            * Email: saw@cebaf.gov  Tel: (804) 249-7367  Fax: (804) 249-5800
  10            *-----------------------------------------------------------------------------
  11            * 
  12            * Description:
  13            *  The expression parser and stack executor for the Test Package
  14            *	
  15            * Author:  Stephen Wood, CEBAF Hall C
  16            *
  17            * Revision History:
  18            *   $Log: thTestParse.c,v $
  19            *   Revision 1.16  1996/07/31 20:36:56  saw
  20            *   Support floating point for mod command.  Add trig functions.
  21            *
  22 saw   1.1  * Revision 1.15  1995/08/03  13:56:36  saw
  23            * Add single argument functions
  24            *
  25            * Revision 1.14  1995/04/10  15:51:21  saw
  26            * thEvalImed returns INTOVF if double result is to large to convert to int.
  27            *
  28            * Revision 1.13  1995/02/14  16:53:52  saw
  29            * Make compatible with OSF/Alpha (64 bit pointers)
  30            *
  31            * Revision 1.12  1995/01/09  16:06:11  saw
  32            * Fix a short malloc for a string
  33            *
  34            * Revision 1.11  1994/11/17  18:14:21  saw
  35            * Strip out unary + operators when parsing expressions
  36            *
  37            * Revision 1.10  1994/11/07  14:28:34  saw
  38            * Add thevalchk fortran call to check for expressions.
  39            * Try to avoid bomb outs for bad expressions
  40            *
  41            * Revision 1.9  1994/10/03  12:41:22  saw
  42            * All "/" (division) has real result.  New op "//" has integerized
  43 saw   1.1  * result.  thEvalImed actually gets a double from thTestExecute.
  44            * Added fortran interfaces to thEvalImed (itheval, ftheval, dtheval).
  45            *
  46            * Revision 1.8  1994/09/12  15:12:31  saw
  47            * thGetTok was missing reset of lastop on EOL
  48            *
  49            * Revision 1.7  1994/08/29  20:08:10  saw
  50            * Fix calculation of testscalervarname length
  51            *
  52            * Revision 1.6  1994/08/26  17:46:18  saw
  53            * Register test scaler results
  54            *
  55            * Revision 1.5  1994/08/26  13:36:46  saw
  56            * Add DAVAR_REPOINTOK to some flags
  57            *
  58            * Revision 1.4  1994/06/03  18:54:29  saw
  59            * Replace stderr with STDERR
  60            *
  61            * Revision 1.3  1993/12/02  21:33:36  saw
  62            * Fully allow use of doubles in test expressions
  63            *
  64 saw   1.1  * Revision 1.2  1993/11/24  21:24:54  saw
  65            * thEvalImed now returns double instead of floating result.
  66            *
  67            *	  Revision 1.3  1993/09/22  17:51:06  saw
  68            *	  Allow integer constants to be octal or hex.
  69            *
  70            *	  Revision 1.2  1993/05/11  18:00:10  saw
  71            *	  Update header
  72            *
  73            */
  74           
  75           /* thTestParse.c
  76              
  77              Make test result variable that are created take the type of the rhs???
  78              Add variable names to stack so that expressions can be recreated.
  79              Allow constants to be hex or octal.
  80              Agree on a new comment character or syntax since ! is not part
  81              of expressions.
  82              Add unary operators to executor.  Allow + to be a unary operator too.
  83           
  84              Need to build up a linked list of test results used in a block.  Don't
  85 saw   1.1    duplicate any variables.  Print warning when a scaler test result is
  86              reused.
  87           
  88           */
  89           /*An argument is a variable name, an array, or a number.  Numbers are not
  90           allowed for test result.  Arrays start at 0 if []'s are used and start
  91           at 1 if ()'s are used.  Arrays may only be used for test results if they
  92           are already registered by the analyzer.  (May add option to declare them
  93           in the test package.)*/
  94           
  95           #include <stdio.h>
  96           #include <string.h>
  97           #include <math.h>
  98           #include <values.h>
  99           #include "daVar.h"
 100           #include "th.h"
 101           #include "thUtils.h"
 102           #include "thTestParse.h"
 103           #include "thInternal.h"
 104           #include "cfortran.h"
 105           
 106 saw   1.1 extern daVarStatus thTestRHandler();
 107           
 108           CODE opstack[100];		/* Operator stack */
 109           CODE typstack[100];		/* Result type stack */
 110           
 111           typedef struct
 112           {
 113             char *ops;
 114             int  toks[3];
 115           } OPTABLE;
 116           
 117           OPTABLE optable[] =
 118           {
 119             {"(",{OPLP}},
 120             {")",{OPRP}},
 121             {"[",{OPLINDEXB}},
 122             {"]",{OPRP}},
 123             {"-",{OPSUB}},
 124             {"+",{OPADD}},
 125             {"<<=",{OPISLT,OPSHL,OPISLE}},
 126             {">>=",{OPISGT,OPSHR,OPISGE}},
 127 saw   1.1   {"==",{OPEQUAL,OPISEQUAL}},
 128             {"!=",{OPNOT,OPISNOTEQUAL}},
 129             {"&&",{OPBITAND,OPLOGAND}},
 130             {"||",{OPBITOR,OPLOGOR}},
 131             {"^^",{OPBITXOR,OPLOGXOR}},
 132             {"*",{OPTIMES}},
 133             {"//",{OPDIV,OPIDIV}},
 134             {"%",{OPMOD}},
 135             {"~",{OPCOMP}},
 136             {",",{OPCOMMA}},
 137             {0,{0,0,0}}};
 138           static char *opchars=0;
 139           
 140           /* For Q like test package format, must be in same order as type
 141              types listed in typedef for thTestType. */
 142           char *testCodes[tBAD] 
 143             = {"GA","PA","EQ","BI","AN","IO","EO","MA","US"};
 144           
 145           typedef struct
 146           {
 147             CODE op;
 148 saw   1.1   CODE result[9];
 149           } TYPETABLE;
 150           
 151           TYPETABLE typetable[] =
 152           {
 153             {OPLINDEX,{0,0,0,1,1,1,2,2,2}}, /* Result is same as variable */
 154             {OPLINDEXB,{0,0,0,1,1,1,2,2,2}}, /* being indexed */
 155             {OPLINDEXP,{0,0,0,1,1,1,2,2,2}}, /* Result is same as variable */
 156             {OPLINDEXPB,{0,0,0,1,1,1,2,2,2}}, /* being indexed */
 157             {OPEQUAL,{0,0,0,1,1,1,2,2,2}}, /* Set result type to LHS type */
 158             {OPLOGOR,{0,0,0,0,0,0,0,0,0}}, /* Result is always integer */
 159             {OPLOGXOR,{0,0,0,0,0,0,0,0,0}},
 160             {OPLOGAND,{0,0,0,0,0,0,0,0,0}},
 161             {OPBITOR,{0,0,0,0,0,0,0,0,0}},
 162             {OPBITXOR,{0,0,0,0,0,0,0,0,0}},
 163             {OPBITAND,{0,0,0,0,0,0,0,0,0}},
 164             {OPISEQUAL,{0,0,0,0,0,0,0,0,0}},
 165             {OPISNOTEQUAL,{0,0,0,0,0,0,0,0,0}},
 166             {OPISLT,{0,0,0,0,0,0,0,0,0}},
 167             {OPISLE,{0,0,0,0,0,0,0,0,0}},
 168             {OPISGT,{0,0,0,0,0,0,0,0,0}},
 169 saw   1.1   {OPISGE,{0,0,0,0,0,0,0,0,0}},
 170             {OPSHL,{0,0,0,0,0,0,0,0,0}},
 171             {OPSHR,{0,0,0,0,0,0,0,0,0}},
 172             {OPADD,{0,2,2,2,2,2,2,2,2}},	/* Result is double unless both ops int */
 173             {OPSUB,{0,2,2,2,2,2,2,2,2}},
 174             {OPTIMES,{0,2,2,2,2,2,2,2,2}},
 175             {OPDIV,{2,2,2,2,2,2,2,2,2}},	/* Result always double */
 176             {OPIDIV,{0,0,0,0,0,0,0,0,0}},	/* Result always integer */
 177             {OPMOD,{0,2,2,2,2,2,2,2,2}},
 178             {OPNEG,{0,1,2,0,1,2,0,1,2}},	/* No lh operand, type = rh type */
 179             {OPNOT,{0,0,0,0,0,0,0,0,0}},	/* No lh operand, type always int */
 180             {OPCOMP,{0,0,0,0,0,0,0,0,0}},	/* No lh operand, type always int */
 181             {0,{0,0,0,0,0,0,0,0,0}}};
 182           
 183           INTRINSIC_FUNCTIONS intrinsic_functions[] =
 184           {
 185             {"abs",{0,1,2}},
 186             {"sqrt",{2,2,2}},
 187             {"exp",{2,2,2}},
 188             {"sin",{2,2,2}},
 189             {"cos",{2,2,2}},
 190 saw   1.1   {"tan",{2,2,2}},
 191             {0,{0,0,0}}
 192           };
 193           char *thGetTok(char *linep, int *tokenid, char **tokstr,
 194           	       CODE *tokval, void **tokptr, int expflag, daVarStructList **vlisthead)
 195           /* Pass a pointer to the unscanned portion of the line.
 196              Returns An ID code for operators, and an operand type for operands in
 197              tokenid.
 198              Returns the string for the operand in tokstr.  (Null otherwise)
 199              Returns the operand value in tokval, or in tokptr if the operand is
 200              a pointer.
 201              If the operand is a function, then tokenid will be pushfunction, and
 202              tokval will be a the fuction id.
 203           
 204              Function returns pointer to remainder of the line.
 205           
 206           
 207              */
 208           {
 209             static char string[100];
 210             static int lasttoktype=0;	/* Last tok was an operator */
 211 saw   1.1   static CODE lastop=0;
 212           
 213             char *savelinep;
 214             char *stringp;
 215             char *ptr,c;
 216             int tindex,sindex;
 217             daVarStruct *varp;
 218             DAFLOAT f;
 219           
 220             /* Build up a list of characters that can start operators */
 221             if(opchars == 0){
 222               int count=0;
 223               int i;
 224           
 225               while(optable[count++].ops != 0) ;
 226               opchars = (char *) malloc(count);
 227               for(i=0;i<(count-1); i++)
 228                 opchars[i] = optable[i].ops[0];
 229               opchars[count-1] = 0;
 230             }
 231           
 232 saw   1.1   *tokstr = 0;
 233             *tokval = 0;
 234             *tokptr = 0;
 235             *tokenid = 0;			/* Will signify an undeclared operand */
 236           
 237             if(!(*linep)) {
 238               *tokenid = OPEOL;
 239               lasttoktype = 0;
 240               lastop = 0;
 241               return(0);
 242             }
 243             savelinep = linep;
 244             while(*linep == ' ' || *linep == '\t') linep++;
 245             if((ptr = strchr(opchars,*linep))) { /* Operator */
 246               tindex = ptr -  opchars;
 247               if(lasttoktype == 0 && *linep == '-') { /*  Last thing was an operator */
 248                 *tokenid = OPNEG;		/* So the '-' must be a negative sign */
 249                 linep++;
 250               } else if(lasttoktype == 0 && *linep == '+') { /* Unary plus */
 251                 linep++;
 252                 goto operand;
 253 saw   1.1     } else if(lasttoktype == 1 && *linep == '(') {
 254                 *tokenid = OPLINDEX;
 255                 linep++;
 256               } else if(lasttoktype == 3 && *linep == '(') {
 257           	/* How will we know when the right hand operator is the closing
 258           	   paren of the function?  We don't need to know.  The RHP only
 259           	   acts to determine precedence.  */
 260                 *tokenid = OPLFARG;
 261                 linep++;
 262               } else {
 263                 linep++;
 264                 *tokenid = optable[tindex].toks[0];
 265                 sindex = 1;
 266                 if(*linep) {		/* Don't search past end of line */
 267           	while((c = optable[tindex].ops[sindex])) {
 268           	  if(*linep == c) {
 269           	    *tokenid = optable[tindex].toks[sindex];
 270           	    linep++;
 271           	    break;
 272           	  }
 273           	  sindex++;
 274 saw   1.1 	}
 275                 }
 276               }
 277               /*  Following two lines were before last }. */
 278               if(*tokenid == OPRP) lasttoktype = 2; /* Minus is minus after ) or ] */
 279               else lasttoktype = 0;
 280               /* For OPLINDEX and OPLINDEXB, need to search ahead for matching ) or ]
 281                  and check if the next operator is an = not ==).  If so, then we
 282                  need to return OPLINDEXP or OPLINDEXPB.  */
 283               if(*tokenid == OPLINDEX || *tokenid == OPLINDEXB){
 284                 char *p; char rc; int ccount=0; int bcount=0;
 285                 if(*tokenid == OPLINDEXB) rc = ']';
 286                 else rc = ')';
 287                 p = linep;
 288                 while(*p && (*p != rc || bcount || ccount)) {
 289           	switch(*p++)
 290           	  {
 291           	  case '(': ccount++; break;
 292           	  case ')': ccount--; break;
 293           	  case '[': bcount++; break;
 294           	  case ']': bcount--; break;
 295 saw   1.1 	  default: break;
 296           	  }
 297                 }				/* Only NULL or balanced rc terminates */
 298                 if(*p++){			/* Search for = */
 299           	while(*p == ' ' || *p=='\t') p++;
 300           	if(*p == '=' && *(p+1) != '=') {
 301           	  *tokenid += (OPLINDEXP - OPLINDEX); 
 302           	  /* Assumes OPLINDEXBP-OPLINDEXB is the same*/
 303           	}
 304                 } else
 305           	fprintf(STDERR,"thTest: Parenthesis balance problem\n");
 306               }
 307               lastop = *tokenid;
 308             } else {			/* Operand */
 309               int optype;
 310               int isnum;
 311               int efound;
 312           
 313             operand:
 314               lasttoktype = 1;
 315               stringp = string;
 316 saw   1.1     /* Scan until operator or whitespace is reached */
 317               isnum = 1; efound = 0;
 318           /* What a hack to check for scientific notation */
 319               while(*linep && *linep!=' ' && *linep!='\t' && !strchr(opchars,*linep)){
 320                 if(*linep == 'e' || *linep == 'E') {
 321           	if(efound) {
 322           	  isnum = 0;
 323           	} else {
 324           	  if(stringp > string) {
 325           	    efound=1;
 326           	  } else {
 327           	    isnum = 0;
 328           	  }
 329           	}
 330                 } else if(!isdigit(*linep) && *linep != '.') isnum = 0;
 331                 *stringp++ = *linep++;
 332               }
 333               if(isnum && efound) {	/* Exponential, scan past last digit */
 334                 if(*linep == '-' || *linep == '+') *stringp++ = *linep++;
 335                 while(isdigit(*linep)) {
 336           	*stringp++ = *linep++;
 337 saw   1.1       }
 338               }
 339               while(*linep == ' ' || *linep == '\t') linep++; /* Skip past whitespace */
 340               *stringp = 0;
 341               *tokstr = string;
 342           /*    printf("token=%s\n",string);*/
 343               switch(thIDToken(string))
 344                 {
 345                 case TOKINT:
 346           	sscanf(string,"%li",tokval);
 347           	*tokenid = OPPUSHINT;
 348           	break;
 349                 case TOKFLOAT:
 350           	f = atof(string);
 351           	*tokval = *(DAINT *)&f;	/* Copy floating value */
 352           	*tokenid = OPPUSHFLOAT;
 353           	break;
 354                 case TOKVAR:
 355           	{
 356           	  char **classlist;
 357           	  thOperandType optype;
 358 saw   1.1 
 359           	  optype = thGetOperandType(string,linep,lastop,0);
 360           	  classlist = thGetClassList(optype);
 361           /* If token is a result variable (and we are in non-immediate mode), and the
 362              variable is an integer type, then we need to add this variable to a list
 363              of variables for the current block.   (Probably add real  variable to
 364              the list anyway. ) This will allow us to acumulate scalers.  The opaque
 365              pointer of each variable in the list will point to the scaler array. */
 366           
 367           	  /* First check if variable is really an intrinsic function */
 368           	  {
 369           	    int ifunc;
 370           	    ifunc = 0;
 371           	    while(intrinsic_functions[ifunc].name) {
 372           	      if(strcasecmp(string,intrinsic_functions[ifunc].name)==0) {
 373           		*tokenid = OPPUSHFUNCTION;
 374           		*tokval = ifunc;
 375           		lasttoktype = 3;
 376           		break;
 377           	      }
 378           	      ifunc++;
 379 saw   1.1 	    }
 380           	    if(*tokenid) break;	/* Hopefully this breaks out of case */
 381           	  }
 382           	  if(daVarLookupPWithClass(string,classlist,&varp) == S_SUCCESS) {
 383           /*	    printf("Found variable %s[%s]\n",string,varp->name);*/
 384           	    if(varp->type == DAVARFLOAT) {/* If next operator is a ( or [ */
 385           /*	      printf("FLOAT ");*/
 386           	      /* then push pointer instead of */
 387           #define ISARRAYORLHS(x) (*x=='(' || *x=='[' || (*x=='=' && *(x+1)!='='))
 388           	      *tokenid = ISARRAYORLHS(linep) ? OPPUSHPFLOAT : OPPUSHFLOATP; 
 389           	    } else if(varp->type == DAVARDOUBLE){	/* value onto rpn stack */
 390           /*	      printf("DOUBL ");*/
 391           	      *tokenid = ISARRAYORLHS(linep) ? OPPUSHPDOUBLE : OPPUSHDOUBLEP;
 392           	    } else if(varp->type == DAVARINT){	/* value onto rpn stack */
 393           /*	      printf("INT   ");*/
 394           	      *tokenid = ISARRAYORLHS(linep) ? OPPUSHPINT : OPPUSHINTP;
 395           	    }
 396           	    else {
 397           	      fprintf(STDERR
 398           		      ,"thTest: Variable %s[%s] must be integer, float or double\n"
 399           		      ,string,varp->name);
 400 saw   1.1 	    }
 401           /*	    *tokval = *(DAINT *)&varp->varptr;*/ /* Get the pointer */
 402           	    *tokptr = varp->varptr;
 403           	  } else if(*linep=='=' && (*(linep+1)!='=')){
 404           	    /* Undefined variable is an unindexed result */
 405           	    /* For now, create an integer variable.  Later figure out how
 406           	       to make the variable the same type as the rhs */
 407           	    daVarStruct var;
 408           	    var.name = (char *) malloc(strlen(classlist[0])
 409           				       +strlen(string)+2);
 410           	    strcpy(var.name,classlist[0]);
 411           	    strcat(var.name,".");
 412           	    strcat(var.name,string);
 413           	    var.varptr = (void *) malloc(sizeof(DAINT));
 414           	    var.size = 1;
 415           	    var.opaque = 0;
 416           	    var.rhook = var.whook = 0;
 417           	    var.type = DAVARINT;
 418           	    var.flag = DAVAR_READONLY | DAVAR_REPOINTOK;
 419           	    var.title = savelinep;
 420           	    daVarRegister((int) 0,&var); /* Create test result */
 421 saw   1.1 	    daVarLookupP(var.name,&varp);
 422           	    free(var.name);
 423           printf("Created test result %s\n",varp->name);
 424           	    *tokenid = OPPUSHPINT;
 425           /*	    *tokval = *(DAINT *)&varp->varptr;*/
 426           	    *tokptr = varp->varptr;
 427           	  } /* else 
 428           	       printf("%s not found\n",string);
 429           	       }*/
 430           	  /* If variable does not exist, caller will note that toktype and
 431           	     tokval have not been set. */
 432           	  if(optype == otRESULT && vlisthead){ /* Don't make scalers for */
 433           	    thAddVarToList(vlisthead,varp); /* Variables created in */
 434           	    if(varp->type == DAVARINT) { /* thEvalImed */
 435           	      DAINT *sarray; int i;
 436           	      if(varp->opaque == 0) { /* No scaler array yet */
 437           		char *testscalervarname;
 438           		daVarStruct *svarp; /* Pointer to scaler var struct */
 439           		testscalervarname = /* Add the "scaler" attribute */
 440           		  (char *) malloc(strlen(varp->name)+strlen(SCALERSTR)+2);
 441           		strcpy(testscalervarname,varp->name);
 442 saw   1.1 		strcat(testscalervarname,".");
 443           		strcat(testscalervarname,SCALERSTR);
 444           		if(daVarLookupP(testscalervarname,&svarp) != S_SUCCESS) {
 445           		  daVarStruct svar;
 446           		  svar.name = testscalervarname;
 447           		  svar.opaque = 0;
 448           		  svar.rhook = svar.whook = 0;
 449           		  svar.type = DAVARINT;
 450           		  svar.flag = DAVAR_READONLY | DAVAR_REPOINTOK;
 451           		  svar.varptr = (void *) malloc(varp->size*sizeof(DAINT));
 452           		  svar.size = varp->size;
 453           		  /* Actually not OK to repoint, but this says CTP made it */
 454           		  svar.title = varp->name;
 455           		  daVarRegister((int) 0, &svar);
 456           		  daVarLookupP(svar.name,&svarp);
 457           		}
 458           		varp->opaque = (DAINT *) svarp->varptr;
 459           		varp->rhook = thTestRHandler;
 460           		free(testscalervarname);
 461           	      }
 462           	      sarray = varp->opaque;
 463 saw   1.1 	      for(i=0;i<varp->size;i++)
 464           		sarray[i] = 0;
 465           	    }
 466           	  }
 467           	}
 468           	break;
 469                 default:
 470           	fprintf(STDERR,"thTest: Error understanding %s\n",string);
 471           	break;
 472                 }
 473           /*    printf("token = %x\n",*tokenid);*/
 474               lastop = 0;
 475             }
 476             while(*linep == ' ' || *linep == '\t') linep++; /* Skip whitespace */
 477             return(linep);
 478           }
 479             
 480           
 481           char **thGetClassList(thOperandType optype)
 482           {
 483             static char *explist[]={PARMSTR,EVENTSTR,TESTSTR,0}; /* Immediate expressions */
 484 saw   1.1   static char *loglist[]={TESTSTR,PARMSTR,EVENTSTR,0}; /* Logical operand */
 485             static char *numlist[]={EVENTSTR,PARMSTR,TESTSTR,0}; /* Operand is a value */
 486             static char *resultlistp[]={TESTSTR,EVENTSTR,PARMSTR,0}; /* Operand is a result */
 487           
 488             switch(optype)
 489               {
 490               case otIMMED:
 491                 return(explist);
 492               case otLOGIC:
 493                 return(loglist);
 494               case otVALUE:
 495                 return(numlist);
 496               case otRESULT:
 497                 return(resultlistp);
 498               }
 499           }
 500           
 501           thOperandType thGetOperandType(char *soperand, char *rest, CODE lastop,
 502           			       int expflag)
 503           {
 504             if(expflag)
 505 saw   1.1     return(otIMMED);
 506             else if(lastop == OPNOT)
 507               return(otLOGIC);
 508             else if(lastop != 0 && (lastop != OPLOGOR)
 509           		  && (lastop != OPLOGAND) && (lastop != OPLOGXOR)
 510           		  && (lastop != OPEQUAL) && (lastop != OPCOMMA)
 511           		  && (lastop != OPLP))
 512               return(otVALUE);
 513             else {
 514               /* This is really ugly code to determine if the operand
 515                  is a result, logical operand, or numerical operand from the
 516                  surrounding operators.  The last operator is known, but it must
 517                  search ahead for the next operator.  This code should be  burried
 518                  in a subroutine. */
 519               
 520               char *p;
 521               p = rest;
 522               if(*p == '(' || *p == '[') {
 523                 int ccount=0; int bcount=0;
 524                 if(*p++ == '(') ccount++; else bcount++;
 525                 while(*p && (bcount || ccount)){
 526 saw   1.1 	/*	      printf("%c(%d,%d)\n",*p,ccount,bcount);*/
 527           	switch(*p++) {
 528           	case '(': ccount++; break; case ')': ccount--; break;
 529           	case '[': bcount++; break; case ']': bcount--; break;
 530           	default: break;
 531           	}
 532                 }
 533                 /*	    printf("pos=%c, %d %d ",*p,ccount,bcount);*/
 534               }
 535               while(*p == ' ' || *p =='\t') p++;
 536           #define ISLOG(x,y) (*x==y && *(x+1)==y)
 537               /*	  printf(", Nextchar=%c:  ",*p);*/
 538               if(*p=='=' && *(p+1)!='=') {
 539                 return(otRESULT);
 540               } else if((ISLOG(p,'|') || ISLOG(p,'&') || ISLOG(p,'^')
 541           	       || *p=='\0' || *p==',' || *p == ')'))
 542                 return(otLOGIC);
 543             }
 544             return(otVALUE);
 545           }
 546           
 547 saw   1.1 CODE thGetResultType(CODE operator, CODE leftoptype, CODE rightoptype)
 548           {
 549             /* For a given operator, determine the data type of the result a given
 550                combination of the types of the lh and rh operands.
 551                Assumes that only types 0, 1, or 2 are allowed. */
 552             
 553             int lrindex;
 554             int i;
 555           
 556             if(leftoptype < 0 || leftoptype > 2 || rightoptype < 0 || rightoptype > 2) {
 557               fprintf(STDERR,"thTest: Illegal operand type %x %x\n",leftoptype,rightoptype);
 558               return(0);
 559             }
 560             lrindex = (leftoptype * 3) + rightoptype;
 561             for(i=0; typetable[i].op; i++) { /* Do Linear search for the operator */
 562               if(operator == typetable[i].op) {
 563                 return(typetable[i].result[lrindex]);
 564               }
 565             }
 566             fprintf(STDERR,"Operator %x not found in result type table\n",operator);
 567             return(0);
 568 saw   1.1 }
 569           
 570           thStatus thEvalImed(char *line, double *d, DAINT *i)
 571           /* ImmedOBiately evaluate the expression in line.  Will internally evaluate to
 572              a float, and then pass back both the float and interized values. */
 573           {
 574             CODEPTR codehead, codenext, codelimit, codelastop;
 575             int codesize;
 576           #define RDOUBLE
 577           #ifdef RDOUBLE
 578             double result;
 579           #else
 580             float result;			/* Should    change to double */
 581           #endif
 582             thStatus retcode;
 583           
 584           /*  printf("%s=",line);*/
 585             codesize = 10+2*strlen(line);
 586             codehead = codenext = (CODEPTR) malloc(sizeof(CODE)*codesize);
 587             codelimit = codehead + codesize;
 588           #ifdef RDOUBLE
 589 saw   1.1   *codenext++ = OPPUSHPDOUBLE;
 590           #ifdef USEMEMCPY
 591             {
 592               void *resultp;
 593               resultp = &result;
 594             memcpy(((void **)codenext)++, (void *) &resultp, sizeof(void *));
 595             }
 596           #else
 597             *((void **) codenext)++ = (void *) &result;
 598           #endif
 599           /*  printf("%x\n",codenext);*/
 600           #else
 601             *codenext++ = OPPUSHPFLOAT;	/* Should change to double */
 602             *((void **) codenext)++ = (void *) &result;
 603           #endif
 604             retcode = S_SUCCESS;
 605             if(thBookaTest(line,&codehead,&codenext,&codelimit,&codelastop,0)!=S_SUCCESS) {
 606               fprintf(STDERR,"Failure interpreting expression |%s|\n",line);
 607               result = 0.0;
 608               retcode = S_FAILURE;
 609             } else {
 610 saw   1.1     int exptype;
 611               CODE lastop;
 612           #if 0
 613               printf("%x-%x=%d\n",codenext,codehead,codenext-codehead);
 614               {
 615                 CODEPTR code;
 616                 for(code=codehead;code < codenext; code++)
 617           	if(code==codelastop) printf("* %x\n",*code);
 618           	else printf("  %x\n",*code);
 619               }
 620           #endif
 621               codenext = codelastop;
 622               exptype = *codenext++ & OPRESTYPEMASK;
 623               lastop = *codelastop & OPCODEMASK;
 624               if(lastop == OPPUSHPINT || lastop == OPPUSHINTP) {
 625                 *((DAINT **)codenext)++;
 626               } else if(lastop == OPPUSHINT) {
 627                 if(exptype == OPRDOUBLE) {
 628           	*((DADOUBLE *)codenext)++;
 629                 } else {			/* Assume ints, floats have size */
 630           	*((DAINT *)codenext)++;
 631 saw   1.1       }
 632               }
 633           #ifdef RDOUBLE
 634               *codenext++ = OPEQUAL | 0x202 | (exptype<<4);
 635           #else
 636               *codenext++ = OPEQUAL | 0x101 | (exptype<<4);
 637           #endif
 638           #ifdef RDOUBLE
 639               *codenext++ = OPEOL | (OPRDOUBLE<<4);
 640           #else
 641               *codenext++ = OPEOL;
 642           #endif
 643               if(thExecuteCode("IMMED",codehead,codenext)!=S_SUCCESS){
 644                 fprintf(STDERR,"Failure evaluating expression |%s|\n",line);
 645                 result = 0.0;
 646                 retcode = S_FAILURE;
 647               }
 648             }
 649           /*  printf("%f\n",result);*/
 650             free(codehead);
 651             if(d) *d = result;
 652 saw   1.1   if(i) {
 653               if(result>=MAXINT || result <=-MAXINT) {
 654                 if(retcode==S_SUCCESS)
 655           	retcode=S_INTOVF;
 656               } else {
 657                 *i = floatToLong(result);
 658               }
 659             }
 660             return(retcode);
 661           }
 662             
 663           thStatus thBookaTest(char *line, CODEPTR *codeheadp, CODEPTR *codenextp,
 664           		     CODEPTR *codelimitp, CODEPTR *codelastop, daVarStructList **vlisthead)
 665           /* if expflag != 0, still treat as an expression even if there is no
 666              equal sign in the line.
 667              Return codes:
 668                S_SUCCESS = Line OK
 669                S_FAILURE = Line not executable
 670           */
 671           {
 672             /*  int type;*/
 673 saw   1.1   char *args[20];
 674             int nargs;
 675             thTokenType toktyp;
 676             daVarStruct var, *varp;
 677             thTestType test_type;
 678             int forcefloat;
 679             int iarg;
 680             char *token;
 681             CODEPTR codenext;
 682             int index;			/* Used for index into arrays */
 683             thStatus status;
 684             int expflag;
 685           
 686             if(codelastop) expflag = 1; else expflag = 0;
 687             status = S_SUCCESS;
 688             if(*codenextp + 2*strlen(line) > *codelimitp) {
 689               CODEPTR src,dst,newhead;
 690               int newsize;
 691           /*    printf("Increasing the size of the code stack from %d ",
 692           	   *codelimitp-*codeheadp);*/
 693               src = *codeheadp;
 694 saw   1.1     newsize = max((*codelimitp-*codeheadp)+CODEGROWSIZE
 695           		  ,(*codenextp-*codeheadp)+2*strlen(line));
 696               newhead = dst = (CODEPTR) malloc(sizeof(CODE)*newsize);
 697               while(src < *codenextp) *dst++ = *src++;
 698               if(*codeheadp) free(*codeheadp);
 699               *codelimitp = newhead + newsize;
 700               *codeheadp = newhead;
 701               *codenextp = *codenextp + (dst - src);
 702               
 703               /*printf("to %d, using %d\n",*codelimitp-*codeheadp,*codenextp - *codeheadp);*/
 704             }
 705             codenext = *codenextp;
 706           
 707           /*  printf("Booking \"%s\"\n",line);*/
 708             if(strchr(line,'=')||expflag) {
 709               char *linep;
 710               int TOKEN,TOKCOMP;
 711               char *tokstr; CODE tokval;
 712               void *tokptr;
 713               CODE *osp, *tsp, opcode;
 714               CODE rightoptype,leftoptype,resultoptype;
 715 saw   1.1 
 716               osp = opstack;		/* Stack of pending operators */
 717               *osp = '\0';
 718           
 719               tsp = typstack;		/* Stack of Current result type */
 720           				/* Like the stack in the executor but only */
 721           				/* contains the data types */
 722               linep = line;
 723               do {
 724                 /* Get tokens until there are no more (last token will be OPEOL) */
 725                 linep = thGetTok(linep,&TOKEN, &tokstr, &tokval, &tokptr, expflag, vlisthead);
 726                 if(tokstr) {		/* Operand */
 727           /*	printf("Operand %s |",tokstr);*/
 728           	if(codelastop) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */
 729           	if(TOKEN) {
 730           	  if(tokptr == 0) {	/* Value operand - 4 bytes */
 731           	    *codenext++ = TOKEN;	/* String not put on stack at moment */
 732           	    *codenext++ = tokval;
 733           	  } else {		/* Pointer operand - maybe 8 bytes */
 734           	    *codenext++ = TOKEN;
 735           #ifdef USEMEMCPY
 736 saw   1.1 	    memcpy(((void **)codenext)++,&tokptr,sizeof(void *));
 737           #else
 738           	    *((void **)codenext)++ = tokptr;
 739           #endif
 740           	  }
 741           	  /* If TOKEN is push function, then tokval is an index into a list of
 742           	     functions.  We put this index on tsp instead of the result type. */
 743           	  if(TOKEN==OPPUSHFUNCTION) {
 744           	    *tsp++ = tokval;
 745           	  } else {
 746           	    *tsp++ = TOKEN & OPRESTYPEMASK;
 747           	  }
 748           	} else {
 749           	  fprintf(STDERR,"thTest: Unregistered variable %s\n",tokstr);
 750                     status = S_TH_UNREG;
 751           	  *codenext++ = OPPUSHINT;
 752           	  *codenext++ = 0;
 753           	  *tsp++ = OPPUSHINT & OPRESTYPEMASK;
 754           	}
 755                 } else {			/* Operator */
 756           	switch(TOKEN)
 757 saw   1.1 	  {
 758           	  case 0:
 759           	    fprintf(STDERR,"thTest: Bad token\n");
 760           	    return(S_FAILURE);
 761           	    break;
 762           	  case OPLP:
 763           	    *++osp = TOKEN;
 764           	    break;
 765           	  default:
 766           /*	    printf("OSP:");
 767           	    {CODE *sp; for(sp=opstack;sp<=osp;sp++)
 768           	       printf("%x:",*sp);}
 769           	    printf("\n");
 770           */
 771           	    /* Generate code for all operators of equal or higher precedence
 772           	       that are pending on the operator stack. */
 773           	    if((TOKEN & OPGROUPMASK) == OPLINDEXGROUP)
 774           	      TOKCOMP = 0xFFFFFFF; /* Nothing higher in precedence */
 775           	    else
 776           	      TOKCOMP = TOKEN & OPPRECMASK;
 777           	    while((*osp & OPPRECMASK) >= TOKCOMP){
 778 saw   1.1 /*	      if((*osp & OPPRECMASK) == OPLINDEX){*/
 779           	      if((*osp & OPGROUPMASK) == OPLINDEXGROUP){
 780           		if(TOKEN == OPRP) {
 781           		  if(*osp == OPLFARG) TOKEN = OPRFARG;
 782           		  else TOKEN = OPRINDEX; /* Break from case */
 783           		}
 784           		TOKCOMP = 0xFFFFFFF; /* Terminate osp rundown */
 785           	      }
 786           	      rightoptype = *--tsp;
 787           	      leftoptype = ((*osp & OPPRECMASK) == OPUNARY) ? 0 : (*--tsp);
 788           	      /* If the Operator is "evaluate function", we need to find out
 789           		 what the function is so that we can get the correct
 790           		 result type.  leftoptype should be an index into
 791           		 "intrinsic_functions".  We can use that and rightoptype
 792           		 to look up the resulttype. */
 793           	      if(*osp==OPLFARG) {
 794           		resultoptype = 
 795           		  intrinsic_functions[leftoptype].result[rightoptype];
 796           	      } else {
 797           		resultoptype = thGetResultType(*osp,leftoptype,rightoptype);
 798           	      }
 799 saw   1.1 	      opcode = *osp--;
 800           	      opcode |= (leftoptype << 8) | (rightoptype << 4)
 801           		| resultoptype;
 802           	      if(codelastop) if((opcode&&OPCODEMASK) !=OPEOL) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */
 803           	      *codenext++ = opcode;
 804           	      *tsp++ = resultoptype; /* Keep a rpn stack of the data type */
 805           	    }
 806           	    if(TOKEN == OPRINDEX || TOKEN == OPRFARG) break; /* No clean up needed */
 807           
 808           	    if(TOKEN == OPRP) {
 809           	      if(*osp == OPLP) osp--; /* ) removes matching ( */
 810           	      else {
 811           		fprintf(STDERR,"Right paren not matched by left\n");
 812           		return(S_FAILURE);
 813           	      }
 814           	    } else if(TOKEN == OPEOL || TOKEN == OPCOMMA) {
 815           	      if(codelastop) if(TOKEN==OPCOMMA) *codelastop = codenext; /* HACK for thImmed: Save ptr to last operator */
 816           	      *codenext++ = TOKEN | (*--tsp) << 4; /* Leave type in Right type field */
 817           	    } else {
 818           	      *++osp = TOKEN;
 819           	    }
 820 saw   1.1 	    break;
 821           	  }
 822                 }
 823                 /* Token processed */
 824               } while (linep);
 825           /* Check that stacks are OK.  Need to add some clean up of allocated memory. */
 826               if(tsp != typstack) {
 827                 fprintf(STDERR,"%d items left on type stack\n",tsp-typstack);
 828                 return(S_FAILURE);
 829               }
 830               if(osp != opstack) {
 831                 fprintf(STDERR,"%d items left on operand stack\n",osp-opstack);
 832                 return(S_FAILURE);
 833               }
 834             } else {			/* Old style test lines */
 835               int i;
 836               nargs = thCommas(line,args);
 837               for(i=0;i<nargs;i++){
 838                 args[i] = thSpaceStrip(args[i]); /* Remove all space from the argument */
 839               }
 840               
 841 saw   1.1     if(nargs <= 1) return(S_FAILURE);
 842               
 843               {				/* Interpret the test type. */
 844                 
 845                 for(test_type=0;test_type<tBAD;test_type++){
 846           	if(testCodes[test_type][0] == toupper(args[1][0]) &&
 847           	   testCodes[test_type][1] == toupper(args[1][1])) break;
 848                 }
 849                 if(test_type == tBAD) return(S_FAILURE);
 850                 /*    printf("%s\n",testCodes[test_type]);*/
 851               }
 852               if(test_type == tGATE || test_type == tEQ) {
 853                 forcefloat = 1;
 854               } else forcefloat = 0;
 855               for(iarg=2;iarg<nargs;iarg++){
 856                 DAFLOAT f;		/* Should do double  here */
 857                 token = args[iarg];
 858                 toktyp = thIDToken(token);
 859                 switch((toktyp = thIDToken(token)))
 860           	{
 861           	case TOKINT:
 862 saw   1.1 	  *codenext++ = PUSHI;
 863           	  if(forcefloat) {
 864           	    f = atof(token);
 865           	    *codenext++ = *(DAINT *)&f;
 866           	  } else {
 867           	    DAINT i;
 868           	    sscanf(token,"%li",&i);
 869           	    *codenext++ = i;
 870           	  }
 871           	  break;
 872           	case TOKFLOAT:		/* Should Do all floats as doubles */
 873           	  *codenext++ = PUSHI;
 874           	  if(forcefloat) {
 875           	    f = atof(token);
 876           	    *codenext++ = *(DAINT *)&f;
 877           	  } else {
 878           	    *codenext++ = (DAINT) floatToLong(atof(token));
 879           	  }
 880           	  break;
 881           	case TOKARRAY:
 882           	case TOKVAR:
 883 saw   1.1 	  {
 884           	    char *p; int index; char leftp;
 885           	    if(toktyp == TOKARRAY) {
 886           	      p = thTokenArray(token,&index);
 887           	      leftp = *p; *p = 0;	/* Save ( or [ then null terminate */
 888           	    } else
 889           	      index = 0;
 890           	    if(daVarLookup(token,&var)!=S_SUCCESS) {
 891           	      fprintf(STDERR,"(thTest) %s not registered\n",token);
 892           	      *codenext++ = PUSHI;
 893           	      if(forcefloat) {
 894           		f = 0.0;
 895           		*codenext++ = *(DAINT *)&f;
 896           	      } else
 897           		*codenext++ = 0;
 898           	    } else {
 899           	      if(forcefloat)
 900           		if(var.type == DAVARINT)
 901           		  *codenext++ = PUSHITOFS; /* Push converting to float and skip */
 902           		else if(var.type == DAVARFLOAT)
 903           		  *codenext++ = PUSHS;
 904 saw   1.1 		else
 905           		  *codenext++ = PUSHI; /* Push immediate */
 906           	      else
 907           		if(var.type == DAVARINT)
 908           		  *codenext++ = PUSHS; /* Push and skip */
 909           		else if(var.type == DAVARFLOAT)
 910           		  *codenext++ = PUSHFTOIS;
 911           		else
 912           		  *codenext++ = PUSHI; /* Push immediate */
 913           	      if(toktyp == TOKARRAY)
 914           		*p = leftp;
 915           	      if(var.type == DAVARINT || var.type == DAVARFLOAT) {
 916           		*((void **)codenext)++ = ((DAINT *) var.varptr+index);
 917           		*((void **)codenext) = (void *) malloc(sizeof(token)+1);
 918           		strcpy((char *) *((void **)codenext)++,token);
 919           	      } else {
 920           		if(forcefloat) {
 921           		  f = 0.0;
 922           		  *codenext++ = *(DAINT *)&f;
 923           		} else
 924           		  *codenext++ = 0;
 925 saw   1.1 	      }
 926           	    }
 927           	  }
 928           	  break;
 929           	}
 930               }
 931               *codenext++ = test_type;	/* Operation to do on pushed args */
 932               *codenext++ = nargs-2;	/* # of args pushed on stack for this op */
 933               
 934               /* Now push test result on stack */
 935               *codenext++ = POPS;
 936               
 937               token = args[0];
 938               toktyp = thIDToken(token);
 939               index = 0;
 940               switch((toktyp = thIDToken(token)))
 941                 {
 942                 case TOKINT:
 943                 case TOKFLOAT:
 944           	fprintf(STDERR,"(thTest) Test result must be a variable name\n");
 945           	return(S_FAILURE);	/* No test is added to program */
 946 saw   1.1       case TOKARRAY:
 947           	/* First check if variable with index has been already registered
 948           	   perhaps from a previous booking of histograms */
 949           	if(daVarLookup(token,&var) != S_SUCCESS){
 950           	  char *p; char leftp;
 951           	  p = thTokenArray(token,&index);
 952           	  leftp = *p; *p = 0;	/* Save ( or [ then null terminate */
 953           	  if(daVarLookup(token,&var) != S_SUCCESS){
 954           	    fprintf(STDERR,
 955           		    "(thTest) Arrays %s must be registered\n",token);
 956           	    return(S_FAILURE);
 957           	  }
 958           	  *p = leftp;		/* Restore the left ( or [ */
 959           	  if(index >= var.size) {
 960           	    fprintf(STDERR,
 961           		    "(thTest) Array size for %s exceeded\n",token);
 962           	    return(S_FAILURE);
 963           	  }
 964           	  if(var.type != DAVARINT) {
 965           	    fprintf(STDERR,
 966           		    "(thTest) Array %s must be of integer*4\n",token);
 967 saw   1.1 	    return(S_FAILURE);
 968           	  }
 969           	  var.varptr = (DAINT *) var.varptr + index;
 970           	  var.name = token;
 971           	  var.opaque = 0;
 972           	}
 973           	var.title = token;	/* Eventually be the input line */
 974           	break;
 975                 case TOKVAR:
 976           	if(daVarLookup(token,&var)!=S_SUCCESS) {
 977           	  var.name = token;
 978           	  var.varptr = (void *) malloc(sizeof(DAINT));
 979           	  var.opaque = 0;
 980           	  var.rhook = var.whook = 0;
 981           	  var.type = DAVARINT;
 982           	  var.flag = DAVAR_READONLY | DAVAR_REPOINTOK;
 983           /* Do I need to set the size to 1 here??? */
 984           	}
 985           	var.title = token;
 986           	break;
 987                 }
 988 saw   1.1     daVarRegister((int) 0, &var);	/* Create or replace variable */
 989               *((void **)codenext)++ = ((DAINT *) var.varptr);
 990               /* Save the token string for future reference */
 991               *((void **)codenext) =  ((void *) malloc(strlen(token)+1));
 992               strcpy((char *) *((void **)codenext)++,token);
 993               
 994             }
 995             *codenextp = codenext;
 996             return(status);
 997             
 998           }
 999           long thevalchk_(char *A1,unsigned C1)
1000           /* Check if an expression is valid.  Return's zero if valid */
1001           {
1002             long A0;
1003             char *B1;
1004             thStatus status;
1005           
1006             status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1:
1007           		      (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0'
1008           		       ,kill_trailing(B1,' ')),0,0);
1009 saw   1.1   if(B1) free(B1);
1010             return(status);
1011           }
1012           
1013           long itheval_(char *A1,unsigned C1)
1014           {
1015             long A0;
1016             char *B1;
1017             DAINT i;
1018             double d;
1019             thStatus status;
1020           
1021             status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1:
1022           		      (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0'
1023           		       ,kill_trailing(B1,' ')),0,&i);
1024             if(B1) free(B1);
1025             return i;
1026           }
1027           double dtheval_(char *A1,unsigned C1)
1028           {
1029             long A0;
1030 saw   1.1   char *B1;
1031             double d;
1032             thStatus status;
1033           
1034             status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1:
1035           		      (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0'
1036           		       ,kill_trailing(B1,' ')),&d,0);
1037             if(B1) free(B1);
1038             return d;
1039           }
1040           float ftheval_(char *A1,unsigned C1)
1041           {
1042             long A0;
1043             char *B1;
1044             DAINT i;
1045             double d;
1046             float f;
1047             thStatus status;
1048           
1049             status = thEvalImed((!*(int *)A1)?0:memchr(A1,'\0',C1)?A1:
1050           		      (memcpy(B1=malloc(C1+1),A1,C1),B1[C1]='\0'
1051 saw   1.1 		       ,kill_trailing(B1,' ')),&d,0);
1052             if(B1) free(B1);
1053             f = d;
1054             return f;
1055           }

Analyzer/Replay: Mark Jones, Documents: Stephen Wood
Powered by
ViewCVS 0.9.2-cvsgraph-1.4.0