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