ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.3
Committed: Thu May 7 22:30:41 1992 UTC (32 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +5 -8 lines
Log Message:
simplified and improved logic for testing of constant functions

File Contents

# Content
1 /* Copyright (c) 1991 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
31 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
32
33 #define isdecimal(c) (isdigit(c) || (c) == '.')
34
35 #ifndef atof
36 extern double atof();
37 #endif
38 extern double 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,
82 ebotch,
83 0,0,
84 ebotch,
85 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
86 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
87 epow,
88 };
89
90 static FILE *infp; /* input file pointer */
91 static char *linbuf; /* line buffer */
92 static char *infile; /* input file name */
93 static int lineno; /* input line number */
94 static int linepos; /* position in buffer */
95
96
97 EPNODE *
98 eparse(expr) /* parse an expression string */
99 char *expr;
100 {
101 EPNODE *ep;
102
103 initstr(expr, NULL, 0);
104 #if defined(VARIABLE) && defined(FUNCTION)
105 curfunc = NULL;
106 #endif
107 ep = getE1();
108 if (nextc != EOF)
109 syntax("unexpected character");
110 return(ep);
111 }
112
113
114 double
115 eval(expr) /* evaluate an expression string */
116 char *expr;
117 {
118 register EPNODE *ep;
119 double rval;
120
121 ep = eparse(expr);
122 rval = evalue(ep);
123 epfree(ep);
124 return(rval);
125 }
126
127
128 epfree(epar) /* free a parse tree */
129 register EPNODE *epar;
130 {
131 register EPNODE *ep;
132
133 switch (epar->type) {
134
135 #if defined(VARIABLE) || defined(FUNCTION)
136 case VAR:
137 varfree(epar->v.ln);
138 break;
139 #endif
140
141 case SYM:
142 freestr(epar->v.name);
143 break;
144
145 case NUM:
146 case CHAN:
147 case ARG:
148 case TICK:
149 break;
150
151 default:
152 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
153 epfree(ep);
154 break;
155
156 }
157
158 efree((char *)epar);
159 }
160
161 /* the following used to be a switch */
162 #ifdef FUNCTION
163 static double
164 eargument(ep)
165 EPNODE *ep;
166 {
167 return(argument(ep->v.chan));
168 }
169 #endif
170
171 static double
172 enumber(ep)
173 EPNODE *ep;
174 {
175 return(ep->v.num);
176 }
177
178 static double
179 euminus(ep)
180 EPNODE *ep;
181 {
182 register EPNODE *ep1 = ep->v.kid;
183
184 return(-evalue(ep1));
185 }
186
187 #ifdef INCHAN
188 static double
189 echannel(ep)
190 EPNODE *ep;
191 {
192 return(chanvalue(ep->v.chan));
193 }
194 #endif
195
196 static double
197 eadd(ep)
198 EPNODE *ep;
199 {
200 register EPNODE *ep1 = ep->v.kid;
201
202 return(evalue(ep1) + evalue(ep1->sibling));
203 }
204
205 static double
206 esubtr(ep)
207 EPNODE *ep;
208 {
209 register EPNODE *ep1 = ep->v.kid;
210
211 return(evalue(ep1) - evalue(ep1->sibling));
212 }
213
214 static double
215 emult(ep)
216 EPNODE *ep;
217 {
218 register EPNODE *ep1 = ep->v.kid;
219
220 return(evalue(ep1) * evalue(ep1->sibling));
221 }
222
223 static double
224 edivi(ep)
225 EPNODE *ep;
226 {
227 register EPNODE *ep1 = ep->v.kid;
228 double d;
229
230 d = evalue(ep1->sibling);
231 if (d == 0.0) {
232 wputs("Division by zero\n");
233 errno = ERANGE;
234 return(0.0);
235 }
236 return(evalue(ep1) / d);
237 }
238
239 static double
240 epow(ep)
241 EPNODE *ep;
242 {
243 register EPNODE *ep1 = ep->v.kid;
244 double d;
245 int lasterrno;
246
247 lasterrno = errno;
248 errno = 0;
249 d = pow(evalue(ep1), evalue(ep1->sibling));
250 #ifdef IEEE
251 if (!finite(d))
252 errno = EDOM;
253 #endif
254 if (errno) {
255 wputs("Illegal power\n");
256 return(0.0);
257 }
258 errno = lasterrno;
259 return(d);
260 }
261
262 static double
263 ebotch(ep)
264 EPNODE *ep;
265 {
266 eputs("Bad expression!\n");
267 quit(1);
268 }
269
270
271 EPNODE *
272 ekid(ep, n) /* return pointer to a node's nth kid */
273 register EPNODE *ep;
274 register int n;
275 {
276
277 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
278 if (--n < 0)
279 break;
280
281 return(ep);
282 }
283
284
285 int
286 nekids(ep) /* return # of kids for node ep */
287 register EPNODE *ep;
288 {
289 register int n = 0;
290
291 for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
292 n++;
293
294 return(n);
295 }
296
297
298 initfile(fp, fn, ln) /* prepare input file */
299 FILE *fp;
300 char *fn;
301 int ln;
302 {
303 static char inpbuf[MAXLINE];
304
305 infp = fp;
306 linbuf = inpbuf;
307 infile = fn;
308 lineno = ln;
309 linepos = 0;
310 inpbuf[0] = '\0';
311 scan();
312 }
313
314
315 initstr(s, fn, ln) /* prepare input string */
316 char *s;
317 char *fn;
318 int ln;
319 {
320 infp = NULL;
321 infile = fn;
322 lineno = ln;
323 linbuf = s;
324 linepos = 0;
325 scan();
326 }
327
328
329 getscanpos(fnp, lnp, spp, fpp) /* return current scan position */
330 char **fnp;
331 int *lnp;
332 char **spp;
333 FILE **fpp;
334 {
335 if (fnp != NULL) *fnp = infile;
336 if (lnp != NULL) *lnp = lineno;
337 if (spp != NULL) *spp = linbuf+linepos;
338 if (fpp != NULL) *fpp = infp;
339 }
340
341
342 int
343 scan() /* scan next character, return literal next */
344 {
345 register int lnext = 0;
346
347 do {
348 if (linbuf[linepos] == '\0')
349 if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
350 nextc = EOF;
351 else {
352 nextc = linbuf[0];
353 lineno++;
354 linepos = 1;
355 }
356 else
357 nextc = linbuf[linepos++];
358 if (!lnext)
359 lnext = nextc;
360 if (nextc == '{') {
361 scan();
362 while (nextc != '}')
363 if (nextc == EOF)
364 syntax("'}' expected");
365 else
366 scan();
367 scan();
368 }
369 } while (isspace(nextc));
370 return(lnext);
371 }
372
373
374 char *
375 ltoa(l) /* convert long to ascii */
376 long l;
377 {
378 static char buf[16];
379 register char *cp;
380 int neg = 0;
381
382 if (l == 0)
383 return("0");
384 if (l < 0) {
385 l = -l;
386 neg++;
387 }
388 cp = buf + sizeof(buf);
389 *--cp = '\0';
390 while (l) {
391 *--cp = l % 10 + '0';
392 l /= 10;
393 }
394 if (neg)
395 *--cp = '-';
396 return(cp);
397 }
398
399
400 syntax(err) /* report syntax error and quit */
401 char *err;
402 {
403 register int i;
404
405 if (infile != NULL || lineno != 0) {
406 if (infile != NULL) eputs(infile);
407 if (lineno != 0) {
408 eputs(infile != NULL ? ", line " : "line ");
409 eputs(ltoa((long)lineno));
410 }
411 eputs(": syntax error:\n");
412 }
413 eputs(linbuf);
414 if (linbuf[strlen(linbuf)-1] != '\n')
415 eputs("\n");
416 for (i = 0; i < linepos-1; i++)
417 eputs(linbuf[i] == '\t' ? "\t" : " ");
418 eputs("^ ");
419 eputs(err);
420 eputs("\n");
421 quit(1);
422 }
423
424
425 addekid(ep, ekid) /* add a child to ep */
426 register EPNODE *ep;
427 EPNODE *ekid;
428 {
429 if (ep->v.kid == NULL)
430 ep->v.kid = ekid;
431 else {
432 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
433 ;
434 ep->sibling = ekid;
435 }
436 ekid->sibling = NULL;
437 }
438
439
440 char *
441 getname() /* scan an identifier */
442 {
443 static char str[MAXWORD+1];
444 register int i, lnext;
445
446 lnext = nextc;
447 for (i = 0; i < MAXWORD && isid(lnext); i++, lnext = scan())
448 str[i] = lnext;
449 str[i] = '\0';
450 while (isid(lnext)) /* skip rest of name */
451 lnext = scan();
452
453 return(str);
454 }
455
456
457 int
458 getinum() /* scan a positive integer */
459 {
460 register int n, lnext;
461
462 n = 0;
463 lnext = nextc;
464 while (isdigit(lnext)) {
465 n = n * 10 + lnext - '0';
466 lnext = scan();
467 }
468 return(n);
469 }
470
471
472 double
473 getnum() /* scan a positive float */
474 {
475 register int i, lnext;
476 char str[MAXWORD+1];
477
478 i = 0;
479 lnext = nextc;
480 while (isdigit(lnext) && i < MAXWORD) {
481 str[i++] = lnext;
482 lnext = scan();
483 }
484 if (lnext == '.' && i < MAXWORD) {
485 str[i++] = lnext;
486 lnext = scan();
487 while (isdigit(lnext) && i < MAXWORD) {
488 str[i++] = lnext;
489 lnext = scan();
490 }
491 }
492 if ((lnext == 'e' || lnext == 'E') && i < MAXWORD) {
493 str[i++] = lnext;
494 lnext = scan();
495 if ((lnext == '-' || lnext == '+') && i < MAXWORD) {
496 str[i++] = lnext;
497 lnext = scan();
498 }
499 while (isdigit(lnext) && i < MAXWORD) {
500 str[i++] = lnext;
501 lnext = scan();
502 }
503 }
504 str[i] = '\0';
505
506 return(atof(str));
507 }
508
509
510 EPNODE *
511 getE1() /* E1 -> E1 ADDOP E2 */
512 /* E2 */
513 {
514 register EPNODE *ep1, *ep2;
515
516 ep1 = getE2();
517 while (nextc == '+' || nextc == '-') {
518 ep2 = newnode();
519 ep2->type = nextc;
520 scan();
521 addekid(ep2, ep1);
522 addekid(ep2, getE2());
523 #ifdef RCONST
524 if (ep1->type == NUM && ep1->sibling->type == NUM)
525 ep2 = rconst(ep2);
526 #endif
527 ep1 = ep2;
528 }
529 return(ep1);
530 }
531
532
533 EPNODE *
534 getE2() /* E2 -> E2 MULOP E3 */
535 /* E3 */
536 {
537 register EPNODE *ep1, *ep2;
538
539 ep1 = getE3();
540 while (nextc == '*' || nextc == '/') {
541 ep2 = newnode();
542 ep2->type = nextc;
543 scan();
544 addekid(ep2, ep1);
545 addekid(ep2, getE3());
546 #ifdef RCONST
547 if (ep1->type == NUM && ep1->sibling->type == NUM)
548 ep2 = rconst(ep2);
549 #endif
550 ep1 = ep2;
551 }
552 return(ep1);
553 }
554
555
556 EPNODE *
557 getE3() /* E3 -> E4 ^ E3 */
558 /* E4 */
559 {
560 register EPNODE *ep1, *ep2;
561
562 ep1 = getE4();
563 if (nextc == '^') {
564 ep2 = newnode();
565 ep2->type = nextc;
566 scan();
567 addekid(ep2, ep1);
568 addekid(ep2, getE3());
569 #ifdef RCONST
570 if (ep1->type == NUM && ep1->sibling->type == NUM)
571 ep2 = rconst(ep2);
572 #endif
573 return(ep2);
574 }
575 return(ep1);
576 }
577
578
579 EPNODE *
580 getE4() /* E4 -> ADDOP E5 */
581 /* E5 */
582 {
583 register EPNODE *ep1, *ep2;
584
585 if (nextc == '-') {
586 scan();
587 ep2 = getE5();
588 if (ep2->type == NUM) {
589 ep2->v.num = -ep2->v.num;
590 return(ep2);
591 }
592 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
593 efree((char *)ep2);
594 return(ep2->v.kid);
595 }
596 ep1 = newnode();
597 ep1->type = UMINUS;
598 addekid(ep1, ep2);
599 return(ep1);
600 }
601 if (nextc == '+')
602 scan();
603 return(getE5());
604 }
605
606
607 EPNODE *
608 getE5() /* E5 -> (E1) */
609 /* VAR */
610 /* NUM */
611 /* $N */
612 /* FUNC(E1,..) */
613 /* ARG */
614 {
615 int i;
616 char *nam;
617 register EPNODE *ep1, *ep2;
618
619 if (nextc == '(') {
620 scan();
621 ep1 = getE1();
622 if (nextc != ')')
623 syntax("')' expected");
624 scan();
625 return(ep1);
626 }
627
628 #ifdef INCHAN
629 if (nextc == '$') {
630 scan();
631 ep1 = newnode();
632 ep1->type = CHAN;
633 ep1->v.chan = getinum();
634 return(ep1);
635 }
636 #endif
637
638 #if defined(VARIABLE) || defined(FUNCTION)
639 if (isalpha(nextc) || nextc == CNTXMARK) {
640 nam = getname();
641 #if defined(VARIABLE) && defined(FUNCTION)
642 ep1 = NULL;
643 if (curfunc != NULL)
644 for (i = 1, ep2 = curfunc->v.kid->sibling;
645 ep2 != NULL; i++, ep2 = ep2->sibling)
646 if (!strcmp(ep2->v.name, nam)) {
647 ep1 = newnode();
648 ep1->type = ARG;
649 ep1->v.chan = i;
650 break;
651 }
652 if (ep1 == NULL)
653 #endif
654 {
655 ep1 = newnode();
656 ep1->type = VAR;
657 ep1->v.ln = varinsert(nam);
658 }
659 #ifdef FUNCTION
660 if (nextc == '(') {
661 ep2 = newnode();
662 ep2->type = FUNC;
663 addekid(ep2, ep1);
664 ep1 = ep2;
665 do {
666 scan();
667 addekid(ep1, getE1());
668 } while (nextc == ',');
669 if (nextc != ')')
670 syntax("')' expected");
671 scan();
672 }
673 #ifndef VARIABLE
674 else
675 syntax("'(' expected");
676 #endif
677 #endif
678 #ifdef RCONST
679 if (isconstvar(ep1))
680 ep1 = rconst(ep1);
681 #endif
682 return(ep1);
683 }
684 #endif
685
686 if (isdecimal(nextc)) {
687 ep1 = newnode();
688 ep1->type = NUM;
689 ep1->v.num = getnum();
690 return(ep1);
691 }
692 syntax("unexpected character");
693 }
694
695
696 #ifdef RCONST
697 EPNODE *
698 rconst(epar) /* reduce a constant expression */
699 register EPNODE *epar;
700 {
701 register EPNODE *ep;
702
703 ep = newnode();
704 ep->type = NUM;
705 errno = 0;
706 ep->v.num = evalue(epar);
707 if (errno)
708 syntax("bad constant expression");
709 epfree(epar);
710
711 return(ep);
712 }
713
714
715 isconstvar(ep) /* is ep linked to a constant expression? */
716 register EPNODE *ep;
717 {
718 #ifdef VARIABLE
719 register EPNODE *ep1;
720 #ifdef FUNCTION
721
722 if (ep->type == FUNC) {
723 if (!isconstfun(ep->v.kid))
724 return(0);
725 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
726 if (ep1->type != NUM && !isconstfun(ep1))
727 return(0);
728 return(1);
729 }
730 #endif
731 if (ep->type != VAR)
732 return(0);
733 ep1 = ep->v.ln->def;
734 if (ep1 == NULL || ep1->type != ':')
735 return(0);
736 #ifdef FUNCTION
737 if (ep1->v.kid->type != SYM)
738 return(0);
739 #endif
740 return(1);
741 #else
742 return(ep->type == FUNC);
743 #endif
744 }
745
746
747 #if defined(FUNCTION) && defined(VARIABLE)
748 isconstfun(ep) /* is ep linked to a constant function? */
749 register EPNODE *ep;
750 {
751 register EPNODE *dp;
752 register LIBR *lp;
753
754 if (ep->type != VAR)
755 return(0);
756 if ((dp = ep->v.ln->def) != NULL && dp->v.kid->type == FUNC)
757 return(dp->type == ':');
758 if ((lp = liblookup(ep->v.ln->name)) != NULL)
759 return(lp->atyp == ':');
760 return(0);
761 }
762 #endif
763 #endif