ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.2
Committed: Mon Apr 10 22:06:37 1989 UTC (35 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.1: +2 -0 lines
Log Message:
Fixed conditional compile error in epfree()

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