Annotation of src/usr.bin/m4/expr.c, Revision 1.12
1.12 ! millert 1: /* $OpenBSD: expr.c,v 1.11 2000/01/11 14:00:57 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.12 ! millert 44: static char rcsid[] = "$OpenBSD: expr.c,v 1.11 2000/01/11 14:00:57 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
145: expr(expbuf)
1.10 espie 146: const char *expbuf;
1.1 deraadt 147: {
1.7 espie 148: int rval;
1.1 deraadt 149:
150: nxtch = expbuf;
1.11 espie 151: where = expbuf;
1.1 deraadt 152: if (setjmp(expjump) != 0)
153: return FALSE;
154:
155: rval = query();
156: if (skipws() == EOS)
157: return rval;
158:
159: printf("m4: ill-formed expression.\n");
160: return FALSE;
161: }
162:
163: /*
164: * query : lor | lor '?' query ':' query
165: */
166: static int
167: query()
168: {
1.7 espie 169: int bool, true_val, false_val;
1.1 deraadt 170:
171: bool = lor();
172: if (skipws() != '?') {
173: ungetch();
174: return bool;
175: }
176:
177: true_val = query();
178: if (skipws() != ':')
179: experr("bad query");
180:
181: false_val = query();
182: return bool ? true_val : false_val;
183: }
184:
185: /*
186: * lor : land { '||' land }
187: */
188: static int
189: lor()
190: {
1.7 espie 191: int c, vl, vr;
1.1 deraadt 192:
193: vl = land();
194: while ((c = skipws()) == '|') {
195: if (getch() != '|')
196: ungetch();
197: vr = land();
198: vl = vl || vr;
199: }
200:
201: ungetch();
202: return vl;
203: }
204:
205: /*
206: * land : not { '&&' not }
207: */
208: static int
209: land()
210: {
1.7 espie 211: int c, vl, vr;
1.1 deraadt 212:
213: vl = not();
214: while ((c = skipws()) == '&') {
215: if (getch() != '&')
216: ungetch();
217: vr = not();
218: vl = vl && vr;
219: }
220:
221: ungetch();
222: return vl;
223: }
224:
225: /*
226: * not : eqrel | '!' not
227: */
228: static int
229: not()
230: {
1.7 espie 231: int val, c;
1.1 deraadt 232:
233: if ((c = skipws()) == '!' && getch() != '=') {
234: ungetch();
235: val = not();
236: return !val;
237: }
238:
239: if (c == '!')
240: ungetch();
241: ungetch();
242: return eqrel();
243: }
244:
245: /*
246: * eqrel : shift { eqrelop shift }
247: */
248: static int
249: eqrel()
250: {
1.7 espie 251: int vl, vr, eqrel;
1.1 deraadt 252:
253: vl = shift();
254: while ((eqrel = geteqrel()) != -1) {
255: vr = shift();
256:
257: switch (eqrel) {
258:
259: case EQL:
260: vl = (vl == vr);
261: break;
262: case NEQ:
263: vl = (vl != vr);
264: break;
265:
266: case LEQ:
267: vl = (vl <= vr);
268: break;
269: case LSS:
270: vl = (vl < vr);
271: break;
272: case GTR:
273: vl = (vl > vr);
274: break;
275: case GEQ:
276: vl = (vl >= vr);
277: break;
278: }
279: }
280: return vl;
281: }
282:
283: /*
284: * shift : primary { shop primary }
285: */
286: static int
287: shift()
288: {
1.7 espie 289: int vl, vr, c;
1.1 deraadt 290:
291: vl = primary();
292: while (((c = skipws()) == '<' || c == '>') && getch() == c) {
293: vr = primary();
294:
295: if (c == '<')
296: vl <<= vr;
297: else
298: vl >>= vr;
299: }
300:
301: if (c == '<' || c == '>')
302: ungetch();
303: ungetch();
304: return vl;
305: }
306:
307: /*
308: * primary : term { addop term }
309: */
310: static int
311: primary()
312: {
1.7 espie 313: int c, vl, vr;
1.1 deraadt 314:
315: vl = term();
316: while ((c = skipws()) == '+' || c == '-') {
317: vr = term();
318:
319: if (c == '+')
320: vl += vr;
321: else
322: vl -= vr;
323: }
324:
325: ungetch();
326: return vl;
327: }
328:
329: /*
330: * <term> := <exp> { <mulop> <exp> }
331: */
332: static int
333: term()
334: {
1.7 espie 335: int c, vl, vr;
1.1 deraadt 336:
337: vl = exp();
338: while ((c = skipws()) == '*' || c == '/' || c == '%') {
339: vr = exp();
340:
341: switch (c) {
342: case '*':
343: vl *= vr;
344: break;
345: case '/':
1.8 espie 346: if (vr == 0)
347: errx(1, "division by zero in eval.");
348: else
349: vl /= vr;
1.1 deraadt 350: break;
351: case '%':
1.8 espie 352: if (vr == 0)
353: errx(1, "modulo zero in eval.");
354: else
355: vl %= vr;
1.1 deraadt 356: break;
357: }
358: }
359: ungetch();
360: return vl;
361: }
362:
363: /*
364: * <term> := <unary> { <expop> <unary> }
365: */
366: static int
367: exp()
368: {
1.7 espie 369: int c, vl, vr, n;
1.1 deraadt 370:
371: vl = unary();
372: switch (c = skipws()) {
373:
374: case '*':
375: if (getch() != '*') {
376: ungetch();
377: break;
378: }
379:
380: case '^':
381: vr = exp();
382: n = 1;
383: while (vr-- > 0)
384: n *= vl;
385: return n;
386: }
387:
388: ungetch();
389: return vl;
390: }
391:
392: /*
393: * unary : factor | unop unary
394: */
395: static int
396: unary()
397: {
1.7 espie 398: int val, c;
1.1 deraadt 399:
400: if ((c = skipws()) == '+' || c == '-' || c == '~') {
401: val = unary();
402:
403: switch (c) {
404: case '+':
405: return val;
406: case '-':
407: return -val;
408: case '~':
409: return ~val;
410: }
411: }
412:
413: ungetch();
414: return factor();
415: }
416:
417: /*
418: * factor : constant | '(' query ')'
419: */
420: static int
421: factor()
422: {
1.7 espie 423: int val;
1.1 deraadt 424:
425: if (skipws() == '(') {
426: val = query();
427: if (skipws() != ')')
428: experr("bad factor");
429: return val;
430: }
431:
432: ungetch();
433: return constant();
434: }
435:
436: /*
437: * constant: num | 'char'
438: * Note: constant() handles multi-byte constants
439: */
440: static int
441: constant()
442: {
1.7 espie 443: int i;
444: int value;
445: int c;
1.1 deraadt 446: int v[sizeof(int)];
447:
448: if (skipws() != '\'') {
449: ungetch();
450: return num();
451: }
452: for (i = 0; i < sizeof(int); i++) {
453: if ((c = getch()) == '\'') {
454: ungetch();
455: break;
456: }
457: if (c == '\\') {
458: switch (c = getch()) {
459: case '0':
460: case '1':
461: case '2':
462: case '3':
463: case '4':
464: case '5':
465: case '6':
466: case '7':
467: ungetch();
468: c = num();
469: break;
470: case 'n':
471: c = 012;
472: break;
473: case 'r':
474: c = 015;
475: break;
476: case 't':
477: c = 011;
478: break;
479: case 'b':
480: c = 010;
481: break;
482: case 'f':
483: c = 014;
484: break;
485: }
486: }
487: v[i] = c;
488: }
489: if (i == 0 || getch() != '\'')
490: experr("illegal character constant");
491: for (value = 0; --i >= 0;) {
492: value <<= 8;
493: value += v[i];
494: }
495: return value;
496: }
497:
498: /*
499: * num : digit | num digit
500: */
501: static int
502: num()
503: {
1.7 espie 504: int rval, c, base;
1.1 deraadt 505: int ndig;
506:
507: rval = 0;
508: ndig = 0;
1.5 espie 509: c = skipws();
510: if (c == '0') {
511: c = skipws();
512: if (c == 'x' || c == 'X') {
513: base = HEX;
514: c = skipws();
515: } else {
516: base = OCTAL;
517: ndig++;
518: }
519: } else
520: base = DECIMAL;
521: for(;;) {
522: switch(c) {
523: case '8': case '9':
1.9 espie 524: if (base == OCTAL)
1.5 espie 525: goto bad_digit;
526: /*FALLTHRU*/
527: case '0': case '1': case '2': case '3':
528: case '4': case '5': case '6': case '7':
529: rval *= base;
530: rval += c - '0';
531: break;
532: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
533: c = tolower(c);
534: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
535: if (base == HEX) {
536: rval *= base;
537: rval += c - 'a' + 10;
538: break;
539: }
540: /*FALLTHRU*/
541: default:
542: goto bad_digit;
543: }
1.1 deraadt 544: c = getch();
545: ndig++;
546: }
1.5 espie 547: bad_digit:
1.1 deraadt 548: ungetch();
549:
550: if (ndig == 0)
551: experr("bad constant");
552:
553: return rval;
554: }
555:
556: /*
557: * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
558: */
559: static int
560: geteqrel()
561: {
1.7 espie 562: int c1, c2;
1.1 deraadt 563:
564: c1 = skipws();
565: c2 = getch();
566:
567: switch (c1) {
568:
569: case '=':
570: if (c2 != '=')
571: ungetch();
572: return EQL;
573:
574: case '!':
575: if (c2 == '=')
576: return NEQ;
577: ungetch();
578: ungetch();
579: return -1;
580:
581: case '<':
582: if (c2 == '=')
583: return LEQ;
584: ungetch();
585: return LSS;
586:
587: case '>':
588: if (c2 == '=')
589: return GEQ;
590: ungetch();
591: return GTR;
592:
593: default:
594: ungetch();
595: ungetch();
596: return -1;
597: }
598: }
599:
600: /*
601: * Skip over any white space and return terminating char.
602: */
603: static int
604: skipws()
605: {
1.7 espie 606: int c;
1.1 deraadt 607:
608: while ((c = getch()) <= ' ' && c > EOS)
609: ;
610: return c;
611: }
612:
613: /*
614: * resets environment to eval(), prints an error
615: * and forces eval to return FALSE.
616: */
617: static void
618: experr(msg)
1.10 espie 619: const char *msg;
1.1 deraadt 620: {
1.11 espie 621: printf("m4: %s in expr %s.\n", msg, where);
1.1 deraadt 622: longjmp(expjump, -1);
623: }