source: trunk/minix/commands/m4/expr.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.9 KB
Line 
1/*
2 * expression evaluator: performs a standard recursive
3 * descent parse to evaluate any expression permissible
4 * within the following grammar:
5 *
6 * expr : query EOS
7 * query : lor
8 * | lor "?" query ":" query
9 * lor : land { "||" land }
10 * land : bor { "&&" bor }
11 * bor : bxor { "|" bxor }
12 * bxor : band { "^" band }
13 * band : eql { "&" eql }
14 * eql : relat { eqrel relat }
15 * relat : shift { rel shift }
16 * shift : primary { shop primary }
17 * primary : term { addop term }
18 * term : unary { mulop unary }
19 * unary : factor
20 * | unop unary
21 * factor : constant
22 * | "(" query ")"
23 * constant: num
24 * | "'" CHAR "'"
25 * num : decnum
26 * | "0" octnum
27 * | "0x" hexnum
28 * octnum : OCTDIGIT
29 * | OCTDIGIT octnum
30 * decnum : DECDIGIT
31 * | DECDIGIT decnum
32 * hexnum : HEXDIGIT
33 * | HEXDIGIT hexnum
34 * shop : "<<"
35 * | ">>"
36 * eqlrel : "="
37 * | "=="
38 * | "!="
39 * rel : "<"
40 * | ">"
41 * | "<="
42 * | ">="
43 *
44 *
45 * This expression evaluator is lifted from a public-domain
46 * C Pre-Processor included with the DECUS C Compiler distribution.
47 * It is hacked somewhat to be suitable for m4.
48 *
49 * Originally by: Mike Lutz
50 * Bob Harper
51 */
52
53#include "mdef.h"
54
55#define TRUE 1
56#define FALSE 0
57#define EOS (char) 0
58#define EQL 0
59#define NEQ 1
60#define LSS 2
61#define LEQ 3
62#define GTR 4
63#define GEQ 5
64
65static char *nxtch; /* Parser scan pointer */
66
67/*
68 * For longjmp
69 */
70#include <setjmp.h>
71static jmp_buf expjump;
72
73/*
74 * macros:
75 *
76 * ungetch - Put back the last character examined.
77 * getch - return the next character from expr string.
78 */
79#define ungetch() nxtch--
80#define getch() *nxtch++
81
82int expr(expbuf)
83char *expbuf;
84{
85 register int rval;
86
87 nxtch = expbuf;
88 if (setjmp(expjump) != 0)
89 return (FALSE);
90 rval = query();
91 if (skipws() == EOS)
92 return(rval);
93 experr("Ill-formed expression");
94 /* NOTREACHED */
95 return(0);
96}
97
98/*
99 * query : lor | lor '?' query ':' query
100 *
101 */
102int query()
103{
104 register int bool, true_val, false_val;
105
106 bool = lor();
107 if (skipws() != '?') {
108 ungetch();
109 return(bool);
110 }
111
112 true_val = query();
113 if (skipws() != ':')
114 experr("Bad query");
115
116 false_val = query();
117 return(bool ? true_val : false_val);
118}
119
120/*
121 * lor : land { '||' land }
122 *
123 */
124int lor()
125{
126 register int c, vl, vr;
127
128 vl = land();
129 while ((c = skipws()) == '|' && getch() == '|') {
130 vr = land();
131 vl = vl || vr;
132 }
133
134 if (c == '|')
135 ungetch();
136 ungetch();
137 return(vl);
138}
139
140/*
141 * land : bor { '&&' bor }
142 *
143 */
144int land()
145{
146 register int c, vl, vr;
147
148 vl = bor();
149 while ((c = skipws()) == '&' && getch() == '&') {
150 vr = bor();
151 vl = vl && vr;
152 }
153
154 if (c == '&')
155 ungetch();
156 ungetch();
157 return(vl);
158}
159
160/*
161 * bor : bxor { '|' bxor }
162 *
163 */
164int bor()
165{
166 register int vl, vr, c;
167
168 vl = bxor();
169 while ((c = skipws()) == '|' && getch() != '|') {
170 ungetch();
171 vr = bxor();
172 vl |= vr;
173 }
174
175 if (c == '|')
176 ungetch();
177 ungetch();
178 return(vl);
179}
180
181/*
182 * bxor : band { '^' band }
183 *
184 */
185int bxor()
186{
187 register int vl, vr;
188
189 vl = band();
190 while (skipws() == '^') {
191 vr = band();
192 vl ^= vr;
193 }
194
195 ungetch();
196 return(vl);
197}
198
199/*
200 * band : eql { '&' eql }
201 *
202 */
203int band()
204{
205 register int vl, vr, c;
206
207 vl = eql();
208 while ((c = skipws()) == '&' && getch() != '&') {
209 ungetch();
210 vr = eql();
211 vl &= vr;
212 }
213
214 if (c == '&')
215 ungetch();
216 ungetch();
217 return(vl);
218}
219
220/*
221 * eql : relat { eqrel relat }
222 *
223 */
224int eql()
225{
226 register int vl, vr, rel;
227
228 vl = relat();
229 while ((rel = geteql()) != -1) {
230 vr = relat();
231
232 switch (rel) {
233
234 case EQL:
235 vl = (vl == vr);
236 break;
237 case NEQ:
238 vl = (vl != vr);
239 break;
240 }
241 }
242 return(vl);
243}
244
245/*
246 * relat : shift { rel shift }
247 *
248 */
249int relat()
250{
251 register int vl, vr, rel;
252
253 vl = shift();
254 while ((rel = getrel()) != -1) {
255
256 vr = shift();
257 switch (rel) {
258
259 case LEQ:
260 vl = (vl <= vr);
261 break;
262 case LSS:
263 vl = (vl < vr);
264 break;
265 case GTR:
266 vl = (vl > vr);
267 break;
268 case GEQ:
269 vl = (vl >= vr);
270 break;
271 }
272 }
273 return(vl);
274}
275
276/*
277 * shift : primary { shop primary }
278 *
279 */
280int shift()
281{
282 register int vl, vr, c;
283
284 vl = primary();
285 while (((c = skipws()) == '<' || c == '>') && c == getch()) {
286 vr = primary();
287
288 if (c == '<')
289 vl <<= vr;
290 else
291 vl >>= vr;
292 }
293
294 if (c == '<' || c == '>')
295 ungetch();
296 ungetch();
297 return(vl);
298}
299
300/*
301 * primary : term { addop term }
302 *
303 */
304int primary()
305{
306 register int c, vl, vr;
307
308 vl = term();
309 while ((c = skipws()) == '+' || c == '-') {
310 vr = term();
311 if (c == '+')
312 vl += vr;
313 else
314 vl -= vr;
315 }
316
317 ungetch();
318 return(vl);
319}
320
321/*
322 * <term> := <unary> { <mulop> <unary> }
323 *
324 */
325int term()
326{
327 register int c, vl, vr;
328
329 vl = unary();
330 while ((c = skipws()) == '*' || c == '/' || c == '%') {
331 vr = unary();
332
333 switch (c) {
334 case '*':
335 vl *= vr;
336 break;
337 case '/':
338 vl /= vr;
339 break;
340 case '%':
341 vl %= vr;
342 break;
343 }
344 }
345 ungetch();
346 return(vl);
347}
348
349/*
350 * unary : factor | unop unary
351 *
352 */
353int unary()
354{
355 register int val, c;
356
357 if ((c = skipws()) == '!' || c == '~' || c == '-') {
358 val = unary();
359
360 switch (c) {
361 case '!':
362 return(! val);
363 case '~':
364 return(~ val);
365 case '-':
366 return(- val);
367 }
368 }
369
370 ungetch();
371 return(factor());
372}
373
374/*
375 * factor : constant | '(' query ')'
376 *
377 */
378int factor()
379{
380 register int val;
381
382 if (skipws() == '(') {
383 val = query();
384 if (skipws() != ')')
385 experr("Bad factor");
386 return(val);
387 }
388
389 ungetch();
390 return(constant());
391}
392
393/*
394 * constant: num | 'char'
395 *
396 */
397int constant()
398{
399 /*
400 * Note: constant() handles multi-byte constants
401 */
402
403 register int i;
404 register int value;
405 register char c;
406 int v[sizeof (int)];
407
408 if (skipws() != '\'') {
409 ungetch();
410 return(num());
411 }
412 for (i = 0; i < sizeof(int); i++) {
413 if ((c = getch()) == '\'') {
414 ungetch();
415 break;
416 }
417 if (c == '\\') {
418 switch (c = getch()) {
419 case '0':
420 case '1':
421 case '2':
422 case '3':
423 case '4':
424 case '5':
425 case '6':
426 case '7':
427 ungetch();
428 c = num();
429 break;
430 case 'n':
431 c = 012;
432 break;
433 case 'r':
434 c = 015;
435 break;
436 case 't':
437 c = 011;
438 break;
439 case 'b':
440 c = 010;
441 break;
442 case 'f':
443 c = 014;
444 break;
445 }
446 }
447 v[i] = c;
448 }
449 if (i == 0 || getch() != '\'')
450 experr("Illegal character constant");
451 for (value = 0; --i >= 0;) {
452 value <<= 8;
453 value += v[i];
454 }
455 return(value);
456}
457
458/*
459 * num : digit | num digit
460 *
461 */
462int num()
463{
464 register int rval, c, base;
465 int ndig;
466
467 ndig = 0;
468 if ((c = skipws()) == '0') {
469 c = getch ();
470 if (c == 'x' || c == 'X') {
471 base = 16;
472 c = getch ();
473 } else {
474 base = 8;
475 ndig = 1;
476 }
477 } else {
478 base = 10;
479 }
480 rval = 0;
481 for (;;) {
482 if (isdigit(c)) c -= '0';
483 else if (isupper (c)) c -= ('A' - 10);
484 else if (islower (c)) c -= ('a' - 10);
485 else break;
486 if (c < 0 || c >= base)
487 break;
488
489 rval *= base;
490 rval += c;
491 c = getch();
492 ndig++;
493 }
494 ungetch();
495 if (ndig)
496 return(rval);
497 experr("Bad constant");
498 /* NOTREACHED */
499 return(0);
500}
501
502/*
503 * eqlrel : '=' | '==' | '!='
504 *
505 */
506int geteql()
507{
508 register int c1, c2;
509
510 c1 = skipws();
511 c2 = getch();
512
513 switch (c1) {
514
515 case '=':
516 if (c2 != '=')
517 ungetch();
518 return(EQL);
519
520 case '!':
521 if (c2 == '=')
522 return(NEQ);
523 ungetch();
524 ungetch();
525 return(-1);
526
527 default:
528 ungetch();
529 ungetch();
530 return(-1);
531 }
532}
533
534/*
535 * rel : '<' | '>' | '<=' | '>='
536 *
537 */
538int getrel()
539{
540 register int c1, c2;
541
542 c1 = skipws();
543 c2 = getch();
544
545 switch (c1) {
546
547 case '<':
548 if (c2 == '=')
549 return(LEQ);
550 ungetch();
551 return(LSS);
552
553 case '>':
554 if (c2 == '=')
555 return(GEQ);
556 ungetch();
557 return(GTR);
558
559 default:
560 ungetch();
561 ungetch();
562 return(-1);
563 }
564}
565
566/*
567 * Skip over any white space and return terminating char.
568 */
569int skipws()
570{
571 register char c;
572
573 while ((c = getch()) <= ' ' && c > EOS)
574 ;
575 return(c);
576}
577
578/*
579 * Error handler - resets environment to eval(), prints an error,
580 * and returns FALSE.
581 */
582int experr(msg)
583char *msg;
584{
585 printf("mp: %s\n",msg);
586 longjmp(expjump, -1); /* Force eval() to return FALSE */
587}
Note: See TracBrowser for help on using the repository browser.