Annotation of src/usr.bin/m4/expr.c, Revision 1.7
1.7 ! espie 1: /* $OpenBSD: expr.c,v 1.4 1998/04/25 18:47:19 millert 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.7 ! espie 44: static char rcsid[] = "$OpenBSD: expr.c,v 1.4 1998/04/25 18:47:19 millert 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 '/':
341: vl /= vr;
342: break;
343: case '%':
344: vl %= vr;
345: break;
346: }
347: }
348: ungetch();
349: return vl;
350: }
351:
352: /*
353: * <term> := <unary> { <expop> <unary> }
354: */
355: static int
356: exp()
357: {
1.7 ! espie 358: int c, vl, vr, n;
1.1 deraadt 359:
360: vl = unary();
361: switch (c = skipws()) {
362:
363: case '*':
364: if (getch() != '*') {
365: ungetch();
366: break;
367: }
368:
369: case '^':
370: vr = exp();
371: n = 1;
372: while (vr-- > 0)
373: n *= vl;
374: return n;
375: }
376:
377: ungetch();
378: return vl;
379: }
380:
381: /*
382: * unary : factor | unop unary
383: */
384: static int
385: unary()
386: {
1.7 ! espie 387: int val, c;
1.1 deraadt 388:
389: if ((c = skipws()) == '+' || c == '-' || c == '~') {
390: val = unary();
391:
392: switch (c) {
393: case '+':
394: return val;
395: case '-':
396: return -val;
397: case '~':
398: return ~val;
399: }
400: }
401:
402: ungetch();
403: return factor();
404: }
405:
406: /*
407: * factor : constant | '(' query ')'
408: */
409: static int
410: factor()
411: {
1.7 ! espie 412: int val;
1.1 deraadt 413:
414: if (skipws() == '(') {
415: val = query();
416: if (skipws() != ')')
417: experr("bad factor");
418: return val;
419: }
420:
421: ungetch();
422: return constant();
423: }
424:
425: /*
426: * constant: num | 'char'
427: * Note: constant() handles multi-byte constants
428: */
429: static int
430: constant()
431: {
1.7 ! espie 432: int i;
! 433: int value;
! 434: int c;
1.1 deraadt 435: int v[sizeof(int)];
436:
437: if (skipws() != '\'') {
438: ungetch();
439: return num();
440: }
441: for (i = 0; i < sizeof(int); i++) {
442: if ((c = getch()) == '\'') {
443: ungetch();
444: break;
445: }
446: if (c == '\\') {
447: switch (c = getch()) {
448: case '0':
449: case '1':
450: case '2':
451: case '3':
452: case '4':
453: case '5':
454: case '6':
455: case '7':
456: ungetch();
457: c = num();
458: break;
459: case 'n':
460: c = 012;
461: break;
462: case 'r':
463: c = 015;
464: break;
465: case 't':
466: c = 011;
467: break;
468: case 'b':
469: c = 010;
470: break;
471: case 'f':
472: c = 014;
473: break;
474: }
475: }
476: v[i] = c;
477: }
478: if (i == 0 || getch() != '\'')
479: experr("illegal character constant");
480: for (value = 0; --i >= 0;) {
481: value <<= 8;
482: value += v[i];
483: }
484: return value;
485: }
486:
487: /*
488: * num : digit | num digit
489: */
490: static int
491: num()
492: {
1.7 ! espie 493: int rval, c, base;
1.1 deraadt 494: int ndig;
495:
496: rval = 0;
497: ndig = 0;
1.5 espie 498: c = skipws();
499: if (c == '0') {
500: c = skipws();
501: if (c == 'x' || c == 'X') {
502: base = HEX;
503: c = skipws();
504: } else {
505: base = OCTAL;
506: ndig++;
507: }
508: } else
509: base = DECIMAL;
510: for(;;) {
511: switch(c) {
512: case '8': case '9':
513: if (base != OCTAL)
514: goto bad_digit;
515: /*FALLTHRU*/
516: case '0': case '1': case '2': case '3':
517: case '4': case '5': case '6': case '7':
518: rval *= base;
519: rval += c - '0';
520: break;
521: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
522: c = tolower(c);
523: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
524: if (base == HEX) {
525: rval *= base;
526: rval += c - 'a' + 10;
527: break;
528: }
529: /*FALLTHRU*/
530: default:
531: goto bad_digit;
532: }
1.1 deraadt 533: c = getch();
534: ndig++;
535: }
1.5 espie 536: bad_digit:
1.1 deraadt 537: ungetch();
538:
539: if (ndig == 0)
540: experr("bad constant");
541:
542: return rval;
543: }
544:
545: /*
546: * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
547: */
548: static int
549: geteqrel()
550: {
1.7 ! espie 551: int c1, c2;
1.1 deraadt 552:
553: c1 = skipws();
554: c2 = getch();
555:
556: switch (c1) {
557:
558: case '=':
559: if (c2 != '=')
560: ungetch();
561: return EQL;
562:
563: case '!':
564: if (c2 == '=')
565: return NEQ;
566: ungetch();
567: ungetch();
568: return -1;
569:
570: case '<':
571: if (c2 == '=')
572: return LEQ;
573: ungetch();
574: return LSS;
575:
576: case '>':
577: if (c2 == '=')
578: return GEQ;
579: ungetch();
580: return GTR;
581:
582: default:
583: ungetch();
584: ungetch();
585: return -1;
586: }
587: }
588:
589: /*
590: * Skip over any white space and return terminating char.
591: */
592: static int
593: skipws()
594: {
1.7 ! espie 595: int c;
1.1 deraadt 596:
597: while ((c = getch()) <= ' ' && c > EOS)
598: ;
599: return c;
600: }
601:
602: /*
603: * resets environment to eval(), prints an error
604: * and forces eval to return FALSE.
605: */
606: static void
607: experr(msg)
1.7 ! espie 608: char *msg;
1.1 deraadt 609: {
610: printf("m4: %s in expr.\n", msg);
611: longjmp(expjump, -1);
612: }