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