xref: /freebsd/usr.bin/m4/expr.c (revision 9b50d9027575220cb6dd09b3e62f03f511e908b8)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
69b50d902SRodney W. Grimes  * Ozan Yigit at York University.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes  * are met:
119b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
169b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
179b50d902SRodney W. Grimes  *    must display the following acknowledgement:
189b50d902SRodney W. Grimes  *	This product includes software developed by the University of
199b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
209b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
219b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
229b50d902SRodney W. Grimes  *    without specific prior written permission.
239b50d902SRodney W. Grimes  *
249b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
259b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
269b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
279b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
289b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
299b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
309b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
319b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
329b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
339b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
349b50d902SRodney W. Grimes  * SUCH DAMAGE.
359b50d902SRodney W. Grimes  */
369b50d902SRodney W. Grimes 
379b50d902SRodney W. Grimes #ifndef lint
389b50d902SRodney W. Grimes static char sccsid[] = "@(#)expr.c	8.1 (Berkeley) 6/6/93";
399b50d902SRodney W. Grimes #endif /* not lint */
409b50d902SRodney W. Grimes 
419b50d902SRodney W. Grimes #include <sys/cdefs.h>
429b50d902SRodney W. Grimes #include <stdio.h>
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes /*
459b50d902SRodney W. Grimes  *      expression evaluator: performs a standard recursive
469b50d902SRodney W. Grimes  *      descent parse to evaluate any expression permissible
479b50d902SRodney W. Grimes  *      within the following grammar:
489b50d902SRodney W. Grimes  *
499b50d902SRodney W. Grimes  *      expr    :       query EOS
509b50d902SRodney W. Grimes  *      query   :       lor
519b50d902SRodney W. Grimes  *              |       lor "?" query ":" query
529b50d902SRodney W. Grimes  *      lor     :       land { "||" land }
539b50d902SRodney W. Grimes  *      land    :       bor { "&&" bor }
549b50d902SRodney W. Grimes  *      bor     :       bxor { "|" bxor }
559b50d902SRodney W. Grimes  *      bxor    :       band { "^" band }
569b50d902SRodney W. Grimes  *      band    :       eql { "&" eql }
579b50d902SRodney W. Grimes  *      eql     :       relat { eqrel relat }
589b50d902SRodney W. Grimes  *      relat   :       shift { rel shift }
599b50d902SRodney W. Grimes  *      shift   :       primary { shop primary }
609b50d902SRodney W. Grimes  *      primary :       term { addop term }
619b50d902SRodney W. Grimes  *      term    :       unary { mulop unary }
629b50d902SRodney W. Grimes  *      unary   :       factor
639b50d902SRodney W. Grimes  *              |       unop unary
649b50d902SRodney W. Grimes  *      factor  :       constant
659b50d902SRodney W. Grimes  *              |       "(" query ")"
669b50d902SRodney W. Grimes  *      constant:       num
679b50d902SRodney W. Grimes  *              |       "'" CHAR "'"
689b50d902SRodney W. Grimes  *      num     :       DIGIT
699b50d902SRodney W. Grimes  *              |       DIGIT num
709b50d902SRodney W. Grimes  *      shop    :       "<<"
719b50d902SRodney W. Grimes  *              |       ">>"
729b50d902SRodney W. Grimes  *      eqlrel  :       "="
739b50d902SRodney W. Grimes  *              |       "=="
749b50d902SRodney W. Grimes  *              |       "!="
759b50d902SRodney W. Grimes  *      rel     :       "<"
769b50d902SRodney W. Grimes  *              |       ">"
779b50d902SRodney W. Grimes  *              |       "<="
789b50d902SRodney W. Grimes  *              |       ">="
799b50d902SRodney W. Grimes  *
809b50d902SRodney W. Grimes  *
819b50d902SRodney W. Grimes  *      This expression evaluator is lifted from a public-domain
829b50d902SRodney W. Grimes  *      C Pre-Processor included with the DECUS C Compiler distribution.
839b50d902SRodney W. Grimes  *      It is hacked somewhat to be suitable for m4.
849b50d902SRodney W. Grimes  *
859b50d902SRodney W. Grimes  *      Originally by:  Mike Lutz
869b50d902SRodney W. Grimes  *                      Bob Harper
879b50d902SRodney W. Grimes  */
889b50d902SRodney W. Grimes 
899b50d902SRodney W. Grimes #define TRUE    1
909b50d902SRodney W. Grimes #define FALSE   0
919b50d902SRodney W. Grimes #define EOS     (char) 0
929b50d902SRodney W. Grimes #define EQL     0
939b50d902SRodney W. Grimes #define NEQ     1
949b50d902SRodney W. Grimes #define LSS     2
959b50d902SRodney W. Grimes #define LEQ     3
969b50d902SRodney W. Grimes #define GTR     4
979b50d902SRodney W. Grimes #define GEQ     5
989b50d902SRodney W. Grimes #define OCTAL   8
999b50d902SRodney W. Grimes #define DECIMAL 10
1009b50d902SRodney W. Grimes 
1019b50d902SRodney W. Grimes static char *nxtch;		       /* Parser scan pointer */
1029b50d902SRodney W. Grimes 
1039b50d902SRodney W. Grimes static int query __P((void));
1049b50d902SRodney W. Grimes static int lor __P((void));
1059b50d902SRodney W. Grimes static int land __P((void));
1069b50d902SRodney W. Grimes static int bor __P((void));
1079b50d902SRodney W. Grimes static int bxor __P((void));
1089b50d902SRodney W. Grimes static int band __P((void));
1099b50d902SRodney W. Grimes static int eql __P((void));
1109b50d902SRodney W. Grimes static int relat __P((void));
1119b50d902SRodney W. Grimes static int shift __P((void));
1129b50d902SRodney W. Grimes static int primary __P((void));
1139b50d902SRodney W. Grimes static int term __P((void));
1149b50d902SRodney W. Grimes static int unary __P((void));
1159b50d902SRodney W. Grimes static int factor __P((void));
1169b50d902SRodney W. Grimes static int constant __P((void));
1179b50d902SRodney W. Grimes static int num __P((void));
1189b50d902SRodney W. Grimes static int geteql __P((void));
1199b50d902SRodney W. Grimes static int getrel __P((void));
1209b50d902SRodney W. Grimes static int skipws __P((void));
1219b50d902SRodney W. Grimes static void experr __P((char *));
1229b50d902SRodney W. Grimes 
1239b50d902SRodney W. Grimes /*
1249b50d902SRodney W. Grimes  * For longjmp
1259b50d902SRodney W. Grimes  */
1269b50d902SRodney W. Grimes #include <setjmp.h>
1279b50d902SRodney W. Grimes static jmp_buf expjump;
1289b50d902SRodney W. Grimes 
1299b50d902SRodney W. Grimes /*
1309b50d902SRodney W. Grimes  * macros:
1319b50d902SRodney W. Grimes  *      ungetch - Put back the last character examined.
1329b50d902SRodney W. Grimes  *      getch   - return the next character from expr string.
1339b50d902SRodney W. Grimes  */
1349b50d902SRodney W. Grimes #define ungetch()       nxtch--
1359b50d902SRodney W. Grimes #define getch()         *nxtch++
1369b50d902SRodney W. Grimes 
1379b50d902SRodney W. Grimes int
1389b50d902SRodney W. Grimes expr(expbuf)
1399b50d902SRodney W. Grimes char *expbuf;
1409b50d902SRodney W. Grimes {
1419b50d902SRodney W. Grimes 	register int rval;
1429b50d902SRodney W. Grimes 
1439b50d902SRodney W. Grimes 	nxtch = expbuf;
1449b50d902SRodney W. Grimes 	if (setjmp(expjump) != 0)
1459b50d902SRodney W. Grimes 		return FALSE;
1469b50d902SRodney W. Grimes 
1479b50d902SRodney W. Grimes 	rval = query();
1489b50d902SRodney W. Grimes 	if (skipws() == EOS)
1499b50d902SRodney W. Grimes 		return rval;
1509b50d902SRodney W. Grimes 
1519b50d902SRodney W. Grimes 	printf("m4: ill-formed expression.\n");
1529b50d902SRodney W. Grimes 	return FALSE;
1539b50d902SRodney W. Grimes }
1549b50d902SRodney W. Grimes 
1559b50d902SRodney W. Grimes /*
1569b50d902SRodney W. Grimes  * query : lor | lor '?' query ':' query
1579b50d902SRodney W. Grimes  */
1589b50d902SRodney W. Grimes static int
1599b50d902SRodney W. Grimes query()
1609b50d902SRodney W. Grimes {
1619b50d902SRodney W. Grimes 	register int bool, true_val, false_val;
1629b50d902SRodney W. Grimes 
1639b50d902SRodney W. Grimes 	bool = lor();
1649b50d902SRodney W. Grimes 	if (skipws() != '?') {
1659b50d902SRodney W. Grimes 		ungetch();
1669b50d902SRodney W. Grimes 		return bool;
1679b50d902SRodney W. Grimes 	}
1689b50d902SRodney W. Grimes 
1699b50d902SRodney W. Grimes 	true_val = query();
1709b50d902SRodney W. Grimes 	if (skipws() != ':')
1719b50d902SRodney W. Grimes 		experr("bad query");
1729b50d902SRodney W. Grimes 
1739b50d902SRodney W. Grimes 	false_val = query();
1749b50d902SRodney W. Grimes 	return bool ? true_val : false_val;
1759b50d902SRodney W. Grimes }
1769b50d902SRodney W. Grimes 
1779b50d902SRodney W. Grimes /*
1789b50d902SRodney W. Grimes  * lor : land { '||' land }
1799b50d902SRodney W. Grimes  */
1809b50d902SRodney W. Grimes static int
1819b50d902SRodney W. Grimes lor()
1829b50d902SRodney W. Grimes {
1839b50d902SRodney W. Grimes 	register int c, vl, vr;
1849b50d902SRodney W. Grimes 
1859b50d902SRodney W. Grimes 	vl = land();
1869b50d902SRodney W. Grimes 	while ((c = skipws()) == '|' && getch() == '|') {
1879b50d902SRodney W. Grimes 		vr = land();
1889b50d902SRodney W. Grimes 		vl = vl || vr;
1899b50d902SRodney W. Grimes 	}
1909b50d902SRodney W. Grimes 
1919b50d902SRodney W. Grimes 	if (c == '|')
1929b50d902SRodney W. Grimes 		ungetch();
1939b50d902SRodney W. Grimes 	ungetch();
1949b50d902SRodney W. Grimes 	return vl;
1959b50d902SRodney W. Grimes }
1969b50d902SRodney W. Grimes 
1979b50d902SRodney W. Grimes /*
1989b50d902SRodney W. Grimes  * land : bor { '&&' bor }
1999b50d902SRodney W. Grimes  */
2009b50d902SRodney W. Grimes static int
2019b50d902SRodney W. Grimes land()
2029b50d902SRodney W. Grimes {
2039b50d902SRodney W. Grimes 	register int c, vl, vr;
2049b50d902SRodney W. Grimes 
2059b50d902SRodney W. Grimes 	vl = bor();
2069b50d902SRodney W. Grimes 	while ((c = skipws()) == '&' && getch() == '&') {
2079b50d902SRodney W. Grimes 		vr = bor();
2089b50d902SRodney W. Grimes 		vl = vl && vr;
2099b50d902SRodney W. Grimes 	}
2109b50d902SRodney W. Grimes 
2119b50d902SRodney W. Grimes 	if (c == '&')
2129b50d902SRodney W. Grimes 		ungetch();
2139b50d902SRodney W. Grimes 	ungetch();
2149b50d902SRodney W. Grimes 	return vl;
2159b50d902SRodney W. Grimes }
2169b50d902SRodney W. Grimes 
2179b50d902SRodney W. Grimes /*
2189b50d902SRodney W. Grimes  * bor : bxor { '|' bxor }
2199b50d902SRodney W. Grimes  */
2209b50d902SRodney W. Grimes static int
2219b50d902SRodney W. Grimes bor()
2229b50d902SRodney W. Grimes {
2239b50d902SRodney W. Grimes 	register int vl, vr, c;
2249b50d902SRodney W. Grimes 
2259b50d902SRodney W. Grimes 	vl = bxor();
2269b50d902SRodney W. Grimes 	while ((c = skipws()) == '|' && getch() != '|') {
2279b50d902SRodney W. Grimes 		ungetch();
2289b50d902SRodney W. Grimes 		vr = bxor();
2299b50d902SRodney W. Grimes 		vl |= vr;
2309b50d902SRodney W. Grimes 	}
2319b50d902SRodney W. Grimes 
2329b50d902SRodney W. Grimes 	if (c == '|')
2339b50d902SRodney W. Grimes 		ungetch();
2349b50d902SRodney W. Grimes 	ungetch();
2359b50d902SRodney W. Grimes 	return vl;
2369b50d902SRodney W. Grimes }
2379b50d902SRodney W. Grimes 
2389b50d902SRodney W. Grimes /*
2399b50d902SRodney W. Grimes  * bxor : band { '^' band }
2409b50d902SRodney W. Grimes  */
2419b50d902SRodney W. Grimes static int
2429b50d902SRodney W. Grimes bxor()
2439b50d902SRodney W. Grimes {
2449b50d902SRodney W. Grimes 	register int vl, vr;
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 	vl = band();
2479b50d902SRodney W. Grimes 	while (skipws() == '^') {
2489b50d902SRodney W. Grimes 		vr = band();
2499b50d902SRodney W. Grimes 		vl ^= vr;
2509b50d902SRodney W. Grimes 	}
2519b50d902SRodney W. Grimes 
2529b50d902SRodney W. Grimes 	ungetch();
2539b50d902SRodney W. Grimes 	return vl;
2549b50d902SRodney W. Grimes }
2559b50d902SRodney W. Grimes 
2569b50d902SRodney W. Grimes /*
2579b50d902SRodney W. Grimes  * band : eql { '&' eql }
2589b50d902SRodney W. Grimes  */
2599b50d902SRodney W. Grimes static int
2609b50d902SRodney W. Grimes band()
2619b50d902SRodney W. Grimes {
2629b50d902SRodney W. Grimes 	register int vl, vr, c;
2639b50d902SRodney W. Grimes 
2649b50d902SRodney W. Grimes 	vl = eql();
2659b50d902SRodney W. Grimes 	while ((c = skipws()) == '&' && getch() != '&') {
2669b50d902SRodney W. Grimes 		ungetch();
2679b50d902SRodney W. Grimes 		vr = eql();
2689b50d902SRodney W. Grimes 		vl &= vr;
2699b50d902SRodney W. Grimes 	}
2709b50d902SRodney W. Grimes 
2719b50d902SRodney W. Grimes 	if (c == '&')
2729b50d902SRodney W. Grimes 		ungetch();
2739b50d902SRodney W. Grimes 	ungetch();
2749b50d902SRodney W. Grimes 	return vl;
2759b50d902SRodney W. Grimes }
2769b50d902SRodney W. Grimes 
2779b50d902SRodney W. Grimes /*
2789b50d902SRodney W. Grimes  * eql : relat { eqrel relat }
2799b50d902SRodney W. Grimes  */
2809b50d902SRodney W. Grimes static int
2819b50d902SRodney W. Grimes eql()
2829b50d902SRodney W. Grimes {
2839b50d902SRodney W. Grimes 	register int vl, vr, rel;
2849b50d902SRodney W. Grimes 
2859b50d902SRodney W. Grimes 	vl = relat();
2869b50d902SRodney W. Grimes 	while ((rel = geteql()) != -1) {
2879b50d902SRodney W. Grimes 		vr = relat();
2889b50d902SRodney W. Grimes 
2899b50d902SRodney W. Grimes 		switch (rel) {
2909b50d902SRodney W. Grimes 
2919b50d902SRodney W. Grimes 		case EQL:
2929b50d902SRodney W. Grimes 			vl = (vl == vr);
2939b50d902SRodney W. Grimes 			break;
2949b50d902SRodney W. Grimes 		case NEQ:
2959b50d902SRodney W. Grimes 			vl = (vl != vr);
2969b50d902SRodney W. Grimes 			break;
2979b50d902SRodney W. Grimes 		}
2989b50d902SRodney W. Grimes 	}
2999b50d902SRodney W. Grimes 	return vl;
3009b50d902SRodney W. Grimes }
3019b50d902SRodney W. Grimes 
3029b50d902SRodney W. Grimes /*
3039b50d902SRodney W. Grimes  * relat : shift { rel shift }
3049b50d902SRodney W. Grimes  */
3059b50d902SRodney W. Grimes static int
3069b50d902SRodney W. Grimes relat()
3079b50d902SRodney W. Grimes {
3089b50d902SRodney W. Grimes 	register int vl, vr, rel;
3099b50d902SRodney W. Grimes 
3109b50d902SRodney W. Grimes 	vl = shift();
3119b50d902SRodney W. Grimes 	while ((rel = getrel()) != -1) {
3129b50d902SRodney W. Grimes 
3139b50d902SRodney W. Grimes 		vr = shift();
3149b50d902SRodney W. Grimes 		switch (rel) {
3159b50d902SRodney W. Grimes 
3169b50d902SRodney W. Grimes 		case LEQ:
3179b50d902SRodney W. Grimes 			vl = (vl <= vr);
3189b50d902SRodney W. Grimes 			break;
3199b50d902SRodney W. Grimes 		case LSS:
3209b50d902SRodney W. Grimes 			vl = (vl < vr);
3219b50d902SRodney W. Grimes 			break;
3229b50d902SRodney W. Grimes 		case GTR:
3239b50d902SRodney W. Grimes 			vl = (vl > vr);
3249b50d902SRodney W. Grimes 			break;
3259b50d902SRodney W. Grimes 		case GEQ:
3269b50d902SRodney W. Grimes 			vl = (vl >= vr);
3279b50d902SRodney W. Grimes 			break;
3289b50d902SRodney W. Grimes 		}
3299b50d902SRodney W. Grimes 	}
3309b50d902SRodney W. Grimes 	return vl;
3319b50d902SRodney W. Grimes }
3329b50d902SRodney W. Grimes 
3339b50d902SRodney W. Grimes /*
3349b50d902SRodney W. Grimes  * shift : primary { shop primary }
3359b50d902SRodney W. Grimes  */
3369b50d902SRodney W. Grimes static int
3379b50d902SRodney W. Grimes shift()
3389b50d902SRodney W. Grimes {
3399b50d902SRodney W. Grimes 	register int vl, vr, c;
3409b50d902SRodney W. Grimes 
3419b50d902SRodney W. Grimes 	vl = primary();
3429b50d902SRodney W. Grimes 	while (((c = skipws()) == '<' || c == '>') && c == getch()) {
3439b50d902SRodney W. Grimes 		vr = primary();
3449b50d902SRodney W. Grimes 
3459b50d902SRodney W. Grimes 		if (c == '<')
3469b50d902SRodney W. Grimes 			vl <<= vr;
3479b50d902SRodney W. Grimes 		else
3489b50d902SRodney W. Grimes 			vl >>= vr;
3499b50d902SRodney W. Grimes 	}
3509b50d902SRodney W. Grimes 
3519b50d902SRodney W. Grimes 	if (c == '<' || c == '>')
3529b50d902SRodney W. Grimes 		ungetch();
3539b50d902SRodney W. Grimes 	ungetch();
3549b50d902SRodney W. Grimes 	return vl;
3559b50d902SRodney W. Grimes }
3569b50d902SRodney W. Grimes 
3579b50d902SRodney W. Grimes /*
3589b50d902SRodney W. Grimes  * primary : term { addop term }
3599b50d902SRodney W. Grimes  */
3609b50d902SRodney W. Grimes static int
3619b50d902SRodney W. Grimes primary()
3629b50d902SRodney W. Grimes {
3639b50d902SRodney W. Grimes 	register int c, vl, vr;
3649b50d902SRodney W. Grimes 
3659b50d902SRodney W. Grimes 	vl = term();
3669b50d902SRodney W. Grimes 	while ((c = skipws()) == '+' || c == '-') {
3679b50d902SRodney W. Grimes 		vr = term();
3689b50d902SRodney W. Grimes 		if (c == '+')
3699b50d902SRodney W. Grimes 			vl += vr;
3709b50d902SRodney W. Grimes 		else
3719b50d902SRodney W. Grimes 			vl -= vr;
3729b50d902SRodney W. Grimes 	}
3739b50d902SRodney W. Grimes 
3749b50d902SRodney W. Grimes 	ungetch();
3759b50d902SRodney W. Grimes 	return vl;
3769b50d902SRodney W. Grimes }
3779b50d902SRodney W. Grimes 
3789b50d902SRodney W. Grimes /*
3799b50d902SRodney W. Grimes  * <term> := <unary> { <mulop> <unary> }
3809b50d902SRodney W. Grimes  */
3819b50d902SRodney W. Grimes static int
3829b50d902SRodney W. Grimes term()
3839b50d902SRodney W. Grimes {
3849b50d902SRodney W. Grimes 	register int c, vl, vr;
3859b50d902SRodney W. Grimes 
3869b50d902SRodney W. Grimes 	vl = unary();
3879b50d902SRodney W. Grimes 	while ((c = skipws()) == '*' || c == '/' || c == '%') {
3889b50d902SRodney W. Grimes 		vr = unary();
3899b50d902SRodney W. Grimes 
3909b50d902SRodney W. Grimes 		switch (c) {
3919b50d902SRodney W. Grimes 		case '*':
3929b50d902SRodney W. Grimes 			vl *= vr;
3939b50d902SRodney W. Grimes 			break;
3949b50d902SRodney W. Grimes 		case '/':
3959b50d902SRodney W. Grimes 			vl /= vr;
3969b50d902SRodney W. Grimes 			break;
3979b50d902SRodney W. Grimes 		case '%':
3989b50d902SRodney W. Grimes 			vl %= vr;
3999b50d902SRodney W. Grimes 			break;
4009b50d902SRodney W. Grimes 		}
4019b50d902SRodney W. Grimes 	}
4029b50d902SRodney W. Grimes 	ungetch();
4039b50d902SRodney W. Grimes 	return vl;
4049b50d902SRodney W. Grimes }
4059b50d902SRodney W. Grimes 
4069b50d902SRodney W. Grimes /*
4079b50d902SRodney W. Grimes  * unary : factor | unop unary
4089b50d902SRodney W. Grimes  */
4099b50d902SRodney W. Grimes static int
4109b50d902SRodney W. Grimes unary()
4119b50d902SRodney W. Grimes {
4129b50d902SRodney W. Grimes 	register int val, c;
4139b50d902SRodney W. Grimes 
4149b50d902SRodney W. Grimes 	if ((c = skipws()) == '!' || c == '~' || c == '-') {
4159b50d902SRodney W. Grimes 		val = unary();
4169b50d902SRodney W. Grimes 
4179b50d902SRodney W. Grimes 		switch (c) {
4189b50d902SRodney W. Grimes 		case '!':
4199b50d902SRodney W. Grimes 			return !val;
4209b50d902SRodney W. Grimes 		case '~':
4219b50d902SRodney W. Grimes 			return ~val;
4229b50d902SRodney W. Grimes 		case '-':
4239b50d902SRodney W. Grimes 			return -val;
4249b50d902SRodney W. Grimes 		}
4259b50d902SRodney W. Grimes 	}
4269b50d902SRodney W. Grimes 
4279b50d902SRodney W. Grimes 	ungetch();
4289b50d902SRodney W. Grimes 	return factor();
4299b50d902SRodney W. Grimes }
4309b50d902SRodney W. Grimes 
4319b50d902SRodney W. Grimes /*
4329b50d902SRodney W. Grimes  * factor : constant | '(' query ')'
4339b50d902SRodney W. Grimes  */
4349b50d902SRodney W. Grimes static int
4359b50d902SRodney W. Grimes factor()
4369b50d902SRodney W. Grimes {
4379b50d902SRodney W. Grimes 	register int val;
4389b50d902SRodney W. Grimes 
4399b50d902SRodney W. Grimes 	if (skipws() == '(') {
4409b50d902SRodney W. Grimes 		val = query();
4419b50d902SRodney W. Grimes 		if (skipws() != ')')
4429b50d902SRodney W. Grimes 			experr("bad factor");
4439b50d902SRodney W. Grimes 		return val;
4449b50d902SRodney W. Grimes 	}
4459b50d902SRodney W. Grimes 
4469b50d902SRodney W. Grimes 	ungetch();
4479b50d902SRodney W. Grimes 	return constant();
4489b50d902SRodney W. Grimes }
4499b50d902SRodney W. Grimes 
4509b50d902SRodney W. Grimes /*
4519b50d902SRodney W. Grimes  * constant: num | 'char'
4529b50d902SRodney W. Grimes  * Note: constant() handles multi-byte constants
4539b50d902SRodney W. Grimes  */
4549b50d902SRodney W. Grimes static int
4559b50d902SRodney W. Grimes constant()
4569b50d902SRodney W. Grimes {
4579b50d902SRodney W. Grimes 	register int i;
4589b50d902SRodney W. Grimes 	register int value;
4599b50d902SRodney W. Grimes 	register char c;
4609b50d902SRodney W. Grimes 	int v[sizeof(int)];
4619b50d902SRodney W. Grimes 
4629b50d902SRodney W. Grimes 	if (skipws() != '\'') {
4639b50d902SRodney W. Grimes 		ungetch();
4649b50d902SRodney W. Grimes 		return num();
4659b50d902SRodney W. Grimes 	}
4669b50d902SRodney W. Grimes 	for (i = 0; i < sizeof(int); i++) {
4679b50d902SRodney W. Grimes 		if ((c = getch()) == '\'') {
4689b50d902SRodney W. Grimes 			ungetch();
4699b50d902SRodney W. Grimes 			break;
4709b50d902SRodney W. Grimes 		}
4719b50d902SRodney W. Grimes 		if (c == '\\') {
4729b50d902SRodney W. Grimes 			switch (c = getch()) {
4739b50d902SRodney W. Grimes 			case '0':
4749b50d902SRodney W. Grimes 			case '1':
4759b50d902SRodney W. Grimes 			case '2':
4769b50d902SRodney W. Grimes 			case '3':
4779b50d902SRodney W. Grimes 			case '4':
4789b50d902SRodney W. Grimes 			case '5':
4799b50d902SRodney W. Grimes 			case '6':
4809b50d902SRodney W. Grimes 			case '7':
4819b50d902SRodney W. Grimes 				ungetch();
4829b50d902SRodney W. Grimes 				c = num();
4839b50d902SRodney W. Grimes 				break;
4849b50d902SRodney W. Grimes 			case 'n':
4859b50d902SRodney W. Grimes 				c = 012;
4869b50d902SRodney W. Grimes 				break;
4879b50d902SRodney W. Grimes 			case 'r':
4889b50d902SRodney W. Grimes 				c = 015;
4899b50d902SRodney W. Grimes 				break;
4909b50d902SRodney W. Grimes 			case 't':
4919b50d902SRodney W. Grimes 				c = 011;
4929b50d902SRodney W. Grimes 				break;
4939b50d902SRodney W. Grimes 			case 'b':
4949b50d902SRodney W. Grimes 				c = 010;
4959b50d902SRodney W. Grimes 				break;
4969b50d902SRodney W. Grimes 			case 'f':
4979b50d902SRodney W. Grimes 				c = 014;
4989b50d902SRodney W. Grimes 				break;
4999b50d902SRodney W. Grimes 			}
5009b50d902SRodney W. Grimes 		}
5019b50d902SRodney W. Grimes 		v[i] = c;
5029b50d902SRodney W. Grimes 	}
5039b50d902SRodney W. Grimes 	if (i == 0 || getch() != '\'')
5049b50d902SRodney W. Grimes 		experr("illegal character constant");
5059b50d902SRodney W. Grimes 	for (value = 0; --i >= 0;) {
5069b50d902SRodney W. Grimes 		value <<= 8;
5079b50d902SRodney W. Grimes 		value += v[i];
5089b50d902SRodney W. Grimes 	}
5099b50d902SRodney W. Grimes 	return value;
5109b50d902SRodney W. Grimes }
5119b50d902SRodney W. Grimes 
5129b50d902SRodney W. Grimes /*
5139b50d902SRodney W. Grimes  * num : digit | num digit
5149b50d902SRodney W. Grimes  */
5159b50d902SRodney W. Grimes static int
5169b50d902SRodney W. Grimes num()
5179b50d902SRodney W. Grimes {
5189b50d902SRodney W. Grimes 	register int rval, c, base;
5199b50d902SRodney W. Grimes 	int ndig;
5209b50d902SRodney W. Grimes 
5219b50d902SRodney W. Grimes 	base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
5229b50d902SRodney W. Grimes 	rval = 0;
5239b50d902SRodney W. Grimes 	ndig = 0;
5249b50d902SRodney W. Grimes 	while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
5259b50d902SRodney W. Grimes 		rval *= base;
5269b50d902SRodney W. Grimes 		rval += (c - '0');
5279b50d902SRodney W. Grimes 		c = getch();
5289b50d902SRodney W. Grimes 		ndig++;
5299b50d902SRodney W. Grimes 	}
5309b50d902SRodney W. Grimes 	ungetch();
5319b50d902SRodney W. Grimes 
5329b50d902SRodney W. Grimes 	if (ndig == 0)
5339b50d902SRodney W. Grimes 		experr("bad constant");
5349b50d902SRodney W. Grimes 
5359b50d902SRodney W. Grimes 	return rval;
5369b50d902SRodney W. Grimes 
5379b50d902SRodney W. Grimes }
5389b50d902SRodney W. Grimes 
5399b50d902SRodney W. Grimes /*
5409b50d902SRodney W. Grimes  * eqlrel : '=' | '==' | '!='
5419b50d902SRodney W. Grimes  */
5429b50d902SRodney W. Grimes static int
5439b50d902SRodney W. Grimes geteql()
5449b50d902SRodney W. Grimes {
5459b50d902SRodney W. Grimes 	register int c1, c2;
5469b50d902SRodney W. Grimes 
5479b50d902SRodney W. Grimes 	c1 = skipws();
5489b50d902SRodney W. Grimes 	c2 = getch();
5499b50d902SRodney W. Grimes 
5509b50d902SRodney W. Grimes 	switch (c1) {
5519b50d902SRodney W. Grimes 
5529b50d902SRodney W. Grimes 	case '=':
5539b50d902SRodney W. Grimes 		if (c2 != '=')
5549b50d902SRodney W. Grimes 			ungetch();
5559b50d902SRodney W. Grimes 		return EQL;
5569b50d902SRodney W. Grimes 
5579b50d902SRodney W. Grimes 	case '!':
5589b50d902SRodney W. Grimes 		if (c2 == '=')
5599b50d902SRodney W. Grimes 			return NEQ;
5609b50d902SRodney W. Grimes 		ungetch();
5619b50d902SRodney W. Grimes 		ungetch();
5629b50d902SRodney W. Grimes 		return -1;
5639b50d902SRodney W. Grimes 
5649b50d902SRodney W. Grimes 	default:
5659b50d902SRodney W. Grimes 		ungetch();
5669b50d902SRodney W. Grimes 		ungetch();
5679b50d902SRodney W. Grimes 		return -1;
5689b50d902SRodney W. Grimes 	}
5699b50d902SRodney W. Grimes }
5709b50d902SRodney W. Grimes 
5719b50d902SRodney W. Grimes /*
5729b50d902SRodney W. Grimes  * rel : '<' | '>' | '<=' | '>='
5739b50d902SRodney W. Grimes  */
5749b50d902SRodney W. Grimes static int
5759b50d902SRodney W. Grimes getrel()
5769b50d902SRodney W. Grimes {
5779b50d902SRodney W. Grimes 	register int c1, c2;
5789b50d902SRodney W. Grimes 
5799b50d902SRodney W. Grimes 	c1 = skipws();
5809b50d902SRodney W. Grimes 	c2 = getch();
5819b50d902SRodney W. Grimes 
5829b50d902SRodney W. Grimes 	switch (c1) {
5839b50d902SRodney W. Grimes 
5849b50d902SRodney W. Grimes 	case '<':
5859b50d902SRodney W. Grimes 		if (c2 == '=')
5869b50d902SRodney W. Grimes 			return LEQ;
5879b50d902SRodney W. Grimes 		ungetch();
5889b50d902SRodney W. Grimes 		return LSS;
5899b50d902SRodney W. Grimes 
5909b50d902SRodney W. Grimes 	case '>':
5919b50d902SRodney W. Grimes 		if (c2 == '=')
5929b50d902SRodney W. Grimes 			return GEQ;
5939b50d902SRodney W. Grimes 		ungetch();
5949b50d902SRodney W. Grimes 		return GTR;
5959b50d902SRodney W. Grimes 
5969b50d902SRodney W. Grimes 	default:
5979b50d902SRodney W. Grimes 		ungetch();
5989b50d902SRodney W. Grimes 		ungetch();
5999b50d902SRodney W. Grimes 		return -1;
6009b50d902SRodney W. Grimes 	}
6019b50d902SRodney W. Grimes }
6029b50d902SRodney W. Grimes 
6039b50d902SRodney W. Grimes /*
6049b50d902SRodney W. Grimes  * Skip over any white space and return terminating char.
6059b50d902SRodney W. Grimes  */
6069b50d902SRodney W. Grimes static int
6079b50d902SRodney W. Grimes skipws()
6089b50d902SRodney W. Grimes {
6099b50d902SRodney W. Grimes 	register char c;
6109b50d902SRodney W. Grimes 
6119b50d902SRodney W. Grimes 	while ((c = getch()) <= ' ' && c > EOS)
6129b50d902SRodney W. Grimes 		;
6139b50d902SRodney W. Grimes 	return c;
6149b50d902SRodney W. Grimes }
6159b50d902SRodney W. Grimes 
6169b50d902SRodney W. Grimes /*
6179b50d902SRodney W. Grimes  * resets environment to eval(), prints an error
6189b50d902SRodney W. Grimes  * and forces eval to return FALSE.
6199b50d902SRodney W. Grimes  */
6209b50d902SRodney W. Grimes static void
6219b50d902SRodney W. Grimes experr(msg)
6229b50d902SRodney W. Grimes char *msg;
6239b50d902SRodney W. Grimes {
6249b50d902SRodney W. Grimes 	printf("m4: %s in expr.\n", msg);
6259b50d902SRodney W. Grimes 	longjmp(expjump, -1);
6269b50d902SRodney W. Grimes }
627