ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.9
Committed: Tue Oct 6 12:29:36 1992 UTC (31 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +2 -2 lines
Log Message:
Changes for 32-bit PC port

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