expr.y revision 50471
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 * $FreeBSD: head/bin/expr/expr.y 50471 1999-08-27 23:15:48Z peter $
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
17enum valtype {
18	integer, numeric_string, string
19} ;
20
21struct val {
22	enum valtype type;
23	union {
24		char *s;
25		int   i;
26	} u;
27} ;
28
29struct val *result;
30struct val *op_or ();
31struct val *op_and ();
32struct val *op_eq ();
33struct val *op_gt ();
34struct val *op_lt ();
35struct val *op_ge ();
36struct val *op_le ();
37struct val *op_ne ();
38struct val *op_plus ();
39struct val *op_minus ();
40struct val *op_times ();
41struct val *op_div ();
42struct val *op_rem ();
43struct val *op_colon ();
44
45char **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
65start: expr { result = $$; }
66
67expr:	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
88struct val *
89make_integer (i)
90int 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
104struct val *
105make_str (s)
106char *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
133void
134free_value (vp)
135struct val *vp;
136{
137	if (vp->type == string || vp->type == numeric_string)
138		free (vp->u.s);
139}
140
141
142int
143to_integer (vp)
144struct 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
162void
163to_string (vp)
164struct 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
182int
183isstring (vp)
184struct val *vp;
185{
186	/* only TRUE if this string is not a valid integer */
187	return (vp->type == string);
188}
189
190
191int
192yylex ()
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
216int
217is_zero_or_null (vp)
218struct 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
228int yyparse ();
229
230int
231main (argc, argv)
232int argc;
233char **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
249int
250yyerror (s)
251char *s;
252{
253	errx (2, "syntax error");
254}
255
256
257struct val *
258op_or (a, b)
259struct 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
270struct val *
271op_and (a, b)
272struct 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
284struct val *
285op_eq (a, b)
286struct 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
305struct val *
306op_gt (a, b)
307struct 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
326struct val *
327op_lt (a, b)
328struct 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
347struct val *
348op_ge (a, b)
349struct 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
368struct val *
369op_le (a, b)
370struct 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
389struct val *
390op_ne (a, b)
391struct 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
410struct val *
411op_plus (a, b)
412struct 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
426struct val *
427op_minus (a, b)
428struct 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
442struct val *
443op_times (a, b)
444struct 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
458struct val *
459op_div (a, b)
460struct 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
478struct val *
479op_rem (a, b)
480struct 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
501struct val *
502op_colon (a, b)
503struct 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