Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | %{ |
2 | /* Written by Pace Willisson (pace@blitz.com) | |
78ed81a3 | 3 | * and placed in the public domain. |
15637ed4 | 4 | * |
78ed81a3 | 5 | * Largely rewritten by J.T. Conklin (jtc@wimsey.com) |
15637ed4 | 6 | * |
78ed81a3 | 7 | * $Id : /b/source/CVS/src/bin/expr/expr.y,v 1.11 1993/08/17 16:01:23 jtc Exp $ |
15637ed4 | 8 | */ |
78ed81a3 | 9 | |
15637ed4 RG |
10 | #include <stdio.h> |
11 | #include <stdlib.h> | |
12 | #include <string.h> | |
78ed81a3 | 13 | #include <locale.h> |
15637ed4 | 14 | #include <ctype.h> |
78ed81a3 | 15 | #include <err.h> |
16 | ||
15637ed4 RG |
17 | enum valtype { |
18 | integer, string | |
19 | } ; | |
78ed81a3 | 20 | |
15637ed4 RG |
21 | struct val { |
22 | enum valtype type; | |
23 | union { | |
24 | char *s; | |
25 | int i; | |
26 | } u; | |
78ed81a3 | 27 | } ; |
15637ed4 RG |
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); } | |
15637ed4 RG |
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) { | |
78ed81a3 | 97 | err (2, NULL); |
15637ed4 RG |
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)) { | |
78ed81a3 | 113 | err (2, NULL); |
15637ed4 RG |
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) { | |
78ed81a3 | 176 | err (2, NULL); |
15637ed4 RG |
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 | { | |
15637ed4 RG |
223 | if (vp->type == integer) { |
224 | return (vp->u.i == 0); | |
225 | } else { | |
78ed81a3 | 226 | return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0)); |
15637ed4 RG |
227 | } |
228 | /* NOTREACHED */ | |
229 | } | |
230 | ||
231 | void | |
232 | main (argc, argv) | |
233 | int argc; | |
234 | char **argv; | |
235 | { | |
78ed81a3 | 236 | setlocale (LC_ALL, ""); |
237 | ||
15637ed4 RG |
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 | ||
78ed81a3 | 247 | exit (is_zero_or_null (result)); |
15637ed4 RG |
248 | } |
249 | ||
250 | int | |
251 | yyerror (s) | |
252 | char *s; | |
253 | { | |
78ed81a3 | 254 | errx (2, "syntax error"); |
15637ed4 RG |
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 | ||
15637ed4 RG |
291 | if (isstring (a) || isstring (b)) { |
292 | to_string (a); | |
293 | to_string (b); | |
78ed81a3 | 294 | r = make_integer (strcoll (a->u.s, b->u.s) == 0); |
15637ed4 RG |
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 | ||
15637ed4 RG |
310 | if (isstring (a) || isstring (b)) { |
311 | to_string (a); | |
312 | to_string (b); | |
78ed81a3 | 313 | r = make_integer (strcoll (a->u.s, b->u.s) > 0); |
15637ed4 RG |
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 | ||
15637ed4 RG |
329 | if (isstring (a) || isstring (b)) { |
330 | to_string (a); | |
331 | to_string (b); | |
78ed81a3 | 332 | r = make_integer (strcoll (a->u.s, b->u.s) < 0); |
15637ed4 RG |
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 | ||
15637ed4 RG |
348 | if (isstring (a) || isstring (b)) { |
349 | to_string (a); | |
350 | to_string (b); | |
78ed81a3 | 351 | r = make_integer (strcoll (a->u.s, b->u.s) >= 0); |
15637ed4 RG |
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 | ||
15637ed4 RG |
367 | if (isstring (a) || isstring (b)) { |
368 | to_string (a); | |
369 | to_string (b); | |
78ed81a3 | 370 | r = make_integer (strcoll (a->u.s, b->u.s) <= 0); |
15637ed4 RG |
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 | ||
15637ed4 RG |
386 | if (isstring (a) || isstring (b)) { |
387 | to_string (a); | |
388 | to_string (b); | |
78ed81a3 | 389 | r = make_integer (strcoll (a->u.s, b->u.s) != 0); |
15637ed4 RG |
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)) { | |
78ed81a3 | 406 | errx (2, "non-numeric argument"); |
15637ed4 RG |
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)) { | |
78ed81a3 | 422 | errx (2, "non-numeric argument"); |
15637ed4 RG |
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)) { | |
78ed81a3 | 438 | errx (2, "non-numeric argument"); |
15637ed4 RG |
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)) { | |
78ed81a3 | 454 | errx (2, "non-numeric argument"); |
15637ed4 RG |
455 | } |
456 | ||
457 | if (b->u.i == 0) { | |
78ed81a3 | 458 | errx (2, "division by zero"); |
15637ed4 RG |
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)) { | |
78ed81a3 | 474 | errx (2, "non-numeric argument"); |
15637ed4 RG |
475 | } |
476 | ||
477 | if (b->u.i == 0) { | |
78ed81a3 | 478 | errx (2, "division by zero"); |
15637ed4 RG |
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 | ||
78ed81a3 | 487 | #include <regex.h> |
15637ed4 RG |
488 | |
489 | struct val * | |
490 | op_colon (a, b) | |
491 | struct val *a, *b; | |
492 | { | |
78ed81a3 | 493 | regex_t rp; |
494 | regmatch_t rm[2]; | |
495 | char errbuf[256]; | |
496 | int eval; | |
497 | struct val *v; | |
498 | ||
499 | /* coerce to both arguments to strings */ | |
500 | to_string(a); | |
501 | to_string(b); | |
502 | ||
503 | /* compile regular expression */ | |
504 | if ((eval = regcomp (&rp, b->u.s, 0)) != 0) { | |
505 | regerror (eval, &rp, errbuf, sizeof(errbuf)); | |
506 | errx (2, "%s", errbuf); | |
15637ed4 | 507 | } |
78ed81a3 | 508 | |
509 | /* compare string against pattern */ | |
510 | /* remember that patterns are anchored to the beginning of the line */ | |
511 | if (regexec(&rp, a->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) { | |
512 | if (rm[1].rm_so >= 0) { | |
513 | *(a->u.s + rm[1].rm_eo) = '\0'; | |
514 | v = make_str (a->u.s + rm[1].rm_so); | |
515 | ||
15637ed4 | 516 | } else { |
78ed81a3 | 517 | v = make_integer (rm[0].rm_eo - rm[0].rm_so); |
15637ed4 RG |
518 | } |
519 | } else { | |
78ed81a3 | 520 | if (rp.re_nsub == 0) { |
521 | v = make_integer (0); | |
522 | } else { | |
523 | v = make_str (""); | |
524 | } | |
15637ed4 | 525 | } |
15637ed4 | 526 | |
78ed81a3 | 527 | /* free arguments and pattern buffer */ |
528 | free_value (a); | |
529 | free_value (b); | |
530 | regfree (&rp); | |
531 | ||
532 | return v; | |
15637ed4 | 533 | } |