summaryrefslogtreecommitdiff
path: root/usr.bin/m4/expr.c
diff options
context:
space:
mode:
authorglass <glass@NetBSD.org>1994-06-19 03:58:22 +0000
committerglass <glass@NetBSD.org>1994-06-19 03:58:22 +0000
commita7c89f0ff9463df9e8104f76f9c538fe1bfb3cbe (patch)
treee6f67a067cb8c538cdf1b076210d28862cb06b55 /usr.bin/m4/expr.c
parent72679b6801126ce177d4ddfd7166cdd154fe167b (diff)
upgrade to 4.4-lite m4. no local changes of note
Diffstat (limited to 'usr.bin/m4/expr.c')
-rw-r--r--usr.bin/m4/expr.c1183
1 files changed, 596 insertions, 587 deletions
diff --git a/usr.bin/m4/expr.c b/usr.bin/m4/expr.c
index fc48eb31e02..850373336fd 100644
--- a/usr.bin/m4/expr.c
+++ b/usr.bin/m4/expr.c
@@ -1,617 +1,626 @@
-/* File : expr.c
- Authors: Mike Lutz & Bob Harper
- Editors: Ozan Yigit & Richard A. O'Keefe
- Updated: %G%
- Purpose: arithmetic expression evaluator.
-
- expr() performs a standard recursive descent parse to evaluate any
- expression permitted byf the following grammar:
-
- expr : query EOS
- query : lor
- | lor "?" query ":" query
- lor : land { "||" land } or OR, for Pascal
- land : bor { "&&" bor } or AND, for Pascal
- bor : bxor { "|" bxor }
- bxor : band { "^" band }
- band : eql { "&" eql }
- eql : relat { eqrel relat }
- relat : shift { rel shift }
- shift : primary { shop primary }
- primary : term { addop term }
- term : unary { mulop unary }
- unary : factor
- | unop unary
- factor : constant
- | "(" query ")"
- constant: num
- | "'" CHAR "'" or '"' CHAR '"'
- num : DIGIT full ANSI C syntax
- | DIGIT num
- shop : "<<"
- | ">>"
- eqlrel : "="
- | "=="
- | "!="
- rel : "<" or <>, Pascal not-equal
- | ">"
- | "<=" or =<, for Prolog users.
- | ">="
-
- This expression evaluator was lifted from a public-domain
- C Pre-Processor included with the DECUS C Compiler distribution.
- It has been hacked somewhat to be suitable for m4.
-
- 26-Mar-1993 Changed to work in any of EBCDIC, ASCII, DEC MNCS,
- or ISO 8859/n.
-
- 26-Mar-1993 Changed to use "long int" rather than int, so that
- we get the same 32-bit arithmetic on a PC as on a Sun.
- It isn't fully portable, of course, but then on a 64-
- bit machine we _want_ 64-bit arithmetic...
- Shifting rewritten (using LONG_BIT) to give signed
- shifts even when (long) >> (long) is unsigned.
-
- 26-Mar-1993 I finally got sick of the fact that &&, ||, and ?:
- don't do conditional evaluation. What is the good
- of having eval(0&&(1/0)) crash and dump core? Now
- every function has a doit? argument.
-
- 26-Mar-1993 charcon() didn't actually accept 'abcd', which it
- should have. Fixed it.
-
- 20-Apr-1993 eval(1/0) and eval(1%0) dumped core and crashed.
- This is also true of the System V r 3.2 m4, but
- it isn't good enough for ours! Changed it so that
- x % 0 => x as per Concrete Mathematics
- x / 0 => error and return 0 from expr().
-*/
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)expr.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <stdio.h>
+/*
+ * expression evaluator: performs a standard recursive
+ * descent parse to evaluate any expression permissible
+ * within the following grammar:
+ *
+ * expr : query EOS
+ * query : lor
+ * | lor "?" query ":" query
+ * lor : land { "||" land }
+ * land : bor { "&&" bor }
+ * bor : bxor { "|" bxor }
+ * bxor : band { "^" band }
+ * band : eql { "&" eql }
+ * eql : relat { eqrel relat }
+ * relat : shift { rel shift }
+ * shift : primary { shop primary }
+ * primary : term { addop term }
+ * term : unary { mulop unary }
+ * unary : factor
+ * | unop unary
+ * factor : constant
+ * | "(" query ")"
+ * constant: num
+ * | "'" CHAR "'"
+ * num : DIGIT
+ * | DIGIT num
+ * shop : "<<"
+ * | ">>"
+ * eqlrel : "="
+ * | "=="
+ * | "!="
+ * rel : "<"
+ * | ">"
+ * | "<="
+ * | ">="
+ *
+ *
+ * This expression evaluator is lifted from a public-domain
+ * C Pre-Processor included with the DECUS C Compiler distribution.
+ * It is hacked somewhat to be suitable for m4.
+ *
+ * Originally by: Mike Lutz
+ * Bob Harper
+ */
+
+#define TRUE 1
#define FALSE 0
-#define TRUE 1
-
-#include <stdio.h>
+#define EOS (char) 0
+#define EQL 0
+#define NEQ 1
+#define LSS 2
+#define LEQ 3
+#define GTR 4
+#define GEQ 5
+#define OCTAL 8
+#define DECIMAL 10
+
+static char *nxtch; /* Parser scan pointer */
+
+static int query __P((void));
+static int lor __P((void));
+static int land __P((void));
+static int bor __P((void));
+static int bxor __P((void));
+static int band __P((void));
+static int eql __P((void));
+static int relat __P((void));
+static int shift __P((void));
+static int primary __P((void));
+static int term __P((void));
+static int unary __P((void));
+static int factor __P((void));
+static int constant __P((void));
+static int num __P((void));
+static int geteql __P((void));
+static int getrel __P((void));
+static int skipws __P((void));
+static void experr __P((char *));
+
+/*
+ * For longjmp
+ */
#include <setjmp.h>
-static jmp_buf expjump; /* Error exit point for expr() */
-
-static unsigned char *nxtchr; /* Parser scan pointer */
-
-#define deblank0 while ((unsigned)(*nxtchr-1) < ' ') nxtchr++
-#define deblank1 while ((unsigned)(*++nxtchr - 1) < ' ')
-#define deblank2 nxtchr++; deblank1
-
-#include "ourlims.h"
-static char digval[1+UCHAR_MAX];
-
-/* This file should work in any C implementation that doesn't have too
- many characters to fit in one table. We use a table to convert
- (unsigned) characters to numeric codes:
- 0 to 9 for '0' to '9'
- 10 to 35 for 'a' to 'z'
- 10 to 35 for 'A' to 'Z'
- 36 for '_'
- Instead of asking whether tolower(c) == 'a' we ask whether
- digval[c] == DIGIT_A, and so on. This essentially duplicates the
- chtype[] table in main.c; we should use just one table.
-*/
-#define DIGIT_A 10
-#define DIGIT_B 11
-#define DIGIT_C 12
-#define DIGIT_D 13
-#define DIGIT_E 14
-#define DIGIT_F 15
-#define DIGIT_G 16
-#define DIGIT_H 17
-#define DIGIT_I 18
-#define DIGIT_J 19
-#define DIGIT_K 20
-#define DIGIT_L 21
-#define DIGIT_M 22
-#define DIGIT_N 23
-#define DIGIT_O 24
-#define DIGIT_P 25
-#define DIGIT_Q 26
-#define DIGIT_R 27
-#define DIGIT_S 28
-#define DIGIT_T 29
-#define DIGIT_U 30
-#define DIGIT_V 31
-#define DIGIT_W 32
-#define DIGIT_X 33
-#define DIGIT_Y 34
-#define DIGIT_Z 35
-
-
-#ifdef __STDC__
-static long int query(int);
-#else
-static long int query();
-#endif
-
-
-/* experr(msg)
- prints an error message, resets environment to expr(), and
- forces expr() to return FALSE.
-*/
-void experr(msg)
- char *msg;
- {
- (void) fprintf(stderr, "m4: %s\n", msg);
- longjmp(expjump, -1); /* Force expr() to return FALSE */
- }
-
-
-/* <numcon> ::= '0x' <hex> | '0X' <hex> | '0' <oct> | <dec>
- For ANSI C, an integer may be followed by u, l, ul, or lu,
- in any mix of cases. We accept and ignore those letters;
- all the numbers are treated as long.
-*/
-static long int numcon(doit)
- int doit;
- {
- register long int v; /* current value */
- register int b; /* base (radix) */
- register int c; /* character or digit value */
-
- if (!doit) {
- do nxtchr++; while (digval[*nxtchr] <= 36);
- deblank0;
- return 0;
+static jmp_buf expjump;
+
+/*
+ * macros:
+ * ungetch - Put back the last character examined.
+ * getch - return the next character from expr string.
+ */
+#define ungetch() nxtch--
+#define getch() *nxtch++
+
+int
+expr(expbuf)
+char *expbuf;
+{
+ register int rval;
+
+ nxtch = expbuf;
+ if (setjmp(expjump) != 0)
+ return FALSE;
+
+ rval = query();
+ if (skipws() == EOS)
+ return rval;
+
+ printf("m4: ill-formed expression.\n");
+ return FALSE;
+}
+
+/*
+ * query : lor | lor '?' query ':' query
+ */
+static int
+query()
+{
+ register int bool, true_val, false_val;
+
+ bool = lor();
+ if (skipws() != '?') {
+ ungetch();
+ return bool;
}
- v = digval[*nxtchr++]; /* We already know it's a digit */
- if (v != 0) {
- b = 10; /* decimal number */
- } else
- if (digval[*nxtchr] == DIGIT_X) {
- nxtchr++;
- b = 16; /* hexadecimal number */
- } else {
- b = 8; /* octal number */
+ true_val = query();
+ if (skipws() != ':')
+ experr("bad query");
+
+ false_val = query();
+ return bool ? true_val : false_val;
+}
+
+/*
+ * lor : land { '||' land }
+ */
+static int
+lor()
+{
+ register int c, vl, vr;
+
+ vl = land();
+ while ((c = skipws()) == '|' && getch() == '|') {
+ vr = land();
+ vl = vl || vr;
}
- do {
- while (digval[c = *nxtchr++] < b) v = v*b + digval[c];
- } while (c == '_');
- while (digval[c] == DIGIT_L || digval[c] == DIGIT_U) c = *nxtchr++;
- nxtchr--; /* unread c */
- if ((unsigned)(c-1) < ' ') { deblank1; }
- return v;
- }
-
-
-/* <charcon> ::= <qt> { <char> } <qt>
- Note: multibyte constants are accepted.
- Note: BEL (\a) and ESC (\e) have the same values in EBCDIC and ASCII.
-*/
-static long int charcon(doit)
- int doit;
- {
- register int i;
- long int value;
- register int c;
- int q;
- int v[sizeof value];
-
- q = *nxtchr++; /* the quote character */
- for (i = 0; ; i++) {
- c = *nxtchr++;
- if (c == q) { /* end of literal, or doubled quote */
- if (*nxtchr != c) break;
- nxtchr++; /* doubled quote stands for one quote */
- }
- if (i == sizeof value) experr("Unterminated character constant");
- if (c == '\\') {
- switch (c = *nxtchr++) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- c -= '0';
- if ((unsigned)(*nxtchr - '0') < 8)
- c = (c << 3) | (*nxtchr++ - '0');
- if ((unsigned)(*nxtchr - '0') < 8)
- c = (c << 3) | (*nxtchr++ - '0');
+
+ if (c == '|')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * land : bor { '&&' bor }
+ */
+static int
+land()
+{
+ register int c, vl, vr;
+
+ vl = bor();
+ while ((c = skipws()) == '&' && getch() == '&') {
+ vr = bor();
+ vl = vl && vr;
+ }
+
+ if (c == '&')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * bor : bxor { '|' bxor }
+ */
+static int
+bor()
+{
+ register int vl, vr, c;
+
+ vl = bxor();
+ while ((c = skipws()) == '|' && getch() != '|') {
+ ungetch();
+ vr = bxor();
+ vl |= vr;
+ }
+
+ if (c == '|')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * bxor : band { '^' band }
+ */
+static int
+bxor()
+{
+ register int vl, vr;
+
+ vl = band();
+ while (skipws() == '^') {
+ vr = band();
+ vl ^= vr;
+ }
+
+ ungetch();
+ return vl;
+}
+
+/*
+ * band : eql { '&' eql }
+ */
+static int
+band()
+{
+ register int vl, vr, c;
+
+ vl = eql();
+ while ((c = skipws()) == '&' && getch() != '&') {
+ ungetch();
+ vr = eql();
+ vl &= vr;
+ }
+
+ if (c == '&')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * eql : relat { eqrel relat }
+ */
+static int
+eql()
+{
+ register int vl, vr, rel;
+
+ vl = relat();
+ while ((rel = geteql()) != -1) {
+ vr = relat();
+
+ switch (rel) {
+
+ case EQL:
+ vl = (vl == vr);
+ break;
+ case NEQ:
+ vl = (vl != vr);
break;
- case 'n': case 'N': c = '\n'; break;
- case 'r': case 'R': c = '\r'; break;
- case 't': case 'T': c = '\t'; break;
- case 'b': case 'B': c = '\b'; break;
- case 'f': case 'F': c = '\f'; break;
- case 'a': case 'A': c = 007; break;
- case 'e': case 'E': c = 033; break;
-#if ' ' == 64
- case 'd': case 'D': c = 045; break; /*EBCDIC DEL */
-#else
- case 'd': case 'D': c = 127; break; /* ASCII DEL */
-#endif
- default : break;
}
- }
- v[i] = c;
- }
- deblank0;
- if (!doit) return 0;
- for (value = 0; --i >= 0; ) value = (value << CHAR_BIT) | v[i];
- return value;
- }
-
-
-/* <unary> ::= <unop> <unary> | <factor>
- <unop> ::= '!' || '~' | '-'
- <factor> ::= '(' <query> ')' | <'> <char> <'> | <"> <char> <"> | <num>
-*/
-static long int unary(doit)
- int doit;
- {
- long int v;
-
- switch (nxtchr[0]) {
- case 'n': case 'N':
- if (digval[nxtchr[1]] != DIGIT_O
- || digval[nxtchr[2]] != DIGIT_T)
- experr("Bad 'not'");
- nxtchr += 2;
- case '!': deblank1; return !unary(doit);
- case '~': deblank1; return ~unary(doit);
- case '-': deblank1; return -unary(doit);
- case '+': deblank1; return unary(doit);
- case '(': deblank1; v = query(doit);
- if (nxtchr[0] != ')') experr("Bad factor");
- deblank1; return v;
- case '\'':
- case '\"': return charcon(doit);
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9': return numcon(doit);
- default : experr("Bad constant");
}
- return 0; /*NOTREACHED*/
- }
+ return vl;
+}
+/*
+ * relat : shift { rel shift }
+ */
+static int
+relat()
+{
+ register int vl, vr, rel;
-/* <term> ::= <unary> { <mulop> <unary> }
- <mulop> ::= '*' | '/' || '%'
-*/
-static long int term(doit)
- int doit;
- {
- register long int vl, vr;
+ vl = shift();
+ while ((rel = getrel()) != -1) {
- vl = unary(doit);
- for (;;)
- switch (nxtchr[0]) {
- case '*':
- deblank1;
- vr = unary(doit);
- if (doit) vl *= vr;
- break;
- case 'd': case 'D':
- if (digval[nxtchr[1]] != DIGIT_I
- || digval[nxtchr[2]] != DIGIT_V)
- experr("Bad 'div'");
- nxtchr += 2;
- /*FALLTHROUGH*/
- case '/':
- deblank1;
- vr = unary(doit);
- if (doit) {
- if (vr == 0) experr("Division by 0");
- vl /= vr;
- }
- break;
- case 'm': case 'M':
- if (digval[nxtchr[1]] != DIGIT_O
- || digval[nxtchr[2]] != DIGIT_D)
- experr("Bad 'mod'");
- nxtchr += 2;
- /*FALLTHROUGH*/
- case '%':
- deblank1;
- vr = unary(doit);
- if (doit) {
- if (vr != 0) vl %= vr;
- }
- break;
- default:
- return vl;
- }
- /*NOTREACHED*/
- }
-
-/* <primary> ::= <term> { <addop> <term> }
- <addop> ::= '+' | '-'
-*/
-static long int primary(doit)
- int doit;
- {
- register long int vl;
-
- vl = term(doit);
- for (;;)
- if (nxtchr[0] == '+') {
- deblank1;
- if (doit) vl += term(doit); else (void)term(doit);
- } else
- if (nxtchr[0] == '-') {
- deblank1;
- if (doit) vl -= term(doit); else (void)term(doit);
- } else
- return vl;
- /*NOTREACHED*/
- }
-
-
-/* <shift> ::= <primary> { <shop> <primary> }
- <shop> ::= '<<' | '>>'
-*/
-static long int shift(doit)
- int doit;
- {
- register long int vl, vr;
-
- vl = primary(doit);
- for (;;) {
- if (nxtchr[0] == '<' && nxtchr[1] == '<') {
- deblank2;
- vr = primary(doit);
- } else
- if (nxtchr[0] == '>' && nxtchr[1] == '>') {
- deblank2;
- vr = -primary(doit);
- } else {
- return vl;
- }
- /* The following code implements shifts portably */
- /* Shifts are signed shifts, and the shift count */
- /* acts like repeated one-bit shifts, not modulo anything */
- if (doit) {
- if (vr >= LONG_BIT) {
- vl = 0;
- } else
- if (vr <= -LONG_BIT) {
- vl = -(vl < 0);
- } else
- if (vr > 0) {
- vl <<= vr;
- } else
- if (vr < 0) {
- vl = (vl >> -vr) | (-(vl < 0) << (LONG_BIT + vr));
+ vr = shift();
+ switch (rel) {
+
+ case LEQ:
+ vl = (vl <= vr);
+ break;
+ case LSS:
+ vl = (vl < vr);
+ break;
+ case GTR:
+ vl = (vl > vr);
+ break;
+ case GEQ:
+ vl = (vl >= vr);
+ break;
}
- }
}
- /*NOTREACHED*/
- }
-
-
-/* <relat> ::= <shift> { <rel> <shift> }
- <rel> ::= '<=' | '>=' | '=<' | '=>' | '<' | '>'
- Here I rely on the fact that '<<' and '>>' are swallowed by <shift>
-*/
-static long int relat(doit)
- int doit;
- {
- register long int vl;
-
- vl = shift(doit);
- for (;;)
- switch (nxtchr[0]) {
- case '=':
- switch (nxtchr[1]) {
- case '<': /* =<, take as <= */
- deblank2;
- vl = vl <= shift(doit);
- break;
- case '>': /* =>, take as >= */
- deblank2;
- vl = vl >= shift(doit);
- break;
- default: /* == or =; OOPS */
- return vl;
- }
- break;
- case '<':
- if (nxtchr[1] == '=') { /* <= */
- deblank2;
- vl = vl <= shift(doit);
- } else
- if (nxtchr[1] == '>') { /* <> (Pascal) */
- deblank2;
- vl = vl != shift(doit);
- } else { /* < */
- deblank1;
- vl = vl < shift(doit);
- }
- break;
- case '>':
- if (nxtchr[1] == '=') { /* >= */
- deblank2;
- vl = vl >= shift(doit);
- } else { /* > */
- deblank1;
- vl = vl > shift(doit);
- }
- break;
- default:
- return vl;
+ return vl;
+}
+
+/*
+ * shift : primary { shop primary }
+ */
+static int
+shift()
+{
+ register int vl, vr, c;
+
+ vl = primary();
+ while (((c = skipws()) == '<' || c == '>') && c == getch()) {
+ vr = primary();
+
+ if (c == '<')
+ vl <<= vr;
+ else
+ vl >>= vr;
}
- /*NOTREACHED*/
- }
-
-
-/* <eql> ::= <relat> { <eqrel> <relat> }
- <eqlrel> ::= '!=' | '==' | '='
-*/
-static long int eql(doit)
- int doit;
- {
- register long int vl;
-
- vl = relat(doit);
- for (;;)
- if (nxtchr[0] == '!' && nxtchr[1] == '=') {
- deblank2;
- vl = vl != relat(doit);
- } else
- if (nxtchr[0] == '=' && nxtchr[1] == '=') {
- deblank2;
- vl = vl == relat(doit);
- } else
- if (nxtchr[0] == '=') {
- deblank1;
- vl = vl == relat(doit);
- } else
- return vl;
- /*NOTREACHED*/
- }
-
-
-/* <band> ::= <eql> { '&' <eql> }
-*/
-static long int band(doit)
- int doit;
- {
- register long int vl;
-
- vl = eql(doit);
- while (nxtchr[0] == '&' && nxtchr[1] != '&') {
- deblank1;
- if (doit) vl &= eql(doit); else (void)eql(doit);
+
+ if (c == '<' || c == '>')
+ ungetch();
+ ungetch();
+ return vl;
+}
+
+/*
+ * primary : term { addop term }
+ */
+static int
+primary()
+{
+ register int c, vl, vr;
+
+ vl = term();
+ while ((c = skipws()) == '+' || c == '-') {
+ vr = term();
+ if (c == '+')
+ vl += vr;
+ else
+ vl -= vr;
}
+
+ ungetch();
return vl;
- }
+}
+/*
+ * <term> := <unary> { <mulop> <unary> }
+ */
+static int
+term()
+{
+ register int c, vl, vr;
-/* <bxor> ::= <band> { '^' <band> }
-*/
-static long int bxor(doit)
- int doit;
- {
- register long int vl;
+ vl = unary();
+ while ((c = skipws()) == '*' || c == '/' || c == '%') {
+ vr = unary();
- vl = band(doit);
- while (nxtchr[0] == '^') {
- deblank1;
- if (doit) vl ^= band(doit); else (void)band(doit);
+ switch (c) {
+ case '*':
+ vl *= vr;
+ break;
+ case '/':
+ vl /= vr;
+ break;
+ case '%':
+ vl %= vr;
+ break;
+ }
}
+ ungetch();
return vl;
- }
+}
+
+/*
+ * unary : factor | unop unary
+ */
+static int
+unary()
+{
+ register int val, c;
+
+ if ((c = skipws()) == '!' || c == '~' || c == '-') {
+ val = unary();
+
+ switch (c) {
+ case '!':
+ return !val;
+ case '~':
+ return ~val;
+ case '-':
+ return -val;
+ }
+ }
+ ungetch();
+ return factor();
+}
+
+/*
+ * factor : constant | '(' query ')'
+ */
+static int
+factor()
+{
+ register int val;
+
+ if (skipws() == '(') {
+ val = query();
+ if (skipws() != ')')
+ experr("bad factor");
+ return val;
+ }
-/* <bor> ::= <bxor> { '|' <bxor> }
-*/
-static long int bor(doit)
- int doit;
- {
- register long int vl;
+ ungetch();
+ return constant();
+}
+
+/*
+ * constant: num | 'char'
+ * Note: constant() handles multi-byte constants
+ */
+static int
+constant()
+{
+ register int i;
+ register int value;
+ register char c;
+ int v[sizeof(int)];
- vl = bxor(doit);
- while (nxtchr[0] == '|' && nxtchr[1] != '|') {
- deblank1;
- if (doit) vl |= bxor(doit); else (void)bxor(doit);
+ if (skipws() != '\'') {
+ ungetch();
+ return num();
}
- return vl;
- }
-
-
-/* <land> ::= <bor> { '&&' <bor> }
-*/
-static long int land(doit)
- int doit;
- {
- register long int vl;
-
- vl = bor(doit);
- for (;;) {
- if (nxtchr[0] == '&') {
- if (nxtchr[1] != '&') break;
- deblank2;
- } else
- if (digval[nxtchr[0]] == DIGIT_A) {
- if (digval[nxtchr[1]] != DIGIT_N) break;
- if (digval[nxtchr[2]] != DIGIT_D) break;
- nxtchr += 2; deblank1;
- } else {
- /* neither && nor and */
- break;
- }
- vl = bor(doit && vl) != 0;
+ for (i = 0; i < sizeof(int); i++) {
+ if ((c = getch()) == '\'') {
+ ungetch();
+ break;
+ }
+ if (c == '\\') {
+ switch (c = getch()) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ungetch();
+ c = num();
+ break;
+ case 'n':
+ c = 012;
+ break;
+ case 'r':
+ c = 015;
+ break;
+ case 't':
+ c = 011;
+ break;
+ case 'b':
+ c = 010;
+ break;
+ case 'f':
+ c = 014;
+ break;
+ }
+ }
+ v[i] = c;
}
- return vl;
- }
-
-
-/* <lor> ::= <land> { '||' <land> }
-*/
-static long int lor(doit)
- int doit;
- {
- register long int vl;
-
- vl = land(doit);
- for (;;) {
- if (nxtchr[0] == '|') {
- if (nxtchr[1] != '|') break;
- } else
- if (digval[nxtchr[0]] == DIGIT_O) {
- if (digval[nxtchr[1]] != DIGIT_R) break;
- } else {
- /* neither || nor or */
- break;
- }
- deblank2;
- vl = land(doit && !vl) != 0;
+ if (i == 0 || getch() != '\'')
+ experr("illegal character constant");
+ for (value = 0; --i >= 0;) {
+ value <<= 8;
+ value += v[i];
}
- return vl;
- }
-
-
-/* <query> ::= <lor> [ '?' <query> ':' <query> ]
-*/
-static long int query(doit)
- int doit;
- {
- register long int bool, true_val, false_val;
-
- bool = lor(doit);
- if (*nxtchr != '?') return bool;
- deblank1;
- true_val = query(doit && bool);
- if (*nxtchr != ':') experr("Bad query");
- deblank1;
- false_val = query(doit && !bool);
- return bool ? true_val : false_val;
- }
-
-
-static void initialise_digval()
- {
- register unsigned char *s;
- register int c;
-
- for (c = 0; c <= UCHAR_MAX; c++) digval[c] = 99;
- for (c = 0, s = (unsigned char *)"0123456789";
- /*while*/ *s;
- /*doing*/ digval[*s++] = c++) /* skip */;
- for (c = 10, s = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- /*while*/ *s;
- /*doing*/ digval[*s++] = c++) /* skip */;
- for (c = 10, s = (unsigned char *)"abcdefghijklmnopqrstuvwxyz";
- /*while*/ *s;
- /*doing*/ digval[*s++] = c++) /* skip */;
- digval['_'] = 36;
- }
-
-
-long int expr(expbuf)
- char *expbuf;
- {
- register int rval;
-
- if (digval['1'] == 0) initialise_digval();
- nxtchr = (unsigned char *)expbuf;
- deblank0;
- if (setjmp(expjump) != 0) return FALSE;
- rval = query(TRUE);
- if (*nxtchr) experr("Ill-formed expression");
+ return value;
+}
+
+/*
+ * num : digit | num digit
+ */
+static int
+num()
+{
+ register int rval, c, base;
+ int ndig;
+
+ base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
+ rval = 0;
+ ndig = 0;
+ while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
+ rval *= base;
+ rval += (c - '0');
+ c = getch();
+ ndig++;
+ }
+ ungetch();
+
+ if (ndig == 0)
+ experr("bad constant");
+
return rval;
- }
+}
+
+/*
+ * eqlrel : '=' | '==' | '!='
+ */
+static int
+geteql()
+{
+ register int c1, c2;
+
+ c1 = skipws();
+ c2 = getch();
+
+ switch (c1) {
+
+ case '=':
+ if (c2 != '=')
+ ungetch();
+ return EQL;
+
+ case '!':
+ if (c2 == '=')
+ return NEQ;
+ ungetch();
+ ungetch();
+ return -1;
+
+ default:
+ ungetch();
+ ungetch();
+ return -1;
+ }
+}
+
+/*
+ * rel : '<' | '>' | '<=' | '>='
+ */
+static int
+getrel()
+{
+ register int c1, c2;
+
+ c1 = skipws();
+ c2 = getch();
+
+ switch (c1) {
+
+ case '<':
+ if (c2 == '=')
+ return LEQ;
+ ungetch();
+ return LSS;
+
+ case '>':
+ if (c2 == '=')
+ return GEQ;
+ ungetch();
+ return GTR;
+
+ default:
+ ungetch();
+ ungetch();
+ return -1;
+ }
+}
+
+/*
+ * Skip over any white space and return terminating char.
+ */
+static int
+skipws()
+{
+ register char c;
+
+ while ((c = getch()) <= ' ' && c > EOS)
+ ;
+ return c;
+}
+
+/*
+ * resets environment to eval(), prints an error
+ * and forces eval to return FALSE.
+ */
+static void
+experr(msg)
+char *msg;
+{
+ printf("m4: %s in expr.\n", msg);
+ longjmp(expjump, -1);
+}