ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.6
Committed: Thu Jul 19 12:56:50 1990 UTC (33 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.5: +47 -10 lines
Log Message:
added line numbers to error reports

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