Annotation of src/usr.bin/m4/expr.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $ */
2:
3: /*
4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * Ozan Yigit at York University.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)expr.c 8.2 (Berkeley) 4/29/95";
42: #else
43: static char rcsid[] = "$NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $";
44: #endif
45: #endif /* not lint */
46:
47: #include <sys/cdefs.h>
48: #include <stdio.h>
49:
50: /*
51: * expression evaluator: performs a standard recursive
52: * descent parse to evaluate any expression permissible
53: * within the following grammar:
54: *
55: * expr : query EOS
56: * query : lor
57: * | lor "?" query ":" query
58: * lor : land { "||" land }
59: * land : not { "&&" not }
60: * not : eqrel
61: * | '!' not
62: * eqrel : shift { eqrelop shift }
63: * shift : primary { shop primary }
64: * primary : term { addop term }
65: * term : exp { mulop exp }
66: * exp : unary { expop unary }
67: * unary : factor
68: * | unop unary
69: * factor : constant
70: * | "(" query ")"
71: * constant: num
72: * | "'" CHAR "'"
73: * num : DIGIT
74: * | DIGIT num
75: * shop : "<<"
76: * | ">>"
77: * eqrel : "="
78: * | "=="
79: * | "!="
80: * | "<"
81: * | ">"
82: * | "<="
83: * | ">="
84: *
85: *
86: * This expression evaluator is lifted from a public-domain
87: * C Pre-Processor included with the DECUS C Compiler distribution.
88: * It is hacked somewhat to be suitable for m4.
89: *
90: * Originally by: Mike Lutz
91: * Bob Harper
92: */
93:
94: #define TRUE 1
95: #define FALSE 0
96: #define EOS (char) 0
97: #define EQL 0
98: #define NEQ 1
99: #define LSS 2
100: #define LEQ 3
101: #define GTR 4
102: #define GEQ 5
103: #define OCTAL 8
104: #define DECIMAL 10
105:
106: static char *nxtch; /* Parser scan pointer */
107:
108: static int query __P((void));
109: static int lor __P((void));
110: static int land __P((void));
111: static int not __P((void));
112: static int eqrel __P((void));
113: static int shift __P((void));
114: static int primary __P((void));
115: static int term __P((void));
116: static int exp __P((void));
117: static int unary __P((void));
118: static int factor __P((void));
119: static int constant __P((void));
120: static int num __P((void));
121: static int geteqrel __P((void));
122: static int skipws __P((void));
123: static void experr __P((char *));
124:
125: /*
126: * For longjmp
127: */
128: #include <setjmp.h>
129: static jmp_buf expjump;
130:
131: /*
132: * macros:
133: * ungetch - Put back the last character examined.
134: * getch - return the next character from expr string.
135: */
136: #define ungetch() nxtch--
137: #define getch() *nxtch++
138:
139: int
140: expr(expbuf)
141: char *expbuf;
142: {
143: register int rval;
144:
145: nxtch = expbuf;
146: if (setjmp(expjump) != 0)
147: return FALSE;
148:
149: rval = query();
150: if (skipws() == EOS)
151: return rval;
152:
153: printf("m4: ill-formed expression.\n");
154: return FALSE;
155: }
156:
157: /*
158: * query : lor | lor '?' query ':' query
159: */
160: static int
161: query()
162: {
163: register int bool, true_val, false_val;
164:
165: bool = lor();
166: if (skipws() != '?') {
167: ungetch();
168: return bool;
169: }
170:
171: true_val = query();
172: if (skipws() != ':')
173: experr("bad query");
174:
175: false_val = query();
176: return bool ? true_val : false_val;
177: }
178:
179: /*
180: * lor : land { '||' land }
181: */
182: static int
183: lor()
184: {
185: register int c, vl, vr;
186:
187: vl = land();
188: while ((c = skipws()) == '|') {
189: if (getch() != '|')
190: ungetch();
191: vr = land();
192: vl = vl || vr;
193: }
194:
195: ungetch();
196: return vl;
197: }
198:
199: /*
200: * land : not { '&&' not }
201: */
202: static int
203: land()
204: {
205: register int c, vl, vr;
206:
207: vl = not();
208: while ((c = skipws()) == '&') {
209: if (getch() != '&')
210: ungetch();
211: vr = not();
212: vl = vl && vr;
213: }
214:
215: ungetch();
216: return vl;
217: }
218:
219: /*
220: * not : eqrel | '!' not
221: */
222: static int
223: not()
224: {
225: register int val, c;
226:
227: if ((c = skipws()) == '!' && getch() != '=') {
228: ungetch();
229: val = not();
230: return !val;
231: }
232:
233: if (c == '!')
234: ungetch();
235: ungetch();
236: return eqrel();
237: }
238:
239: /*
240: * eqrel : shift { eqrelop shift }
241: */
242: static int
243: eqrel()
244: {
245: register int vl, vr, eqrel;
246:
247: vl = shift();
248: while ((eqrel = geteqrel()) != -1) {
249: vr = shift();
250:
251: switch (eqrel) {
252:
253: case EQL:
254: vl = (vl == vr);
255: break;
256: case NEQ:
257: vl = (vl != vr);
258: break;
259:
260: case LEQ:
261: vl = (vl <= vr);
262: break;
263: case LSS:
264: vl = (vl < vr);
265: break;
266: case GTR:
267: vl = (vl > vr);
268: break;
269: case GEQ:
270: vl = (vl >= vr);
271: break;
272: }
273: }
274: return vl;
275: }
276:
277: /*
278: * shift : primary { shop primary }
279: */
280: static int
281: shift()
282: {
283: register int vl, vr, c;
284:
285: vl = primary();
286: while (((c = skipws()) == '<' || c == '>') && getch() == c) {
287: vr = primary();
288:
289: if (c == '<')
290: vl <<= vr;
291: else
292: vl >>= vr;
293: }
294:
295: if (c == '<' || c == '>')
296: ungetch();
297: ungetch();
298: return vl;
299: }
300:
301: /*
302: * primary : term { addop term }
303: */
304: static int
305: primary()
306: {
307: register int c, vl, vr;
308:
309: vl = term();
310: while ((c = skipws()) == '+' || c == '-') {
311: vr = term();
312:
313: if (c == '+')
314: vl += vr;
315: else
316: vl -= vr;
317: }
318:
319: ungetch();
320: return vl;
321: }
322:
323: /*
324: * <term> := <exp> { <mulop> <exp> }
325: */
326: static int
327: term()
328: {
329: register int c, vl, vr;
330:
331: vl = exp();
332: while ((c = skipws()) == '*' || c == '/' || c == '%') {
333: vr = exp();
334:
335: switch (c) {
336: case '*':
337: vl *= vr;
338: break;
339: case '/':
340: vl /= vr;
341: break;
342: case '%':
343: vl %= vr;
344: break;
345: }
346: }
347: ungetch();
348: return vl;
349: }
350:
351: /*
352: * <term> := <unary> { <expop> <unary> }
353: */
354: static int
355: exp()
356: {
357: register c, vl, vr, n;
358:
359: vl = unary();
360: switch (c = skipws()) {
361:
362: case '*':
363: if (getch() != '*') {
364: ungetch();
365: break;
366: }
367:
368: case '^':
369: vr = exp();
370: n = 1;
371: while (vr-- > 0)
372: n *= vl;
373: return n;
374: }
375:
376: ungetch();
377: return vl;
378: }
379:
380: /*
381: * unary : factor | unop unary
382: */
383: static int
384: unary()
385: {
386: register int val, c;
387:
388: if ((c = skipws()) == '+' || c == '-' || c == '~') {
389: val = unary();
390:
391: switch (c) {
392: case '+':
393: return val;
394: case '-':
395: return -val;
396: case '~':
397: return ~val;
398: }
399: }
400:
401: ungetch();
402: return factor();
403: }
404:
405: /*
406: * factor : constant | '(' query ')'
407: */
408: static int
409: factor()
410: {
411: register int val;
412:
413: if (skipws() == '(') {
414: val = query();
415: if (skipws() != ')')
416: experr("bad factor");
417: return val;
418: }
419:
420: ungetch();
421: return constant();
422: }
423:
424: /*
425: * constant: num | 'char'
426: * Note: constant() handles multi-byte constants
427: */
428: static int
429: constant()
430: {
431: register int i;
432: register int value;
433: register char c;
434: int v[sizeof(int)];
435:
436: if (skipws() != '\'') {
437: ungetch();
438: return num();
439: }
440: for (i = 0; i < sizeof(int); i++) {
441: if ((c = getch()) == '\'') {
442: ungetch();
443: break;
444: }
445: if (c == '\\') {
446: switch (c = getch()) {
447: case '0':
448: case '1':
449: case '2':
450: case '3':
451: case '4':
452: case '5':
453: case '6':
454: case '7':
455: ungetch();
456: c = num();
457: break;
458: case 'n':
459: c = 012;
460: break;
461: case 'r':
462: c = 015;
463: break;
464: case 't':
465: c = 011;
466: break;
467: case 'b':
468: c = 010;
469: break;
470: case 'f':
471: c = 014;
472: break;
473: }
474: }
475: v[i] = c;
476: }
477: if (i == 0 || getch() != '\'')
478: experr("illegal character constant");
479: for (value = 0; --i >= 0;) {
480: value <<= 8;
481: value += v[i];
482: }
483: return value;
484: }
485:
486: /*
487: * num : digit | num digit
488: */
489: static int
490: num()
491: {
492: register int rval, c, base;
493: int ndig;
494:
495: base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
496: rval = 0;
497: ndig = 0;
498: while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
499: rval *= base;
500: rval += (c - '0');
501: c = getch();
502: ndig++;
503: }
504: ungetch();
505:
506: if (ndig == 0)
507: experr("bad constant");
508:
509: return rval;
510:
511: }
512:
513: /*
514: * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
515: */
516: static int
517: geteqrel()
518: {
519: register int c1, c2;
520:
521: c1 = skipws();
522: c2 = getch();
523:
524: switch (c1) {
525:
526: case '=':
527: if (c2 != '=')
528: ungetch();
529: return EQL;
530:
531: case '!':
532: if (c2 == '=')
533: return NEQ;
534: ungetch();
535: ungetch();
536: return -1;
537:
538: case '<':
539: if (c2 == '=')
540: return LEQ;
541: ungetch();
542: return LSS;
543:
544: case '>':
545: if (c2 == '=')
546: return GEQ;
547: ungetch();
548: return GTR;
549:
550: default:
551: ungetch();
552: ungetch();
553: return -1;
554: }
555: }
556:
557: /*
558: * Skip over any white space and return terminating char.
559: */
560: static int
561: skipws()
562: {
563: register char c;
564:
565: while ((c = getch()) <= ' ' && c > EOS)
566: ;
567: return c;
568: }
569:
570: /*
571: * resets environment to eval(), prints an error
572: * and forces eval to return FALSE.
573: */
574: static void
575: experr(msg)
576: char *msg;
577: {
578: printf("m4: %s in expr.\n", msg);
579: longjmp(expjump, -1);
580: }