ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.15
Committed: Wed Sep 8 09:12:37 1993 UTC (30 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.14: +4 -0 lines
Log Message:
added conditional declaration of atof()

File Contents

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