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