expr.c revision 95060
195060Sjmallett/*	$OpenBSD: expr.c,v 1.12 2002/02/16 21:27:48 millert Exp $	*/
295060Sjmallett/*	$NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $	*/
395060Sjmallett
41590Srgrimes/*
51590Srgrimes * Copyright (c) 1989, 1993
61590Srgrimes *	The Regents of the University of California.  All rights reserved.
71590Srgrimes *
81590Srgrimes * This code is derived from software contributed to Berkeley by
91590Srgrimes * Ozan Yigit at York University.
101590Srgrimes *
111590Srgrimes * Redistribution and use in source and binary forms, with or without
121590Srgrimes * modification, are permitted provided that the following conditions
131590Srgrimes * are met:
141590Srgrimes * 1. Redistributions of source code must retain the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer.
161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171590Srgrimes *    notice, this list of conditions and the following disclaimer in the
181590Srgrimes *    documentation and/or other materials provided with the distribution.
191590Srgrimes * 3. All advertising materials mentioning features or use of this software
201590Srgrimes *    must display the following acknowledgement:
211590Srgrimes *	This product includes software developed by the University of
221590Srgrimes *	California, Berkeley and its contributors.
231590Srgrimes * 4. Neither the name of the University nor the names of its contributors
241590Srgrimes *    may be used to endorse or promote products derived from this software
251590Srgrimes *    without specific prior written permission.
261590Srgrimes *
271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
281590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
291590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
301590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
311590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
321590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
331590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
341590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
351590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
361590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
371590Srgrimes * SUCH DAMAGE.
381590Srgrimes */
391590Srgrimes
4095060Sjmallett#include <sys/cdefs.h>
4195060Sjmallett__SCCSID("@(#)expr.c      8.2 (Berkeley) 4/29/95");
4295060Sjmallett__RCSID_SOURCE("$OpenBSD: expr.c,v 1.12 2002/02/16 21:27:48 millert Exp $");
4395060Sjmallett__FBSDID("$FreeBSD: head/usr.bin/m4/expr.c 95060 2002-04-19 17:26:21Z jmallett $");
441590Srgrimes
4595060Sjmallett#include <sys/types.h>
4695060Sjmallett#include <ctype.h>
4795060Sjmallett#include <err.h>
4895060Sjmallett#include <stddef.h>
491590Srgrimes#include <stdio.h>
5095060Sjmallett#include "mdef.h"
5195060Sjmallett#include "extern.h"
521590Srgrimes
531590Srgrimes/*
541590Srgrimes *      expression evaluator: performs a standard recursive
551590Srgrimes *      descent parse to evaluate any expression permissible
561590Srgrimes *      within the following grammar:
571590Srgrimes *
581590Srgrimes *      expr    :       query EOS
591590Srgrimes *      query   :       lor
601590Srgrimes *              |       lor "?" query ":" query
611590Srgrimes *      lor     :       land { "||" land }
627896Sache *      land    :       not { "&&" not }
637896Sache *	not	:	eqrel
647896Sache *		|	'!' not
657896Sache *      eqrel   :       shift { eqrelop shift }
661590Srgrimes *      shift   :       primary { shop primary }
671590Srgrimes *      primary :       term { addop term }
687896Sache *      term    :       exp { mulop exp }
697896Sache *	exp	:	unary { expop unary }
701590Srgrimes *      unary   :       factor
711590Srgrimes *              |       unop unary
721590Srgrimes *      factor  :       constant
731590Srgrimes *              |       "(" query ")"
741590Srgrimes *      constant:       num
751590Srgrimes *              |       "'" CHAR "'"
761590Srgrimes *      num     :       DIGIT
771590Srgrimes *              |       DIGIT num
781590Srgrimes *      shop    :       "<<"
791590Srgrimes *              |       ">>"
807896Sache *      eqrel   :       "="
811590Srgrimes *              |       "=="
821590Srgrimes *              |       "!="
837896Sache *      	|       "<"
841590Srgrimes *              |       ">"
851590Srgrimes *              |       "<="
861590Srgrimes *              |       ">="
871590Srgrimes *
881590Srgrimes *
891590Srgrimes *      This expression evaluator is lifted from a public-domain
901590Srgrimes *      C Pre-Processor included with the DECUS C Compiler distribution.
911590Srgrimes *      It is hacked somewhat to be suitable for m4.
921590Srgrimes *
931590Srgrimes *      Originally by:  Mike Lutz
941590Srgrimes *                      Bob Harper
951590Srgrimes */
961590Srgrimes
971590Srgrimes#define EQL     0
981590Srgrimes#define NEQ     1
991590Srgrimes#define LSS     2
1001590Srgrimes#define LEQ     3
1011590Srgrimes#define GTR     4
1021590Srgrimes#define GEQ     5
1031590Srgrimes#define OCTAL   8
1041590Srgrimes#define DECIMAL 10
10595060Sjmallett#define HEX	16
1061590Srgrimes
10795060Sjmallettstatic const char *nxtch;		       /* Parser scan pointer */
10895060Sjmallettstatic const char *where;
1091590Srgrimes
11092921Simpstatic int query(void);
11192921Simpstatic int lor(void);
11292921Simpstatic int land(void);
11392921Simpstatic int not(void);
11492921Simpstatic int eqrel(void);
11592921Simpstatic int shift(void);
11692921Simpstatic int primary(void);
11792921Simpstatic int term(void);
11892921Simpstatic int exp(void);
11992921Simpstatic int unary(void);
12092921Simpstatic int factor(void);
12192921Simpstatic int constant(void);
12292921Simpstatic int num(void);
12392921Simpstatic int geteqrel(void);
12492921Simpstatic int skipws(void);
12595060Sjmallettstatic void experr(const char *);
1261590Srgrimes
1271590Srgrimes/*
1281590Srgrimes * For longjmp
1291590Srgrimes */
1301590Srgrimes#include <setjmp.h>
1311590Srgrimesstatic jmp_buf expjump;
1321590Srgrimes
1331590Srgrimes/*
1341590Srgrimes * macros:
1351590Srgrimes *      ungetch - Put back the last character examined.
1361590Srgrimes *      getch   - return the next character from expr string.
1371590Srgrimes */
1381590Srgrimes#define ungetch()       nxtch--
1391590Srgrimes#define getch()         *nxtch++
1401590Srgrimes
1411590Srgrimesint
1421590Srgrimesexpr(expbuf)
14395060Sjmallett	const char *expbuf;
1441590Srgrimes{
14595060Sjmallett	int rval;
1461590Srgrimes
1471590Srgrimes	nxtch = expbuf;
14895060Sjmallett	where = expbuf;
1491590Srgrimes	if (setjmp(expjump) != 0)
1501590Srgrimes		return FALSE;
1511590Srgrimes
1521590Srgrimes	rval = query();
1531590Srgrimes	if (skipws() == EOS)
1541590Srgrimes		return rval;
1551590Srgrimes
1561590Srgrimes	printf("m4: ill-formed expression.\n");
1571590Srgrimes	return FALSE;
1581590Srgrimes}
1591590Srgrimes
1601590Srgrimes/*
1611590Srgrimes * query : lor | lor '?' query ':' query
1621590Srgrimes */
1631590Srgrimesstatic int
1641590Srgrimesquery()
1651590Srgrimes{
16695060Sjmallett	int bool, true_val, false_val;
1671590Srgrimes
1681590Srgrimes	bool = lor();
1691590Srgrimes	if (skipws() != '?') {
1701590Srgrimes		ungetch();
1711590Srgrimes		return bool;
1721590Srgrimes	}
1731590Srgrimes
1741590Srgrimes	true_val = query();
1751590Srgrimes	if (skipws() != ':')
1761590Srgrimes		experr("bad query");
1771590Srgrimes
1781590Srgrimes	false_val = query();
1791590Srgrimes	return bool ? true_val : false_val;
1801590Srgrimes}
1811590Srgrimes
1821590Srgrimes/*
1831590Srgrimes * lor : land { '||' land }
1841590Srgrimes */
1851590Srgrimesstatic int
1861590Srgrimeslor()
1871590Srgrimes{
18895060Sjmallett	int c, vl, vr;
1891590Srgrimes
1901590Srgrimes	vl = land();
1917896Sache	while ((c = skipws()) == '|') {
1927896Sache		if (getch() != '|')
1937896Sache			ungetch();
1941590Srgrimes		vr = land();
1951590Srgrimes		vl = vl || vr;
1961590Srgrimes	}
1971590Srgrimes
1981590Srgrimes	ungetch();
1991590Srgrimes	return vl;
2001590Srgrimes}
2011590Srgrimes
2021590Srgrimes/*
2037896Sache * land : not { '&&' not }
2041590Srgrimes */
2051590Srgrimesstatic int
2061590Srgrimesland()
2071590Srgrimes{
20895060Sjmallett	int c, vl, vr;
2091590Srgrimes
2107896Sache	vl = not();
2117896Sache	while ((c = skipws()) == '&') {
2127896Sache		if (getch() != '&')
2137896Sache			ungetch();
2147896Sache		vr = not();
2151590Srgrimes		vl = vl && vr;
2161590Srgrimes	}
2171590Srgrimes
2181590Srgrimes	ungetch();
2191590Srgrimes	return vl;
2201590Srgrimes}
2211590Srgrimes
2221590Srgrimes/*
2237896Sache * not : eqrel | '!' not
2241590Srgrimes */
2251590Srgrimesstatic int
2267896Sachenot()
2271590Srgrimes{
22895060Sjmallett	int val, c;
2291590Srgrimes
2307896Sache	if ((c = skipws()) == '!' && getch() != '=') {
2311590Srgrimes		ungetch();
2327896Sache		val = not();
2337896Sache		return !val;
2341590Srgrimes	}
2351590Srgrimes
2367896Sache	if (c == '!')
2371590Srgrimes		ungetch();
2381590Srgrimes	ungetch();
2397896Sache	return eqrel();
2401590Srgrimes}
2411590Srgrimes
2421590Srgrimes/*
2437896Sache * eqrel : shift { eqrelop shift }
2441590Srgrimes */
2451590Srgrimesstatic int
2467896Sacheeqrel()
2471590Srgrimes{
24895060Sjmallett	int vl, vr, eqrel;
2491590Srgrimes
2507896Sache	vl = shift();
2517896Sache	while ((eqrel = geteqrel()) != -1) {
2527896Sache		vr = shift();
2531590Srgrimes
2547896Sache		switch (eqrel) {
2551590Srgrimes
2561590Srgrimes		case EQL:
2571590Srgrimes			vl = (vl == vr);
2581590Srgrimes			break;
2591590Srgrimes		case NEQ:
2601590Srgrimes			vl = (vl != vr);
2611590Srgrimes			break;
2621590Srgrimes
2631590Srgrimes		case LEQ:
2641590Srgrimes			vl = (vl <= vr);
2651590Srgrimes			break;
2661590Srgrimes		case LSS:
2671590Srgrimes			vl = (vl < vr);
2681590Srgrimes			break;
2691590Srgrimes		case GTR:
2701590Srgrimes			vl = (vl > vr);
2711590Srgrimes			break;
2721590Srgrimes		case GEQ:
2731590Srgrimes			vl = (vl >= vr);
2741590Srgrimes			break;
2751590Srgrimes		}
2761590Srgrimes	}
2771590Srgrimes	return vl;
2781590Srgrimes}
2791590Srgrimes
2801590Srgrimes/*
2811590Srgrimes * shift : primary { shop primary }
2821590Srgrimes */
2831590Srgrimesstatic int
2841590Srgrimesshift()
2851590Srgrimes{
28695060Sjmallett	int vl, vr, c;
2871590Srgrimes
2881590Srgrimes	vl = primary();
2897896Sache	while (((c = skipws()) == '<' || c == '>') && getch() == c) {
2901590Srgrimes		vr = primary();
2911590Srgrimes
2921590Srgrimes		if (c == '<')
2931590Srgrimes			vl <<= vr;
2941590Srgrimes		else
2951590Srgrimes			vl >>= vr;
2961590Srgrimes	}
2971590Srgrimes
2981590Srgrimes	if (c == '<' || c == '>')
2991590Srgrimes		ungetch();
3001590Srgrimes	ungetch();
3011590Srgrimes	return vl;
3021590Srgrimes}
3031590Srgrimes
3041590Srgrimes/*
3051590Srgrimes * primary : term { addop term }
3061590Srgrimes */
3071590Srgrimesstatic int
3081590Srgrimesprimary()
3091590Srgrimes{
31095060Sjmallett	int c, vl, vr;
3111590Srgrimes
3121590Srgrimes	vl = term();
3131590Srgrimes	while ((c = skipws()) == '+' || c == '-') {
3141590Srgrimes		vr = term();
3157896Sache
3161590Srgrimes		if (c == '+')
3171590Srgrimes			vl += vr;
3181590Srgrimes		else
3191590Srgrimes			vl -= vr;
3201590Srgrimes	}
3211590Srgrimes
3221590Srgrimes	ungetch();
3231590Srgrimes	return vl;
3241590Srgrimes}
3251590Srgrimes
3261590Srgrimes/*
3277896Sache * <term> := <exp> { <mulop> <exp> }
3281590Srgrimes */
3291590Srgrimesstatic int
3301590Srgrimesterm()
3311590Srgrimes{
33295060Sjmallett	int c, vl, vr;
3331590Srgrimes
3347896Sache	vl = exp();
3351590Srgrimes	while ((c = skipws()) == '*' || c == '/' || c == '%') {
3367896Sache		vr = exp();
3371590Srgrimes
3381590Srgrimes		switch (c) {
3391590Srgrimes		case '*':
3401590Srgrimes			vl *= vr;
3411590Srgrimes			break;
3421590Srgrimes		case '/':
34395060Sjmallett			if (vr == 0)
34495060Sjmallett				errx(1, "division by zero in eval.");
34595060Sjmallett			else
34695060Sjmallett				vl /= vr;
3471590Srgrimes			break;
3481590Srgrimes		case '%':
34995060Sjmallett			if (vr == 0)
35095060Sjmallett				errx(1, "modulo zero in eval.");
35195060Sjmallett			else
35295060Sjmallett				vl %= vr;
3531590Srgrimes			break;
3541590Srgrimes		}
3551590Srgrimes	}
3561590Srgrimes	ungetch();
3571590Srgrimes	return vl;
3581590Srgrimes}
3591590Srgrimes
3601590Srgrimes/*
3617896Sache * <term> := <unary> { <expop> <unary> }
3627896Sache */
3637896Sachestatic int
3647896Sacheexp()
3657896Sache{
36695060Sjmallett	int c, vl, vr, n;
3677896Sache
3687896Sache	vl = unary();
3697896Sache	switch (c = skipws()) {
3707896Sache
3717896Sache	case '*':
3727896Sache		if (getch() != '*') {
3737896Sache			ungetch();
3747896Sache			break;
3757896Sache		}
3767896Sache
3777896Sache	case '^':
3787896Sache		vr = exp();
3797896Sache		n = 1;
3807896Sache		while (vr-- > 0)
3817896Sache			n *= vl;
3827896Sache		return n;
3837896Sache	}
3847896Sache
3857896Sache	ungetch();
3867896Sache	return vl;
3877896Sache}
3887896Sache
3897896Sache/*
3901590Srgrimes * unary : factor | unop unary
3911590Srgrimes */
3921590Srgrimesstatic int
3931590Srgrimesunary()
3941590Srgrimes{
39595060Sjmallett	int val, c;
3961590Srgrimes
3977896Sache	if ((c = skipws()) == '+' || c == '-' || c == '~') {
3981590Srgrimes		val = unary();
3991590Srgrimes
4001590Srgrimes		switch (c) {
4017896Sache		case '+':
4027896Sache			return val;
4037896Sache		case '-':
4047896Sache			return -val;
4051590Srgrimes		case '~':
4061590Srgrimes			return ~val;
4071590Srgrimes		}
4081590Srgrimes	}
4091590Srgrimes
4101590Srgrimes	ungetch();
4111590Srgrimes	return factor();
4121590Srgrimes}
4131590Srgrimes
4141590Srgrimes/*
4151590Srgrimes * factor : constant | '(' query ')'
4161590Srgrimes */
4171590Srgrimesstatic int
4181590Srgrimesfactor()
4191590Srgrimes{
42095060Sjmallett	int val;
4211590Srgrimes
4221590Srgrimes	if (skipws() == '(') {
4231590Srgrimes		val = query();
4241590Srgrimes		if (skipws() != ')')
4251590Srgrimes			experr("bad factor");
4261590Srgrimes		return val;
4271590Srgrimes	}
4281590Srgrimes
4291590Srgrimes	ungetch();
4301590Srgrimes	return constant();
4311590Srgrimes}
4321590Srgrimes
4331590Srgrimes/*
4341590Srgrimes * constant: num | 'char'
4351590Srgrimes * Note: constant() handles multi-byte constants
4361590Srgrimes */
4371590Srgrimesstatic int
4381590Srgrimesconstant()
4391590Srgrimes{
44095060Sjmallett	int i;
44195060Sjmallett	int value;
44295060Sjmallett	int c;
4431590Srgrimes	int v[sizeof(int)];
4441590Srgrimes
4451590Srgrimes	if (skipws() != '\'') {
4461590Srgrimes		ungetch();
4471590Srgrimes		return num();
4481590Srgrimes	}
4491590Srgrimes	for (i = 0; i < sizeof(int); i++) {
4501590Srgrimes		if ((c = getch()) == '\'') {
4511590Srgrimes			ungetch();
4521590Srgrimes			break;
4531590Srgrimes		}
4541590Srgrimes		if (c == '\\') {
4551590Srgrimes			switch (c = getch()) {
4561590Srgrimes			case '0':
4571590Srgrimes			case '1':
4581590Srgrimes			case '2':
4591590Srgrimes			case '3':
4601590Srgrimes			case '4':
4611590Srgrimes			case '5':
4621590Srgrimes			case '6':
4631590Srgrimes			case '7':
4641590Srgrimes				ungetch();
4651590Srgrimes				c = num();
4661590Srgrimes				break;
4671590Srgrimes			case 'n':
4681590Srgrimes				c = 012;
4691590Srgrimes				break;
4701590Srgrimes			case 'r':
4711590Srgrimes				c = 015;
4721590Srgrimes				break;
4731590Srgrimes			case 't':
4741590Srgrimes				c = 011;
4751590Srgrimes				break;
4761590Srgrimes			case 'b':
4771590Srgrimes				c = 010;
4781590Srgrimes				break;
4791590Srgrimes			case 'f':
4801590Srgrimes				c = 014;
4811590Srgrimes				break;
4821590Srgrimes			}
4831590Srgrimes		}
4841590Srgrimes		v[i] = c;
4851590Srgrimes	}
4861590Srgrimes	if (i == 0 || getch() != '\'')
4871590Srgrimes		experr("illegal character constant");
4881590Srgrimes	for (value = 0; --i >= 0;) {
4891590Srgrimes		value <<= 8;
4901590Srgrimes		value += v[i];
4911590Srgrimes	}
4921590Srgrimes	return value;
4931590Srgrimes}
4941590Srgrimes
4951590Srgrimes/*
4961590Srgrimes * num : digit | num digit
4971590Srgrimes */
4981590Srgrimesstatic int
4991590Srgrimesnum()
5001590Srgrimes{
50195060Sjmallett	int rval, c, base;
5021590Srgrimes	int ndig;
5031590Srgrimes
5041590Srgrimes	rval = 0;
5051590Srgrimes	ndig = 0;
50695060Sjmallett	c = skipws();
50795060Sjmallett	if (c == '0') {
50895060Sjmallett		c = skipws();
50995060Sjmallett		if (c == 'x' || c == 'X') {
51095060Sjmallett			base = HEX;
51195060Sjmallett			c = skipws();
51295060Sjmallett		} else {
51395060Sjmallett			base = OCTAL;
51495060Sjmallett			ndig++;
51595060Sjmallett		}
51695060Sjmallett	} else
51795060Sjmallett		base = DECIMAL;
51895060Sjmallett	for(;;) {
51995060Sjmallett		switch(c) {
52095060Sjmallett			case '8': case '9':
52195060Sjmallett				if (base == OCTAL)
52295060Sjmallett					goto bad_digit;
52395060Sjmallett				/*FALLTHRU*/
52495060Sjmallett			case '0': case '1': case '2': case '3':
52595060Sjmallett			case '4': case '5': case '6': case '7':
52695060Sjmallett				rval *= base;
52795060Sjmallett				rval += c - '0';
52895060Sjmallett				break;
52995060Sjmallett			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
53095060Sjmallett				c = tolower(c);
53195060Sjmallett			case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
53295060Sjmallett				if (base == HEX) {
53395060Sjmallett					rval *= base;
53495060Sjmallett					rval += c - 'a' + 10;
53595060Sjmallett					break;
53695060Sjmallett				}
53795060Sjmallett				/*FALLTHRU*/
53895060Sjmallett			default:
53995060Sjmallett				goto bad_digit;
54095060Sjmallett		}
5411590Srgrimes		c = getch();
5421590Srgrimes		ndig++;
5431590Srgrimes	}
54495060Sjmallettbad_digit:
5451590Srgrimes	ungetch();
54695060Sjmallett
5471590Srgrimes	if (ndig == 0)
5481590Srgrimes		experr("bad constant");
54995060Sjmallett
5501590Srgrimes	return rval;
5511590Srgrimes}
5521590Srgrimes
5531590Srgrimes/*
5547896Sache * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
5551590Srgrimes */
5561590Srgrimesstatic int
5577896Sachegeteqrel()
5581590Srgrimes{
55995060Sjmallett	int c1, c2;
5601590Srgrimes
5611590Srgrimes	c1 = skipws();
5621590Srgrimes	c2 = getch();
5631590Srgrimes
5641590Srgrimes	switch (c1) {
5651590Srgrimes
5661590Srgrimes	case '=':
5671590Srgrimes		if (c2 != '=')
5681590Srgrimes			ungetch();
5691590Srgrimes		return EQL;
5701590Srgrimes
5711590Srgrimes	case '!':
5721590Srgrimes		if (c2 == '=')
5731590Srgrimes			return NEQ;
5741590Srgrimes		ungetch();
5751590Srgrimes		ungetch();
5761590Srgrimes		return -1;
5771590Srgrimes
5781590Srgrimes	case '<':
5791590Srgrimes		if (c2 == '=')
5801590Srgrimes			return LEQ;
5811590Srgrimes		ungetch();
5821590Srgrimes		return LSS;
5831590Srgrimes
5841590Srgrimes	case '>':
5851590Srgrimes		if (c2 == '=')
5861590Srgrimes			return GEQ;
5871590Srgrimes		ungetch();
5881590Srgrimes		return GTR;
5891590Srgrimes
5901590Srgrimes	default:
5911590Srgrimes		ungetch();
5921590Srgrimes		ungetch();
5931590Srgrimes		return -1;
5941590Srgrimes	}
5951590Srgrimes}
5961590Srgrimes
5971590Srgrimes/*
5981590Srgrimes * Skip over any white space and return terminating char.
5991590Srgrimes */
6001590Srgrimesstatic int
6011590Srgrimesskipws()
6021590Srgrimes{
60395060Sjmallett	int c;
6041590Srgrimes
6051590Srgrimes	while ((c = getch()) <= ' ' && c > EOS)
6061590Srgrimes		;
6071590Srgrimes	return c;
6081590Srgrimes}
6091590Srgrimes
6101590Srgrimes/*
61195060Sjmallett * resets environment to eval(), prints an error
6121590Srgrimes * and forces eval to return FALSE.
6131590Srgrimes */
6141590Srgrimesstatic void
6151590Srgrimesexperr(msg)
61695060Sjmallett	const char *msg;
6171590Srgrimes{
61895060Sjmallett	printf("m4: %s in expr %s.\n", msg, where);
6191590Srgrimes	longjmp(expjump, -1);
6201590Srgrimes}
621