expr.y revision 181
1%{
2/* Written by Pace Willisson (pace@blitz.com)
3 * and placed in the public domain
4 *
5 * $Header: /b/source/CVS/src/bin/expr/expr.y,v 1.9 1993/07/20 01:10:55 jtc Exp $
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <ctype.h>
11
12enum valtype {
13	integer, string
14} ;
15
16struct val {
17	enum valtype type;
18	union {
19		char *s;
20		int   i;
21	} u;
22} ;
23
24struct val *result;
25struct val *op_or ();
26struct val *op_and ();
27struct val *op_eq ();
28struct val *op_gt ();
29struct val *op_lt ();
30struct val *op_ge ();
31struct val *op_le ();
32struct val *op_ne ();
33struct val *op_plus ();
34struct val *op_minus ();
35struct val *op_times ();
36struct val *op_div ();
37struct val *op_rem ();
38struct val *op_colon ();
39
40char **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
61start: expr { result = $$; }
62
63expr:	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
85struct val *
86make_integer (i)
87int i;
88{
89	struct val *vp;
90
91	vp = (struct val *) malloc (sizeof (*vp));
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
102struct val *
103make_str (s)
104char *s;
105{
106	struct val *vp;
107
108	vp = (struct val *) malloc (sizeof (*vp));
109	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
110		fprintf (stderr, "expr: out of memory\n");
111		exit (2);
112	}
113
114	vp->type = string;
115	return vp;
116}
117
118
119void
120free_value (vp)
121struct val *vp;
122{
123	if (vp->type == string)
124		free (vp->u.s);
125}
126
127
128int
129to_integer (vp)
130struct 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';
152	}
153
154	free (vp->u.s);
155	if (neg)
156		i *= -1;
157
158	vp->type = integer;
159	vp->u.i  = i;
160	return 1;
161}
162
163void
164to_string (vp)
165struct val *vp;
166{
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
183
184int
185isstring (vp)
186struct val *vp;
187{
188	return (vp->type == string);
189}
190
191
192int
193yylex ()
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) {
204		if (strchr ("|&=<>+-*/%:()", *p))
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
214	yylval.val = make_str (p);
215	return (TOKEN);
216}
217
218int
219is_zero_or_null (vp)
220struct val *vp;
221{
222	if (vp->type == integer) {
223		return (vp->u.i == 0);
224	} else {
225		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
226	}
227	/* NOTREACHED */
228}
229
230void
231main (argc, argv)
232int argc;
233char **argv;
234{
235	av = argv + 1;
236
237	yyparse ();
238
239	if (result->type == integer)
240		printf ("%d\n", result->u.i);
241	else
242		printf ("%s\n", result->u.s);
243
244	if (is_zero_or_null (result))
245		exit (1);
246	else
247		exit (0);
248}
249
250int
251yyerror (s)
252char *s;
253{
254	fprintf (stderr, "expr: syntax error\n");
255	exit (2);
256}
257
258
259struct val *
260op_or (a, b)
261struct val *a, *b;
262{
263	if (is_zero_or_null (a)) {
264		free_value (a);
265		return (b);
266	} else {
267		free_value (b);
268		return (a);
269	}
270}
271
272struct val *
273op_and (a, b)
274struct val *a, *b;
275{
276	if (is_zero_or_null (a) || is_zero_or_null (b)) {
277		free_value (a);
278		free_value (b);
279		return (make_integer (0));
280	} else {
281		free_value (b);
282		return (a);
283	}
284}
285
286struct val *
287op_eq (a, b)
288struct val *a, *b;
289{
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;
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 (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;
322}
323
324struct val *
325op_lt (a, b)
326struct val *a, *b;
327{
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;
341}
342
343struct val *
344op_ge (a, b)
345struct val *a, *b;
346{
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;
360}
361
362struct val *
363op_le (a, b)
364struct val *a, *b;
365{
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;
379}
380
381struct val *
382op_ne (a, b)
383struct val *a, *b;
384{
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;
398}
399
400struct val *
401op_plus (a, b)
402struct val *a, *b;
403{
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	}
410
411	r = make_integer (a->u.i + b->u.i);
412	free_value (a);
413	free_value (b);
414	return r;
415}
416
417struct val *
418op_minus (a, b)
419struct val *a, *b;
420{
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	}
427
428	r = make_integer (a->u.i - b->u.i);
429	free_value (a);
430	free_value (b);
431	return r;
432}
433
434struct val *
435op_times (a, b)
436struct val *a, *b;
437{
438	struct val *r;
439
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);
449}
450
451struct val *
452op_div (a, b)
453struct val *a, *b;
454{
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	}
466
467	r = make_integer (a->u.i / b->u.i);
468	free_value (a);
469	free_value (b);
470	return r;
471}
472
473struct val *
474op_rem (a, b)
475struct val *a, *b;
476{
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	}
488
489	r = make_integer (a->u.i % b->u.i);
490	free_value (a);
491	free_value (b);
492	return r;
493}
494
495#include <regex.h>
496#define SE_MAX	30
497
498struct val *
499op_colon (a, b)
500struct val *a, *b;
501{
502	regex_t rp;
503	regmatch_t rm[SE_MAX];
504	char errbuf[256];
505	int eval;
506	struct val *v;
507	char *newpat;
508
509	/* coerce to both arguments to strings */
510	to_string(a);
511	to_string(b);
512
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
518	/* compile regular expression */
519	if ((eval = regcomp (&rp, newpat, 0)) != 0) {
520		regerror (eval, &rp, errbuf, sizeof(errbuf));
521		fprintf (stderr, "expr: %s\n", errbuf);
522		exit (2);
523	}
524	free (newpat);
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);
531
532		} else {
533			v = make_integer (rm[0].rm_eo - rm[0].rm_so);
534		}
535	} else {
536		v = make_integer (0);
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