xref: /csrg-svn/usr.bin/m4/expr.c (revision 69109)
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