Home | History | Annotate | Line # | Download | only in m4
expr.c revision 1.17
      1  1.17  drochner /*	$NetBSD: expr.c,v 1.17 2005/10/06 17:28:33 drochner Exp $	*/
      2  1.12        tv /*	$OpenBSD: expr.c,v 1.11 2000/01/11 14:00:57 espie Exp $	*/
      3   1.7       tls 
      4   1.5     glass /*
      5   1.5     glass  * Copyright (c) 1989, 1993
      6   1.5     glass  *	The Regents of the University of California.  All rights reserved.
      7   1.5     glass  *
      8   1.5     glass  * This code is derived from software contributed to Berkeley by
      9   1.5     glass  * Ozan Yigit at York University.
     10   1.5     glass  *
     11   1.5     glass  * Redistribution and use in source and binary forms, with or without
     12   1.5     glass  * modification, are permitted provided that the following conditions
     13   1.5     glass  * are met:
     14   1.5     glass  * 1. Redistributions of source code must retain the above copyright
     15   1.5     glass  *    notice, this list of conditions and the following disclaimer.
     16   1.5     glass  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.5     glass  *    notice, this list of conditions and the following disclaimer in the
     18   1.5     glass  *    documentation and/or other materials provided with the distribution.
     19  1.15       agc  * 3. Neither the name of the University nor the names of its contributors
     20   1.5     glass  *    may be used to endorse or promote products derived from this software
     21   1.5     glass  *    without specific prior written permission.
     22   1.5     glass  *
     23   1.5     glass  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24   1.5     glass  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25   1.5     glass  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26   1.5     glass  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27   1.5     glass  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28   1.5     glass  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29   1.5     glass  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30   1.5     glass  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31   1.5     glass  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32   1.5     glass  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33   1.5     glass  * SUCH DAMAGE.
     34   1.5     glass  */
     35   1.5     glass 
     36  1.16       jmc #if HAVE_NBTOOL_CONFIG_H
     37  1.16       jmc #include "nbtool_config.h"
     38  1.16       jmc #endif
     39  1.16       jmc 
     40   1.8     lukem #include <sys/cdefs.h>
     41  1.14        tv #if defined(__RCSID) && !defined(lint)
     42   1.7       tls #if 0
     43   1.7       tls static char sccsid[] = "@(#)expr.c	8.2 (Berkeley) 4/29/95";
     44   1.7       tls #else
     45  1.17  drochner __RCSID("$NetBSD: expr.c,v 1.17 2005/10/06 17:28:33 drochner Exp $");
     46   1.7       tls #endif
     47   1.5     glass #endif /* not lint */
     48   1.2     glass 
     49  1.13        tv #include <sys/types.h>
     50  1.12        tv #include <ctype.h>
     51  1.12        tv #include <stddef.h>
     52   1.5     glass #include <stdio.h>
     53   1.8     lukem #include "mdef.h"
     54   1.8     lukem #include "extern.h"
     55   1.8     lukem 
     56   1.5     glass /*
     57   1.5     glass  *      expression evaluator: performs a standard recursive
     58   1.5     glass  *      descent parse to evaluate any expression permissible
     59   1.5     glass  *      within the following grammar:
     60   1.5     glass  *
     61  1.17  drochner  *	expr	:	query EOS
     62  1.17  drochner  *	query	:	lor
     63  1.17  drochner  *		|	lor "?" query ":" query
     64  1.17  drochner  *	lor	:	land { "||" land }
     65  1.17  drochner  *	land	:	bor { "&&" bor }
     66  1.17  drochner  *	bor	:	xor { "|" xor }
     67  1.17  drochner  *	xor	:	band { "^" eqrel }
     68  1.17  drochner  *	band	:	eqrel { "&" eqrel }
     69  1.17  drochner  *	eqrel	:	nerel { ("==" | "!=") nerel }
     70  1.17  drochner  *	nerel	:	shift { ("<" | ">" | "<=" | ">=") shift }
     71  1.17  drochner  *	shift	:	primary { ("<<" | ">>") primary }
     72  1.17  drochner  *	primary	:	term { ("+" | "-") term }
     73  1.17  drochner  *	term	:	exp { ("*" | "/" | "%") exp }
     74  1.17  drochner  *	exp	:	unary { "**" unary }
     75  1.17  drochner  *	unary	:	factor
     76  1.17  drochner  *		|	("+" | "-" | "~" | "!") unary
     77  1.17  drochner  *	factor	:	constant
     78  1.17  drochner  *		|	"(" query ")"
     79  1.17  drochner  *	constant:	num
     80  1.17  drochner  *		|	"'" CHAR "'"
     81  1.17  drochner  *	num	:	DIGIT
     82  1.17  drochner  *		|	DIGIT num
     83   1.5     glass  *
     84   1.5     glass  *
     85   1.5     glass  *      This expression evaluator is lifted from a public-domain
     86   1.5     glass  *      C Pre-Processor included with the DECUS C Compiler distribution.
     87   1.5     glass  *      It is hacked somewhat to be suitable for m4.
     88   1.5     glass  *
     89   1.5     glass  *      Originally by:  Mike Lutz
     90   1.5     glass  *                      Bob Harper
     91   1.5     glass  */
     92   1.5     glass 
     93   1.5     glass #define EQL     0
     94   1.5     glass #define NEQ     1
     95   1.5     glass #define LSS     2
     96   1.5     glass #define LEQ     3
     97   1.5     glass #define GTR     4
     98   1.5     glass #define GEQ     5
     99   1.5     glass #define OCTAL   8
    100   1.5     glass #define DECIMAL 10
    101   1.9  matthias #define HEX	16
    102   1.5     glass 
    103  1.12        tv static const char *nxtch;		       /* Parser scan pointer */
    104  1.12        tv static const char *where;
    105   1.5     glass 
    106  1.17  drochner static int query(int);
    107  1.17  drochner static int lor(int);
    108  1.17  drochner static int land(int);
    109  1.17  drochner static int bor(int);
    110  1.17  drochner static int xor(int);
    111  1.17  drochner static int band(int);
    112  1.17  drochner static int eqrel(int);
    113  1.17  drochner static int nerel(int);
    114  1.17  drochner static int shift(int);
    115  1.17  drochner static int primary(int);
    116  1.17  drochner static int term(int);
    117  1.17  drochner static int exp(int);
    118  1.17  drochner static int unary(int);
    119  1.17  drochner static int factor(int);
    120  1.17  drochner static int constant(int);
    121  1.17  drochner static int num(int);
    122  1.17  drochner static int skipws(void);
    123  1.17  drochner static void experr(const char *);
    124   1.5     glass 
    125   1.5     glass /*
    126   1.5     glass  * For longjmp
    127   1.5     glass  */
    128   1.5     glass #include <setjmp.h>
    129   1.5     glass static jmp_buf expjump;
    130   1.2     glass 
    131   1.5     glass /*
    132   1.5     glass  * macros:
    133   1.5     glass  *      ungetch - Put back the last character examined.
    134   1.5     glass  *      getch   - return the next character from expr string.
    135   1.5     glass  */
    136   1.5     glass #define ungetch()       nxtch--
    137   1.5     glass #define getch()         *nxtch++
    138   1.5     glass 
    139   1.5     glass int
    140   1.5     glass expr(expbuf)
    141  1.12        tv 	const char *expbuf;
    142   1.5     glass {
    143   1.8     lukem 	int rval;
    144   1.5     glass 
    145   1.5     glass 	nxtch = expbuf;
    146  1.12        tv 	where = expbuf;
    147   1.5     glass 	if (setjmp(expjump) != 0)
    148   1.5     glass 		return FALSE;
    149   1.5     glass 
    150  1.17  drochner 	rval = query(1);
    151   1.5     glass 	if (skipws() == EOS)
    152   1.5     glass 		return rval;
    153   1.5     glass 
    154   1.5     glass 	printf("m4: ill-formed expression.\n");
    155   1.5     glass 	return FALSE;
    156   1.5     glass }
    157   1.5     glass 
    158   1.5     glass /*
    159   1.5     glass  * query : lor | lor '?' query ':' query
    160   1.5     glass  */
    161   1.5     glass static int
    162  1.17  drochner query(int mayeval)
    163   1.5     glass {
    164   1.8     lukem 	int bool, true_val, false_val;
    165   1.5     glass 
    166  1.17  drochner 	bool = lor(mayeval);
    167   1.5     glass 	if (skipws() != '?') {
    168   1.5     glass 		ungetch();
    169   1.5     glass 		return bool;
    170   1.5     glass 	}
    171   1.5     glass 
    172  1.17  drochner 	true_val = query(bool);
    173   1.5     glass 	if (skipws() != ':')
    174  1.17  drochner 		experr("bad query: missing \":\"");
    175   1.5     glass 
    176  1.17  drochner 	false_val = query(!bool);
    177   1.5     glass 	return bool ? true_val : false_val;
    178   1.5     glass }
    179   1.2     glass 
    180   1.5     glass /*
    181   1.5     glass  * lor : land { '||' land }
    182   1.5     glass  */
    183   1.5     glass static int
    184  1.17  drochner lor(int mayeval)
    185   1.5     glass {
    186   1.8     lukem 	int c, vl, vr;
    187   1.5     glass 
    188  1.17  drochner 	vl = land(mayeval);
    189   1.6   mycroft 	while ((c = skipws()) == '|') {
    190  1.17  drochner 		if (getch() != '|') {
    191   1.6   mycroft 			ungetch();
    192  1.17  drochner 			break;
    193  1.17  drochner 		}
    194  1.17  drochner 		if (vl != 0)
    195  1.17  drochner 			mayeval = 0;
    196  1.17  drochner 		vr = land(mayeval);
    197   1.5     glass 		vl = vl || vr;
    198   1.5     glass 	}
    199   1.5     glass 
    200   1.5     glass 	ungetch();
    201   1.5     glass 	return vl;
    202   1.5     glass }
    203   1.2     glass 
    204   1.5     glass /*
    205   1.6   mycroft  * land : not { '&&' not }
    206   1.5     glass  */
    207   1.5     glass static int
    208  1.17  drochner land(int mayeval)
    209   1.5     glass {
    210   1.8     lukem 	int c, vl, vr;
    211   1.5     glass 
    212  1.17  drochner 	vl = bor(mayeval);
    213   1.6   mycroft 	while ((c = skipws()) == '&') {
    214  1.17  drochner 		if (getch() != '&') {
    215   1.6   mycroft 			ungetch();
    216  1.17  drochner 			break;
    217  1.17  drochner 		}
    218  1.17  drochner 		if (vl == 0)
    219  1.17  drochner 			mayeval = 0;
    220  1.17  drochner 		vr = bor(mayeval);
    221   1.5     glass 		vl = vl && vr;
    222   1.5     glass 	}
    223   1.5     glass 
    224   1.5     glass 	ungetch();
    225   1.5     glass 	return vl;
    226   1.5     glass }
    227   1.2     glass 
    228   1.5     glass /*
    229  1.17  drochner  * bor : xor { "|" xor }
    230   1.5     glass  */
    231   1.5     glass static int
    232  1.17  drochner bor(int mayeval)
    233   1.5     glass {
    234  1.17  drochner 	int vl, vr, c, cr;
    235   1.5     glass 
    236  1.17  drochner 	vl = xor(mayeval);
    237  1.17  drochner 	while ((c = skipws()) == '|') {
    238  1.17  drochner 		cr = getch();
    239   1.5     glass 		ungetch();
    240  1.17  drochner 		if (cr == '|')
    241  1.17  drochner 			break;
    242  1.17  drochner 		vr = xor(mayeval);
    243  1.17  drochner 		vl |= vr;
    244   1.5     glass 	}
    245  1.17  drochner 	ungetch();
    246  1.17  drochner 	return (vl);
    247  1.17  drochner }
    248   1.5     glass 
    249  1.17  drochner /*
    250  1.17  drochner  * xor : band { "^" band }
    251  1.17  drochner  */
    252  1.17  drochner static int
    253  1.17  drochner xor(int mayeval)
    254  1.17  drochner {
    255  1.17  drochner 	int vl, vr, c;
    256  1.17  drochner 
    257  1.17  drochner 	vl = band(mayeval);
    258  1.17  drochner 	while ((c = skipws()) == '^') {
    259  1.17  drochner 		vr = band(mayeval);
    260  1.17  drochner 		vl ^= vr;
    261  1.17  drochner 	}
    262   1.5     glass 	ungetch();
    263  1.17  drochner 	return (vl);
    264   1.5     glass }
    265   1.2     glass 
    266   1.5     glass /*
    267  1.17  drochner  * band : eqrel { "&" eqrel }
    268   1.5     glass  */
    269   1.5     glass static int
    270  1.17  drochner band(int mayeval)
    271   1.5     glass {
    272  1.17  drochner 	int c, cr, vl, vr;
    273   1.5     glass 
    274  1.17  drochner 	vl = eqrel(mayeval);
    275  1.17  drochner 	while ((c = skipws()) == '&') {
    276  1.17  drochner 		cr = getch();
    277  1.17  drochner 		ungetch();
    278  1.17  drochner 		if (cr == '&')
    279  1.17  drochner 			break;
    280  1.17  drochner 		vr = eqrel(mayeval);
    281  1.17  drochner 		vl &= vr;
    282  1.17  drochner 	}
    283  1.17  drochner 	ungetch();
    284  1.17  drochner 	return vl;
    285  1.17  drochner }
    286   1.5     glass 
    287  1.17  drochner /*
    288  1.17  drochner  * eqrel : nerel { ("==" | "!=" ) nerel }
    289  1.17  drochner  */
    290  1.17  drochner static int
    291  1.17  drochner eqrel(int mayeval)
    292  1.17  drochner {
    293  1.17  drochner 	int vl, vr, c, cr;
    294   1.5     glass 
    295  1.17  drochner 	vl = nerel(mayeval);
    296  1.17  drochner 	while ((c = skipws()) == '!' || c == '=') {
    297  1.17  drochner 		if ((cr = getch()) != '=') {
    298  1.17  drochner 			ungetch();
    299  1.17  drochner 			break;
    300  1.17  drochner 		}
    301  1.17  drochner 		vr = nerel(mayeval);
    302  1.17  drochner 		switch (c) {
    303  1.17  drochner 		case '=':
    304   1.5     glass 			vl = (vl == vr);
    305   1.5     glass 			break;
    306  1.17  drochner 		case '!':
    307   1.5     glass 			vl = (vl != vr);
    308   1.5     glass 			break;
    309  1.17  drochner 		}
    310  1.17  drochner 	}
    311  1.17  drochner 	ungetch();
    312  1.17  drochner 	return vl;
    313  1.17  drochner }
    314   1.5     glass 
    315  1.17  drochner /*
    316  1.17  drochner  * nerel : shift { ("<=" | ">=" | "<" | ">") shift }
    317  1.17  drochner  */
    318  1.17  drochner static int
    319  1.17  drochner nerel(int mayeval)
    320  1.17  drochner {
    321  1.17  drochner 	int vl, vr, c, cr;
    322  1.17  drochner 
    323  1.17  drochner 	vl = shift(mayeval);
    324  1.17  drochner 	while ((c = skipws()) == '<' || c == '>') {
    325  1.17  drochner 		if ((cr = getch()) != '=') {
    326  1.17  drochner 			ungetch();
    327  1.17  drochner 			cr = '\0';
    328  1.17  drochner 		}
    329  1.17  drochner 		vr = shift(mayeval);
    330  1.17  drochner 		switch (c) {
    331  1.17  drochner 		case '<':
    332  1.17  drochner 			vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
    333   1.5     glass 			break;
    334  1.17  drochner 		case '>':
    335  1.17  drochner 			vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
    336   1.5     glass 			break;
    337   1.5     glass 		}
    338   1.2     glass 	}
    339  1.17  drochner 	ungetch();
    340   1.2     glass 	return vl;
    341   1.5     glass }
    342   1.2     glass 
    343   1.5     glass /*
    344  1.17  drochner  * shift : primary { ("<<" | ">>") primary }
    345   1.5     glass  */
    346   1.5     glass static int
    347  1.17  drochner shift(int mayeval)
    348   1.5     glass {
    349   1.8     lukem 	int vl, vr, c;
    350   1.5     glass 
    351  1.17  drochner 	vl = primary(mayeval);
    352   1.6   mycroft 	while (((c = skipws()) == '<' || c == '>') && getch() == c) {
    353  1.17  drochner 		vr = primary(mayeval);
    354   1.5     glass 
    355   1.5     glass 		if (c == '<')
    356   1.5     glass 			vl <<= vr;
    357   1.5     glass 		else
    358   1.5     glass 			vl >>= vr;
    359   1.5     glass 	}
    360   1.5     glass 
    361   1.5     glass 	if (c == '<' || c == '>')
    362   1.5     glass 		ungetch();
    363   1.5     glass 	ungetch();
    364   1.5     glass 	return vl;
    365   1.5     glass }
    366   1.2     glass 
    367   1.5     glass /*
    368  1.17  drochner  * primary : term { ("+" | "-") term }
    369   1.5     glass  */
    370   1.5     glass static int
    371  1.17  drochner primary(int mayeval)
    372   1.5     glass {
    373   1.8     lukem 	int c, vl, vr;
    374   1.5     glass 
    375  1.17  drochner 	vl = term(mayeval);
    376   1.5     glass 	while ((c = skipws()) == '+' || c == '-') {
    377  1.17  drochner 		vr = term(mayeval);
    378   1.6   mycroft 
    379   1.5     glass 		if (c == '+')
    380   1.5     glass 			vl += vr;
    381   1.5     glass 		else
    382   1.5     glass 			vl -= vr;
    383   1.2     glass 	}
    384   1.5     glass 
    385   1.5     glass 	ungetch();
    386   1.2     glass 	return vl;
    387   1.5     glass }
    388   1.2     glass 
    389   1.5     glass /*
    390  1.17  drochner  * term : exp { ("*" | "/" | "%") exp }
    391   1.5     glass  */
    392   1.5     glass static int
    393  1.17  drochner term(int mayeval)
    394   1.5     glass {
    395   1.8     lukem 	int c, vl, vr;
    396   1.5     glass 
    397  1.17  drochner 	vl = exp(mayeval);
    398   1.5     glass 	while ((c = skipws()) == '*' || c == '/' || c == '%') {
    399  1.17  drochner 		vr = exp(mayeval);
    400   1.2     glass 
    401   1.5     glass 		switch (c) {
    402   1.5     glass 		case '*':
    403   1.5     glass 			vl *= vr;
    404   1.5     glass 			break;
    405   1.5     glass 		case '/':
    406  1.17  drochner 			if (!mayeval)
    407  1.17  drochner 				/* short-circuit */;
    408  1.17  drochner 			else if (vr == 0)
    409  1.12        tv 				errx(1, "division by zero in eval.");
    410  1.12        tv 			else
    411  1.12        tv 				vl /= vr;
    412   1.5     glass 			break;
    413   1.5     glass 		case '%':
    414  1.17  drochner 			if (!mayeval)
    415  1.17  drochner 				/* short-circuit */;
    416  1.17  drochner 			else if (vr == 0)
    417  1.12        tv 				errx(1, "modulo zero in eval.");
    418  1.12        tv 			else
    419  1.12        tv 				vl %= vr;
    420   1.5     glass 			break;
    421   1.5     glass 		}
    422   1.2     glass 	}
    423   1.5     glass 	ungetch();
    424   1.2     glass 	return vl;
    425   1.5     glass }
    426   1.2     glass 
    427   1.5     glass /*
    428  1.17  drochner  * exp : unary { "**" exp }
    429   1.6   mycroft  */
    430   1.6   mycroft static int
    431  1.17  drochner exp(int mayeval)
    432   1.6   mycroft {
    433   1.8     lukem 	int c, vl, vr, n;
    434   1.6   mycroft 
    435  1.17  drochner 	vl = unary(mayeval);
    436  1.17  drochner 	while ((c = skipws()) == '*') {
    437   1.6   mycroft 		if (getch() != '*') {
    438   1.6   mycroft 			ungetch();
    439   1.6   mycroft 			break;
    440   1.6   mycroft 		}
    441  1.17  drochner 		vr = unary(mayeval);
    442   1.6   mycroft 		n = 1;
    443   1.6   mycroft 		while (vr-- > 0)
    444   1.6   mycroft 			n *= vl;
    445   1.6   mycroft 		return n;
    446   1.6   mycroft 	}
    447   1.6   mycroft 
    448   1.6   mycroft 	ungetch();
    449   1.6   mycroft 	return vl;
    450   1.6   mycroft }
    451   1.6   mycroft 
    452   1.6   mycroft /*
    453  1.17  drochner  * unary : factor | ("+" | "-" | "~" | "!") unary
    454   1.5     glass  */
    455   1.5     glass static int
    456  1.17  drochner unary(int mayeval)
    457   1.5     glass {
    458   1.8     lukem 	int val, c;
    459   1.5     glass 
    460  1.17  drochner 	if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
    461  1.17  drochner 		val = unary(mayeval);
    462   1.5     glass 
    463   1.5     glass 		switch (c) {
    464   1.6   mycroft 		case '+':
    465   1.6   mycroft 			return val;
    466   1.6   mycroft 		case '-':
    467   1.6   mycroft 			return -val;
    468   1.5     glass 		case '~':
    469   1.5     glass 			return ~val;
    470  1.17  drochner 		case '!':
    471  1.17  drochner 			return !val;
    472   1.5     glass 		}
    473   1.5     glass 	}
    474   1.2     glass 
    475   1.5     glass 	ungetch();
    476  1.17  drochner 	return factor(mayeval);
    477   1.5     glass }
    478   1.5     glass 
    479   1.5     glass /*
    480   1.5     glass  * factor : constant | '(' query ')'
    481   1.5     glass  */
    482   1.5     glass static int
    483  1.17  drochner factor(int mayeval)
    484   1.5     glass {
    485   1.8     lukem 	int val;
    486   1.5     glass 
    487   1.5     glass 	if (skipws() == '(') {
    488  1.17  drochner 		val = query(mayeval);
    489   1.5     glass 		if (skipws() != ')')
    490  1.17  drochner 			experr("bad factor: missing \")\"");
    491   1.5     glass 		return val;
    492   1.5     glass 	}
    493   1.5     glass 
    494   1.5     glass 	ungetch();
    495  1.17  drochner 	return constant(mayeval);
    496   1.5     glass }
    497   1.5     glass 
    498   1.5     glass /*
    499   1.5     glass  * constant: num | 'char'
    500   1.5     glass  * Note: constant() handles multi-byte constants
    501   1.5     glass  */
    502   1.5     glass static int
    503  1.17  drochner constant(int mayeval)
    504   1.5     glass {
    505   1.8     lukem 	int i;
    506   1.8     lukem 	int value;
    507   1.8     lukem 	char c;
    508   1.5     glass 	int v[sizeof(int)];
    509   1.5     glass 
    510   1.5     glass 	if (skipws() != '\'') {
    511   1.5     glass 		ungetch();
    512  1.17  drochner 		return num(mayeval);
    513   1.5     glass 	}
    514   1.5     glass 	for (i = 0; i < sizeof(int); i++) {
    515   1.5     glass 		if ((c = getch()) == '\'') {
    516   1.5     glass 			ungetch();
    517   1.5     glass 			break;
    518   1.5     glass 		}
    519   1.5     glass 		if (c == '\\') {
    520   1.5     glass 			switch (c = getch()) {
    521   1.5     glass 			case '0':
    522   1.5     glass 			case '1':
    523   1.5     glass 			case '2':
    524   1.5     glass 			case '3':
    525   1.5     glass 			case '4':
    526   1.5     glass 			case '5':
    527   1.5     glass 			case '6':
    528   1.5     glass 			case '7':
    529   1.5     glass 				ungetch();
    530  1.17  drochner 				c = num(mayeval);
    531   1.5     glass 				break;
    532   1.5     glass 			case 'n':
    533   1.5     glass 				c = 012;
    534   1.5     glass 				break;
    535   1.5     glass 			case 'r':
    536   1.5     glass 				c = 015;
    537   1.5     glass 				break;
    538   1.5     glass 			case 't':
    539   1.5     glass 				c = 011;
    540   1.5     glass 				break;
    541   1.5     glass 			case 'b':
    542   1.5     glass 				c = 010;
    543   1.5     glass 				break;
    544   1.5     glass 			case 'f':
    545   1.5     glass 				c = 014;
    546   1.5     glass 				break;
    547   1.5     glass 			}
    548   1.5     glass 		}
    549   1.5     glass 		v[i] = c;
    550   1.5     glass 	}
    551   1.5     glass 	if (i == 0 || getch() != '\'')
    552   1.5     glass 		experr("illegal character constant");
    553   1.5     glass 	for (value = 0; --i >= 0;) {
    554   1.5     glass 		value <<= 8;
    555   1.5     glass 		value += v[i];
    556   1.5     glass 	}
    557   1.5     glass 	return value;
    558   1.5     glass }
    559   1.2     glass 
    560   1.5     glass /*
    561   1.5     glass  * num : digit | num digit
    562   1.5     glass  */
    563   1.5     glass static int
    564  1.17  drochner num(int mayeval)
    565   1.5     glass {
    566   1.8     lukem 	int rval, c, base;
    567   1.5     glass 	int ndig;
    568   1.5     glass 
    569   1.5     glass 	base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
    570   1.5     glass 	rval = 0;
    571   1.5     glass 	ndig = 0;
    572   1.9  matthias 	if (base == OCTAL) {
    573   1.9  matthias 		c = skipws();
    574   1.9  matthias 		if (c == 'x' || c == 'X') {
    575   1.9  matthias 			base = HEX;
    576   1.9  matthias 			c = skipws();
    577   1.9  matthias 		} else
    578   1.9  matthias 			ndig++;
    579   1.9  matthias 	}
    580   1.9  matthias 	while ((base == HEX && isxdigit(c)) ||
    581   1.9  matthias 			(c >= '0' && c <= (base == OCTAL ? '7' : '9'))) {
    582   1.5     glass 		rval *= base;
    583   1.9  matthias 		if (isalpha(c))
    584   1.9  matthias 			rval += (tolower(c) - 'a' + 10);
    585   1.9  matthias 		else
    586   1.9  matthias 			rval += (c - '0');
    587   1.5     glass 		c = getch();
    588   1.5     glass 		ndig++;
    589   1.5     glass 	}
    590   1.5     glass 	ungetch();
    591  1.10  jdolecek 
    592   1.5     glass 	if (ndig == 0)
    593   1.5     glass 		experr("bad constant");
    594  1.10  jdolecek 
    595   1.5     glass 	return rval;
    596   1.5     glass }
    597   1.1       cgd 
    598   1.5     glass /*
    599   1.5     glass  * Skip over any white space and return terminating char.
    600   1.5     glass  */
    601   1.5     glass static int
    602   1.5     glass skipws()
    603   1.5     glass {
    604   1.8     lukem 	char c;
    605   1.5     glass 
    606   1.5     glass 	while ((c = getch()) <= ' ' && c > EOS)
    607   1.5     glass 		;
    608   1.5     glass 	return c;
    609   1.5     glass }
    610   1.5     glass 
    611   1.5     glass /*
    612   1.5     glass  * resets environment to eval(), prints an error
    613   1.5     glass  * and forces eval to return FALSE.
    614   1.5     glass  */
    615   1.5     glass static void
    616   1.5     glass experr(msg)
    617  1.11       wiz 	const char *msg;
    618   1.5     glass {
    619  1.12        tv 	printf("m4: %s in expr %s.\n", msg, where);
    620   1.5     glass 	longjmp(expjump, -1);
    621   1.5     glass }
    622