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