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