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