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