ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.5
Committed: Tue Jun 26 09:15:11 1990 UTC (33 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.4: +4 -3 lines
Log Message:
nit-picking for Stardent compiler

File Contents

# Content
1 /* Copyright (c) 1986 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * Compute data values using expression parser
9 *
10 * 7/1/85 Greg Ward
11 *
12 * 11/11/85 Made channel input conditional with (INCHAN) compiles.
13 *
14 * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
15 *
16 * 1/29/87 Made variables conditional (VARIABLE)
17 *
18 * 5/19/88 Added constant subexpression elimination (RCONST)
19 */
20
21 #include <stdio.h>
22
23 #include <ctype.h>
24
25 #include <errno.h>
26
27 #include "calcomp.h"
28
29 #define MAXLINE 256 /* maximum line length */
30 #define MAXWORD 64 /* maximum word length */
31
32 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
33
34 #define isid(c) (isalnum(c) || (c) == '_' || (c) == '.')
35
36 #define isdecimal(c) (isdigit(c) || (c) == '.')
37
38 extern double atof(), pow();
39 extern char *fgets(), *savestr();
40 extern char *emalloc(), *ecalloc();
41 extern EPNODE *curfunc;
42 extern double efunc(), evariable();
43 static double euminus(), echannel(), eargument(), enumber();
44 static double eadd(), esubtr(), emult(), edivi(), epow();
45 static double ebotch();
46 extern int errno;
47
48 int nextc; /* lookahead character */
49
50 double (*eoper[])() = { /* expression operations */
51 ebotch,
52 #ifdef VARIABLE
53 evariable,
54 #else
55 ebotch,
56 #endif
57 enumber,
58 euminus,
59 #ifdef INCHAN
60 echannel,
61 #else
62 ebotch,
63 #endif
64 #ifdef FUNCTION
65 efunc,
66 eargument,
67 #else
68 ebotch,
69 ebotch,
70 #endif
71 ebotch,
72 ebotch,
73 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
74 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
75 emult,
76 eadd,
77 0,
78 esubtr,
79 0,
80 edivi,
81 0,0,0,0,0,0,0,0,0,0,0,0,0,
82 ebotch,
83 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
85 epow,
86 };
87
88 static char *infile; /* input file name */
89 static FILE *infp; /* input file pointer */
90 static char *linbuf; /* line buffer */
91 static int linepos; /* position in buffer */
92
93
94 EPNODE *
95 eparse(expr) /* parse an expression string */
96 char *expr;
97 {
98 EPNODE *ep;
99
100 initstr(NULL, expr);
101 #if defined(VARIABLE) && defined(FUNCTION)
102 curfunc = NULL;
103 #endif
104 ep = getE1();
105 if (nextc != EOF)
106 syntax("unexpected character");
107 return(ep);
108 }
109
110
111 double
112 eval(expr) /* evaluate an expression string */
113 char *expr;
114 {
115 register EPNODE *ep;
116 double rval;
117
118 ep = eparse(expr);
119 rval = evalue(ep);
120 epfree(ep);
121 return(rval);
122 }
123
124
125 epfree(epar) /* free a parse tree */
126 register EPNODE *epar;
127 {
128 register EPNODE *ep;
129
130 switch (epar->type) {
131
132 #if defined(VARIABLE) || defined(FUNCTION)
133 case VAR:
134 varfree(epar->v.ln);
135 break;
136 #endif
137
138 case SYM:
139 freestr(epar->v.name);
140 break;
141
142 case NUM:
143 case CHAN:
144 case ARG:
145 case TICK:
146 break;
147
148 default:
149 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
150 epfree(ep);
151 break;
152
153 }
154
155 efree((char *)epar);
156 }
157
158 /* the following used to be a switch */
159 #ifdef FUNCTION
160 static double
161 eargument(ep)
162 EPNODE *ep;
163 {
164 return(argument(ep->v.chan));
165 }
166 #endif
167
168 static double
169 enumber(ep)
170 EPNODE *ep;
171 {
172 return(ep->v.num);
173 }
174
175 static double
176 euminus(ep)
177 EPNODE *ep;
178 {
179 register EPNODE *ep1 = ep->v.kid;
180
181 return(-evalue(ep1));
182 }
183
184 #ifdef INCHAN
185 static double
186 echannel(ep)
187 EPNODE *ep;
188 {
189 return(chanvalue(ep->v.chan));
190 }
191 #endif
192
193 static double
194 eadd(ep)
195 EPNODE *ep;
196 {
197 register EPNODE *ep1 = ep->v.kid;
198
199 return(evalue(ep1) + evalue(ep1->sibling));
200 }
201
202 static double
203 esubtr(ep)
204 EPNODE *ep;
205 {
206 register EPNODE *ep1 = ep->v.kid;
207
208 return(evalue(ep1) - evalue(ep1->sibling));
209 }
210
211 static double
212 emult(ep)
213 EPNODE *ep;
214 {
215 register EPNODE *ep1 = ep->v.kid;
216
217 return(evalue(ep1) * evalue(ep1->sibling));
218 }
219
220 static double
221 edivi(ep)
222 EPNODE *ep;
223 {
224 register EPNODE *ep1 = ep->v.kid;
225 double d;
226
227 d = evalue(ep1->sibling);
228 if (d == 0.0) {
229 wputs("Division by zero\n");
230 errno = ERANGE;
231 return(0.0);
232 }
233 return(evalue(ep1) / d);
234 }
235
236 static double
237 epow(ep)
238 EPNODE *ep;
239 {
240 register EPNODE *ep1 = ep->v.kid;
241 double d;
242 int lasterrno;
243
244 lasterrno = errno;
245 errno = 0;
246 d = pow(evalue(ep1), evalue(ep1->sibling));
247 #ifdef IEEE
248 if (!finite(d))
249 errno = EDOM;
250 #endif
251 if (errno) {
252 wputs("Illegal power\n");
253 return(0.0);
254 }
255 errno = lasterrno;
256 return(d);
257 }
258
259 static double
260 ebotch(ep)
261 EPNODE *ep;
262 {
263 eputs("Bad expression!\n");
264 quit(1);
265 }
266
267
268 EPNODE *
269 ekid(ep, n) /* return pointer to a node's nth kid */
270 register EPNODE *ep;
271 register int n;
272 {
273
274 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
275 if (--n < 0)
276 break;
277
278 return(ep);
279 }
280
281
282 int
283 nekids(ep) /* return # of kids for node ep */
284 register EPNODE *ep;
285 {
286 register int n = 0;
287
288 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
289 n++;
290
291 return(n);
292 }
293
294
295 initfile(file, fp) /* prepare input file */
296 char *file;
297 FILE *fp;
298 {
299 static char inpbuf[MAXLINE];
300
301 infile = file;
302 infp = fp;
303 linbuf = inpbuf;
304 linepos = 0;
305 inpbuf[0] = '\0';
306 scan();
307 }
308
309
310 initstr(file, s) /* prepare input string */
311 char *file;
312 char *s;
313 {
314 infile = file;
315 infp = NULL;
316 linbuf = s;
317 linepos = 0;
318 scan();
319 }
320
321
322 scan() /* scan next character */
323 {
324 do {
325 if (linbuf[linepos] == '\0')
326 if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
327 nextc = EOF;
328 else {
329 nextc = linbuf[0];
330 linepos = 1;
331 }
332 else
333 nextc = linbuf[linepos++];
334 if (nextc == '{') {
335 scan();
336 while (nextc != '}')
337 if (nextc == EOF)
338 syntax("'}' expected");
339 else
340 scan();
341 scan();
342 }
343 } while (isspace(nextc));
344 }
345
346
347 syntax(err) /* report syntax error and quit */
348 char *err;
349 {
350 register int i;
351
352 eputs(linbuf);
353 if (linbuf[strlen(linbuf)-1] != '\n')
354 eputs("\n");
355 for (i = 0; i < linepos-1; i++)
356 eputs(linbuf[i] == '\t' ? "\t" : " ");
357 eputs("^ ");
358 if (infile != NULL) {
359 eputs(infile);
360 eputs(": ");
361 }
362 eputs(err);
363 eputs("\n");
364 quit(1);
365 }
366
367
368 addekid(ep, ekid) /* add a child to ep */
369 register EPNODE *ep;
370 EPNODE *ekid;
371 {
372 if (ep->v.kid == NULL)
373 ep->v.kid = ekid;
374 else {
375 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
376 ;
377 ep->sibling = ekid;
378 }
379 ekid->sibling = NULL;
380 }
381
382
383 char *
384 getname() /* scan an identifier */
385 {
386 static char str[MAXWORD+1];
387 register int i;
388
389 for (i = 0; i < MAXWORD && isid(nextc); i++, scan())
390 str[i] = nextc;
391 str[i] = '\0';
392
393 return(str);
394 }
395
396
397 int
398 getinum() /* scan a positive integer */
399 {
400 register int n;
401
402 n = 0;
403 while (isdigit(nextc)) {
404 n = n * 10 + nextc - '0';
405 scan();
406 }
407 return(n);
408 }
409
410
411 double
412 getnum() /* scan a positive float */
413 {
414 register int i;
415 char str[MAXWORD+1];
416
417 i = 0;
418 while (isdigit(nextc) && i < MAXWORD) {
419 str[i++] = nextc;
420 scan();
421 }
422 if (nextc == '.' && i < MAXWORD) {
423 str[i++] = nextc;
424 scan();
425 while (isdigit(nextc) && i < MAXWORD) {
426 str[i++] = nextc;
427 scan();
428 }
429 }
430 if ((nextc == 'e' || nextc == 'E') && i < MAXWORD) {
431 str[i++] = nextc;
432 scan();
433 if ((nextc == '-' || nextc == '+') && i < MAXWORD) {
434 str[i++] = nextc;
435 scan();
436 }
437 while (isdigit(nextc) && i < MAXWORD) {
438 str[i++] = nextc;
439 scan();
440 }
441 }
442 str[i] = '\0';
443
444 return(atof(str));
445 }
446
447
448 EPNODE *
449 getE1() /* E1 -> E1 ADDOP E2 */
450 /* E2 */
451 {
452 register EPNODE *ep1, *ep2;
453
454 ep1 = getE2();
455 while (nextc == '+' || nextc == '-') {
456 ep2 = newnode();
457 ep2->type = nextc;
458 scan();
459 addekid(ep2, ep1);
460 addekid(ep2, getE2());
461 #ifdef RCONST
462 if (ep1->type == NUM && ep1->sibling->type == NUM)
463 ep2 = rconst(ep2);
464 #endif
465 ep1 = ep2;
466 }
467 return(ep1);
468 }
469
470
471 EPNODE *
472 getE2() /* E2 -> E2 MULOP E3 */
473 /* E3 */
474 {
475 register EPNODE *ep1, *ep2;
476
477 ep1 = getE3();
478 while (nextc == '*' || nextc == '/') {
479 ep2 = newnode();
480 ep2->type = nextc;
481 scan();
482 addekid(ep2, ep1);
483 addekid(ep2, getE3());
484 #ifdef RCONST
485 if (ep1->type == NUM && ep1->sibling->type == NUM)
486 ep2 = rconst(ep2);
487 #endif
488 ep1 = ep2;
489 }
490 return(ep1);
491 }
492
493
494 EPNODE *
495 getE3() /* E3 -> E3 ^ E4 */
496 /* E4 */
497 {
498 register EPNODE *ep1, *ep2;
499
500 ep1 = getE4();
501 while (nextc == '^') {
502 ep2 = newnode();
503 ep2->type = nextc;
504 scan();
505 addekid(ep2, ep1);
506 addekid(ep2, getE4());
507 #ifdef RCONST
508 if (ep1->type == NUM && ep1->sibling->type == NUM)
509 ep2 = rconst(ep2);
510 #endif
511 ep1 = ep2;
512 }
513 return(ep1);
514 }
515
516
517 EPNODE *
518 getE4() /* E4 -> ADDOP E5 */
519 /* E5 */
520 {
521 register EPNODE *ep1, *ep2;
522
523 if (nextc == '-') {
524 scan();
525 ep2 = getE5();
526 if (ep2->type == NUM) {
527 ep2->v.num = -ep2->v.num;
528 return(ep2);
529 }
530 ep1 = newnode();
531 ep1->type = UMINUS;
532 addekid(ep1, ep2);
533 return(ep1);
534 }
535 if (nextc == '+')
536 scan();
537 return(getE5());
538 }
539
540
541 EPNODE *
542 getE5() /* E5 -> (E1) */
543 /* VAR */
544 /* NUM */
545 /* $N */
546 /* FUNC(E1,..) */
547 /* ARG */
548 {
549 int i;
550 register EPNODE *ep1, *ep2;
551
552 if (nextc == '(') {
553 scan();
554 ep1 = getE1();
555 if (nextc != ')')
556 syntax("')' expected");
557 scan();
558 return(ep1);
559 }
560
561 #ifdef INCHAN
562 if (nextc == '$') {
563 scan();
564 ep1 = newnode();
565 ep1->type = CHAN;
566 ep1->v.chan = getinum();
567 return(ep1);
568 }
569 #endif
570
571 #if defined(VARIABLE) || defined(FUNCTION)
572 if (isalpha(nextc)) {
573 ep1 = newnode();
574 ep1->type = VAR;
575 ep1->v.ln = varinsert(getname());
576
577 #if defined(VARIABLE) && defined(FUNCTION)
578 if (curfunc != NULL)
579 for (i = 1, ep2 = curfunc->v.kid->sibling;
580 ep2 != NULL; i++, ep2 = ep2->sibling)
581 if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
582 epfree(ep1);
583 ep1 = newnode();
584 ep1->type = ARG;
585 ep1->v.chan = i;
586 break;
587 }
588 #endif
589 #ifdef FUNCTION
590 if (nextc == '(') {
591 ep2 = newnode();
592 ep2->type = FUNC;
593 addekid(ep2, ep1);
594 ep1 = ep2;
595 do {
596 scan();
597 addekid(ep1, getE1());
598 } while (nextc == ',');
599 if (nextc != ')')
600 syntax("')' expected");
601 scan();
602 }
603 #ifndef VARIABLE
604 else
605 syntax("'(' expected");
606 #endif
607 #endif
608 return(ep1);
609 }
610 #endif
611
612 if (isdecimal(nextc)) {
613 ep1 = newnode();
614 ep1->type = NUM;
615 ep1->v.num = getnum();
616 return(ep1);
617 }
618 syntax("unexpected character");
619 }
620
621
622 #ifdef RCONST
623 EPNODE *
624 rconst(epar) /* reduce a constant expression */
625 register EPNODE *epar;
626 {
627 register EPNODE *ep;
628
629 ep = newnode();
630 ep->type = NUM;
631 errno = 0;
632 ep->v.num = evalue(epar);
633 if (errno)
634 syntax("bad constant expression");
635 epfree(epar);
636
637 return(ep);
638 }
639 #endif