ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.12
Committed: Fri Mar 5 15:14:00 1993 UTC (31 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +4 -1 lines
Log Message:
portability improvements

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