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