|
|
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.