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