ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.16
Committed: Wed Aug 14 16:26:31 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.15: +4 -0 lines
Log Message:
eliminated possibility of generating -(-E5) parse tree

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 extern double atof(), pow();
36 extern char *fgets(), *savestr();
37 extern char *emalloc(), *ecalloc();
38 extern EPNODE *curfunc;
39 extern double efunc(), evariable();
40 static double euminus(), echannel(), eargument(), enumber();
41 static double eadd(), esubtr(), emult(), edivi(), epow();
42 static double ebotch();
43 extern int errno;
44
45 int nextc; /* lookahead character */
46
47 double (*eoper[])() = { /* expression operations */
48 ebotch,
49 #ifdef VARIABLE
50 evariable,
51 #else
52 ebotch,
53 #endif
54 enumber,
55 euminus,
56 #ifdef INCHAN
57 echannel,
58 #else
59 ebotch,
60 #endif
61 #ifdef FUNCTION
62 efunc,
63 eargument,
64 #else
65 ebotch,
66 ebotch,
67 #endif
68 ebotch,
69 ebotch,
70 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
71 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
72 emult,
73 eadd,
74 0,
75 esubtr,
76 0,
77 edivi,
78 0,0,0,0,0,0,0,0,0,0,
79 ebotch,
80 0,0,
81 ebotch,
82 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
83 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84 epow,
85 };
86
87 static FILE *infp; /* input file pointer */
88 static char *linbuf; /* line buffer */
89 static char *infile; /* input file name */
90 static int lineno; /* input line number */
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(expr, NULL, 0);
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(fp, fn, ln) /* prepare input file */
296 FILE *fp;
297 char *fn;
298 int ln;
299 {
300 static char inpbuf[MAXLINE];
301
302 infp = fp;
303 linbuf = inpbuf;
304 infile = fn;
305 lineno = ln;
306 linepos = 0;
307 inpbuf[0] = '\0';
308 scan();
309 }
310
311
312 initstr(s, fn, ln) /* prepare input string */
313 char *s;
314 char *fn;
315 int ln;
316 {
317 infp = NULL;
318 infile = fn;
319 lineno = ln;
320 linbuf = s;
321 linepos = 0;
322 scan();
323 }
324
325
326 getscanpos(fnp, lnp, spp, fpp) /* return current scan position */
327 char **fnp;
328 int *lnp;
329 char **spp;
330 FILE **fpp;
331 {
332 if (fnp != NULL) *fnp = infile;
333 if (lnp != NULL) *lnp = lineno;
334 if (spp != NULL) *spp = linbuf+linepos;
335 if (fpp != NULL) *fpp = infp;
336 }
337
338
339 int
340 scan() /* scan next character, return literal next */
341 {
342 register int lnext = 0;
343
344 do {
345 if (linbuf[linepos] == '\0')
346 if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
347 nextc = EOF;
348 else {
349 nextc = linbuf[0];
350 lineno++;
351 linepos = 1;
352 }
353 else
354 nextc = linbuf[linepos++];
355 if (!lnext)
356 lnext = nextc;
357 if (nextc == '{') {
358 scan();
359 while (nextc != '}')
360 if (nextc == EOF)
361 syntax("'}' expected");
362 else
363 scan();
364 scan();
365 }
366 } while (isspace(nextc));
367 return(lnext);
368 }
369
370
371 char *
372 ltoa(l) /* convert long to ascii */
373 long l;
374 {
375 static char buf[16];
376 register char *cp;
377 int neg = 0;
378
379 if (l == 0)
380 return("0");
381 if (l < 0) {
382 l = -l;
383 neg++;
384 }
385 cp = buf + sizeof(buf);
386 *--cp = '\0';
387 while (l) {
388 *--cp = l % 10 + '0';
389 l /= 10;
390 }
391 if (neg)
392 *--cp = '-';
393 return(cp);
394 }
395
396
397 syntax(err) /* report syntax error and quit */
398 char *err;
399 {
400 register int i;
401
402 if (infile != NULL || lineno != 0) {
403 if (infile != NULL) eputs(infile);
404 if (lineno != 0) {
405 eputs(infile != NULL ? ", line " : "line ");
406 eputs(ltoa((long)lineno));
407 }
408 eputs(": syntax error:\n");
409 }
410 eputs(linbuf);
411 if (linbuf[strlen(linbuf)-1] != '\n')
412 eputs("\n");
413 for (i = 0; i < linepos-1; i++)
414 eputs(linbuf[i] == '\t' ? "\t" : " ");
415 eputs("^ ");
416 eputs(err);
417 eputs("\n");
418 quit(1);
419 }
420
421
422 addekid(ep, ekid) /* add a child to ep */
423 register EPNODE *ep;
424 EPNODE *ekid;
425 {
426 if (ep->v.kid == NULL)
427 ep->v.kid = ekid;
428 else {
429 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
430 ;
431 ep->sibling = ekid;
432 }
433 ekid->sibling = NULL;
434 }
435
436
437 char *
438 getname() /* scan an identifier */
439 {
440 static char str[MAXWORD+1];
441 register int i, lnext;
442
443 lnext = nextc;
444 for (i = 0; i < MAXWORD && isid(lnext); i++, lnext = scan())
445 str[i] = lnext;
446 str[i] = '\0';
447 while (isid(lnext)) /* skip rest of name */
448 lnext = scan();
449
450 return(str);
451 }
452
453
454 int
455 getinum() /* scan a positive integer */
456 {
457 register int n, lnext;
458
459 n = 0;
460 lnext = nextc;
461 while (isdigit(lnext)) {
462 n = n * 10 + lnext - '0';
463 lnext = scan();
464 }
465 return(n);
466 }
467
468
469 double
470 getnum() /* scan a positive float */
471 {
472 register int i, lnext;
473 char str[MAXWORD+1];
474
475 i = 0;
476 lnext = nextc;
477 while (isdigit(lnext) && i < MAXWORD) {
478 str[i++] = lnext;
479 lnext = scan();
480 }
481 if (lnext == '.' && i < MAXWORD) {
482 str[i++] = lnext;
483 lnext = scan();
484 while (isdigit(lnext) && i < MAXWORD) {
485 str[i++] = lnext;
486 lnext = scan();
487 }
488 }
489 if ((lnext == 'e' || lnext == 'E') && i < MAXWORD) {
490 str[i++] = lnext;
491 lnext = scan();
492 if ((lnext == '-' || lnext == '+') && i < MAXWORD) {
493 str[i++] = lnext;
494 lnext = scan();
495 }
496 while (isdigit(lnext) && i < MAXWORD) {
497 str[i++] = lnext;
498 lnext = scan();
499 }
500 }
501 str[i] = '\0';
502
503 return(atof(str));
504 }
505
506
507 EPNODE *
508 getE1() /* E1 -> E1 ADDOP E2 */
509 /* E2 */
510 {
511 register EPNODE *ep1, *ep2;
512
513 ep1 = getE2();
514 while (nextc == '+' || nextc == '-') {
515 ep2 = newnode();
516 ep2->type = nextc;
517 scan();
518 addekid(ep2, ep1);
519 addekid(ep2, getE2());
520 #ifdef RCONST
521 if (ep1->type == NUM && ep1->sibling->type == NUM)
522 ep2 = rconst(ep2);
523 #endif
524 ep1 = ep2;
525 }
526 return(ep1);
527 }
528
529
530 EPNODE *
531 getE2() /* E2 -> E2 MULOP E3 */
532 /* E3 */
533 {
534 register EPNODE *ep1, *ep2;
535
536 ep1 = getE3();
537 while (nextc == '*' || nextc == '/') {
538 ep2 = newnode();
539 ep2->type = nextc;
540 scan();
541 addekid(ep2, ep1);
542 addekid(ep2, getE3());
543 #ifdef RCONST
544 if (ep1->type == NUM && ep1->sibling->type == NUM)
545 ep2 = rconst(ep2);
546 #endif
547 ep1 = ep2;
548 }
549 return(ep1);
550 }
551
552
553 EPNODE *
554 getE3() /* E3 -> E4 ^ E3 */
555 /* E4 */
556 {
557 register EPNODE *ep1, *ep2;
558
559 ep1 = getE4();
560 if (nextc == '^') {
561 ep2 = newnode();
562 ep2->type = nextc;
563 scan();
564 addekid(ep2, ep1);
565 addekid(ep2, getE3());
566 #ifdef RCONST
567 if (ep1->type == NUM && ep1->sibling->type == NUM)
568 ep2 = rconst(ep2);
569 #endif
570 return(ep2);
571 }
572 return(ep1);
573 }
574
575
576 EPNODE *
577 getE4() /* E4 -> ADDOP E5 */
578 /* E5 */
579 {
580 register EPNODE *ep1, *ep2;
581
582 if (nextc == '-') {
583 scan();
584 ep2 = getE5();
585 if (ep2->type == NUM) {
586 ep2->v.num = -ep2->v.num;
587 return(ep2);
588 }
589 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
590 efree((char *)ep2);
591 return(ep2->v.kid);
592 }
593 ep1 = newnode();
594 ep1->type = UMINUS;
595 addekid(ep1, ep2);
596 return(ep1);
597 }
598 if (nextc == '+')
599 scan();
600 return(getE5());
601 }
602
603
604 EPNODE *
605 getE5() /* E5 -> (E1) */
606 /* VAR */
607 /* NUM */
608 /* $N */
609 /* FUNC(E1,..) */
610 /* ARG */
611 {
612 int i;
613 char *nam;
614 register EPNODE *ep1, *ep2;
615
616 if (nextc == '(') {
617 scan();
618 ep1 = getE1();
619 if (nextc != ')')
620 syntax("')' expected");
621 scan();
622 return(ep1);
623 }
624
625 #ifdef INCHAN
626 if (nextc == '$') {
627 scan();
628 ep1 = newnode();
629 ep1->type = CHAN;
630 ep1->v.chan = getinum();
631 return(ep1);
632 }
633 #endif
634
635 #if defined(VARIABLE) || defined(FUNCTION)
636 if (isalpha(nextc) || nextc == CNTXMARK) {
637 nam = getname();
638 #if defined(VARIABLE) && defined(FUNCTION)
639 ep1 = NULL;
640 if (curfunc != NULL)
641 for (i = 1, ep2 = curfunc->v.kid->sibling;
642 ep2 != NULL; i++, ep2 = ep2->sibling)
643 if (!strcmp(ep2->v.name, nam)) {
644 ep1 = newnode();
645 ep1->type = ARG;
646 ep1->v.chan = i;
647 break;
648 }
649 if (ep1 == NULL)
650 #endif
651 {
652 ep1 = newnode();
653 ep1->type = VAR;
654 ep1->v.ln = varinsert(nam);
655 }
656 #ifdef FUNCTION
657 if (nextc == '(') {
658 ep2 = newnode();
659 ep2->type = FUNC;
660 addekid(ep2, ep1);
661 ep1 = ep2;
662 do {
663 scan();
664 addekid(ep1, getE1());
665 } while (nextc == ',');
666 if (nextc != ')')
667 syntax("')' expected");
668 scan();
669 }
670 #ifndef VARIABLE
671 else
672 syntax("'(' expected");
673 #endif
674 #endif
675 #ifdef RCONST
676 if (isconstvar(ep1))
677 ep1 = rconst(ep1);
678 #endif
679 return(ep1);
680 }
681 #endif
682
683 if (isdecimal(nextc)) {
684 ep1 = newnode();
685 ep1->type = NUM;
686 ep1->v.num = getnum();
687 return(ep1);
688 }
689 syntax("unexpected character");
690 }
691
692
693 #ifdef RCONST
694 EPNODE *
695 rconst(epar) /* reduce a constant expression */
696 register EPNODE *epar;
697 {
698 register EPNODE *ep;
699
700 ep = newnode();
701 ep->type = NUM;
702 errno = 0;
703 ep->v.num = evalue(epar);
704 if (errno)
705 syntax("bad constant expression");
706 epfree(epar);
707
708 return(ep);
709 }
710
711
712 isconstvar(ep) /* is ep linked to a constant expression? */
713 register EPNODE *ep;
714 {
715 #ifdef VARIABLE
716 register EPNODE *ep1;
717 #ifdef FUNCTION
718
719 if (ep->type == FUNC) {
720 if (!isconstfun(ep->v.kid))
721 return(0);
722 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
723 if (ep1->type != NUM && !isconstfun(ep1))
724 return(0);
725 return(1);
726 }
727 #endif
728 if (ep->type != VAR)
729 return(0);
730 ep1 = ep->v.ln->def;
731 if (ep1 == NULL || ep1->type != ':')
732 return(0);
733 #ifdef FUNCTION
734 if (ep1->v.kid->type != SYM)
735 return(0);
736 #endif
737 return(1);
738 #else
739 return(ep->type == FUNC);
740 #endif
741 }
742
743
744 #if defined(FUNCTION) && defined(VARIABLE)
745 isconstfun(ep) /* is ep linked to a constant function? */
746 register EPNODE *ep;
747 {
748 register EPNODE *dp;
749 register LIBR *lp;
750
751 if (ep->type != VAR)
752 return(0);
753 dp = ep->v.ln->def;
754 if (dp != NULL && dp->type != ':')
755 return(0);
756 if ((dp == NULL || dp->v.kid->type != FUNC)
757 && ((lp = liblookup(ep->v.ln->name)) == NULL
758 || lp->atyp != ':'))
759 return(0);
760 return(1);
761 }
762 #endif
763 #endif