xref: /freebsd/bin/expr/expr.y (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
1 %{
2 /* Written by Pace Willisson (pace@blitz.com)
3  * and placed in the public domain.
4  *
5  * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6  *
7  * $Id$
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <locale.h>
14 #include <ctype.h>
15 #include <err.h>
16 
17 enum valtype {
18 	integer, numeric_string, string
19 } ;
20 
21 struct val {
22 	enum valtype type;
23 	union {
24 		char *s;
25 		int   i;
26 	} u;
27 } ;
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 
60 %token <val> TOKEN
61 %type <val> start expr
62 
63 %%
64 
65 start: expr { result = $$; }
66 
67 expr:	TOKEN
68 	| '(' expr ')' { $$ = $2; }
69 	| expr '|' expr { $$ = op_or ($1, $3); }
70 	| expr '&' expr { $$ = op_and ($1, $3); }
71 	| expr '=' expr { $$ = op_eq ($1, $3); }
72 	| expr '>' expr { $$ = op_gt ($1, $3); }
73 	| expr '<' expr { $$ = op_lt ($1, $3); }
74 	| expr GE expr  { $$ = op_ge ($1, $3); }
75 	| expr LE expr  { $$ = op_le ($1, $3); }
76 	| expr NE expr  { $$ = op_ne ($1, $3); }
77 	| expr '+' expr { $$ = op_plus ($1, $3); }
78 	| expr '-' expr { $$ = op_minus ($1, $3); }
79 	| expr '*' expr { $$ = op_times ($1, $3); }
80 	| expr '/' expr { $$ = op_div ($1, $3); }
81 	| expr '%' expr { $$ = op_rem ($1, $3); }
82 	| expr ':' expr { $$ = op_colon ($1, $3); }
83 	;
84 
85 
86 %%
87 
88 struct val *
89 make_integer (i)
90 int i;
91 {
92 	struct val *vp;
93 
94 	vp = (struct val *) malloc (sizeof (*vp));
95 	if (vp == NULL) {
96 		errx (2, "malloc() failed");
97 	}
98 
99 	vp->type = integer;
100 	vp->u.i  = i;
101 	return vp;
102 }
103 
104 struct val *
105 make_str (s)
106 char *s;
107 {
108 	struct val *vp;
109 	int i, isint;
110 
111 	vp = (struct val *) malloc (sizeof (*vp));
112 	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
113 		errx (2, "malloc() failed");
114 	}
115 
116 	for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
117 	    isint && i < strlen(s);
118 	    i++)
119 	{
120 		if(!isdigit(s[i]))
121 			 isint = 0;
122 	}
123 
124 	if (isint)
125 		vp->type = numeric_string;
126 	else
127 		vp->type = string;
128 
129 	return vp;
130 }
131 
132 
133 void
134 free_value (vp)
135 struct val *vp;
136 {
137 	if (vp->type == string || vp->type == numeric_string)
138 		free (vp->u.s);
139 }
140 
141 
142 int
143 to_integer (vp)
144 struct val *vp;
145 {
146 	int i;
147 
148 	if (vp->type == integer)
149 		return 1;
150 
151 	if (vp->type == string)
152 		return 0;
153 
154 	/* vp->type == numeric_string, make it numeric */
155 	i  = atoi(vp->u.s);
156 	free (vp->u.s);
157 	vp->u.i = i;
158 	vp->type = integer;
159 	return 1;
160 }
161 
162 void
163 to_string (vp)
164 struct val *vp;
165 {
166 	char *tmp;
167 
168 	if (vp->type == string || vp->type == numeric_string)
169 		return;
170 
171 	tmp = malloc (25);
172 	if (tmp == NULL) {
173 		errx (2, "malloc() failed");
174 	}
175 
176 	sprintf (tmp, "%d", vp->u.i);
177 	vp->type = string;
178 	vp->u.s  = tmp;
179 }
180 
181 
182 int
183 isstring (vp)
184 struct val *vp;
185 {
186 	/* only TRUE if this string is not a valid integer */
187 	return (vp->type == string);
188 }
189 
190 
191 int
192 yylex ()
193 {
194 	char *p;
195 
196 	if (*av == NULL)
197 		return (0);
198 
199 	p = *av++;
200 
201 	if (strlen (p) == 1) {
202 		if (strchr ("|&=<>+-*/%:()", *p))
203 			return (*p);
204 	} else if (strlen (p) == 2 && p[1] == '=') {
205 		switch (*p) {
206 		case '>': return (GE);
207 		case '<': return (LE);
208 		case '!': return (NE);
209 		}
210 	}
211 
212 	yylval.val = make_str (p);
213 	return (TOKEN);
214 }
215 
216 int
217 is_zero_or_null (vp)
218 struct val *vp;
219 {
220 	if (vp->type == integer) {
221 		return (vp->u.i == 0);
222 	} else {
223 		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
224 	}
225 	/* NOTREACHED */
226 }
227 
228 int yyparse ();
229 
230 int
231 main (argc, argv)
232 int argc;
233 char **argv;
234 {
235 	setlocale (LC_ALL, "");
236 
237 	av = argv + 1;
238 
239 	yyparse ();
240 
241 	if (result->type == integer)
242 		printf ("%d\n", result->u.i);
243 	else
244 		printf ("%s\n", result->u.s);
245 
246 	return (is_zero_or_null (result));
247 }
248 
249 int
250 yyerror (s)
251 char *s;
252 {
253 	errx (2, "syntax error");
254 }
255 
256 
257 struct val *
258 op_or (a, b)
259 struct val *a, *b;
260 {
261 	if (is_zero_or_null (a)) {
262 		free_value (a);
263 		return (b);
264 	} else {
265 		free_value (b);
266 		return (a);
267 	}
268 }
269 
270 struct val *
271 op_and (a, b)
272 struct val *a, *b;
273 {
274 	if (is_zero_or_null (a) || is_zero_or_null (b)) {
275 		free_value (a);
276 		free_value (b);
277 		return (make_integer (0));
278 	} else {
279 		free_value (b);
280 		return (a);
281 	}
282 }
283 
284 struct val *
285 op_eq (a, b)
286 struct val *a, *b;
287 {
288 	struct val *r;
289 
290 	if (isstring (a) || isstring (b)) {
291 		to_string (a);
292 		to_string (b);
293 		r = make_integer (strcoll (a->u.s, b->u.s) == 0);
294 	} else {
295 		(void)to_integer(a);
296 		(void)to_integer(b);
297 		r = make_integer (a->u.i == b->u.i);
298 	}
299 
300 	free_value (a);
301 	free_value (b);
302 	return r;
303 }
304 
305 struct val *
306 op_gt (a, b)
307 struct val *a, *b;
308 {
309 	struct val *r;
310 
311 	if (isstring (a) || isstring (b)) {
312 		to_string (a);
313 		to_string (b);
314 		r = make_integer (strcoll (a->u.s, b->u.s) > 0);
315 	} else {
316 		(void)to_integer(a);
317 		(void)to_integer(b);
318 		r= make_integer (a->u.i > b->u.i);
319 	}
320 
321 	free_value (a);
322 	free_value (b);
323 	return r;
324 }
325 
326 struct val *
327 op_lt (a, b)
328 struct val *a, *b;
329 {
330 	struct val *r;
331 
332 	if (isstring (a) || isstring (b)) {
333 		to_string (a);
334 		to_string (b);
335 		r = make_integer (strcoll (a->u.s, b->u.s) < 0);
336 	} else {
337 		(void)to_integer(a);
338 		(void)to_integer(b);
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_ge (a, b)
349 struct val *a, *b;
350 {
351 	struct val *r;
352 
353 	if (isstring (a) || isstring (b)) {
354 		to_string (a);
355 		to_string (b);
356 		r = make_integer (strcoll (a->u.s, b->u.s) >= 0);
357 	} else {
358 		(void)to_integer(a);
359 		(void)to_integer(b);
360 		r = make_integer (a->u.i >= b->u.i);
361 	}
362 
363 	free_value (a);
364 	free_value (b);
365 	return r;
366 }
367 
368 struct val *
369 op_le (a, b)
370 struct val *a, *b;
371 {
372 	struct val *r;
373 
374 	if (isstring (a) || isstring (b)) {
375 		to_string (a);
376 		to_string (b);
377 		r = make_integer (strcoll (a->u.s, b->u.s) <= 0);
378 	} else {
379 		(void)to_integer(a);
380 		(void)to_integer(b);
381 		r = make_integer (a->u.i <= b->u.i);
382 	}
383 
384 	free_value (a);
385 	free_value (b);
386 	return r;
387 }
388 
389 struct val *
390 op_ne (a, b)
391 struct val *a, *b;
392 {
393 	struct val *r;
394 
395 	if (isstring (a) || isstring (b)) {
396 		to_string (a);
397 		to_string (b);
398 		r = make_integer (strcoll (a->u.s, b->u.s) != 0);
399 	} else {
400 		(void)to_integer(a);
401 		(void)to_integer(b);
402 		r = make_integer (a->u.i != b->u.i);
403 	}
404 
405 	free_value (a);
406 	free_value (b);
407 	return r;
408 }
409 
410 struct val *
411 op_plus (a, b)
412 struct val *a, *b;
413 {
414 	struct val *r;
415 
416 	if (!to_integer (a) || !to_integer (b)) {
417 		errx (2, "non-numeric argument");
418 	}
419 
420 	r = make_integer (a->u.i + b->u.i);
421 	free_value (a);
422 	free_value (b);
423 	return r;
424 }
425 
426 struct val *
427 op_minus (a, b)
428 struct val *a, *b;
429 {
430 	struct val *r;
431 
432 	if (!to_integer (a) || !to_integer (b)) {
433 		errx (2, "non-numeric argument");
434 	}
435 
436 	r = make_integer (a->u.i - b->u.i);
437 	free_value (a);
438 	free_value (b);
439 	return r;
440 }
441 
442 struct val *
443 op_times (a, b)
444 struct val *a, *b;
445 {
446 	struct val *r;
447 
448 	if (!to_integer (a) || !to_integer (b)) {
449 		errx (2, "non-numeric argument");
450 	}
451 
452 	r = make_integer (a->u.i * b->u.i);
453 	free_value (a);
454 	free_value (b);
455 	return (r);
456 }
457 
458 struct val *
459 op_div (a, b)
460 struct val *a, *b;
461 {
462 	struct val *r;
463 
464 	if (!to_integer (a) || !to_integer (b)) {
465 		errx (2, "non-numeric argument");
466 	}
467 
468 	if (b->u.i == 0) {
469 		errx (2, "division by zero");
470 	}
471 
472 	r = make_integer (a->u.i / b->u.i);
473 	free_value (a);
474 	free_value (b);
475 	return r;
476 }
477 
478 struct val *
479 op_rem (a, b)
480 struct val *a, *b;
481 {
482 	struct val *r;
483 
484 	if (!to_integer (a) || !to_integer (b)) {
485 		errx (2, "non-numeric argument");
486 	}
487 
488 	if (b->u.i == 0) {
489 		errx (2, "division by zero");
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 #include <sys/types.h>
499 #include <regex.h>
500 
501 struct val *
502 op_colon (a, b)
503 struct val *a, *b;
504 {
505 	regex_t rp;
506 	regmatch_t rm[2];
507 	char errbuf[256];
508 	int eval;
509 	struct val *v;
510 
511 	/* coerce to both arguments to strings */
512 	to_string(a);
513 	to_string(b);
514 
515 	/* compile regular expression */
516 	if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
517 		regerror (eval, &rp, errbuf, sizeof(errbuf));
518 		errx (2, "%s", errbuf);
519 	}
520 
521 	/* compare string against pattern */
522 	/* remember that patterns are anchored to the beginning of the line */
523 	if (regexec(&rp, a->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
524 		if (rm[1].rm_so >= 0) {
525 			*(a->u.s + rm[1].rm_eo) = '\0';
526 			v = make_str (a->u.s + rm[1].rm_so);
527 
528 		} else {
529 			v = make_integer (rm[0].rm_eo - rm[0].rm_so);
530 		}
531 	} else {
532 		if (rp.re_nsub == 0) {
533 			v = make_integer (0);
534 		} else {
535 			v = make_str ("");
536 		}
537 	}
538 
539 	/* free arguments and pattern buffer */
540 	free_value (a);
541 	free_value (b);
542 	regfree (&rp);
543 
544 	return v;
545 }
546