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

# 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 greg 1.6 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 greg 1.7 eputs(": syntax error:\n");
391 greg 1.1 }
392 greg 1.7 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 greg 1.1 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 greg 1.3 register EPNODE *ep1, *ep2;
558 greg 1.1
559     if (nextc == '-') {
560     scan();
561 greg 1.3 ep2 = getE5();
562     if (ep2->type == NUM) {
563     ep2->v.num = -ep2->v.num;
564     return(ep2);
565     }
566 greg 1.1 ep1 = newnode();
567     ep1->type = UMINUS;
568 greg 1.3 addekid(ep1, ep2);
569 greg 1.1 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