ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 1.7
Committed: Sat Aug 18 16:28:52 1990 UTC (33 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.6: +7 -8 lines
Log Message:
changed appearance of syntax error reports once more

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 if (infile != NULL || lineno != 0) {
385 if (infile != NULL) eputs(infile);
386 if (lineno != 0) {
387 eputs(infile != NULL ? ", line " : "line ");
388 eputs(ltoa((long)lineno));
389 }
390 eputs(": syntax error:\n");
391 }
392 eputs(linbuf);
393 if (linbuf[strlen(linbuf)-1] != '\n')
394 eputs("\n");
395 for (i = 0; i < linepos-1; i++)
396 eputs(linbuf[i] == '\t' ? "\t" : " ");
397 eputs("^ ");
398 eputs(err);
399 eputs("\n");
400 quit(1);
401 }
402
403
404 addekid(ep, ekid) /* add a child to ep */
405 register EPNODE *ep;
406 EPNODE *ekid;
407 {
408 if (ep->v.kid == NULL)
409 ep->v.kid = ekid;
410 else {
411 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
412 ;
413 ep->sibling = ekid;
414 }
415 ekid->sibling = NULL;
416 }
417
418
419 char *
420 getname() /* scan an identifier */
421 {
422 static char str[MAXWORD+1];
423 register int i;
424
425 for (i = 0; i < MAXWORD && isid(nextc); i++, scan())
426 str[i] = nextc;
427 str[i] = '\0';
428
429 return(str);
430 }
431
432
433 int
434 getinum() /* scan a positive integer */
435 {
436 register int n;
437
438 n = 0;
439 while (isdigit(nextc)) {
440 n = n * 10 + nextc - '0';
441 scan();
442 }
443 return(n);
444 }
445
446
447 double
448 getnum() /* scan a positive float */
449 {
450 register int i;
451 char str[MAXWORD+1];
452
453 i = 0;
454 while (isdigit(nextc) && i < MAXWORD) {
455 str[i++] = nextc;
456 scan();
457 }
458 if (nextc == '.' && i < MAXWORD) {
459 str[i++] = nextc;
460 scan();
461 while (isdigit(nextc) && i < MAXWORD) {
462 str[i++] = nextc;
463 scan();
464 }
465 }
466 if ((nextc == 'e' || nextc == 'E') && i < MAXWORD) {
467 str[i++] = nextc;
468 scan();
469 if ((nextc == '-' || nextc == '+') && i < MAXWORD) {
470 str[i++] = nextc;
471 scan();
472 }
473 while (isdigit(nextc) && i < MAXWORD) {
474 str[i++] = nextc;
475 scan();
476 }
477 }
478 str[i] = '\0';
479
480 return(atof(str));
481 }
482
483
484 EPNODE *
485 getE1() /* E1 -> E1 ADDOP E2 */
486 /* E2 */
487 {
488 register EPNODE *ep1, *ep2;
489
490 ep1 = getE2();
491 while (nextc == '+' || nextc == '-') {
492 ep2 = newnode();
493 ep2->type = nextc;
494 scan();
495 addekid(ep2, ep1);
496 addekid(ep2, getE2());
497 #ifdef RCONST
498 if (ep1->type == NUM && ep1->sibling->type == NUM)
499 ep2 = rconst(ep2);
500 #endif
501 ep1 = ep2;
502 }
503 return(ep1);
504 }
505
506
507 EPNODE *
508 getE2() /* E2 -> E2 MULOP E3 */
509 /* E3 */
510 {
511 register EPNODE *ep1, *ep2;
512
513 ep1 = getE3();
514 while (nextc == '*' || nextc == '/') {
515 ep2 = newnode();
516 ep2->type = nextc;
517 scan();
518 addekid(ep2, ep1);
519 addekid(ep2, getE3());
520 #ifdef RCONST
521 if (ep1->type == NUM && ep1->sibling->type == NUM)
522 ep2 = rconst(ep2);
523 #endif
524 ep1 = ep2;
525 }
526 return(ep1);
527 }
528
529
530 EPNODE *
531 getE3() /* E3 -> E3 ^ E4 */
532 /* E4 */
533 {
534 register EPNODE *ep1, *ep2;
535
536 ep1 = getE4();
537 while (nextc == '^') {
538 ep2 = newnode();
539 ep2->type = nextc;
540 scan();
541 addekid(ep2, ep1);
542 addekid(ep2, getE4());
543 #ifdef RCONST
544 if (ep1->type == NUM && ep1->sibling->type == NUM)
545 ep2 = rconst(ep2);
546 #endif
547 ep1 = ep2;
548 }
549 return(ep1);
550 }
551
552
553 EPNODE *
554 getE4() /* E4 -> ADDOP E5 */
555 /* E5 */
556 {
557 register EPNODE *ep1, *ep2;
558
559 if (nextc == '-') {
560 scan();
561 ep2 = getE5();
562 if (ep2->type == NUM) {
563 ep2->v.num = -ep2->v.num;
564 return(ep2);
565 }
566 ep1 = newnode();
567 ep1->type = UMINUS;
568 addekid(ep1, ep2);
569 return(ep1);
570 }
571 if (nextc == '+')
572 scan();
573 return(getE5());
574 }
575
576
577 EPNODE *
578 getE5() /* E5 -> (E1) */
579 /* VAR */
580 /* NUM */
581 /* $N */
582 /* FUNC(E1,..) */
583 /* ARG */
584 {
585 int i;
586 register EPNODE *ep1, *ep2;
587
588 if (nextc == '(') {
589 scan();
590 ep1 = getE1();
591 if (nextc != ')')
592 syntax("')' expected");
593 scan();
594 return(ep1);
595 }
596
597 #ifdef INCHAN
598 if (nextc == '$') {
599 scan();
600 ep1 = newnode();
601 ep1->type = CHAN;
602 ep1->v.chan = getinum();
603 return(ep1);
604 }
605 #endif
606
607 #if defined(VARIABLE) || defined(FUNCTION)
608 if (isalpha(nextc)) {
609 ep1 = newnode();
610 ep1->type = VAR;
611 ep1->v.ln = varinsert(getname());
612
613 #if defined(VARIABLE) && defined(FUNCTION)
614 if (curfunc != NULL)
615 for (i = 1, ep2 = curfunc->v.kid->sibling;
616 ep2 != NULL; i++, ep2 = ep2->sibling)
617 if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
618 epfree(ep1);
619 ep1 = newnode();
620 ep1->type = ARG;
621 ep1->v.chan = i;
622 break;
623 }
624 #endif
625 #ifdef FUNCTION
626 if (nextc == '(') {
627 ep2 = newnode();
628 ep2->type = FUNC;
629 addekid(ep2, ep1);
630 ep1 = ep2;
631 do {
632 scan();
633 addekid(ep1, getE1());
634 } while (nextc == ',');
635 if (nextc != ')')
636 syntax("')' expected");
637 scan();
638 }
639 #ifndef VARIABLE
640 else
641 syntax("'(' expected");
642 #endif
643 #endif
644 return(ep1);
645 }
646 #endif
647
648 if (isdecimal(nextc)) {
649 ep1 = newnode();
650 ep1->type = NUM;
651 ep1->v.num = getnum();
652 return(ep1);
653 }
654 syntax("unexpected character");
655 }
656
657
658 #ifdef RCONST
659 EPNODE *
660 rconst(epar) /* reduce a constant expression */
661 register EPNODE *epar;
662 {
663 register EPNODE *ep;
664
665 ep = newnode();
666 ep->type = NUM;
667 errno = 0;
668 ep->v.num = evalue(epar);
669 if (errno)
670 syntax("bad constant expression");
671 epfree(epar);
672
673 return(ep);
674 }
675 #endif