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