diff --git a/bin/expr/expr.y b/bin/expr/expr.y index f8af60039f93..35cdc3b9f8ff 100644 --- a/bin/expr/expr.y +++ b/bin/expr/expr.y @@ -2,22 +2,34 @@ /* Written by Pace Willisson (pace@blitz.com) * and placed in the public domain * - * $Header: /cvsroot/src/bin/expr/expr.y,v 1.3 1993/03/23 00:25:46 cgd Exp $ + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00092 + * -------------------- ----- ---------------------- + * + * 15 Mar 93 J.T. Conklin Added support for parens, string + * expressions that are numeric, and + * fixed division by zero. + * Enhanced performance and memory use. */ #include +#include +#include #include -char *malloc (); -char *calloc (); - +enum valtype { + integer, string +} ; + struct val { - char *sval; - int ival; - int iflag; + enum valtype type; + union { + char *s; + int i; + } u; }; struct val *result; - struct val *op_or (); struct val *op_and (); struct val *op_eq (); @@ -79,44 +91,112 @@ expr: TOKEN %% struct val * -make_val (sval) -char *sval; +make_integer (i) +int i; { struct val *vp; - char *p; - if ((vp = (struct val *)calloc (1, sizeof *vp)) == NULL - || (vp->sval = malloc (strlen (sval) + 1)) == NULL) { - fprintf (stderr, "out of memory\n"); + vp = malloc (sizeof (*vp)); + if (vp == NULL) { + fprintf (stderr, "expr: out of memory\n"); exit (2); } - strcpy (vp->sval, sval); - - p = sval; - - if (*p == '-') - p++; - while (isdigit (*p)) - p++; - if (*p == 0) { - vp->iflag = 1; - vp->ival = atoi (sval); - } - - return (vp); + vp->type = integer; + vp->u.i = i; + return vp; } struct val * -make_integer (ival) -int ival; +make_str (s) +char *s; { - char buf[25]; + struct val *vp; - sprintf (buf, "%d", ival); - return (make_val (buf)); + vp = malloc (sizeof (*vp)); + if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) { + fprintf (stderr, "expr: out of memory\n"); + exit (2); + } + + vp->type = string; + return vp; } + +void +free_value (vp) +struct val *vp; +{ + if (vp->type == string) + free (vp->u.s); +} + + +int +to_integer (vp) +struct val *vp; +{ + char *s; + int neg; + int i; + + if (vp->type == integer) + return 1; + + s = vp->u.s; + i = 0; + + neg = (*s == '-'); + if (neg) + s++; + + for (;*s; s++) { + if (!isdigit (*s)) + return 0; + + i *= 10; + i += *s - '0'; + } + + free (vp->u.s); + if (neg) + i *= -1; + + vp->type = integer; + vp->u.i = i; + return 1; +} + +void +to_string (vp) +struct val *vp; +{ + char *tmp; + + if (vp->type == string) + return; + + tmp = malloc (25); + if (tmp == NULL) { + fprintf (stderr, "expr: out of memory\n"); + exit (2); + } + + sprintf (tmp, "%d", vp->u.i); + vp->type = string; + vp->u.s = tmp; +} + + +int +isstring (vp) +struct val *vp; +{ + return (vp->type == string); +} + + int yylex () { @@ -129,7 +209,7 @@ yylex () p = *av++; if (strlen (p) == 1) { - if (strchr ("|&=<>+-*/%:", *p)) + if (strchr ("|&=<>+-*/%:()", *p)) return (*p); } else if (strlen (p) == 2 && p[1] == '=') { switch (*p) { @@ -139,7 +219,7 @@ yylex () } } - yylval.val = make_val (p); + yylval.val = make_str (p); return (TOKEN); } @@ -147,11 +227,13 @@ int is_zero_or_null (vp) struct val *vp; { - if (vp->iflag && vp->ival == 0) - return (1); - - if (*vp->sval == 0) - return (1); + if (vp->type == integer) { + if (vp->u.i == 0) + return (1); + } else { + if (*vp->u.s == 0) + return (1); + } return (0); } @@ -165,10 +247,10 @@ char **argv; yyparse (); - if (result->iflag) - printf ("%d\n", result->ival); + if (result->type == integer) + printf ("%d\n", result->u.i); else - printf ("%s\n", result->sval); + printf ("%s\n", result->u.s); if (is_zero_or_null (result)) exit (1); @@ -180,143 +262,281 @@ int yyerror (s) char *s; { - fprintf (stderr, "syntax error\n"); + fprintf (stderr, "expr: syntax error\n"); exit (2); } -void -check_integers (a, b) -struct val *a, *b; -{ - if (!a->iflag || !b->iflag) { - fprintf (stderr, "expr: non-numeric argument\n"); - exit (2); - } -} struct val * op_or (a, b) struct val *a, *b; { - if (is_zero_or_null (a)) + if (is_zero_or_null (a)) { + free_value (a); return (b); - else + } else { + free_value (b); return (a); + } } struct val * op_and (a, b) struct val *a, *b; { - if (is_zero_or_null (a) || is_zero_or_null (b)) + if (is_zero_or_null (a) || is_zero_or_null (b)) { + free_value (a); + free_value (b); return (make_integer (0)); - else + } else { + free_value (b); return (a); + } } struct val * op_eq (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival == b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) == 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) == 0); + } else { + r = make_integer (a->u.i == b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_gt (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival > b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) > 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) > 0); + } else { + r= make_integer (a->u.i > b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_lt (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival < b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) < 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) < 0); + } else { + r = make_integer (a->u.i < b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_ge (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival >= b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) >= 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) >= 0); + } else { + r = make_integer (a->u.i >= b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_le (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival <= b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) <= 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) <= 0); + } else { + r = make_integer (a->u.i <= b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_ne (a, b) struct val *a, *b; { - if (a->iflag && b->iflag) - return (make_integer (a->ival != b->ival)); - else - return (make_integer (strcmp (a->sval, b->sval) != 0)); + struct val *r; + + /* attempt to coerce both arguments to integers */ + (void) to_integer (a); + (void) to_integer (b); + + /* But if either one of them really is a string, do + a string comparison */ + if (isstring (a) || isstring (b)) { + to_string (a); + to_string (b); + r = make_integer (strcmp (a->u.s, b->u.s) != 0); + } else { + r = make_integer (a->u.i != b->u.i); + } + + free_value (a); + free_value (b); + return r; } struct val * op_plus (a, b) struct val *a, *b; { - check_integers (a, b); + struct val *r; - return (make_integer (a->ival + b->ival)); + if (!to_integer (a) || !to_integer (b)) { + fprintf (stderr, "expr: non-numeric argument\n"); + exit (2); + } + + r = make_integer (a->u.i + b->u.i); + free_value (a); + free_value (b); + return r; } struct val * op_minus (a, b) struct val *a, *b; { - check_integers (a, b); + struct val *r; - return (make_integer (a->ival - b->ival)); + if (!to_integer (a) || !to_integer (b)) { + fprintf (stderr, "expr: non-numeric argument\n"); + exit (2); + } + + r = make_integer (a->u.i - b->u.i); + free_value (a); + free_value (b); + return r; } struct val * op_times (a, b) struct val *a, *b; { - check_integers (a, b); + struct val *r; - return (make_integer (a->ival * b->ival)); + if (!to_integer (a) || !to_integer (b)) { + fprintf (stderr, "expr: non-numeric argument\n"); + exit (2); + } + + r = make_integer (a->u.i * b->u.i); + free_value (a); + free_value (b); + return (r); } struct val * op_div (a, b) struct val *a, *b; { - check_integers (a, b); + struct val *r; - return (make_integer (a->ival / b->ival)); + if (!to_integer (a) || !to_integer (b)) { + fprintf (stderr, "expr: non-numeric argument\n"); + exit (2); + } + + if (b->u.i == 0) { + fprintf (stderr, "expr: division by zero\n"); + exit (2); + } + + r = make_integer (a->u.i / b->u.i); + free_value (a); + free_value (b); + return r; } struct val * op_rem (a, b) struct val *a, *b; { - check_integers (a, b); + struct val *r; - return (make_integer (a->ival % b->ival)); + if (!to_integer (a) || !to_integer (b)) { + fprintf (stderr, "expr: non-numeric argument\n"); + exit (2); + } + + if (b->u.i == 0) { + fprintf (stderr, "expr: division by zero\n"); + exit (2); + } + + r = make_integer (a->u.i % b->u.i); + free_value (a); + free_value (b); + return r; } #include @@ -330,8 +550,8 @@ struct val *a, *b; char *p; char *q; - newexp = malloc (3 * strlen (b->sval)); - p = b->sval; + newexp = malloc (3 * strlen (b->u.s)); + p = b->u.s; q = newexp; *q++ = '^'; @@ -356,10 +576,10 @@ struct val *a, *b; if ((rp = regcomp (newexp)) == NULL) yyerror ("invalid regular expression"); - if (regexec (rp, a->sval)) { + if (regexec (rp, a->u.s)) { if (rp->startp[1]) { rp->endp[1][0] = 0; - return (make_val (rp->startp[1])); + return (make_str (rp->startp[1])); } else { return (make_integer (rp->endp[0] - rp->startp[0])); }