0bcd6e0bc3936ccec2b74cf7da45182b4c7ac361
[dragonfly.git] / bin / expr / expr.y
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  * $DragonFly: src/bin/expr/expr.y,v 1.6 2005/11/06 11:44:02 swildner Exp $
9  */
10
11 #include <sys/types.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <locale.h>
16 #include <ctype.h>
17 #include <err.h>
18 #include <errno.h>
19 #include <regex.h>
20 #include <limits.h>
21   
22 enum valtype {
23         integer, numeric_string, string
24 } ;
25
26 struct val {
27         enum valtype type;
28         union {
29                 char *s;
30                 quad_t i;
31         } u;
32 } ;
33
34 struct val *result;
35
36 int             chk_div (quad_t, quad_t);
37 int             chk_minus (quad_t, quad_t, quad_t);
38 int             chk_plus (quad_t, quad_t, quad_t);
39 int             chk_times (quad_t, quad_t, quad_t);
40 void            free_value (struct val *);
41 int             is_zero_or_null (struct val *);
42 int             isstring (struct val *);
43 int             main (int, char **);
44 struct val      *make_integer (quad_t);
45 struct val      *make_str (const char *);
46 struct val      *op_and (struct val *, struct val *);
47 struct val      *op_colon (struct val *, struct val *);
48 struct val      *op_div (struct val *, struct val *);
49 struct val      *op_eq (struct val *, struct val *);
50 struct val      *op_ge (struct val *, struct val *);
51 struct val      *op_gt (struct val *, struct val *);
52 struct val      *op_le (struct val *, struct val *);
53 struct val      *op_lt (struct val *, struct val *);
54 struct val      *op_minus (struct val *, struct val *);
55 struct val      *op_ne (struct val *, struct val *);
56 struct val      *op_or (struct val *, struct val *);
57 struct val      *op_plus (struct val *, struct val *);
58 struct val      *op_rem (struct val *, struct val *);
59 struct val      *op_times (struct val *, struct val *);
60 quad_t          to_integer (struct val *);
61 void            to_string (struct val *);
62 int             yyerror (const char *);
63 int             yylex (void);
64 int             yyparse (void);
65
66 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 *
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
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
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, (char**)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
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
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 int
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
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 int
248 main (int argc __unused, char **argv)
249 {
250         setlocale (LC_ALL, "");
251
252         av = argv + 1;
253
254         yyparse ();
255
256         if (result->type == integer)
257                 printf ("%lld\n", (long long)result->u.i);
258         else
259                 printf ("%s\n", result->u.s);
260
261         return (is_zero_or_null (result));
262 }
263
264 int
265 yyerror(const char *s __unused)
266 {
267         errx (2, "syntax error");
268 }
269
270
271 struct val *
272 op_or(struct val *a, struct val *b)
273 {
274         if (is_zero_or_null (a)) {
275                 free_value (a);
276                 return (b);
277         } else {
278                 free_value (b);
279                 return (a);
280         }
281 }
282                 
283 struct val *
284 op_and(struct val *a, struct val *b)
285 {
286         if (is_zero_or_null (a) || is_zero_or_null (b)) {
287                 free_value (a);
288                 free_value (b);
289                 return (make_integer ((quad_t)0));
290         } else {
291                 free_value (b);
292                 return (a);
293         }
294 }
295
296 struct val *
297 op_eq(struct val *a, struct val *b)
298 {
299         struct val *r; 
300
301         if (isstring (a) || isstring (b)) {
302                 to_string (a);
303                 to_string (b);  
304                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
305         } else {
306                 to_integer(a);
307                 to_integer(b);
308                 r = make_integer ((quad_t)(a->u.i == b->u.i));
309         }
310
311         free_value (a);
312         free_value (b);
313         return r;
314 }
315
316 struct val *
317 op_gt(struct val *a, struct val *b)
318 {
319         struct val *r;
320
321         if (isstring (a) || isstring (b)) {
322                 to_string (a);
323                 to_string (b);
324                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
325         } else {
326                 to_integer(a);
327                 to_integer(b);
328                 r = make_integer ((quad_t)(a->u.i > b->u.i));
329         }
330
331         free_value (a);
332         free_value (b);
333         return r;
334 }
335
336 struct val *
337 op_lt(struct val *a, struct val *b)
338 {
339         struct val *r;
340
341         if (isstring (a) || isstring (b)) {
342                 to_string (a);
343                 to_string (b);
344                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
345         } else {
346                 to_integer(a);
347                 to_integer(b);
348                 r = make_integer ((quad_t)(a->u.i < b->u.i));
349         }
350
351         free_value (a);
352         free_value (b);
353         return r;
354 }
355
356 struct val *
357 op_ge(struct val *a, struct val *b)
358 {
359         struct val *r;
360
361         if (isstring (a) || isstring (b)) {
362                 to_string (a);
363                 to_string (b);
364                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
365         } else {
366                 to_integer(a);
367                 to_integer(b);
368                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
369         }
370
371         free_value (a);
372         free_value (b);
373         return r;
374 }
375
376 struct val *
377 op_le(struct val *a, struct val *b)
378 {
379         struct val *r;
380
381         if (isstring (a) || isstring (b)) {
382                 to_string (a);
383                 to_string (b);
384                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
385         } else {
386                 to_integer(a);
387                 to_integer(b);
388                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
389         }
390
391         free_value (a);
392         free_value (b);
393         return r;
394 }
395
396 struct val *
397 op_ne(struct val *a, struct val *b)
398 {
399         struct val *r;
400
401         if (isstring (a) || isstring (b)) {
402                 to_string (a);
403                 to_string (b);
404                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
405         } else {
406                 to_integer(a);
407                 to_integer(b);
408                 r = make_integer ((quad_t)(a->u.i != b->u.i));
409         }
410
411         free_value (a);
412         free_value (b);
413         return r;
414 }
415
416 int
417 chk_plus(quad_t a, quad_t b, quad_t r)
418 {
419         /* sum of two positive numbers must be positive */
420         if (a > 0 && b > 0 && r <= 0)
421                 return 1;
422         /* sum of two negative numbers must be negative */
423         if (a < 0 && b < 0 && r >= 0)
424                 return 1;
425         /* all other cases are OK */
426         return 0;
427 }
428
429 struct val *
430 op_plus(struct val *a, struct val *b)
431 {
432         struct val *r;
433
434         if (!to_integer (a) || !to_integer (b)) {
435                 errx (2, "non-numeric argument");
436         }
437
438         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
439         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
440                 errx (2, "overflow");
441         }
442         free_value (a);
443         free_value (b);
444         return r;
445 }
446
447 int
448 chk_minus(quad_t a, quad_t b, quad_t r)
449 {
450         /* special case subtraction of QUAD_MIN */
451         if (b == QUAD_MIN) {
452                 if (a >= 0)
453                         return 1;
454                 else
455                         return 0;
456         }
457         /* this is allowed for b != QUAD_MIN */
458         return chk_plus (a, -b, r);
459 }
460
461 struct val *
462 op_minus(struct val *a, struct val *b)
463 {
464         struct val *r;
465
466         if (!to_integer (a) || !to_integer (b)) {
467                 errx (2, "non-numeric argument");
468         }
469
470         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
471         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
472                 errx (2, "overflow");
473         }
474         free_value (a);
475         free_value (b);
476         return r;
477 }
478
479 int
480 chk_times(quad_t a, quad_t b, quad_t r)
481 {
482         /* special case: first operand is 0, no overflow possible */
483         if (a == 0)
484                 return 0;
485         /* cerify that result of division matches second operand */
486         if (r / a != b)
487                 return 1;
488         return 0;
489 }
490
491 struct val *
492 op_times(struct val *a, struct val *b)
493 {
494         struct val *r;
495
496         if (!to_integer (a) || !to_integer (b)) {
497                 errx (2, "non-numeric argument");
498         }
499
500         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
501         if (chk_times (a->u.i, b->u.i, r->u.i)) {
502                 errx (2, "overflow");
503         }
504         free_value (a);
505         free_value (b);
506         return (r);
507 }
508
509 int
510 chk_div(quad_t a, quad_t b)
511 {
512         /* div by zero has been taken care of before */
513         /* only QUAD_MIN / -1 causes overflow */
514         if (a == QUAD_MIN && b == -1)
515                 return 1;
516         /* everything else is OK */
517         return 0;
518 }
519
520 struct val *
521 op_div(struct val *a, struct val *b)
522 {
523         struct val *r;
524
525         if (!to_integer (a) || !to_integer (b)) {
526                 errx (2, "non-numeric argument");
527         }
528
529         if (b->u.i == 0) {
530                 errx (2, "division by zero");
531         }
532
533         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
534         if (chk_div (a->u.i, b->u.i)) {
535                 errx (2, "overflow");
536         }
537         free_value (a);
538         free_value (b);
539         return r;
540 }
541         
542 struct val *
543 op_rem(struct val *a, struct val *b)
544 {
545         struct val *r;
546
547         if (!to_integer (a) || !to_integer (b)) {
548                 errx (2, "non-numeric argument");
549         }
550
551         if (b->u.i == 0) {
552                 errx (2, "division by zero");
553         }
554
555         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
556         /* chk_rem necessary ??? */
557         free_value (a);
558         free_value (b);
559         return r;
560 }
561         
562 struct val *
563 op_colon(struct val *a, struct val *b)
564 {
565         regex_t rp;
566         regmatch_t rm[2];
567         char errbuf[256];
568         int eval;
569         struct val *v;
570
571         /* coerce to both arguments to strings */
572         to_string(a);
573         to_string(b);
574
575         /* compile regular expression */
576         if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
577                 regerror (eval, &rp, errbuf, sizeof(errbuf));
578                 errx (2, "%s", errbuf);
579         }
580
581         /* compare string against pattern */
582         /* remember that patterns are anchored to the beginning of the line */
583         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
584                 if (rm[1].rm_so >= 0) {
585                         *(a->u.s + rm[1].rm_eo) = '\0';
586                         v = make_str (a->u.s + rm[1].rm_so);
587
588                 } else {
589                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
590                 }
591         } else {
592                 if (rp.re_nsub == 0) {
593                         v = make_integer ((quad_t)0);
594                 } else {
595                         v = make_str ("");
596                 }
597         }
598
599         /* free arguments and pattern buffer */
600         free_value (a);
601         free_value (b);
602         regfree (&rp);
603
604         return v;
605 }