ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.30
Committed: Tue May 17 17:51:51 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1
Changes since 2.29: +6 -1 lines
Log Message:
Added "eofc" global for specifying an optional EOF character, such as '}'

File Contents

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