ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.3
Committed: Wed Jun 14 22:29:01 1989 UTC (34 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +7 -13 lines
Log Message:
Minor modification of UMINUS compilation

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, *ep2;
521
522 if (nextc == '-') {
523 scan();
524 ep2 = getE5();
525 if (ep2->type == NUM) {
526 ep2->v.num = -ep2->v.num;
527 return(ep2);
528 }
529 ep1 = newnode();
530 ep1->type = UMINUS;
531 addekid(ep1, ep2);
532 return(ep1);
533 }
534 if (nextc == '+')
535 scan();
536 return(getE5());
537 }
538
539
540 EPNODE *
541 getE5() /* E5 -> (E1) */
542 /* VAR */
543 /* NUM */
544 /* $N */
545 /* FUNC(E1,..) */
546 /* ARG */
547 {
548 int i;
549 register EPNODE *ep1, *ep2;
550
551 if (nextc == '(') {
552 scan();
553 ep1 = getE1();
554 if (nextc != ')')
555 syntax("')' expected");
556 scan();
557 return(ep1);
558 }
559
560 #ifdef INCHAN
561 if (nextc == '$') {
562 scan();
563 ep1 = newnode();
564 ep1->type = CHAN;
565 ep1->v.chan = getinum();
566 return(ep1);
567 }
568 #endif
569
570 #if defined(VARIABLE) || defined(FUNCTION)
571 if (isalpha(nextc)) {
572 ep1 = newnode();
573 ep1->type = VAR;
574 ep1->v.ln = varinsert(getname());
575
576 #if defined(VARIABLE) && defined(FUNCTION)
577 if (curfunc != NULL)
578 for (i = 1, ep2 = curfunc->v.kid->sibling;
579 ep2 != NULL; i++, ep2 = ep2->sibling)
580 if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
581 epfree(ep1);
582 ep1 = newnode();
583 ep1->type = ARG;
584 ep1->v.chan = i;
585 break;
586 }
587 #endif
588 #ifdef FUNCTION
589 if (nextc == '(') {
590 ep2 = newnode();
591 ep2->type = FUNC;
592 addekid(ep2, ep1);
593 ep1 = ep2;
594 do {
595 scan();
596 addekid(ep1, getE1());
597 } while (nextc == ',');
598 if (nextc != ')')
599 syntax("')' expected");
600 scan();
601 }
602 #ifndef VARIABLE
603 else
604 syntax("'(' expected");
605 #endif
606 #endif
607 return(ep1);
608 }
609 #endif
610
611 if (isdecimal(nextc)) {
612 ep1 = newnode();
613 ep1->type = NUM;
614 ep1->v.num = getnum();
615 return(ep1);
616 }
617 syntax("unexpected character");
618 }
619
620
621 #ifdef RCONST
622 EPNODE *
623 rconst(epar) /* reduce a constant expression */
624 register EPNODE *epar;
625 {
626 register EPNODE *ep;
627
628 ep = newnode();
629 ep->type = NUM;
630 errno = 0;
631 ep->v.num = evalue(epar);
632 if (errno)
633 syntax("bad constant expression");
634 epfree(epar);
635
636 return(ep);
637 }
638 #endif