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