|
|
1.1 ! root 1: /* Copyright Bell Telephone Laboratories Whippany, N.J. ! 2: ! 3: * ///////////////////////////////////// ! 4: * ///////////////////////////////////// ! 5: * ////////////// evalx.c ////////////// ! 6: * /// J. P. Hawkins WH X4610 8C-001 /// ! 7: * ///// Fri Aug 24 16:40:38 1979 ////// ! 8: * ///////////////////////////////////// ! 9: * ///////////////////////////////////// ! 10: ! 11: * ! 12: * calling format: ! 13: * ! 14: * double value; ! 15: * double evalx(); ! 16: * value = evalx(expstr) ! 17: * ! 18: * where: dummy is now unused ! 19: * expstr is the char string representing the expression ! 20: * to be evaluated. The string must be terminated ! 21: * by a character between values 0 -> 37(8). ! 22: * 0 is the usual ascii string terminator. Values ! 23: * between 001(8) and 37(8) are keyword codes ! 24: * for secondary operations like "then" in an "if" ! 25: * statement or "to" in a "for" statement. ! 26: * ! 27: */ ! 28: /* "@(#) evalx.c: V 1.9 4/21/81" */ ! 29: /* ! 30: * MOD,J.P.Hawkins,31-JAN-81 detects strings and string vars. mixed in ! 31: * numerical expressions as reject. ! 32: */ ! 33: #include "bas.h" ! 34: #define STKSIZ 6 /* stack size */ ! 35: ! 36: int strflg; ! 37: /* ! 38: #define skip00() {while(*expptr == ' ' || *expptr == '\t') *expptr++;} ! 39: */ ! 40: #define skip00() {} /* do nothing */ ! 41: extern int stpflg; /* stop flag for fatal error */ ! 42: double pow(); ! 43: double atof1(); ! 44: double mathcall(); ! 45: ! 46: char *eoexpr; /* pointer to end of expression */ ! 47: /* ! 48: * ! 49: * ! 50: */ ! 51: double ! 52: evalx(exps) ! 53: char exps[]; /* pointer to expression string */ ! 54: { ! 55: char *expptr; /* expression string pointer */ ! 56: char ostack[STKSIZ]; /* operator stack */ ! 57: double nstack[STKSIZ]; /* number stack */ ! 58: int opflag; /* set when operator encountered ! 59: cleared when variable or non-op ! 60: encountered. Used to deal with ! 61: unaries by forcing a 0.0 on the ! 62: number stack */ ! 63: int o, n; /* indicies for ostack & nstack */ ! 64: ! 65: char field[80]; /* expression field */ ! 66: int type; /* field type returned by class */ ! 67: expptr = exps; /* init expression string pointer */ ! 68: o = n = STKSIZ; /* init operator and ! 69: variable stack pointer */ ! 70: opflag = 0; /* init opflag */ ! 71: /* ! 72: * ! 73: * The only ways out of this loop are string terminator or ! 74: * expression terminator (null char) ! 75: * the codes 1 through 37(8) represent encoded keywords (defined in bed.c) ! 76: * those being: ! 77: * goto,go to,then,to,step,<=,=<,<,>=,=>,>, =, or <> ! 78: * ! 79: * This "while" loop is ! 80: * not indented so "all this stuff" fits across standard page ! 81: */ ! 82: while(!(*expptr >= '\0' && *expptr <= '\37')) ! 83: { ! 84: if((type = class(&expptr, field)) < 0) /* get field and type */ ! 85: { ! 86: error(inst.thing.linno, 8); /* EXPR SYNTAX */ ! 87: error(inst.thing.linno, 15); /* FATAL ERROR */ ! 88: stpflg = 1; ! 89: return(0.0);/* return zero on error */ ! 90: } ! 91: ! 92: switch(type){ ! 93: #ifdef STRINGS ! 94: case SVCLASS: ! 95: case STCLASS: ! 96: case SFCLASS: ! 97: case SACLASS: ! 98: error(inst.thing.linno, 49); /* ST. in NUM */ ! 99: stpflg = 1; ! 100: return(0.0); ! 101: break; ! 102: #endif ! 103: case VRCLASS: /* VARIABLE CLASS */ ! 104: getvar(field, &nstack[--n]); ! 105: opflag = 0; ! 106: break; ! 107: case VACLASS: /* SUBSCRIPTED VARIABLE */ ! 108: agetvar(field,&nstack[--n]); ! 109: opflag = 0; ! 110: break; ! 111: case NMCLASS: /* NUMERIC FIELD */ ! 112: nstack[--n] = atof1(field); ! 113: opflag = 0; ! 114: break; ! 115: case FNCLASS: /* FUNCTION REFERENCE */ ! 116: nstack[--n] = mathcall(field); ! 117: opflag = 0; ! 118: break; ! 119: case OPCLASS: /* OPERATOR */ ! 120: switch(*field) { ! 121: case '(': /* begin of expres */ ! 122: nstack[--n] = evalx(expptr); ! 123: opflag = 0; ! 124: expptr = eoexpr; /* put pointer ! 125: to correct place */ ! 126: break; ! 127: case ')': /* end of express */ ! 128: /* ! 129: * eval the rest of the expr ! 130: * between the parens ! 131: */ ! 132: cleanup(nstack,ostack,&n,&o); ! 133: eoexpr = expptr; ! 134: return(nstack[n]); ! 135: break; ! 136: case '+': ! 137: case '-': ! 138: case '*': ! 139: case '/': ! 140: case '^': ! 141: /* ! 142: * handle unaries by forcing ! 143: * a 0.0 onto the nstack before ! 144: * stacking the operator. ! 145: * This occurs when two operators ! 146: * in a row are encountered or the ! 147: * variable stack is empty when ! 148: * an operator encountered. ! 149: */ ! 150: if(opflag || n == STKSIZ) ! 151: nstack[--n] = 0.0; ! 152: opflag = 1; ! 153: stackop(*field,nstack,ostack,&n,&o); ! 154: break; ! 155: default: ! 156: break; ! 157: } ! 158: break; ! 159: default: ! 160: printf("WHAT HAPPENED? TYPE = %d\n", type); ! 161: break; ! 162: } ! 163: /* ! 164: * skip trailing white space so that ! 165: * test at top of this loop fails when ! 166: * it's supposed to ! 167: */ ! 168: skip00(); ! 169: } /* END OF WHILE LOOP */ ! 170: ! 171: cleanup(nstack,ostack,&n,&o); ! 172: eoexpr = expptr; /* save end of expr pointer for ! 173: "for", "if" and other commands */ ! 174: return(nstack[n]); ! 175: } ! 176: /* ! 177: * ! 178: * //// STACK OPERATOR IF PRECIDENCE TEST IS PASSED //// ! 179: */ ! 180: stackop(op,nstack,ostack,n,o) ! 181: char op; ! 182: double nstack[]; ! 183: char ostack[]; ! 184: int *n; ! 185: int *o; ! 186: { ! 187: ! 188: /* ! 189: * if precidence of current operator is ! 190: * HIGHER than the operator on top of the stack ! 191: * or the OPERATOR stack is EMPTY, ! 192: * the precidence test has "passed" so just push ! 193: * the current operator onto the operator stack. ! 194: */ ! 195: if(*o == STKSIZ) /* if stack is empty */ ! 196: { ! 197: ostack[--(*o)] = op; /* stack operator ! 198: precidence done only ! 199: if stack NOT empty */ ! 200: return 0; ! 201: } ! 202: if(precid(op) > precid(ostack[*o])) ! 203: { ! 204: ostack[--(*o)] = op; ! 205: } ! 206: else ! 207: { ! 208: /* ! 209: * OTHERWISE if the current operator ! 210: * precidence is LESS than or EQUAL to the ! 211: * operator on the top of the stack ! 212: * "unstack" the operators from the operator ! 213: * stack until either the stack is empty ! 214: * or the precidence test passes ! 215: */ ! 216: while((precid(op) <= precid(ostack[*o])) && *o < STKSIZ) ! 217: if(unstack(nstack,ostack,n,o) < 0) ! 218: { ! 219: return(-1); /* break loop if bad operator ! 220: encountered */ ! 221: } ! 222: ! 223: ostack[--(*o)] = op; ! 224: } ! 225: return 0; ! 226: } ! 227: /* ! 228: * ! 229: * //// RETURN PRECIDENCE OF OPERATOR IN c //// ! 230: */ ! 231: precid(c) ! 232: char c; ! 233: { ! 234: static char olist[] = "+1-1*2/2^3"; /* list of operators & precidence */ ! 235: register int p; /* scanning register */ ! 236: ! 237: for(p=0; olist[p] != '\0'; p += 2) ! 238: { ! 239: if(c == olist[p]) ! 240: return(olist[p+1] - '0'); ! 241: } ! 242: return(-1); /* if we get here, we're in trouble! */ ! 243: } ! 244: ! 245: ! 246: ! 247: ! 248: /* ! 249: * //// CLEANUP THE REST OF THE EXPRESSION //// ! 250: * ! 251: * "pop and do" operations on opstack until ! 252: * stack empty ! 253: */ ! 254: cleanup(nstack,ostack,n,o) ! 255: double nstack[]; ! 256: char ostack[]; ! 257: int *n; ! 258: int *o; ! 259: { ! 260: while(*o < STKSIZ) ! 261: if(unstack(nstack,ostack,n,o) < 0) ! 262: return(-1); /* break loop if bad operator ! 263: encountered */ ! 264: return 0; ! 265: } ! 266: /* ! 267: * ! 268: * //// POP OPERATER OFF TOP OF OPSTACK //// ! 269: * //// AND PERFORM THAT OPERATION ON ////// ! 270: * //// TOP TWO NUMBERS ON NSTACK ////////// ! 271: * //// NSTACK GETS POPPED AND RESULT ////// ! 272: * //// IS LEFT ON TOP ///////////////////// ! 273: * //// THOSE OPERATIONS ON TOP TWO NUMS ///// ! 274: */ ! 275: unstack(nstack,ostack,n,o) ! 276: double nstack[]; ! 277: char ostack[]; ! 278: int *n; ! 279: int *o; ! 280: { ! 281: switch(ostack[*o]) ! 282: { ! 283: case '^': ! 284: nstack[*n+1] = pow(nstack[*n+1],nstack[*n]); ! 285: break; ! 286: case '*': ! 287: nstack[*n+1] = nstack[*n+1] * nstack[*n]; ! 288: break; ! 289: case '/': ! 290: if(nstack[*n] == 0.0) /* catch overflow */ ! 291: { ! 292: error(inst.thing.linno, 29); /* OVERFLOW ERR */ ! 293: break; ! 294: } ! 295: nstack[*n+1] = nstack[*n+1] / nstack[*n]; ! 296: break; ! 297: case '+': ! 298: nstack[*n+1] = nstack[*n+1] + nstack[*n]; ! 299: break; ! 300: case '-': ! 301: nstack[*n+1] = nstack[*n+1] - nstack[*n]; ! 302: break; ! 303: default: ! 304: error(inst.thing.linno, 8); ! 305: return(-1); ! 306: break; ! 307: } ! 308: (*n)++; /* pop number stack */ ! 309: (*o)++; /* pop operator stack */ ! 310: return(0); ! 311: } ! 312: /* ! 313: * ! 314: * ////// CALL MATH FUNCTION //////// ! 315: * ! 316: * ! 317: * ! 318: * callin format: ! 319: * value = mathcall(string); ! 320: * ! 321: * where: value = floating point value returned by call ! 322: * string = pointer to a null terminated string containong ! 323: * the func text and expression within () - ! 324: * i.e. "sin(EXPRESSION TEXT)" ! 325: */ ! 326: ! 327: /* ! 328: * ! 329: * //////// BASIC INTERPRETER MATH TABLE //////// ! 330: * ! 331: */ ! 332: #ifndef TEST ! 333: double sin(); ! 334: double cos(); ! 335: double atan(); ! 336: double log(); ! 337: double tan(); ! 338: double fact(); ! 339: #ifdef STRINGS ! 340: double len(); ! 341: double val(); ! 342: double asc(); ! 343: #endif ! 344: #endif ! 345: /* ! 346: * //// INSTRUMENT FUNCTIONS //// ! 347: */ ! 348: #ifdef TEST ! 349: double dvmr(); ! 350: double button(); ! 351: double berror(); ! 352: #endif ! 353: double exp(); ! 354: double _int(num) ! 355: double num; ! 356: { ! 357: long trunc; ! 358: trunc=num; ! 359: num=trunc; ! 360: return(num); ! 361: } ! 362: #ifndef TEST ! 363: double sqroot(num) ! 364: double num; ! 365: { ! 366: if(num < 0.0) ! 367: error(inst.thing.linno, 19); ! 368: return(pow(num, 0.5)); ! 369: } ! 370: ! 371: #endif ! 372: double absolute(num) ! 373: double num; ! 374: { ! 375: double fabs(); ! 376: return(fabs(num)); ! 377: } ! 378: ! 379: double rndgen(num) ! 380: double num; ! 381: { ! 382: double rndnum; ! 383: rndnum = rand(); ! 384: return((rndnum/32767.0) * num + 1); ! 385: } ! 386: /* ! 387: * ! 388: * This is the BASIC interpreter math func strin and routine ! 389: * dispatch table. ! 390: * ! 391: */ ! 392: ! 393: /* ! 394: * each entry contains the text for the MATH FUNCTION ! 395: * in question and the address of the routine which services it ! 396: */ ! 397: struct tbl ! 398: { ! 399: char *cmdtxt; ! 400: double (*func)(); ! 401: }; ! 402: #ifndef TEST ! 403: struct tbl mathtbl[] = { ! 404: {"sin", sin}, ! 405: {"cos", cos}, ! 406: {"exp", exp}, ! 407: {"log", log}, ! 408: {"int", _int}, ! 409: {"sqr", sqroot}, ! 410: {"abs", absolute}, ! 411: {"atn", atan}, ! 412: {"rnd", rndgen}, ! 413: {"tan", tan}, ! 414: {"fact", fact}, ! 415: #ifdef STRINGS ! 416: {(char *)1, 0}, /* String function fence */ ! 417: {"len", len}, ! 418: {"val", val}, ! 419: {"asc", asc}, ! 420: #endif ! 421: /* THIS STUFF NOT INCLUDED YET ! 422: {"cot", cotang}, ! 423: {"clg", log10}, ! 424: {"sgn", sign}, ! 425: */ ! 426: {0, 0} ! 427: }; ! 428: #endif ! 429: #ifdef TEST ! 430: struct tbl mathtbl[] { ! 431: {"abs", absolute}, ! 432: {"rnd", rndgen}, ! 433: {"int", _int}, ! 434: {"exp", exp}, ! 435: {"dvmr", dvmr}, ! 436: {"btn", button}, ! 437: {"error", berror}, ! 438: {0, 0} ! 439: }; ! 440: #endif ! 441: /* ! 442: * ! 443: */ ! 444: double ! 445: mathcall(s) ! 446: char s[]; ! 447: { ! 448: char funnam[10]; /* func name copied from 's' ! 449: used for string search */ ! 450: register char *x; /* pointer to paren enclosed expression */ ! 451: double evalx(); ! 452: double value; /* final value returned */ ! 453: double exvalue; /* value of expression before being operated ! 454: upon by the math func */ ! 455: register int i; /* index reg. for expediency */ ! 456: x = s; /* set pointer to func string */ ! 457: /* ! 458: * copy the func name part up to the '(' ! 459: * to use for a string search in the table of names ! 460: */ ! 461: for(i=0; *x != '(' ;) ! 462: { ! 463: funnam[i++] = *x++; ! 464: } ! 465: funnam[i] = '\0'; /* null terminate */ ! 466: /* ! 467: * compare each string in table with funnam ! 468: * when match is found, call using offset code ! 469: * if end-of-table (null) encountered return 0 ! 470: */ ! 471: #ifdef STRINGS ! 472: strflg = 0; ! 473: #endif ! 474: for(i=0; mathtbl[i].cmdtxt != 0 ; i++) ! 475: { ! 476: #ifdef STRINGS ! 477: if(mathtbl[i].cmdtxt == (char *)1) ! 478: { ! 479: i++; ! 480: strflg = 1; /* its a string type */ ! 481: } ! 482: #endif ! 483: if(!(strcmp(funnam, mathtbl[i].cmdtxt))) ! 484: { ! 485: x++; ! 486: #ifdef STRINGS ! 487: if(strflg == 0) ! 488: { ! 489: #endif ! 490: exvalue = evalx(x); ! 491: value = (*mathtbl[i].func)(exvalue); ! 492: return(value); ! 493: #ifdef STRINGS ! 494: } ! 495: else ! 496: { ! 497: value = (*mathtbl[i].func)(x); ! 498: return(value); ! 499: } ! 500: #endif ! 501: } ! 502: } ! 503: error(inst.thing.linno, 17); /* unknown math function */ ! 504: return(0.0); /* oops not in this table, pal */ ! 505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.