ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.7
Committed: Sat Sep 26 08:13:32 1992 UTC (31 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +1 -1 lines
Log Message:
minor change to syntax error reporting

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