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

# User Rev Content
1 greg 1.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 greg 1.5 extern double efunc(), evariable();
43     static double euminus(), echannel(), eargument(), enumber();
44     static double eadd(), esubtr(), emult(), edivi(), epow();
45     static double ebotch();
46 greg 1.1 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 greg 1.6 static char *infile; /* input file name */
91     static int lineno; /* input line number */
92 greg 1.1 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 greg 1.6 initstr(expr, NULL, 0);
102 greg 1.1 #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 greg 1.2 #if defined(VARIABLE) || defined(FUNCTION)
134 greg 1.1 case VAR:
135     varfree(epar->v.ln);
136     break;
137 greg 1.2 #endif
138 greg 1.1
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 greg 1.6 initfile(fp, fn, ln) /* prepare input file */
297 greg 1.1 FILE *fp;
298 greg 1.6 char *fn;
299     int ln;
300 greg 1.1 {
301     static char inpbuf[MAXLINE];
302    
303     infp = fp;
304     linbuf = inpbuf;
305 greg 1.6 infile = fn;
306     lineno = ln;
307 greg 1.1 linepos = 0;
308     inpbuf[0] = '\0';
309     scan();
310     }
311    
312    
313 greg 1.6 initstr(s, fn, ln) /* prepare input string */
314 greg 1.1 char *s;
315 greg 1.6 char *fn;
316     int ln;
317 greg 1.1 {
318     infp = NULL;
319 greg 1.6 infile = fn;
320     lineno = ln;
321 greg 1.1 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 greg 1.6 lineno++;
336 greg 1.1 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 greg 1.6 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 greg 1.1 syntax(err) /* report syntax error and quit */
380     char *err;
381     {
382     register int i;
383    
384     eputs(linbuf);
385 greg 1.4 if (linbuf[strlen(linbuf)-1] != '\n')
386 greg 1.1 eputs("\n");
387     for (i = 0; i < linepos-1; i++)
388     eputs(linbuf[i] == '\t' ? "\t" : " ");
389     eputs("^ ");
390 greg 1.6 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 greg 1.1 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 greg 1.3 register EPNODE *ep1, *ep2;
559 greg 1.1
560     if (nextc == '-') {
561     scan();
562 greg 1.3 ep2 = getE5();
563     if (ep2->type == NUM) {
564     ep2->v.num = -ep2->v.num;
565     return(ep2);
566     }
567 greg 1.1 ep1 = newnode();
568     ep1->type = UMINUS;
569 greg 1.3 addekid(ep1, ep2);
570 greg 1.1 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