138820Sbostic /*
262080Sbostic * Copyright (c) 1989, 1993
362080Sbostic * The Regents of the University of California. All rights reserved.
438820Sbostic *
538820Sbostic * This code is derived from software contributed to Berkeley by
651769Sbostic * Ozan Yigit at York University.
738820Sbostic *
842689Sbostic * %sccs.include.redist.c%
938820Sbostic */
1038820Sbostic
1138820Sbostic #ifndef lint
12*69109Sbostic static char sccsid[] = "@(#)expr.c 8.2 (Berkeley) 04/29/95";
1338820Sbostic #endif /* not lint */
1438820Sbostic
1550960Sbostic #include <sys/cdefs.h>
1646697Sbostic #include <stdio.h>
1746697Sbostic
1838820Sbostic /*
1938820Sbostic * expression evaluator: performs a standard recursive
2038820Sbostic * descent parse to evaluate any expression permissible
2138820Sbostic * within the following grammar:
2238820Sbostic *
2338820Sbostic * expr : query EOS
2438820Sbostic * query : lor
2538820Sbostic * | lor "?" query ":" query
2638820Sbostic * lor : land { "||" land }
27*69109Sbostic * land : not { "&&" not }
28*69109Sbostic * not : eqrel
29*69109Sbostic * | '!' not
30*69109Sbostic * eqrel : shift { eqrelop shift }
3138820Sbostic * shift : primary { shop primary }
3238820Sbostic * primary : term { addop term }
33*69109Sbostic * term : exp { mulop exp }
34*69109Sbostic * exp : unary { expop unary }
3538820Sbostic * unary : factor
3638820Sbostic * | unop unary
3738820Sbostic * factor : constant
3838820Sbostic * | "(" query ")"
3938820Sbostic * constant: num
4038820Sbostic * | "'" CHAR "'"
4138820Sbostic * num : DIGIT
4238820Sbostic * | DIGIT num
4338820Sbostic * shop : "<<"
4438820Sbostic * | ">>"
45*69109Sbostic * eqrel : "="
4638820Sbostic * | "=="
4738820Sbostic * | "!="
48*69109Sbostic * | "<"
4938820Sbostic * | ">"
5038820Sbostic * | "<="
5138820Sbostic * | ">="
5238820Sbostic *
5338820Sbostic *
5438820Sbostic * This expression evaluator is lifted from a public-domain
5538820Sbostic * C Pre-Processor included with the DECUS C Compiler distribution.
5638820Sbostic * It is hacked somewhat to be suitable for m4.
5738820Sbostic *
5838820Sbostic * Originally by: Mike Lutz
5938820Sbostic * Bob Harper
6038820Sbostic */
6150960Sbostic
6238820Sbostic #define TRUE 1
6338820Sbostic #define FALSE 0
6438820Sbostic #define EOS (char) 0
6538820Sbostic #define EQL 0
6638820Sbostic #define NEQ 1
6738820Sbostic #define LSS 2
6838820Sbostic #define LEQ 3
6938820Sbostic #define GTR 4
7038820Sbostic #define GEQ 5
7138820Sbostic #define OCTAL 8
7238820Sbostic #define DECIMAL 10
7350960Sbostic
7450960Sbostic static char *nxtch; /* Parser scan pointer */
7550960Sbostic
7650960Sbostic static int query __P((void));
7750960Sbostic static int lor __P((void));
7850960Sbostic static int land __P((void));
79*69109Sbostic static int not __P((void));
80*69109Sbostic static int eqrel __P((void));
8150960Sbostic static int shift __P((void));
8250960Sbostic static int primary __P((void));
8350960Sbostic static int term __P((void));
84*69109Sbostic static int exp __P((void));
8550960Sbostic static int unary __P((void));
8650960Sbostic static int factor __P((void));
8750960Sbostic static int constant __P((void));
8850960Sbostic static int num __P((void));
89*69109Sbostic static int geteqrel __P((void));
9050960Sbostic static int skipws __P((void));
9150960Sbostic static void experr __P((char *));
9250960Sbostic
9338820Sbostic /*
9438820Sbostic * For longjmp
9538820Sbostic */
9650960Sbostic #include <setjmp.h>
9750960Sbostic static jmp_buf expjump;
9850960Sbostic
9938820Sbostic /*
10038820Sbostic * macros:
10138820Sbostic * ungetch - Put back the last character examined.
10238820Sbostic * getch - return the next character from expr string.
10338820Sbostic */
10438820Sbostic #define ungetch() nxtch--
10538820Sbostic #define getch() *nxtch++
10650960Sbostic
10750960Sbostic int
expr(expbuf)10838820Sbostic expr(expbuf)
10938820Sbostic char *expbuf;
11038820Sbostic {
11150960Sbostic register int rval;
11250960Sbostic
11350960Sbostic nxtch = expbuf;
11450960Sbostic if (setjmp(expjump) != 0)
11550960Sbostic return FALSE;
11650960Sbostic
11750960Sbostic rval = query();
11850960Sbostic if (skipws() == EOS)
11950960Sbostic return rval;
12050960Sbostic
12150960Sbostic printf("m4: ill-formed expression.\n");
12250960Sbostic return FALSE;
12338820Sbostic }
12450960Sbostic
12538820Sbostic /*
12638820Sbostic * query : lor | lor '?' query ':' query
12738820Sbostic */
12850960Sbostic static int
query()12938820Sbostic query()
13038820Sbostic {
13150960Sbostic register int bool, true_val, false_val;
13250960Sbostic
13350960Sbostic bool = lor();
13450960Sbostic if (skipws() != '?') {
13550960Sbostic ungetch();
13650960Sbostic return bool;
13750960Sbostic }
13850960Sbostic
13950960Sbostic true_val = query();
14050960Sbostic if (skipws() != ':')
14150960Sbostic experr("bad query");
14250960Sbostic
14350960Sbostic false_val = query();
14450960Sbostic return bool ? true_val : false_val;
14538820Sbostic }
14650960Sbostic
14738820Sbostic /*
14838820Sbostic * lor : land { '||' land }
14938820Sbostic */
15050960Sbostic static int
lor()15138820Sbostic lor()
15238820Sbostic {
15350960Sbostic register int c, vl, vr;
15450960Sbostic
15550960Sbostic vl = land();
156*69109Sbostic while ((c = skipws()) == '|') {
157*69109Sbostic if (getch() != '|')
158*69109Sbostic ungetch();
15950960Sbostic vr = land();
16050960Sbostic vl = vl || vr;
16150960Sbostic }
16250960Sbostic
16350960Sbostic ungetch();
16450960Sbostic return vl;
16538820Sbostic }
16650960Sbostic
16738820Sbostic /*
168*69109Sbostic * land : not { '&&' not }
16938820Sbostic */
17050960Sbostic static int
land()17138820Sbostic land()
17238820Sbostic {
17350960Sbostic register int c, vl, vr;
17450960Sbostic
175*69109Sbostic vl = not();
176*69109Sbostic while ((c = skipws()) == '&') {
177*69109Sbostic if (getch() != '&')
178*69109Sbostic ungetch();
179*69109Sbostic vr = not();
18050960Sbostic vl = vl && vr;
18150960Sbostic }
18250960Sbostic
18350960Sbostic ungetch();
18450960Sbostic return vl;
18538820Sbostic }
18650960Sbostic
18738820Sbostic /*
188*69109Sbostic * not : eqrel | '!' not
18938820Sbostic */
19050960Sbostic static int
not()191*69109Sbostic not()
19238820Sbostic {
193*69109Sbostic register int val, c;
19450960Sbostic
195*69109Sbostic if ((c = skipws()) == '!' && getch() != '=') {
19650960Sbostic ungetch();
197*69109Sbostic val = not();
198*69109Sbostic return !val;
19950960Sbostic }
20050960Sbostic
201*69109Sbostic if (c == '!')
20250960Sbostic ungetch();
20350960Sbostic ungetch();
204*69109Sbostic return eqrel();
20538820Sbostic }
20650960Sbostic
20738820Sbostic /*
208*69109Sbostic * eqrel : shift { eqrelop shift }
20938820Sbostic */
21050960Sbostic static int
eqrel()211*69109Sbostic eqrel()
21238820Sbostic {
213*69109Sbostic register int vl, vr, eqrel;
21450960Sbostic
215*69109Sbostic vl = shift();
216*69109Sbostic while ((eqrel = geteqrel()) != -1) {
217*69109Sbostic vr = shift();
21850960Sbostic
219*69109Sbostic switch (eqrel) {
22050960Sbostic
22150960Sbostic case EQL:
22250960Sbostic vl = (vl == vr);
22350960Sbostic break;
22450960Sbostic case NEQ:
22550960Sbostic vl = (vl != vr);
22650960Sbostic break;
22750960Sbostic
22850960Sbostic case LEQ:
22950960Sbostic vl = (vl <= vr);
23050960Sbostic break;
23150960Sbostic case LSS:
23250960Sbostic vl = (vl < vr);
23350960Sbostic break;
23450960Sbostic case GTR:
23550960Sbostic vl = (vl > vr);
23650960Sbostic break;
23750960Sbostic case GEQ:
23850960Sbostic vl = (vl >= vr);
23950960Sbostic break;
24050960Sbostic }
24150960Sbostic }
24250960Sbostic return vl;
24338820Sbostic }
24450960Sbostic
24538820Sbostic /*
24638820Sbostic * shift : primary { shop primary }
24738820Sbostic */
24850960Sbostic static int
shift()24938820Sbostic shift()
25038820Sbostic {
25150960Sbostic register int vl, vr, c;
25250960Sbostic
25350960Sbostic vl = primary();
254*69109Sbostic while (((c = skipws()) == '<' || c == '>') && getch() == c) {
25550960Sbostic vr = primary();
25650960Sbostic
25750960Sbostic if (c == '<')
25850960Sbostic vl <<= vr;
25950960Sbostic else
26050960Sbostic vl >>= vr;
26150960Sbostic }
26250960Sbostic
26350960Sbostic if (c == '<' || c == '>')
26450960Sbostic ungetch();
26550960Sbostic ungetch();
26650960Sbostic return vl;
26738820Sbostic }
26850960Sbostic
26938820Sbostic /*
27038820Sbostic * primary : term { addop term }
27138820Sbostic */
27250960Sbostic static int
primary()27338820Sbostic primary()
27438820Sbostic {
27550960Sbostic register int c, vl, vr;
27650960Sbostic
27750960Sbostic vl = term();
27850960Sbostic while ((c = skipws()) == '+' || c == '-') {
27950960Sbostic vr = term();
280*69109Sbostic
28150960Sbostic if (c == '+')
28250960Sbostic vl += vr;
28350960Sbostic else
28450960Sbostic vl -= vr;
28550960Sbostic }
28650960Sbostic
28750960Sbostic ungetch();
28850960Sbostic return vl;
28938820Sbostic }
29050960Sbostic
29138820Sbostic /*
292*69109Sbostic * <term> := <exp> { <mulop> <exp> }
29338820Sbostic */
29450960Sbostic static int
term()29538820Sbostic term()
29638820Sbostic {
29750960Sbostic register int c, vl, vr;
29850960Sbostic
299*69109Sbostic vl = exp();
30050960Sbostic while ((c = skipws()) == '*' || c == '/' || c == '%') {
301*69109Sbostic vr = exp();
30250960Sbostic
30350960Sbostic switch (c) {
30450960Sbostic case '*':
30550960Sbostic vl *= vr;
30650960Sbostic break;
30750960Sbostic case '/':
30850960Sbostic vl /= vr;
30950960Sbostic break;
31050960Sbostic case '%':
31150960Sbostic vl %= vr;
31250960Sbostic break;
31350960Sbostic }
31450960Sbostic }
31550960Sbostic ungetch();
31650960Sbostic return vl;
31738820Sbostic }
31850960Sbostic
31938820Sbostic /*
320*69109Sbostic * <term> := <unary> { <expop> <unary> }
321*69109Sbostic */
322*69109Sbostic static int
exp()323*69109Sbostic exp()
324*69109Sbostic {
325*69109Sbostic register c, vl, vr, n;
326*69109Sbostic
327*69109Sbostic vl = unary();
328*69109Sbostic switch (c = skipws()) {
329*69109Sbostic
330*69109Sbostic case '*':
331*69109Sbostic if (getch() != '*') {
332*69109Sbostic ungetch();
333*69109Sbostic break;
334*69109Sbostic }
335*69109Sbostic
336*69109Sbostic case '^':
337*69109Sbostic vr = exp();
338*69109Sbostic n = 1;
339*69109Sbostic while (vr-- > 0)
340*69109Sbostic n *= vl;
341*69109Sbostic return n;
342*69109Sbostic }
343*69109Sbostic
344*69109Sbostic ungetch();
345*69109Sbostic return vl;
346*69109Sbostic }
347*69109Sbostic
348*69109Sbostic /*
34938820Sbostic * unary : factor | unop unary
35038820Sbostic */
35150960Sbostic static int
unary()35238820Sbostic unary()
35338820Sbostic {
35450960Sbostic register int val, c;
35550960Sbostic
356*69109Sbostic if ((c = skipws()) == '+' || c == '-' || c == '~') {
35750960Sbostic val = unary();
35850960Sbostic
35950960Sbostic switch (c) {
360*69109Sbostic case '+':
361*69109Sbostic return val;
362*69109Sbostic case '-':
363*69109Sbostic return -val;
36450960Sbostic case '~':
36550960Sbostic return ~val;
36650960Sbostic }
36750960Sbostic }
36850960Sbostic
36950960Sbostic ungetch();
37050960Sbostic return factor();
37138820Sbostic }
37250960Sbostic
37338820Sbostic /*
37438820Sbostic * factor : constant | '(' query ')'
37538820Sbostic */
37650960Sbostic static int
factor()37738820Sbostic factor()
37838820Sbostic {
37950960Sbostic register int val;
38050960Sbostic
38150960Sbostic if (skipws() == '(') {
38250960Sbostic val = query();
38350960Sbostic if (skipws() != ')')
38450960Sbostic experr("bad factor");
38550960Sbostic return val;
38650960Sbostic }
38750960Sbostic
38850960Sbostic ungetch();
38950960Sbostic return constant();
39038820Sbostic }
39150960Sbostic
39238820Sbostic /*
39338820Sbostic * constant: num | 'char'
39450960Sbostic * Note: constant() handles multi-byte constants
39538820Sbostic */
39650960Sbostic static int
constant()39738820Sbostic constant()
39838820Sbostic {
39950960Sbostic register int i;
40050960Sbostic register int value;
40150960Sbostic register char c;
40250960Sbostic int v[sizeof(int)];
40350960Sbostic
40450960Sbostic if (skipws() != '\'') {
40550960Sbostic ungetch();
40650960Sbostic return num();
40750960Sbostic }
40850960Sbostic for (i = 0; i < sizeof(int); i++) {
40950960Sbostic if ((c = getch()) == '\'') {
41050960Sbostic ungetch();
41150960Sbostic break;
41250960Sbostic }
41350960Sbostic if (c == '\\') {
41450960Sbostic switch (c = getch()) {
41550960Sbostic case '0':
41650960Sbostic case '1':
41750960Sbostic case '2':
41850960Sbostic case '3':
41950960Sbostic case '4':
42050960Sbostic case '5':
42150960Sbostic case '6':
42250960Sbostic case '7':
42350960Sbostic ungetch();
42450960Sbostic c = num();
42550960Sbostic break;
42650960Sbostic case 'n':
42750960Sbostic c = 012;
42850960Sbostic break;
42950960Sbostic case 'r':
43050960Sbostic c = 015;
43150960Sbostic break;
43250960Sbostic case 't':
43350960Sbostic c = 011;
43450960Sbostic break;
43550960Sbostic case 'b':
43650960Sbostic c = 010;
43750960Sbostic break;
43850960Sbostic case 'f':
43950960Sbostic c = 014;
44050960Sbostic break;
44150960Sbostic }
44250960Sbostic }
44350960Sbostic v[i] = c;
44450960Sbostic }
44550960Sbostic if (i == 0 || getch() != '\'')
44650960Sbostic experr("illegal character constant");
44750960Sbostic for (value = 0; --i >= 0;) {
44850960Sbostic value <<= 8;
44950960Sbostic value += v[i];
45050960Sbostic }
45150960Sbostic return value;
45238820Sbostic }
45350960Sbostic
45438820Sbostic /*
45538820Sbostic * num : digit | num digit
45638820Sbostic */
45750960Sbostic static int
num()45838820Sbostic num()
45938820Sbostic {
46050960Sbostic register int rval, c, base;
46150960Sbostic int ndig;
46250960Sbostic
46350960Sbostic base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
46450960Sbostic rval = 0;
46550960Sbostic ndig = 0;
46650960Sbostic while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
46750960Sbostic rval *= base;
46850960Sbostic rval += (c - '0');
46950960Sbostic c = getch();
47050960Sbostic ndig++;
47150960Sbostic }
47250960Sbostic ungetch();
47350960Sbostic
47450960Sbostic if (ndig == 0)
47550960Sbostic experr("bad constant");
47650960Sbostic
47750960Sbostic return rval;
47850960Sbostic
47938820Sbostic }
48050960Sbostic
48138820Sbostic /*
482*69109Sbostic * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
48338820Sbostic */
48450960Sbostic static int
geteqrel()485*69109Sbostic geteqrel()
48638820Sbostic {
48750960Sbostic register int c1, c2;
48850960Sbostic
48950960Sbostic c1 = skipws();
49050960Sbostic c2 = getch();
49150960Sbostic
49250960Sbostic switch (c1) {
49350960Sbostic
49450960Sbostic case '=':
49550960Sbostic if (c2 != '=')
49650960Sbostic ungetch();
49750960Sbostic return EQL;
49850960Sbostic
49950960Sbostic case '!':
50050960Sbostic if (c2 == '=')
50150960Sbostic return NEQ;
50250960Sbostic ungetch();
50350960Sbostic ungetch();
50450960Sbostic return -1;
50550960Sbostic
50650960Sbostic case '<':
50750960Sbostic if (c2 == '=')
50850960Sbostic return LEQ;
50950960Sbostic ungetch();
51050960Sbostic return LSS;
51150960Sbostic
51250960Sbostic case '>':
51350960Sbostic if (c2 == '=')
51450960Sbostic return GEQ;
51550960Sbostic ungetch();
51650960Sbostic return GTR;
51750960Sbostic
51850960Sbostic default:
51950960Sbostic ungetch();
52050960Sbostic ungetch();
52150960Sbostic return -1;
52250960Sbostic }
52338820Sbostic }
52450960Sbostic
52538820Sbostic /*
52638820Sbostic * Skip over any white space and return terminating char.
52738820Sbostic */
52850960Sbostic static int
skipws()52938820Sbostic skipws()
53038820Sbostic {
53150960Sbostic register char c;
53250960Sbostic
53350960Sbostic while ((c = getch()) <= ' ' && c > EOS)
53450960Sbostic ;
53550960Sbostic return c;
53638820Sbostic }
53750960Sbostic
53838820Sbostic /*
53950960Sbostic * resets environment to eval(), prints an error
54050960Sbostic * and forces eval to return FALSE.
54138820Sbostic */
54250960Sbostic static void
experr(msg)54338820Sbostic experr(msg)
54438820Sbostic char *msg;
54538820Sbostic {
54650960Sbostic printf("m4: %s in expr.\n", msg);
54750960Sbostic longjmp(expjump, -1);
54838820Sbostic }
549