ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.1
Committed: Thu Feb 2 10:34:27 1989 UTC (35 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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