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