ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.15
Committed: Wed Aug 14 08:18:14 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.14: +4 -2 lines
Log Message:
fixed code for long identifiers

File Contents

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