ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.22
Committed: Sat Jun 7 12:50:20 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.21: +65 -66 lines
Log Message:
Various small changes to reduce compile warnings/errors on Windows.

File Contents

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