xref: /dragonfly/bin/expr/expr.y (revision d50f9ae3448247db98eb135b85b2a32e6e4187f4)
1 %{
2 /* Written by Pace Willisson (pace@blitz.com)
3  * and placed in the public domain.
4  *
5  * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6  *
7  * $FreeBSD: src/bin/expr/expr.y,v 1.14.2.3 2001/08/01 02:37:46 obrien Exp $
8  */
9 
10 #include <sys/types.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15 #include <ctype.h>
16 #include <err.h>
17 #include <errno.h>
18 #include <regex.h>
19 #include <limits.h>
20 
21 #define   yylex     expr_yylex
22 
23 enum valtype {
24           integer, numeric_string, string
25 } ;
26 
27 struct val {
28           enum valtype type;
29           union {
30                     char *s;
31                     quad_t i;
32           } u;
33 } ;
34 
35 static struct val *result;
36 
37 int                 chk_div (quad_t, quad_t);
38 int                 chk_minus (quad_t, quad_t, quad_t);
39 int                 chk_plus (quad_t, quad_t, quad_t);
40 int                 chk_times (quad_t, quad_t, quad_t);
41 void                free_value (struct val *);
42 int                 is_zero_or_null (struct val *);
43 int                 isstring (struct val *);
44 int                 main (int, char **);
45 struct val          *make_integer (quad_t);
46 struct val          *make_str (const char *);
47 struct val          *op_and (struct val *, struct val *);
48 struct val          *op_colon (struct val *, struct val *);
49 struct val          *op_div (struct val *, struct val *);
50 struct val          *op_eq (struct val *, struct val *);
51 struct val          *op_ge (struct val *, struct val *);
52 struct val          *op_gt (struct val *, struct val *);
53 struct val          *op_le (struct val *, struct val *);
54 struct val          *op_lt (struct val *, struct val *);
55 struct val          *op_minus (struct val *, struct val *);
56 struct val          *op_ne (struct val *, struct val *);
57 struct val          *op_or (struct val *, struct val *);
58 struct val          *op_plus (struct val *, struct val *);
59 struct val          *op_rem (struct val *, struct val *);
60 struct val          *op_times (struct val *, struct val *);
61 quad_t              to_integer (struct val *);
62 void                to_string (struct val *);
63 int                 yyerror (const char *) __dead2;
64 static int          yylex (void);
65 
66 static char **av;
67 %}
68 
69 %union
70 {
71           struct val *val;
72 }
73 
74 %left <val> '|'
75 %left <val> '&'
76 %left <val> '=' '>' '<' GE LE NE
77 %left <val> '+' '-'
78 %left <val> '*' '/' '%'
79 %left <val> ':'
80 
81 %token <val> TOKEN
82 %type <val> start expr
83 
84 %%
85 
86 start: expr { result = $$; }
87 
88 expr:     TOKEN
89           | '(' expr ')' { $$ = $2; }
90           | expr '|' expr { $$ = op_or ($1, $3); }
91           | expr '&' expr { $$ = op_and ($1, $3); }
92           | expr '=' expr { $$ = op_eq ($1, $3); }
93           | expr '>' expr { $$ = op_gt ($1, $3); }
94           | expr '<' expr { $$ = op_lt ($1, $3); }
95           | expr GE expr  { $$ = op_ge ($1, $3); }
96           | expr LE expr  { $$ = op_le ($1, $3); }
97           | expr NE expr  { $$ = op_ne ($1, $3); }
98           | expr '+' expr { $$ = op_plus ($1, $3); }
99           | expr '-' expr { $$ = op_minus ($1, $3); }
100           | expr '*' expr { $$ = op_times ($1, $3); }
101           | expr '/' expr { $$ = op_div ($1, $3); }
102           | expr '%' expr { $$ = op_rem ($1, $3); }
103           | expr ':' expr { $$ = op_colon ($1, $3); }
104           ;
105 
106 
107 %%
108 
109 struct val *
110 make_integer(quad_t i)
111 {
112           struct val *vp;
113 
114           vp = (struct val *) malloc (sizeof (*vp));
115           if (vp == NULL) {
116                     errx (2, "malloc() failed");
117           }
118 
119           vp->type = integer;
120           vp->u.i  = i;
121           return vp;
122 }
123 
124 struct val *
make_str(const char * s)125 make_str(const char *s)
126 {
127           struct val *vp;
128           size_t i;
129           int isint;
130 
131           vp = (struct val *) malloc (sizeof (*vp));
132           if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
133                     errx (2, "malloc() failed");
134           }
135 
136           for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
137               isint && i < strlen(s);
138               i++)
139           {
140                     if(!isdigit(s[i]))
141                                isint = 0;
142           }
143 
144           if (isint)
145                     vp->type = numeric_string;
146           else
147                     vp->type = string;
148 
149           return vp;
150 }
151 
152 
153 void
free_value(struct val * vp)154 free_value(struct val *vp)
155 {
156           if (vp->type == string || vp->type == numeric_string)
157                     free (vp->u.s);
158 }
159 
160 
161 quad_t
to_integer(struct val * vp)162 to_integer(struct val *vp)
163 {
164           quad_t i;
165 
166           if (vp->type == integer)
167                     return 1;
168 
169           if (vp->type == string)
170                     return 0;
171 
172           /* vp->type == numeric_string, make it numeric */
173           errno = 0;
174           i  = strtoll(vp->u.s, NULL, 10);
175           if (errno != 0) {
176                     errx (2, "overflow");
177           }
178           free (vp->u.s);
179           vp->u.i = i;
180           vp->type = integer;
181           return 1;
182 }
183 
184 void
to_string(struct val * vp)185 to_string(struct val *vp)
186 {
187           char *tmp;
188 
189           if (vp->type == string || vp->type == numeric_string)
190                     return;
191 
192           tmp = malloc ((size_t)25);
193           if (tmp == NULL) {
194                     errx (2, "malloc() failed");
195           }
196 
197           sprintf (tmp, "%lld", (long long)vp->u.i);
198           vp->type = string;
199           vp->u.s  = tmp;
200 }
201 
202 
203 int
isstring(struct val * vp)204 isstring(struct val *vp)
205 {
206           /* only TRUE if this string is not a valid integer */
207           return (vp->type == string);
208 }
209 
210 
211 static int
yylex(void)212 yylex(void)
213 {
214           char *p;
215 
216           if (*av == NULL)
217                     return (0);
218 
219           p = *av++;
220 
221           if (strlen (p) == 1) {
222                     if (strchr ("|&=<>+-*/%:()", *p))
223                               return (*p);
224           } else if (strlen (p) == 2 && p[1] == '=') {
225                     switch (*p) {
226                     case '>': return (GE);
227                     case '<': return (LE);
228                     case '!': return (NE);
229                     }
230           }
231 
232           yylval.val = make_str (p);
233           return (TOKEN);
234 }
235 
236 int
is_zero_or_null(struct val * vp)237 is_zero_or_null(struct val *vp)
238 {
239           if (vp->type == integer) {
240                     return (vp->u.i == 0);
241           } else {
242                     return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
243           }
244           /* NOTREACHED */
245 }
246 
247 static void
usage(void)248 usage(void)
249 {
250         fprintf(stderr,
251                 "usage: expr expression\n");
252         exit(EXIT_FAILURE);
253 }
254 
255 int
main(int argc,char ** argv)256 main (int argc, char **argv)
257 {
258           setlocale (LC_ALL, "");
259 
260           if (argc > 1 && strcmp(argv[1], "--"))
261                     av = argv + 1;
262           else if (argc > 2)
263                     av = argv + 2;
264           else
265                     usage();
266 
267           yyparse ();
268 
269           if (result->type == integer)
270                     printf ("%lld\n", (long long)result->u.i);
271           else
272                     printf ("%s\n", result->u.s);
273 
274           return (is_zero_or_null (result));
275 }
276 
277 int
yyerror(const char * s __unused)278 yyerror(const char *s __unused)
279 {
280           errx (2, "syntax error");
281 }
282 
283 
284 struct val *
op_or(struct val * a,struct val * b)285 op_or(struct val *a, struct val *b)
286 {
287           if (is_zero_or_null (a)) {
288                     free_value (a);
289                     return (b);
290           } else {
291                     free_value (b);
292                     return (a);
293           }
294 }
295 
296 struct val *
op_and(struct val * a,struct val * b)297 op_and(struct val *a, struct val *b)
298 {
299           if (is_zero_or_null (a) || is_zero_or_null (b)) {
300                     free_value (a);
301                     free_value (b);
302                     return (make_integer ((quad_t)0));
303           } else {
304                     free_value (b);
305                     return (a);
306           }
307 }
308 
309 struct val *
op_eq(struct val * a,struct val * b)310 op_eq(struct val *a, struct val *b)
311 {
312           struct val *r;
313 
314           if (isstring (a) || isstring (b)) {
315                     to_string (a);
316                     to_string (b);
317                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
318           } else {
319                     to_integer(a);
320                     to_integer(b);
321                     r = make_integer ((quad_t)(a->u.i == b->u.i));
322           }
323 
324           free_value (a);
325           free_value (b);
326           return r;
327 }
328 
329 struct val *
op_gt(struct val * a,struct val * b)330 op_gt(struct val *a, struct val *b)
331 {
332           struct val *r;
333 
334           if (isstring (a) || isstring (b)) {
335                     to_string (a);
336                     to_string (b);
337                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
338           } else {
339                     to_integer(a);
340                     to_integer(b);
341                     r = make_integer ((quad_t)(a->u.i > b->u.i));
342           }
343 
344           free_value (a);
345           free_value (b);
346           return r;
347 }
348 
349 struct val *
op_lt(struct val * a,struct val * b)350 op_lt(struct val *a, struct val *b)
351 {
352           struct val *r;
353 
354           if (isstring (a) || isstring (b)) {
355                     to_string (a);
356                     to_string (b);
357                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
358           } else {
359                     to_integer(a);
360                     to_integer(b);
361                     r = make_integer ((quad_t)(a->u.i < b->u.i));
362           }
363 
364           free_value (a);
365           free_value (b);
366           return r;
367 }
368 
369 struct val *
op_ge(struct val * a,struct val * b)370 op_ge(struct val *a, struct val *b)
371 {
372           struct val *r;
373 
374           if (isstring (a) || isstring (b)) {
375                     to_string (a);
376                     to_string (b);
377                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
378           } else {
379                     to_integer(a);
380                     to_integer(b);
381                     r = make_integer ((quad_t)(a->u.i >= b->u.i));
382           }
383 
384           free_value (a);
385           free_value (b);
386           return r;
387 }
388 
389 struct val *
op_le(struct val * a,struct val * b)390 op_le(struct val *a, struct val *b)
391 {
392           struct val *r;
393 
394           if (isstring (a) || isstring (b)) {
395                     to_string (a);
396                     to_string (b);
397                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
398           } else {
399                     to_integer(a);
400                     to_integer(b);
401                     r = make_integer ((quad_t)(a->u.i <= b->u.i));
402           }
403 
404           free_value (a);
405           free_value (b);
406           return r;
407 }
408 
409 struct val *
op_ne(struct val * a,struct val * b)410 op_ne(struct val *a, struct val *b)
411 {
412           struct val *r;
413 
414           if (isstring (a) || isstring (b)) {
415                     to_string (a);
416                     to_string (b);
417                     r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
418           } else {
419                     to_integer(a);
420                     to_integer(b);
421                     r = make_integer ((quad_t)(a->u.i != b->u.i));
422           }
423 
424           free_value (a);
425           free_value (b);
426           return r;
427 }
428 
429 int
chk_plus(quad_t a,quad_t b,quad_t r)430 chk_plus(quad_t a, quad_t b, quad_t r)
431 {
432           /* sum of two positive numbers must be positive */
433           if (a > 0 && b > 0 && r <= 0)
434                     return 1;
435           /* sum of two negative numbers must be negative */
436           if (a < 0 && b < 0 && r >= 0)
437                     return 1;
438           /* all other cases are OK */
439           return 0;
440 }
441 
442 struct val *
op_plus(struct val * a,struct val * b)443 op_plus(struct val *a, struct val *b)
444 {
445           struct val *r;
446 
447           if (!to_integer (a) || !to_integer (b)) {
448                     errx (2, "non-numeric argument");
449           }
450 
451           r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
452           if (chk_plus (a->u.i, b->u.i, r->u.i)) {
453                     errx (2, "overflow");
454           }
455           free_value (a);
456           free_value (b);
457           return r;
458 }
459 
460 int
chk_minus(quad_t a,quad_t b,quad_t r)461 chk_minus(quad_t a, quad_t b, quad_t r)
462 {
463           /* special case subtraction of QUAD_MIN */
464           if (b == QUAD_MIN) {
465                     if (a >= 0)
466                               return 1;
467                     else
468                               return 0;
469           }
470           /* this is allowed for b != QUAD_MIN */
471           return chk_plus (a, -b, r);
472 }
473 
474 struct val *
op_minus(struct val * a,struct val * b)475 op_minus(struct val *a, struct val *b)
476 {
477           struct val *r;
478 
479           if (!to_integer (a) || !to_integer (b)) {
480                     errx (2, "non-numeric argument");
481           }
482 
483           r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
484           if (chk_minus (a->u.i, b->u.i, r->u.i)) {
485                     errx (2, "overflow");
486           }
487           free_value (a);
488           free_value (b);
489           return r;
490 }
491 
492 int
chk_times(quad_t a,quad_t b,quad_t r)493 chk_times(quad_t a, quad_t b, quad_t r)
494 {
495           /* special case: first operand is 0, no overflow possible */
496           if (a == 0)
497                     return 0;
498           /* cerify that result of division matches second operand */
499           if (r / a != b)
500                     return 1;
501           return 0;
502 }
503 
504 struct val *
op_times(struct val * a,struct val * b)505 op_times(struct val *a, struct val *b)
506 {
507           struct val *r;
508 
509           if (!to_integer (a) || !to_integer (b)) {
510                     errx (2, "non-numeric argument");
511           }
512 
513           r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
514           if (chk_times (a->u.i, b->u.i, r->u.i)) {
515                     errx (2, "overflow");
516           }
517           free_value (a);
518           free_value (b);
519           return (r);
520 }
521 
522 int
chk_div(quad_t a,quad_t b)523 chk_div(quad_t a, quad_t b)
524 {
525           /* div by zero has been taken care of before */
526           /* only QUAD_MIN / -1 causes overflow */
527           if (a == QUAD_MIN && b == -1)
528                     return 1;
529           /* everything else is OK */
530           return 0;
531 }
532 
533 struct val *
op_div(struct val * a,struct val * b)534 op_div(struct val *a, struct val *b)
535 {
536           struct val *r;
537 
538           if (!to_integer (a) || !to_integer (b)) {
539                     errx (2, "non-numeric argument");
540           }
541 
542           if (b->u.i == 0) {
543                     errx (2, "division by zero");
544           }
545 
546           r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
547           if (chk_div (a->u.i, b->u.i)) {
548                     errx (2, "overflow");
549           }
550           free_value (a);
551           free_value (b);
552           return r;
553 }
554 
555 struct val *
op_rem(struct val * a,struct val * b)556 op_rem(struct val *a, struct val *b)
557 {
558           struct val *r;
559 
560           if (!to_integer (a) || !to_integer (b)) {
561                     errx (2, "non-numeric argument");
562           }
563 
564           if (b->u.i == 0) {
565                     errx (2, "division by zero");
566           }
567 
568           r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
569           /* chk_rem necessary ??? */
570           free_value (a);
571           free_value (b);
572           return r;
573 }
574 
575 struct val *
op_colon(struct val * a,struct val * b)576 op_colon(struct val *a, struct val *b)
577 {
578           regex_t rp;
579           regmatch_t rm[2];
580           char errbuf[256];
581           int eval;
582           struct val *v;
583 
584           /* coerce to both arguments to strings */
585           to_string(a);
586           to_string(b);
587 
588           /* compile regular expression */
589           if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
590                     regerror (eval, &rp, errbuf, sizeof(errbuf));
591                     errx (2, "%s", errbuf);
592           }
593 
594           /* compare string against pattern */
595           /* remember that patterns are anchored to the beginning of the line */
596           if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
597                     if (rm[1].rm_so >= 0) {
598                               *(a->u.s + rm[1].rm_eo) = '\0';
599                               v = make_str (a->u.s + rm[1].rm_so);
600 
601                     } else {
602                               v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
603                     }
604           } else {
605                     if (rp.re_nsub == 0) {
606                               v = make_integer ((quad_t)0);
607                     } else {
608                               v = make_str ("");
609                     }
610           }
611 
612           /* free arguments and pattern buffer */
613           free_value (a);
614           free_value (b);
615           regfree (&rp);
616 
617           return v;
618 }
619