3 * Written by Pace Willisson (pace@blitz.com)
4 * and placed in the public domain.
6 * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
11 #include <sys/types.h>
26 * POSIX specifies a specific error code for syntax errors. We exit
27 * with this code for all errors.
32 integer, numeric_string, string
45 int chk_div(intmax_t, intmax_t);
46 int chk_minus(intmax_t, intmax_t, intmax_t);
47 int chk_plus(intmax_t, intmax_t, intmax_t);
48 int chk_times(intmax_t, intmax_t, intmax_t);
49 void free_value(struct val *);
50 int is_zero_or_null(struct val *);
51 int isstring(struct val *);
52 struct val *make_integer(intmax_t);
53 struct val *make_str(const char *);
54 struct val *op_and(struct val *, struct val *);
55 struct val *op_colon(struct val *, struct val *);
56 struct val *op_div(struct val *, struct val *);
57 struct val *op_eq(struct val *, struct val *);
58 struct val *op_ge(struct val *, struct val *);
59 struct val *op_gt(struct val *, struct val *);
60 struct val *op_le(struct val *, struct val *);
61 struct val *op_lt(struct val *, struct val *);
62 struct val *op_minus(struct val *, struct val *);
63 struct val *op_ne(struct val *, struct val *);
64 struct val *op_or(struct val *, struct val *);
65 struct val *op_plus(struct val *, struct val *);
66 struct val *op_rem(struct val *, struct val *);
67 struct val *op_times(struct val *, struct val *);
68 intmax_t to_integer(struct val *);
69 void to_string(struct val *);
70 int yyerror(const char *);
85 %left <val> '=' '>' '<' GE LE NE
87 %left <val> '*' '/' '%'
91 %type <val> start expr
95 start: expr { result = $$; }
98 | '(' expr ')' { $$ = $2; }
99 | expr '|' expr { $$ = op_or ($1, $3); }
100 | expr '&' expr { $$ = op_and ($1, $3); }
101 | expr '=' expr { $$ = op_eq ($1, $3); }
102 | expr '>' expr { $$ = op_gt ($1, $3); }
103 | expr '<' expr { $$ = op_lt ($1, $3); }
104 | expr GE expr { $$ = op_ge ($1, $3); }
105 | expr LE expr { $$ = op_le ($1, $3); }
106 | expr NE expr { $$ = op_ne ($1, $3); }
107 | expr '+' expr { $$ = op_plus ($1, $3); }
108 | expr '-' expr { $$ = op_minus ($1, $3); }
109 | expr '*' expr { $$ = op_times ($1, $3); }
110 | expr '/' expr { $$ = op_div ($1, $3); }
111 | expr '%' expr { $$ = op_rem ($1, $3); }
112 | expr ':' expr { $$ = op_colon ($1, $3); }
119 make_integer(intmax_t i)
123 vp = (struct val *) malloc (sizeof (*vp));
125 errx(ERR_EXIT, "malloc() failed");
134 make_str(const char *s)
139 vp = (struct val *) malloc (sizeof (*vp));
140 if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
141 errx(ERR_EXIT, "malloc() failed");
145 * Previously we tried to scan the string to see if it ``looked like''
146 * an integer (erroneously, as it happened). Let strtoimax() do the
147 * dirty work. We could cache the value, except that we are using
148 * a union and need to preserve the original string form until we
149 * are certain that it is not needed.
151 * IEEE Std.1003.1-2001 says:
152 * /integer/ An argument consisting only of an (optional) unary minus
153 * followed by digits.
155 * This means that arguments which consist of digits followed by
156 * non-digits MUST NOT be considered integers. strtoimax() will
157 * figure this out for us.
160 (void)strtoimax(s, &ep, 10);
162 (void)strtol(s, &ep, 10);
167 vp->type = numeric_string;
174 free_value(struct val *vp)
176 if (vp->type == string || vp->type == numeric_string)
182 to_integer(struct val *vp)
186 if (vp->type == integer)
189 if (vp->type == string)
192 /* vp->type == numeric_string, make it numeric */
195 i = strtoimax(vp->u.s, (char **)NULL, 10);
199 i = strtol(vp->u.s, (char **)NULL, 10);
209 to_string(struct val *vp)
213 if (vp->type == string || vp->type == numeric_string)
217 * log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number
218 * of digits; add one each for the sign and terminating null
219 * character, respectively.
221 #define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
222 tmp = malloc(NDIGITS(vp->u.i));
224 errx(ERR_EXIT, "malloc() failed");
226 sprintf(tmp, "%jd", vp->u.i);
233 isstring(struct val *vp)
235 /* only TRUE if this string is not a valid integer */
236 return (vp->type == string);
250 if (strlen (p) == 1) {
251 if (strchr ("|&=<>+-*/%:()", *p))
253 } else if (strlen (p) == 2 && p[1] == '=') {
255 case '>': return (GE);
256 case '<': return (LE);
257 case '!': return (NE);
261 yylval.val = make_str (p);
266 is_zero_or_null(struct val *vp)
268 if (vp->type == integer) {
269 return (vp->u.i == 0);
271 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
277 main(int argc, char *argv[])
281 setlocale (LC_ALL, "");
282 if (getenv("EXPR_COMPAT") != NULL
283 || check_utility_compat("expr")) {
287 while ((c = getopt(argc, argv, "e")) != -1)
295 "usage: expr [-e] expression\n");
303 if (result->type == integer)
304 printf("%jd\n", result->u.i);
306 printf("%s\n", result->u.s);
308 return (is_zero_or_null(result));
312 yyerror(const char *s __unused)
314 errx(ERR_EXIT, "syntax error");
319 op_or(struct val *a, struct val *b)
321 if (is_zero_or_null (a)) {
331 op_and(struct val *a, struct val *b)
333 if (is_zero_or_null (a) || is_zero_or_null (b)) {
336 return (make_integer ((intmax_t)0));
344 op_eq(struct val *a, struct val *b)
348 if (isstring (a) || isstring (b)) {
351 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) == 0));
355 r = make_integer ((intmax_t)(a->u.i == b->u.i));
364 op_gt(struct val *a, struct val *b)
368 if (isstring (a) || isstring (b)) {
371 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) > 0));
375 r = make_integer ((intmax_t)(a->u.i > b->u.i));
384 op_lt(struct val *a, struct val *b)
388 if (isstring (a) || isstring (b)) {
391 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) < 0));
395 r = make_integer ((intmax_t)(a->u.i < b->u.i));
404 op_ge(struct val *a, struct val *b)
408 if (isstring (a) || isstring (b)) {
411 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) >= 0));
415 r = make_integer ((intmax_t)(a->u.i >= b->u.i));
424 op_le(struct val *a, struct val *b)
428 if (isstring (a) || isstring (b)) {
431 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) <= 0));
435 r = make_integer ((intmax_t)(a->u.i <= b->u.i));
444 op_ne(struct val *a, struct val *b)
448 if (isstring (a) || isstring (b)) {
451 r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) != 0));
455 r = make_integer ((intmax_t)(a->u.i != b->u.i));
464 chk_plus(intmax_t a, intmax_t b, intmax_t r)
467 /* sum of two positive numbers must be positive */
468 if (a > 0 && b > 0 && r <= 0)
470 /* sum of two negative numbers must be negative */
471 if (a < 0 && b < 0 && r >= 0)
473 /* all other cases are OK */
478 op_plus(struct val *a, struct val *b)
482 if (!to_integer(a) || !to_integer(b)) {
483 errx(ERR_EXIT, "non-numeric argument");
487 r = make_integer(a->u.i + b->u.i);
488 if (chk_plus(a->u.i, b->u.i, r->u.i)) {
489 errx(ERR_EXIT, "overflow");
492 r = make_integer((long)a->u.i + (long)b->u.i);
500 chk_minus(intmax_t a, intmax_t b, intmax_t r)
503 /* special case subtraction of INTMAX_MIN */
504 if (b == INTMAX_MIN) {
510 /* this is allowed for b != INTMAX_MIN */
511 return chk_plus (a, -b, r);
515 op_minus(struct val *a, struct val *b)
519 if (!to_integer(a) || !to_integer(b)) {
520 errx(ERR_EXIT, "non-numeric argument");
524 r = make_integer(a->u.i - b->u.i);
525 if (chk_minus(a->u.i, b->u.i, r->u.i)) {
526 errx(ERR_EXIT, "overflow");
529 r = make_integer((long)a->u.i - (long)b->u.i);
537 chk_times(intmax_t a, intmax_t b, intmax_t r)
539 /* special case: first operand is 0, no overflow possible */
542 /* verify that result of division matches second operand */
549 op_times(struct val *a, struct val *b)
553 if (!to_integer(a) || !to_integer(b)) {
554 errx(ERR_EXIT, "non-numeric argument");
558 r = make_integer(a->u.i * b->u.i);
559 if (chk_times(a->u.i, b->u.i, r->u.i)) {
560 errx(ERR_EXIT, "overflow");
563 r = make_integer((long)a->u.i * (long)b->u.i);
571 chk_div(intmax_t a, intmax_t b)
573 /* div by zero has been taken care of before */
574 /* only INTMAX_MIN / -1 causes overflow */
575 if (a == INTMAX_MIN && b == -1)
577 /* everything else is OK */
582 op_div(struct val *a, struct val *b)
586 if (!to_integer(a) || !to_integer(b)) {
587 errx(ERR_EXIT, "non-numeric argument");
591 errx(ERR_EXIT, "division by zero");
595 r = make_integer(a->u.i / b->u.i);
596 if (chk_div(a->u.i, b->u.i)) {
597 errx(ERR_EXIT, "overflow");
600 r = make_integer((long)a->u.i / (long)b->u.i);
608 op_rem(struct val *a, struct val *b)
612 if (!to_integer(a) || !to_integer(b)) {
613 errx(ERR_EXIT, "non-numeric argument");
617 errx(ERR_EXIT, "division by zero");
621 r = make_integer(a->u.i % b->u.i);
622 /* chk_rem necessary ??? */
624 r = make_integer((long)a->u.i % (long)b->u.i);
632 op_colon(struct val *a, struct val *b)
640 /* coerce both arguments to strings */
644 /* compile regular expression */
645 if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
646 regerror (eval, &rp, errbuf, sizeof(errbuf));
647 errx(ERR_EXIT, "%s", errbuf);
650 /* compare string against pattern */
651 /* remember that patterns are anchored to the beginning of the line */
652 if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
653 if (rm[1].rm_so >= 0) {
654 *(a->u.s + rm[1].rm_eo) = '\0';
655 v = make_str (a->u.s + rm[1].rm_so);
658 v = make_integer ((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
661 if (rp.re_nsub == 0) {
662 v = make_integer ((intmax_t)0);
668 /* free arguments and pattern buffer */