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