ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.13
Committed: Thu Aug 8 12:11:19 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.12: +13 -0 lines
Log Message:
added getscanpos() function

File Contents

# Content
1 /* Copyright (c) 1986 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
448 return(str);
449 }
450
451
452 int
453 getinum() /* scan a positive integer */
454 {
455 register int n, lnext;
456
457 n = 0;
458 lnext = nextc;
459 while (isdigit(lnext)) {
460 n = n * 10 + lnext - '0';
461 lnext = scan();
462 }
463 return(n);
464 }
465
466
467 double
468 getnum() /* scan a positive float */
469 {
470 register int i, lnext;
471 char str[MAXWORD+1];
472
473 i = 0;
474 lnext = nextc;
475 while (isdigit(lnext) && i < MAXWORD) {
476 str[i++] = lnext;
477 lnext = scan();
478 }
479 if (lnext == '.' && i < MAXWORD) {
480 str[i++] = lnext;
481 lnext = scan();
482 while (isdigit(lnext) && i < MAXWORD) {
483 str[i++] = lnext;
484 lnext = scan();
485 }
486 }
487 if ((lnext == 'e' || lnext == 'E') && i < MAXWORD) {
488 str[i++] = lnext;
489 lnext = scan();
490 if ((lnext == '-' || lnext == '+') && i < MAXWORD) {
491 str[i++] = lnext;
492 lnext = scan();
493 }
494 while (isdigit(lnext) && i < MAXWORD) {
495 str[i++] = lnext;
496 lnext = scan();
497 }
498 }
499 str[i] = '\0';
500
501 return(atof(str));
502 }
503
504
505 EPNODE *
506 getE1() /* E1 -> E1 ADDOP E2 */
507 /* E2 */
508 {
509 register EPNODE *ep1, *ep2;
510
511 ep1 = getE2();
512 while (nextc == '+' || nextc == '-') {
513 ep2 = newnode();
514 ep2->type = nextc;
515 scan();
516 addekid(ep2, ep1);
517 addekid(ep2, getE2());
518 #ifdef RCONST
519 if (ep1->type == NUM && ep1->sibling->type == NUM)
520 ep2 = rconst(ep2);
521 #endif
522 ep1 = ep2;
523 }
524 return(ep1);
525 }
526
527
528 EPNODE *
529 getE2() /* E2 -> E2 MULOP E3 */
530 /* E3 */
531 {
532 register EPNODE *ep1, *ep2;
533
534 ep1 = getE3();
535 while (nextc == '*' || nextc == '/') {
536 ep2 = newnode();
537 ep2->type = nextc;
538 scan();
539 addekid(ep2, ep1);
540 addekid(ep2, getE3());
541 #ifdef RCONST
542 if (ep1->type == NUM && ep1->sibling->type == NUM)
543 ep2 = rconst(ep2);
544 #endif
545 ep1 = ep2;
546 }
547 return(ep1);
548 }
549
550
551 EPNODE *
552 getE3() /* E3 -> E4 ^ E3 */
553 /* E4 */
554 {
555 register EPNODE *ep1, *ep2;
556
557 ep1 = getE4();
558 if (nextc == '^') {
559 ep2 = newnode();
560 ep2->type = nextc;
561 scan();
562 addekid(ep2, ep1);
563 addekid(ep2, getE3());
564 #ifdef RCONST
565 if (ep1->type == NUM && ep1->sibling->type == NUM)
566 ep2 = rconst(ep2);
567 #endif
568 return(ep2);
569 }
570 return(ep1);
571 }
572
573
574 EPNODE *
575 getE4() /* E4 -> ADDOP E5 */
576 /* E5 */
577 {
578 register EPNODE *ep1, *ep2;
579
580 if (nextc == '-') {
581 scan();
582 ep2 = getE5();
583 if (ep2->type == NUM) {
584 ep2->v.num = -ep2->v.num;
585 return(ep2);
586 }
587 ep1 = newnode();
588 ep1->type = UMINUS;
589 addekid(ep1, ep2);
590 return(ep1);
591 }
592 if (nextc == '+')
593 scan();
594 return(getE5());
595 }
596
597
598 EPNODE *
599 getE5() /* E5 -> (E1) */
600 /* VAR */
601 /* NUM */
602 /* $N */
603 /* FUNC(E1,..) */
604 /* ARG */
605 {
606 int i;
607 register EPNODE *ep1, *ep2;
608
609 if (nextc == '(') {
610 scan();
611 ep1 = getE1();
612 if (nextc != ')')
613 syntax("')' expected");
614 scan();
615 return(ep1);
616 }
617
618 #ifdef INCHAN
619 if (nextc == '$') {
620 scan();
621 ep1 = newnode();
622 ep1->type = CHAN;
623 ep1->v.chan = getinum();
624 return(ep1);
625 }
626 #endif
627
628 #if defined(VARIABLE) || defined(FUNCTION)
629 if (isalpha(nextc)) {
630 ep1 = newnode();
631 ep1->type = VAR;
632 ep1->v.ln = varinsert(getname());
633
634 #if defined(VARIABLE) && defined(FUNCTION)
635 if (curfunc != NULL)
636 for (i = 1, ep2 = curfunc->v.kid->sibling;
637 ep2 != NULL; i++, ep2 = ep2->sibling)
638 if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
639 epfree(ep1);
640 ep1 = newnode();
641 ep1->type = ARG;
642 ep1->v.chan = i;
643 break;
644 }
645 #endif
646 #ifdef FUNCTION
647 if (nextc == '(') {
648 ep2 = newnode();
649 ep2->type = FUNC;
650 addekid(ep2, ep1);
651 ep1 = ep2;
652 do {
653 scan();
654 addekid(ep1, getE1());
655 } while (nextc == ',');
656 if (nextc != ')')
657 syntax("')' expected");
658 scan();
659 }
660 #ifndef VARIABLE
661 else
662 syntax("'(' expected");
663 #endif
664 #endif
665 #ifdef RCONST
666 if (isconstvar(ep1))
667 ep1 = rconst(ep1);
668 #endif
669 return(ep1);
670 }
671 #endif
672
673 if (isdecimal(nextc)) {
674 ep1 = newnode();
675 ep1->type = NUM;
676 ep1->v.num = getnum();
677 return(ep1);
678 }
679 syntax("unexpected character");
680 }
681
682
683 #ifdef RCONST
684 EPNODE *
685 rconst(epar) /* reduce a constant expression */
686 register EPNODE *epar;
687 {
688 register EPNODE *ep;
689
690 ep = newnode();
691 ep->type = NUM;
692 errno = 0;
693 ep->v.num = evalue(epar);
694 if (errno)
695 syntax("bad constant expression");
696 epfree(epar);
697
698 return(ep);
699 }
700
701
702 isconstvar(ep) /* is ep linked to a constant expression? */
703 register EPNODE *ep;
704 {
705 #ifdef VARIABLE
706 register EPNODE *ep1;
707 #ifdef FUNCTION
708
709 if (ep->type == FUNC) {
710 if (!isconstfun(ep->v.kid))
711 return(0);
712 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
713 if (ep1->type != NUM && !isconstfun(ep1))
714 return(0);
715 return(1);
716 }
717 #endif
718 if (ep->type != VAR)
719 return(0);
720 ep1 = ep->v.ln->def;
721 if (ep1 == NULL || ep1->type != ':')
722 return(0);
723 #ifdef FUNCTION
724 if (ep1->v.kid->type != SYM)
725 return(0);
726 #endif
727 return(1);
728 #else
729 return(ep->type == FUNC);
730 #endif
731 }
732
733
734 #if defined(FUNCTION) && defined(VARIABLE)
735 isconstfun(ep) /* is ep linked to a constant function? */
736 register EPNODE *ep;
737 {
738 register EPNODE *dp;
739 register LIBR *lp;
740
741 if (ep->type != VAR)
742 return(0);
743 dp = ep->v.ln->def;
744 if (dp != NULL && dp->type != ':')
745 return(0);
746 if ((dp == NULL || dp->v.kid->type != FUNC)
747 && ((lp = liblookup(ep->v.ln->name)) == NULL
748 || lp->atyp != ':'))
749 return(0);
750 return(1);
751 }
752 #endif
753 #endif