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