expr.c revision 1.3 1 /* File : expr.c
2 Authors: Mike Lutz & Bob Harper
3 Editors: Ozan Yigit & Richard A. O'Keefe
4 Updated: %G%
5 Purpose: arithmetic expression evaluator.
6
7 expr() performs a standard recursive descent parse to evaluate any
8 expression permitted byf the following grammar:
9
10 expr : query EOS
11 query : lor
12 | lor "?" query ":" query
13 lor : land { "||" land } or OR, for Pascal
14 land : bor { "&&" bor } or AND, for Pascal
15 bor : bxor { "|" bxor }
16 bxor : band { "^" band }
17 band : eql { "&" eql }
18 eql : relat { eqrel relat }
19 relat : shift { rel shift }
20 shift : primary { shop primary }
21 primary : term { addop term }
22 term : unary { mulop unary }
23 unary : factor
24 | unop unary
25 factor : constant
26 | "(" query ")"
27 constant: num
28 | "'" CHAR "'" or '"' CHAR '"'
29 num : DIGIT full ANSI C syntax
30 | DIGIT num
31 shop : "<<"
32 | ">>"
33 eqlrel : "="
34 | "=="
35 | "!="
36 rel : "<" or <>, Pascal not-equal
37 | ">"
38 | "<=" or =<, for Prolog users.
39 | ">="
40
41 This expression evaluator was lifted from a public-domain
42 C Pre-Processor included with the DECUS C Compiler distribution.
43 It has been hacked somewhat to be suitable for m4.
44
45 26-Mar-1993 Changed to work in any of EBCDIC, ASCII, DEC MNCS,
46 or ISO 8859/n.
47
48 26-Mar-1993 Changed to use "long int" rather than int, so that
49 we get the same 32-bit arithmetic on a PC as on a Sun.
50 It isn't fully portable, of course, but then on a 64-
51 bit machine we _want_ 64-bit arithmetic...
52 Shifting rewritten (using LONG_BIT) to give signed
53 shifts even when (long) >> (long) is unsigned.
54
55 26-Mar-1993 I finally got sick of the fact that &&, ||, and ?:
56 don't do conditional evaluation. What is the good
57 of having eval(0&&(1/0)) crash and dump core? Now
58 every function has a doit? argument.
59
60 26-Mar-1993 charcon() didn't actually accept 'abcd', which it
61 should have. Fixed it.
62
63 20-Apr-1993 eval(1/0) and eval(1%0) dumped core and crashed.
64 This is also true of the System V r 3.2 m4, but
65 it isn't good enough for ours! Changed it so that
66 x % 0 => x as per Concrete Mathematics
67 x / 0 => error and return 0 from expr().
68 */
69
70 #ifndef lint
71 static char rcsid[] = "$Id: expr.c,v 1.3 1993/08/02 17:54:38 mycroft Exp $";
72 #endif /* not lint */
73
74 #define FALSE 0
75 #define TRUE 1
76
77 #include <stdio.h>
78 #include <setjmp.h>
79 static jmp_buf expjump; /* Error exit point for expr() */
80
81 static unsigned char *nxtchr; /* Parser scan pointer */
82
83 #define deblank0 while ((unsigned)(*nxtchr-1) < ' ') nxtchr++
84 #define deblank1 while ((unsigned)(*++nxtchr - 1) < ' ')
85 #define deblank2 nxtchr++; deblank1
86
87 #include "ourlims.h"
88 static char digval[1+UCHAR_MAX];
89
90 /* This file should work in any C implementation that doesn't have too
91 many characters to fit in one table. We use a table to convert
92 (unsigned) characters to numeric codes:
93 0 to 9 for '0' to '9'
94 10 to 35 for 'a' to 'z'
95 10 to 35 for 'A' to 'Z'
96 36 for '_'
97 Instead of asking whether tolower(c) == 'a' we ask whether
98 digval[c] == DIGIT_A, and so on. This essentially duplicates the
99 chtype[] table in main.c; we should use just one table.
100 */
101 #define DIGIT_A 10
102 #define DIGIT_B 11
103 #define DIGIT_C 12
104 #define DIGIT_D 13
105 #define DIGIT_E 14
106 #define DIGIT_F 15
107 #define DIGIT_G 16
108 #define DIGIT_H 17
109 #define DIGIT_I 18
110 #define DIGIT_J 19
111 #define DIGIT_K 20
112 #define DIGIT_L 21
113 #define DIGIT_M 22
114 #define DIGIT_N 23
115 #define DIGIT_O 24
116 #define DIGIT_P 25
117 #define DIGIT_Q 26
118 #define DIGIT_R 27
119 #define DIGIT_S 28
120 #define DIGIT_T 29
121 #define DIGIT_U 30
122 #define DIGIT_V 31
123 #define DIGIT_W 32
124 #define DIGIT_X 33
125 #define DIGIT_Y 34
126 #define DIGIT_Z 35
127
128
129 #ifdef __STDC__
130 static long int query(int);
131 #else
132 static long int query();
133 #endif
134
135
136 /* experr(msg)
137 prints an error message, resets environment to expr(), and
138 forces expr() to return FALSE.
139 */
140 void experr(msg)
141 char *msg;
142 {
143 (void) fprintf(stderr, "m4: %s\n", msg);
144 longjmp(expjump, -1); /* Force expr() to return FALSE */
145 }
146
147
148 /* <numcon> ::= '0x' <hex> | '0X' <hex> | '0' <oct> | <dec>
149 For ANSI C, an integer may be followed by u, l, ul, or lu,
150 in any mix of cases. We accept and ignore those letters;
151 all the numbers are treated as long.
152 */
153 static long int numcon(doit)
154 int doit;
155 {
156 register long int v; /* current value */
157 register int b; /* base (radix) */
158 register int c; /* character or digit value */
159
160 if (!doit) {
161 do nxtchr++; while (digval[*nxtchr] <= 36);
162 deblank0;
163 return 0;
164 }
165
166 v = digval[*nxtchr++]; /* We already know it's a digit */
167 if (v != 0) {
168 b = 10; /* decimal number */
169 } else
170 if (digval[*nxtchr] == DIGIT_X) {
171 nxtchr++;
172 b = 16; /* hexadecimal number */
173 } else {
174 b = 8; /* octal number */
175 }
176 do {
177 while (digval[c = *nxtchr++] < b) v = v*b + digval[c];
178 } while (c == '_');
179 while (digval[c] == DIGIT_L || digval[c] == DIGIT_U) c = *nxtchr++;
180 nxtchr--; /* unread c */
181 if ((unsigned)(c-1) < ' ') { deblank1; }
182 return v;
183 }
184
185
186 /* <charcon> ::= <qt> { <char> } <qt>
187 Note: multibyte constants are accepted.
188 Note: BEL (\a) and ESC (\e) have the same values in EBCDIC and ASCII.
189 */
190 static long int charcon(doit)
191 int doit;
192 {
193 register int i;
194 long int value;
195 register int c;
196 int q;
197 int v[sizeof value];
198
199 q = *nxtchr++; /* the quote character */
200 for (i = 0; ; i++) {
201 c = *nxtchr++;
202 if (c == q) { /* end of literal, or doubled quote */
203 if (*nxtchr != c) break;
204 nxtchr++; /* doubled quote stands for one quote */
205 }
206 if (i == sizeof value) experr("Unterminated character constant");
207 if (c == '\\') {
208 switch (c = *nxtchr++) {
209 case '0': case '1': case '2': case '3':
210 case '4': case '5': case '6': case '7':
211 c -= '0';
212 if ((unsigned)(*nxtchr - '0') < 8)
213 c = (c << 3) | (*nxtchr++ - '0');
214 if ((unsigned)(*nxtchr - '0') < 8)
215 c = (c << 3) | (*nxtchr++ - '0');
216 break;
217 case 'n': case 'N': c = '\n'; break;
218 case 'r': case 'R': c = '\r'; break;
219 case 't': case 'T': c = '\t'; break;
220 case 'b': case 'B': c = '\b'; break;
221 case 'f': case 'F': c = '\f'; break;
222 case 'a': case 'A': c = 007; break;
223 case 'e': case 'E': c = 033; break;
224 #if ' ' == 64
225 case 'd': case 'D': c = 045; break; /*EBCDIC DEL */
226 #else
227 case 'd': case 'D': c = 127; break; /* ASCII DEL */
228 #endif
229 default : break;
230 }
231 }
232 v[i] = c;
233 }
234 deblank0;
235 if (!doit) return 0;
236 for (value = 0; --i >= 0; ) value = (value << CHAR_BIT) | v[i];
237 return value;
238 }
239
240
241 /* <unary> ::= <unop> <unary> | <factor>
242 <unop> ::= '!' || '~' | '-'
243 <factor> ::= '(' <query> ')' | <'> <char> <'> | <"> <char> <"> | <num>
244 */
245 static long int unary(doit)
246 int doit;
247 {
248 long int v;
249
250 switch (nxtchr[0]) {
251 case 'n': case 'N':
252 if (digval[nxtchr[1]] != DIGIT_O
253 || digval[nxtchr[2]] != DIGIT_T)
254 experr("Bad 'not'");
255 nxtchr += 2;
256 case '!': deblank1; return !unary(doit);
257 case '~': deblank1; return ~unary(doit);
258 case '-': deblank1; return -unary(doit);
259 case '+': deblank1; return unary(doit);
260 case '(': deblank1; v = query(doit);
261 if (nxtchr[0] != ')') experr("Bad factor");
262 deblank1; return v;
263 case '\'':
264 case '\"': return charcon(doit);
265 case '0': case '1': case '2':
266 case '3': case '4': case '5':
267 case '6': case '7': case '8':
268 case '9': return numcon(doit);
269 default : experr("Bad constant");
270 }
271 return 0; /*NOTREACHED*/
272 }
273
274
275 /* <term> ::= <unary> { <mulop> <unary> }
276 <mulop> ::= '*' | '/' || '%'
277 */
278 static long int term(doit)
279 int doit;
280 {
281 register long int vl, vr;
282
283 vl = unary(doit);
284 for (;;)
285 switch (nxtchr[0]) {
286 case '*':
287 deblank1;
288 vr = unary(doit);
289 if (doit) vl *= vr;
290 break;
291 case 'd': case 'D':
292 if (digval[nxtchr[1]] != DIGIT_I
293 || digval[nxtchr[2]] != DIGIT_V)
294 experr("Bad 'div'");
295 nxtchr += 2;
296 /*FALLTHROUGH*/
297 case '/':
298 deblank1;
299 vr = unary(doit);
300 if (doit) {
301 if (vr == 0) experr("Division by 0");
302 vl /= vr;
303 }
304 break;
305 case 'm': case 'M':
306 if (digval[nxtchr[1]] != DIGIT_O
307 || digval[nxtchr[2]] != DIGIT_D)
308 experr("Bad 'mod'");
309 nxtchr += 2;
310 /*FALLTHROUGH*/
311 case '%':
312 deblank1;
313 vr = unary(doit);
314 if (doit) {
315 if (vr != 0) vl %= vr;
316 }
317 break;
318 default:
319 return vl;
320 }
321 /*NOTREACHED*/
322 }
323
324 /* <primary> ::= <term> { <addop> <term> }
325 <addop> ::= '+' | '-'
326 */
327 static long int primary(doit)
328 int doit;
329 {
330 register long int vl;
331
332 vl = term(doit);
333 for (;;)
334 if (nxtchr[0] == '+') {
335 deblank1;
336 if (doit) vl += term(doit); else (void)term(doit);
337 } else
338 if (nxtchr[0] == '-') {
339 deblank1;
340 if (doit) vl -= term(doit); else (void)term(doit);
341 } else
342 return vl;
343 /*NOTREACHED*/
344 }
345
346
347 /* <shift> ::= <primary> { <shop> <primary> }
348 <shop> ::= '<<' | '>>'
349 */
350 static long int shift(doit)
351 int doit;
352 {
353 register long int vl, vr;
354
355 vl = primary(doit);
356 for (;;) {
357 if (nxtchr[0] == '<' && nxtchr[1] == '<') {
358 deblank2;
359 vr = primary(doit);
360 } else
361 if (nxtchr[0] == '>' && nxtchr[1] == '>') {
362 deblank2;
363 vr = -primary(doit);
364 } else {
365 return vl;
366 }
367 /* The following code implements shifts portably */
368 /* Shifts are signed shifts, and the shift count */
369 /* acts like repeated one-bit shifts, not modulo anything */
370 if (doit) {
371 if (vr >= LONG_BIT) {
372 vl = 0;
373 } else
374 if (vr <= -LONG_BIT) {
375 vl = -(vl < 0);
376 } else
377 if (vr > 0) {
378 vl <<= vr;
379 } else
380 if (vr < 0) {
381 vl = (vl >> -vr) | (-(vl < 0) << (LONG_BIT + vr));
382 }
383 }
384 }
385 /*NOTREACHED*/
386 }
387
388
389 /* <relat> ::= <shift> { <rel> <shift> }
390 <rel> ::= '<=' | '>=' | '=<' | '=>' | '<' | '>'
391 Here I rely on the fact that '<<' and '>>' are swallowed by <shift>
392 */
393 static long int relat(doit)
394 int doit;
395 {
396 register long int vl;
397
398 vl = shift(doit);
399 for (;;)
400 switch (nxtchr[0]) {
401 case '=':
402 switch (nxtchr[1]) {
403 case '<': /* =<, take as <= */
404 deblank2;
405 vl = vl <= shift(doit);
406 break;
407 case '>': /* =>, take as >= */
408 deblank2;
409 vl = vl >= shift(doit);
410 break;
411 default: /* == or =; OOPS */
412 return vl;
413 }
414 break;
415 case '<':
416 if (nxtchr[1] == '=') { /* <= */
417 deblank2;
418 vl = vl <= shift(doit);
419 } else
420 if (nxtchr[1] == '>') { /* <> (Pascal) */
421 deblank2;
422 vl = vl != shift(doit);
423 } else { /* < */
424 deblank1;
425 vl = vl < shift(doit);
426 }
427 break;
428 case '>':
429 if (nxtchr[1] == '=') { /* >= */
430 deblank2;
431 vl = vl >= shift(doit);
432 } else { /* > */
433 deblank1;
434 vl = vl > shift(doit);
435 }
436 break;
437 default:
438 return vl;
439 }
440 /*NOTREACHED*/
441 }
442
443
444 /* <eql> ::= <relat> { <eqrel> <relat> }
445 <eqlrel> ::= '!=' | '==' | '='
446 */
447 static long int eql(doit)
448 int doit;
449 {
450 register long int vl;
451
452 vl = relat(doit);
453 for (;;)
454 if (nxtchr[0] == '!' && nxtchr[1] == '=') {
455 deblank2;
456 vl = vl != relat(doit);
457 } else
458 if (nxtchr[0] == '=' && nxtchr[1] == '=') {
459 deblank2;
460 vl = vl == relat(doit);
461 } else
462 if (nxtchr[0] == '=') {
463 deblank1;
464 vl = vl == relat(doit);
465 } else
466 return vl;
467 /*NOTREACHED*/
468 }
469
470
471 /* <band> ::= <eql> { '&' <eql> }
472 */
473 static long int band(doit)
474 int doit;
475 {
476 register long int vl;
477
478 vl = eql(doit);
479 while (nxtchr[0] == '&' && nxtchr[1] != '&') {
480 deblank1;
481 if (doit) vl &= eql(doit); else (void)eql(doit);
482 }
483 return vl;
484 }
485
486
487 /* <bxor> ::= <band> { '^' <band> }
488 */
489 static long int bxor(doit)
490 int doit;
491 {
492 register long int vl;
493
494 vl = band(doit);
495 while (nxtchr[0] == '^') {
496 deblank1;
497 if (doit) vl ^= band(doit); else (void)band(doit);
498 }
499 return vl;
500 }
501
502
503 /* <bor> ::= <bxor> { '|' <bxor> }
504 */
505 static long int bor(doit)
506 int doit;
507 {
508 register long int vl;
509
510 vl = bxor(doit);
511 while (nxtchr[0] == '|' && nxtchr[1] != '|') {
512 deblank1;
513 if (doit) vl |= bxor(doit); else (void)bxor(doit);
514 }
515 return vl;
516 }
517
518
519 /* <land> ::= <bor> { '&&' <bor> }
520 */
521 static long int land(doit)
522 int doit;
523 {
524 register long int vl;
525
526 vl = bor(doit);
527 for (;;) {
528 if (nxtchr[0] == '&') {
529 if (nxtchr[1] != '&') break;
530 deblank2;
531 } else
532 if (digval[nxtchr[0]] == DIGIT_A) {
533 if (digval[nxtchr[1]] != DIGIT_N) break;
534 if (digval[nxtchr[2]] != DIGIT_D) break;
535 nxtchr += 2; deblank1;
536 } else {
537 /* neither && nor and */
538 break;
539 }
540 vl = bor(doit && vl) != 0;
541 }
542 return vl;
543 }
544
545
546 /* <lor> ::= <land> { '||' <land> }
547 */
548 static long int lor(doit)
549 int doit;
550 {
551 register long int vl;
552
553 vl = land(doit);
554 for (;;) {
555 if (nxtchr[0] == '|') {
556 if (nxtchr[1] != '|') break;
557 } else
558 if (digval[nxtchr[0]] == DIGIT_O) {
559 if (digval[nxtchr[1]] != DIGIT_R) break;
560 } else {
561 /* neither || nor or */
562 break;
563 }
564 deblank2;
565 vl = land(doit && !vl) != 0;
566 }
567 return vl;
568 }
569
570
571 /* <query> ::= <lor> [ '?' <query> ':' <query> ]
572 */
573 static long int query(doit)
574 int doit;
575 {
576 register long int bool, true_val, false_val;
577
578 bool = lor(doit);
579 if (*nxtchr != '?') return bool;
580 deblank1;
581 true_val = query(doit && bool);
582 if (*nxtchr != ':') experr("Bad query");
583 deblank1;
584 false_val = query(doit && !bool);
585 return bool ? true_val : false_val;
586 }
587
588
589 static void initialise_digval()
590 {
591 register unsigned char *s;
592 register int c;
593
594 for (c = 0; c <= UCHAR_MAX; c++) digval[c] = 99;
595 for (c = 0, s = (unsigned char *)"0123456789";
596 /*while*/ *s;
597 /*doing*/ digval[*s++] = c++) /* skip */;
598 for (c = 10, s = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
599 /*while*/ *s;
600 /*doing*/ digval[*s++] = c++) /* skip */;
601 for (c = 10, s = (unsigned char *)"abcdefghijklmnopqrstuvwxyz";
602 /*while*/ *s;
603 /*doing*/ digval[*s++] = c++) /* skip */;
604 digval['_'] = 36;
605 }
606
607
608 long int expr(expbuf)
609 char *expbuf;
610 {
611 register int rval;
612
613 if (digval['1'] == 0) initialise_digval();
614 nxtchr = (unsigned char *)expbuf;
615 deblank0;
616 if (setjmp(expjump) != 0) return FALSE;
617 rval = query(TRUE);
618 if (*nxtchr) experr("Ill-formed expression");
619 return rval;
620 }
621
622