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