expr.c revision 1590
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Ozan Yigit at York University.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 3. All advertising materials mentioning features or use of this software
171590Srgrimes *    must display the following acknowledgement:
181590Srgrimes *	This product includes software developed by the University of
191590Srgrimes *	California, Berkeley and its contributors.
201590Srgrimes * 4. Neither the name of the University nor the names of its contributors
211590Srgrimes *    may be used to endorse or promote products derived from this software
221590Srgrimes *    without specific prior written permission.
231590Srgrimes *
241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341590Srgrimes * SUCH DAMAGE.
351590Srgrimes */
361590Srgrimes
371590Srgrimes#ifndef lint
381590Srgrimesstatic char sccsid[] = "@(#)expr.c	8.1 (Berkeley) 6/6/93";
391590Srgrimes#endif /* not lint */
401590Srgrimes
411590Srgrimes#include <sys/cdefs.h>
421590Srgrimes#include <stdio.h>
431590Srgrimes
441590Srgrimes/*
451590Srgrimes *      expression evaluator: performs a standard recursive
461590Srgrimes *      descent parse to evaluate any expression permissible
471590Srgrimes *      within the following grammar:
481590Srgrimes *
491590Srgrimes *      expr    :       query EOS
501590Srgrimes *      query   :       lor
511590Srgrimes *              |       lor "?" query ":" query
521590Srgrimes *      lor     :       land { "||" land }
531590Srgrimes *      land    :       bor { "&&" bor }
541590Srgrimes *      bor     :       bxor { "|" bxor }
551590Srgrimes *      bxor    :       band { "^" band }
561590Srgrimes *      band    :       eql { "&" eql }
571590Srgrimes *      eql     :       relat { eqrel relat }
581590Srgrimes *      relat   :       shift { rel shift }
591590Srgrimes *      shift   :       primary { shop primary }
601590Srgrimes *      primary :       term { addop term }
611590Srgrimes *      term    :       unary { mulop unary }
621590Srgrimes *      unary   :       factor
631590Srgrimes *              |       unop unary
641590Srgrimes *      factor  :       constant
651590Srgrimes *              |       "(" query ")"
661590Srgrimes *      constant:       num
671590Srgrimes *              |       "'" CHAR "'"
681590Srgrimes *      num     :       DIGIT
691590Srgrimes *              |       DIGIT num
701590Srgrimes *      shop    :       "<<"
711590Srgrimes *              |       ">>"
721590Srgrimes *      eqlrel  :       "="
731590Srgrimes *              |       "=="
741590Srgrimes *              |       "!="
751590Srgrimes *      rel     :       "<"
761590Srgrimes *              |       ">"
771590Srgrimes *              |       "<="
781590Srgrimes *              |       ">="
791590Srgrimes *
801590Srgrimes *
811590Srgrimes *      This expression evaluator is lifted from a public-domain
821590Srgrimes *      C Pre-Processor included with the DECUS C Compiler distribution.
831590Srgrimes *      It is hacked somewhat to be suitable for m4.
841590Srgrimes *
851590Srgrimes *      Originally by:  Mike Lutz
861590Srgrimes *                      Bob Harper
871590Srgrimes */
881590Srgrimes
891590Srgrimes#define TRUE    1
901590Srgrimes#define FALSE   0
911590Srgrimes#define EOS     (char) 0
921590Srgrimes#define EQL     0
931590Srgrimes#define NEQ     1
941590Srgrimes#define LSS     2
951590Srgrimes#define LEQ     3
961590Srgrimes#define GTR     4
971590Srgrimes#define GEQ     5
981590Srgrimes#define OCTAL   8
991590Srgrimes#define DECIMAL 10
1001590Srgrimes
1011590Srgrimesstatic char *nxtch;		       /* Parser scan pointer */
1021590Srgrimes
1031590Srgrimesstatic int query __P((void));
1041590Srgrimesstatic int lor __P((void));
1051590Srgrimesstatic int land __P((void));
1061590Srgrimesstatic int bor __P((void));
1071590Srgrimesstatic int bxor __P((void));
1081590Srgrimesstatic int band __P((void));
1091590Srgrimesstatic int eql __P((void));
1101590Srgrimesstatic int relat __P((void));
1111590Srgrimesstatic int shift __P((void));
1121590Srgrimesstatic int primary __P((void));
1131590Srgrimesstatic int term __P((void));
1141590Srgrimesstatic int unary __P((void));
1151590Srgrimesstatic int factor __P((void));
1161590Srgrimesstatic int constant __P((void));
1171590Srgrimesstatic int num __P((void));
1181590Srgrimesstatic int geteql __P((void));
1191590Srgrimesstatic int getrel __P((void));
1201590Srgrimesstatic int skipws __P((void));
1211590Srgrimesstatic void experr __P((char *));
1221590Srgrimes
1231590Srgrimes/*
1241590Srgrimes * For longjmp
1251590Srgrimes */
1261590Srgrimes#include <setjmp.h>
1271590Srgrimesstatic jmp_buf expjump;
1281590Srgrimes
1291590Srgrimes/*
1301590Srgrimes * macros:
1311590Srgrimes *      ungetch - Put back the last character examined.
1321590Srgrimes *      getch   - return the next character from expr string.
1331590Srgrimes */
1341590Srgrimes#define ungetch()       nxtch--
1351590Srgrimes#define getch()         *nxtch++
1361590Srgrimes
1371590Srgrimesint
1381590Srgrimesexpr(expbuf)
1391590Srgrimeschar *expbuf;
1401590Srgrimes{
1411590Srgrimes	register int rval;
1421590Srgrimes
1431590Srgrimes	nxtch = expbuf;
1441590Srgrimes	if (setjmp(expjump) != 0)
1451590Srgrimes		return FALSE;
1461590Srgrimes
1471590Srgrimes	rval = query();
1481590Srgrimes	if (skipws() == EOS)
1491590Srgrimes		return rval;
1501590Srgrimes
1511590Srgrimes	printf("m4: ill-formed expression.\n");
1521590Srgrimes	return FALSE;
1531590Srgrimes}
1541590Srgrimes
1551590Srgrimes/*
1561590Srgrimes * query : lor | lor '?' query ':' query
1571590Srgrimes */
1581590Srgrimesstatic int
1591590Srgrimesquery()
1601590Srgrimes{
1611590Srgrimes	register int bool, true_val, false_val;
1621590Srgrimes
1631590Srgrimes	bool = lor();
1641590Srgrimes	if (skipws() != '?') {
1651590Srgrimes		ungetch();
1661590Srgrimes		return bool;
1671590Srgrimes	}
1681590Srgrimes
1691590Srgrimes	true_val = query();
1701590Srgrimes	if (skipws() != ':')
1711590Srgrimes		experr("bad query");
1721590Srgrimes
1731590Srgrimes	false_val = query();
1741590Srgrimes	return bool ? true_val : false_val;
1751590Srgrimes}
1761590Srgrimes
1771590Srgrimes/*
1781590Srgrimes * lor : land { '||' land }
1791590Srgrimes */
1801590Srgrimesstatic int
1811590Srgrimeslor()
1821590Srgrimes{
1831590Srgrimes	register int c, vl, vr;
1841590Srgrimes
1851590Srgrimes	vl = land();
1861590Srgrimes	while ((c = skipws()) == '|' && getch() == '|') {
1871590Srgrimes		vr = land();
1881590Srgrimes		vl = vl || vr;
1891590Srgrimes	}
1901590Srgrimes
1911590Srgrimes	if (c == '|')
1921590Srgrimes		ungetch();
1931590Srgrimes	ungetch();
1941590Srgrimes	return vl;
1951590Srgrimes}
1961590Srgrimes
1971590Srgrimes/*
1981590Srgrimes * land : bor { '&&' bor }
1991590Srgrimes */
2001590Srgrimesstatic int
2011590Srgrimesland()
2021590Srgrimes{
2031590Srgrimes	register int c, vl, vr;
2041590Srgrimes
2051590Srgrimes	vl = bor();
2061590Srgrimes	while ((c = skipws()) == '&' && getch() == '&') {
2071590Srgrimes		vr = bor();
2081590Srgrimes		vl = vl && vr;
2091590Srgrimes	}
2101590Srgrimes
2111590Srgrimes	if (c == '&')
2121590Srgrimes		ungetch();
2131590Srgrimes	ungetch();
2141590Srgrimes	return vl;
2151590Srgrimes}
2161590Srgrimes
2171590Srgrimes/*
2181590Srgrimes * bor : bxor { '|' bxor }
2191590Srgrimes */
2201590Srgrimesstatic int
2211590Srgrimesbor()
2221590Srgrimes{
2231590Srgrimes	register int vl, vr, c;
2241590Srgrimes
2251590Srgrimes	vl = bxor();
2261590Srgrimes	while ((c = skipws()) == '|' && getch() != '|') {
2271590Srgrimes		ungetch();
2281590Srgrimes		vr = bxor();
2291590Srgrimes		vl |= vr;
2301590Srgrimes	}
2311590Srgrimes
2321590Srgrimes	if (c == '|')
2331590Srgrimes		ungetch();
2341590Srgrimes	ungetch();
2351590Srgrimes	return vl;
2361590Srgrimes}
2371590Srgrimes
2381590Srgrimes/*
2391590Srgrimes * bxor : band { '^' band }
2401590Srgrimes */
2411590Srgrimesstatic int
2421590Srgrimesbxor()
2431590Srgrimes{
2441590Srgrimes	register int vl, vr;
2451590Srgrimes
2461590Srgrimes	vl = band();
2471590Srgrimes	while (skipws() == '^') {
2481590Srgrimes		vr = band();
2491590Srgrimes		vl ^= vr;
2501590Srgrimes	}
2511590Srgrimes
2521590Srgrimes	ungetch();
2531590Srgrimes	return vl;
2541590Srgrimes}
2551590Srgrimes
2561590Srgrimes/*
2571590Srgrimes * band : eql { '&' eql }
2581590Srgrimes */
2591590Srgrimesstatic int
2601590Srgrimesband()
2611590Srgrimes{
2621590Srgrimes	register int vl, vr, c;
2631590Srgrimes
2641590Srgrimes	vl = eql();
2651590Srgrimes	while ((c = skipws()) == '&' && getch() != '&') {
2661590Srgrimes		ungetch();
2671590Srgrimes		vr = eql();
2681590Srgrimes		vl &= vr;
2691590Srgrimes	}
2701590Srgrimes
2711590Srgrimes	if (c == '&')
2721590Srgrimes		ungetch();
2731590Srgrimes	ungetch();
2741590Srgrimes	return vl;
2751590Srgrimes}
2761590Srgrimes
2771590Srgrimes/*
2781590Srgrimes * eql : relat { eqrel relat }
2791590Srgrimes */
2801590Srgrimesstatic int
2811590Srgrimeseql()
2821590Srgrimes{
2831590Srgrimes	register int vl, vr, rel;
2841590Srgrimes
2851590Srgrimes	vl = relat();
2861590Srgrimes	while ((rel = geteql()) != -1) {
2871590Srgrimes		vr = relat();
2881590Srgrimes
2891590Srgrimes		switch (rel) {
2901590Srgrimes
2911590Srgrimes		case EQL:
2921590Srgrimes			vl = (vl == vr);
2931590Srgrimes			break;
2941590Srgrimes		case NEQ:
2951590Srgrimes			vl = (vl != vr);
2961590Srgrimes			break;
2971590Srgrimes		}
2981590Srgrimes	}
2991590Srgrimes	return vl;
3001590Srgrimes}
3011590Srgrimes
3021590Srgrimes/*
3031590Srgrimes * relat : shift { rel shift }
3041590Srgrimes */
3051590Srgrimesstatic int
3061590Srgrimesrelat()
3071590Srgrimes{
3081590Srgrimes	register int vl, vr, rel;
3091590Srgrimes
3101590Srgrimes	vl = shift();
3111590Srgrimes	while ((rel = getrel()) != -1) {
3121590Srgrimes
3131590Srgrimes		vr = shift();
3141590Srgrimes		switch (rel) {
3151590Srgrimes
3161590Srgrimes		case LEQ:
3171590Srgrimes			vl = (vl <= vr);
3181590Srgrimes			break;
3191590Srgrimes		case LSS:
3201590Srgrimes			vl = (vl < vr);
3211590Srgrimes			break;
3221590Srgrimes		case GTR:
3231590Srgrimes			vl = (vl > vr);
3241590Srgrimes			break;
3251590Srgrimes		case GEQ:
3261590Srgrimes			vl = (vl >= vr);
3271590Srgrimes			break;
3281590Srgrimes		}
3291590Srgrimes	}
3301590Srgrimes	return vl;
3311590Srgrimes}
3321590Srgrimes
3331590Srgrimes/*
3341590Srgrimes * shift : primary { shop primary }
3351590Srgrimes */
3361590Srgrimesstatic int
3371590Srgrimesshift()
3381590Srgrimes{
3391590Srgrimes	register int vl, vr, c;
3401590Srgrimes
3411590Srgrimes	vl = primary();
3421590Srgrimes	while (((c = skipws()) == '<' || c == '>') && c == getch()) {
3431590Srgrimes		vr = primary();
3441590Srgrimes
3451590Srgrimes		if (c == '<')
3461590Srgrimes			vl <<= vr;
3471590Srgrimes		else
3481590Srgrimes			vl >>= vr;
3491590Srgrimes	}
3501590Srgrimes
3511590Srgrimes	if (c == '<' || c == '>')
3521590Srgrimes		ungetch();
3531590Srgrimes	ungetch();
3541590Srgrimes	return vl;
3551590Srgrimes}
3561590Srgrimes
3571590Srgrimes/*
3581590Srgrimes * primary : term { addop term }
3591590Srgrimes */
3601590Srgrimesstatic int
3611590Srgrimesprimary()
3621590Srgrimes{
3631590Srgrimes	register int c, vl, vr;
3641590Srgrimes
3651590Srgrimes	vl = term();
3661590Srgrimes	while ((c = skipws()) == '+' || c == '-') {
3671590Srgrimes		vr = term();
3681590Srgrimes		if (c == '+')
3691590Srgrimes			vl += vr;
3701590Srgrimes		else
3711590Srgrimes			vl -= vr;
3721590Srgrimes	}
3731590Srgrimes
3741590Srgrimes	ungetch();
3751590Srgrimes	return vl;
3761590Srgrimes}
3771590Srgrimes
3781590Srgrimes/*
3791590Srgrimes * <term> := <unary> { <mulop> <unary> }
3801590Srgrimes */
3811590Srgrimesstatic int
3821590Srgrimesterm()
3831590Srgrimes{
3841590Srgrimes	register int c, vl, vr;
3851590Srgrimes
3861590Srgrimes	vl = unary();
3871590Srgrimes	while ((c = skipws()) == '*' || c == '/' || c == '%') {
3881590Srgrimes		vr = unary();
3891590Srgrimes
3901590Srgrimes		switch (c) {
3911590Srgrimes		case '*':
3921590Srgrimes			vl *= vr;
3931590Srgrimes			break;
3941590Srgrimes		case '/':
3951590Srgrimes			vl /= vr;
3961590Srgrimes			break;
3971590Srgrimes		case '%':
3981590Srgrimes			vl %= vr;
3991590Srgrimes			break;
4001590Srgrimes		}
4011590Srgrimes	}
4021590Srgrimes	ungetch();
4031590Srgrimes	return vl;
4041590Srgrimes}
4051590Srgrimes
4061590Srgrimes/*
4071590Srgrimes * unary : factor | unop unary
4081590Srgrimes */
4091590Srgrimesstatic int
4101590Srgrimesunary()
4111590Srgrimes{
4121590Srgrimes	register int val, c;
4131590Srgrimes
4141590Srgrimes	if ((c = skipws()) == '!' || c == '~' || c == '-') {
4151590Srgrimes		val = unary();
4161590Srgrimes
4171590Srgrimes		switch (c) {
4181590Srgrimes		case '!':
4191590Srgrimes			return !val;
4201590Srgrimes		case '~':
4211590Srgrimes			return ~val;
4221590Srgrimes		case '-':
4231590Srgrimes			return -val;
4241590Srgrimes		}
4251590Srgrimes	}
4261590Srgrimes
4271590Srgrimes	ungetch();
4281590Srgrimes	return factor();
4291590Srgrimes}
4301590Srgrimes
4311590Srgrimes/*
4321590Srgrimes * factor : constant | '(' query ')'
4331590Srgrimes */
4341590Srgrimesstatic int
4351590Srgrimesfactor()
4361590Srgrimes{
4371590Srgrimes	register int val;
4381590Srgrimes
4391590Srgrimes	if (skipws() == '(') {
4401590Srgrimes		val = query();
4411590Srgrimes		if (skipws() != ')')
4421590Srgrimes			experr("bad factor");
4431590Srgrimes		return val;
4441590Srgrimes	}
4451590Srgrimes
4461590Srgrimes	ungetch();
4471590Srgrimes	return constant();
4481590Srgrimes}
4491590Srgrimes
4501590Srgrimes/*
4511590Srgrimes * constant: num | 'char'
4521590Srgrimes * Note: constant() handles multi-byte constants
4531590Srgrimes */
4541590Srgrimesstatic int
4551590Srgrimesconstant()
4561590Srgrimes{
4571590Srgrimes	register int i;
4581590Srgrimes	register int value;
4591590Srgrimes	register char c;
4601590Srgrimes	int v[sizeof(int)];
4611590Srgrimes
4621590Srgrimes	if (skipws() != '\'') {
4631590Srgrimes		ungetch();
4641590Srgrimes		return num();
4651590Srgrimes	}
4661590Srgrimes	for (i = 0; i < sizeof(int); i++) {
4671590Srgrimes		if ((c = getch()) == '\'') {
4681590Srgrimes			ungetch();
4691590Srgrimes			break;
4701590Srgrimes		}
4711590Srgrimes		if (c == '\\') {
4721590Srgrimes			switch (c = getch()) {
4731590Srgrimes			case '0':
4741590Srgrimes			case '1':
4751590Srgrimes			case '2':
4761590Srgrimes			case '3':
4771590Srgrimes			case '4':
4781590Srgrimes			case '5':
4791590Srgrimes			case '6':
4801590Srgrimes			case '7':
4811590Srgrimes				ungetch();
4821590Srgrimes				c = num();
4831590Srgrimes				break;
4841590Srgrimes			case 'n':
4851590Srgrimes				c = 012;
4861590Srgrimes				break;
4871590Srgrimes			case 'r':
4881590Srgrimes				c = 015;
4891590Srgrimes				break;
4901590Srgrimes			case 't':
4911590Srgrimes				c = 011;
4921590Srgrimes				break;
4931590Srgrimes			case 'b':
4941590Srgrimes				c = 010;
4951590Srgrimes				break;
4961590Srgrimes			case 'f':
4971590Srgrimes				c = 014;
4981590Srgrimes				break;
4991590Srgrimes			}
5001590Srgrimes		}
5011590Srgrimes		v[i] = c;
5021590Srgrimes	}
5031590Srgrimes	if (i == 0 || getch() != '\'')
5041590Srgrimes		experr("illegal character constant");
5051590Srgrimes	for (value = 0; --i >= 0;) {
5061590Srgrimes		value <<= 8;
5071590Srgrimes		value += v[i];
5081590Srgrimes	}
5091590Srgrimes	return value;
5101590Srgrimes}
5111590Srgrimes
5121590Srgrimes/*
5131590Srgrimes * num : digit | num digit
5141590Srgrimes */
5151590Srgrimesstatic int
5161590Srgrimesnum()
5171590Srgrimes{
5181590Srgrimes	register int rval, c, base;
5191590Srgrimes	int ndig;
5201590Srgrimes
5211590Srgrimes	base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
5221590Srgrimes	rval = 0;
5231590Srgrimes	ndig = 0;
5241590Srgrimes	while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
5251590Srgrimes		rval *= base;
5261590Srgrimes		rval += (c - '0');
5271590Srgrimes		c = getch();
5281590Srgrimes		ndig++;
5291590Srgrimes	}
5301590Srgrimes	ungetch();
5311590Srgrimes
5321590Srgrimes	if (ndig == 0)
5331590Srgrimes		experr("bad constant");
5341590Srgrimes
5351590Srgrimes	return rval;
5361590Srgrimes
5371590Srgrimes}
5381590Srgrimes
5391590Srgrimes/*
5401590Srgrimes * eqlrel : '=' | '==' | '!='
5411590Srgrimes */
5421590Srgrimesstatic int
5431590Srgrimesgeteql()
5441590Srgrimes{
5451590Srgrimes	register int c1, c2;
5461590Srgrimes
5471590Srgrimes	c1 = skipws();
5481590Srgrimes	c2 = getch();
5491590Srgrimes
5501590Srgrimes	switch (c1) {
5511590Srgrimes
5521590Srgrimes	case '=':
5531590Srgrimes		if (c2 != '=')
5541590Srgrimes			ungetch();
5551590Srgrimes		return EQL;
5561590Srgrimes
5571590Srgrimes	case '!':
5581590Srgrimes		if (c2 == '=')
5591590Srgrimes			return NEQ;
5601590Srgrimes		ungetch();
5611590Srgrimes		ungetch();
5621590Srgrimes		return -1;
5631590Srgrimes
5641590Srgrimes	default:
5651590Srgrimes		ungetch();
5661590Srgrimes		ungetch();
5671590Srgrimes		return -1;
5681590Srgrimes	}
5691590Srgrimes}
5701590Srgrimes
5711590Srgrimes/*
5721590Srgrimes * rel : '<' | '>' | '<=' | '>='
5731590Srgrimes */
5741590Srgrimesstatic int
5751590Srgrimesgetrel()
5761590Srgrimes{
5771590Srgrimes	register int c1, c2;
5781590Srgrimes
5791590Srgrimes	c1 = skipws();
5801590Srgrimes	c2 = getch();
5811590Srgrimes
5821590Srgrimes	switch (c1) {
5831590Srgrimes
5841590Srgrimes	case '<':
5851590Srgrimes		if (c2 == '=')
5861590Srgrimes			return LEQ;
5871590Srgrimes		ungetch();
5881590Srgrimes		return LSS;
5891590Srgrimes
5901590Srgrimes	case '>':
5911590Srgrimes		if (c2 == '=')
5921590Srgrimes			return GEQ;
5931590Srgrimes		ungetch();
5941590Srgrimes		return GTR;
5951590Srgrimes
5961590Srgrimes	default:
5971590Srgrimes		ungetch();
5981590Srgrimes		ungetch();
5991590Srgrimes		return -1;
6001590Srgrimes	}
6011590Srgrimes}
6021590Srgrimes
6031590Srgrimes/*
6041590Srgrimes * Skip over any white space and return terminating char.
6051590Srgrimes */
6061590Srgrimesstatic int
6071590Srgrimesskipws()
6081590Srgrimes{
6091590Srgrimes	register char c;
6101590Srgrimes
6111590Srgrimes	while ((c = getch()) <= ' ' && c > EOS)
6121590Srgrimes		;
6131590Srgrimes	return c;
6141590Srgrimes}
6151590Srgrimes
6161590Srgrimes/*
6171590Srgrimes * resets environment to eval(), prints an error
6181590Srgrimes * and forces eval to return FALSE.
6191590Srgrimes */
6201590Srgrimesstatic void
6211590Srgrimesexperr(msg)
6221590Srgrimeschar *msg;
6231590Srgrimes{
6241590Srgrimes	printf("m4: %s in expr.\n", msg);
6251590Srgrimes	longjmp(expjump, -1);
6261590Srgrimes}
627