Annotation of src/bin/expr/expr.y, Revision 1.9
1.1 cgd 1: %{
2: /* Written by Pace Willisson (pace@blitz.com)
3: * and placed in the public domain
1.2 cgd 4: *
1.9 ! jtc 5: * $Header: /b/source/CVS/src/bin/expr/expr.y,v 1.8 1993/07/20 00:52:57 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.4 cgd 222: if (vp->type == integer) {
1.5 cgd 223: return (vp->u.i == 0);
1.4 cgd 224: } else {
1.9 ! jtc 225: return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
1.4 cgd 226: }
1.5 cgd 227: /* NOTREACHED */
1.1 cgd 228: }
229:
230: void
231: main (argc, argv)
232: int argc;
233: char **argv;
234: {
235: av = argv + 1;
236:
237: yyparse ();
238:
1.4 cgd 239: if (result->type == integer)
240: printf ("%d\n", result->u.i);
1.1 cgd 241: else
1.4 cgd 242: printf ("%s\n", result->u.s);
1.1 cgd 243:
244: if (is_zero_or_null (result))
245: exit (1);
246: else
247: exit (0);
248: }
249:
250: int
251: yyerror (s)
252: char *s;
253: {
1.4 cgd 254: fprintf (stderr, "expr: syntax error\n");
1.1 cgd 255: exit (2);
256: }
257:
258:
259: struct val *
260: op_or (a, b)
261: struct val *a, *b;
262: {
1.4 cgd 263: if (is_zero_or_null (a)) {
264: free_value (a);
1.1 cgd 265: return (b);
1.4 cgd 266: } else {
267: free_value (b);
1.1 cgd 268: return (a);
1.4 cgd 269: }
1.1 cgd 270: }
271:
272: struct val *
273: op_and (a, b)
274: struct val *a, *b;
275: {
1.4 cgd 276: if (is_zero_or_null (a) || is_zero_or_null (b)) {
277: free_value (a);
278: free_value (b);
1.1 cgd 279: return (make_integer (0));
1.4 cgd 280: } else {
281: free_value (b);
1.1 cgd 282: return (a);
1.4 cgd 283: }
1.1 cgd 284: }
285:
286: struct val *
287: op_eq (a, b)
288: struct val *a, *b;
289: {
1.4 cgd 290: struct val *r;
291:
292: if (isstring (a) || isstring (b)) {
293: to_string (a);
294: to_string (b);
295: r = make_integer (strcmp (a->u.s, b->u.s) == 0);
296: } else {
297: r = make_integer (a->u.i == b->u.i);
298: }
299:
300: free_value (a);
301: free_value (b);
302: return r;
1.1 cgd 303: }
304:
305: struct val *
306: op_gt (a, b)
307: struct val *a, *b;
308: {
1.4 cgd 309: struct val *r;
310:
311: if (isstring (a) || isstring (b)) {
312: to_string (a);
313: to_string (b);
314: r = make_integer (strcmp (a->u.s, b->u.s) > 0);
315: } else {
316: r= make_integer (a->u.i > b->u.i);
317: }
318:
319: free_value (a);
320: free_value (b);
321: return r;
1.1 cgd 322: }
323:
324: struct val *
325: op_lt (a, b)
326: struct val *a, *b;
327: {
1.4 cgd 328: struct val *r;
329:
330: if (isstring (a) || isstring (b)) {
331: to_string (a);
332: to_string (b);
333: r = make_integer (strcmp (a->u.s, b->u.s) < 0);
334: } else {
335: r = make_integer (a->u.i < b->u.i);
336: }
337:
338: free_value (a);
339: free_value (b);
340: return r;
1.1 cgd 341: }
342:
343: struct val *
344: op_ge (a, b)
345: struct val *a, *b;
346: {
1.4 cgd 347: struct val *r;
348:
349: if (isstring (a) || isstring (b)) {
350: to_string (a);
351: to_string (b);
352: r = make_integer (strcmp (a->u.s, b->u.s) >= 0);
353: } else {
354: r = make_integer (a->u.i >= b->u.i);
355: }
356:
357: free_value (a);
358: free_value (b);
359: return r;
1.1 cgd 360: }
361:
362: struct val *
363: op_le (a, b)
364: struct val *a, *b;
365: {
1.4 cgd 366: struct val *r;
367:
368: if (isstring (a) || isstring (b)) {
369: to_string (a);
370: to_string (b);
371: r = make_integer (strcmp (a->u.s, b->u.s) <= 0);
372: } else {
373: r = make_integer (a->u.i <= b->u.i);
374: }
375:
376: free_value (a);
377: free_value (b);
378: return r;
1.1 cgd 379: }
380:
381: struct val *
382: op_ne (a, b)
383: struct val *a, *b;
384: {
1.4 cgd 385: struct val *r;
386:
387: if (isstring (a) || isstring (b)) {
388: to_string (a);
389: to_string (b);
390: r = make_integer (strcmp (a->u.s, b->u.s) != 0);
391: } else {
392: r = make_integer (a->u.i != b->u.i);
393: }
394:
395: free_value (a);
396: free_value (b);
397: return r;
1.1 cgd 398: }
399:
400: struct val *
401: op_plus (a, b)
402: struct val *a, *b;
403: {
1.4 cgd 404: struct val *r;
405:
406: if (!to_integer (a) || !to_integer (b)) {
407: fprintf (stderr, "expr: non-numeric argument\n");
408: exit (2);
409: }
1.1 cgd 410:
1.4 cgd 411: r = make_integer (a->u.i + b->u.i);
412: free_value (a);
413: free_value (b);
414: return r;
1.1 cgd 415: }
416:
417: struct val *
418: op_minus (a, b)
419: struct val *a, *b;
420: {
1.4 cgd 421: struct val *r;
422:
423: if (!to_integer (a) || !to_integer (b)) {
424: fprintf (stderr, "expr: non-numeric argument\n");
425: exit (2);
426: }
1.1 cgd 427:
1.4 cgd 428: r = make_integer (a->u.i - b->u.i);
429: free_value (a);
430: free_value (b);
431: return r;
1.1 cgd 432: }
433:
434: struct val *
435: op_times (a, b)
436: struct val *a, *b;
437: {
1.4 cgd 438: struct val *r;
1.1 cgd 439:
1.4 cgd 440: if (!to_integer (a) || !to_integer (b)) {
441: fprintf (stderr, "expr: non-numeric argument\n");
442: exit (2);
443: }
444:
445: r = make_integer (a->u.i * b->u.i);
446: free_value (a);
447: free_value (b);
448: return (r);
1.1 cgd 449: }
450:
451: struct val *
452: op_div (a, b)
453: struct val *a, *b;
454: {
1.4 cgd 455: struct val *r;
456:
457: if (!to_integer (a) || !to_integer (b)) {
458: fprintf (stderr, "expr: non-numeric argument\n");
459: exit (2);
460: }
461:
462: if (b->u.i == 0) {
463: fprintf (stderr, "expr: division by zero\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_rem (a, b)
475: struct val *a, *b;
476: {
1.4 cgd 477: struct val *r;
478:
479: if (!to_integer (a) || !to_integer (b)) {
480: fprintf (stderr, "expr: non-numeric argument\n");
481: exit (2);
482: }
483:
484: if (b->u.i == 0) {
485: fprintf (stderr, "expr: division by zero\n");
486: exit (2);
487: }
1.1 cgd 488:
1.4 cgd 489: r = make_integer (a->u.i % b->u.i);
490: free_value (a);
491: free_value (b);
492: return r;
1.1 cgd 493: }
494:
1.6 jtc 495: #include <regex.h>
496: #define SE_MAX 30
1.1 cgd 497:
498: struct val *
499: op_colon (a, b)
500: struct val *a, *b;
501: {
1.6 jtc 502: regex_t rp;
503: regmatch_t rm[SE_MAX];
504: char errbuf[256];
505: int eval;
506: struct val *v;
1.9 ! jtc 507: char *newpat;
1.6 jtc 508:
1.7 jtc 509: /* coerce to both arguments to strings */
510: to_string(a);
511: to_string(b);
1.6 jtc 512:
1.9 ! jtc 513: /* patterns are anchored to the beginning of the line */
! 514: newpat = malloc (strlen (b->u.s) + 2);
! 515: strcpy (newpat, "^");
! 516: strcat (newpat, b->u.s);
! 517:
1.6 jtc 518: /* compile regular expression */
1.9 ! jtc 519: if ((eval = regcomp (&rp, newpat, 0)) != 0) {
1.6 jtc 520: regerror (eval, &rp, errbuf, sizeof(errbuf));
521: fprintf (stderr, "expr: %s\n", errbuf);
522: exit (2);
523: }
1.9 ! jtc 524: free (newpat);
1.6 jtc 525:
526: /* compare string against pattern */
527: if (regexec(&rp, a->u.s, SE_MAX, rm, 0) == 0) {
528: if (rm[1].rm_so >= 0) {
529: *(a->u.s + rm[1].rm_eo) = 0;
530: v = make_str (a->u.s + rm[1].rm_so);
1.1 cgd 531:
532: } else {
1.6 jtc 533: v = make_integer (rm[0].rm_eo - rm[0].rm_so);
1.1 cgd 534: }
535: } else {
1.6 jtc 536: v = make_integer (0);
1.1 cgd 537: }
1.6 jtc 538:
539: /* free arguments and pattern buffer */
540: free_value (a);
541: free_value (b);
542: regfree (&rp);
1.5 cgd 543:
1.6 jtc 544: return v;
1.1 cgd 545: }
CVSweb <webmaster@jp.NetBSD.org>