expr.y revision 31
1%{
2/* Written by Pace Willisson (pace@blitz.com)
3 * and placed in the public domain
4 *
5 * /b/source/CVS/src/bin/expr/expr.y,v 1.6 1993/06/14 19:59:07 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	/* Like most other versions of expr, this version will return
223	   false for a string value of multiple zeros.*/
224
225	if (vp->type == integer) {
226		return (vp->u.i == 0);
227	} else {
228		return (*vp->u.s == 0 || strcmp (vp->u.s, "0") == 0);
229	}
230	/* NOTREACHED */
231}
232
233void
234main (argc, argv)
235int argc;
236char **argv;
237{
238	av = argv + 1;
239
240	yyparse ();
241
242	if (result->type == integer)
243		printf ("%d\n", result->u.i);
244	else
245		printf ("%s\n", result->u.s);
246
247	if (is_zero_or_null (result))
248		exit (1);
249	else
250		exit (0);
251}
252
253int
254yyerror (s)
255char *s;
256{
257	fprintf (stderr, "expr: syntax error\n");
258	exit (2);
259}
260
261
262struct val *
263op_or (a, b)
264struct val *a, *b;
265{
266	if (is_zero_or_null (a)) {
267		free_value (a);
268		return (b);
269	} else {
270		free_value (b);
271		return (a);
272	}
273}
274
275struct val *
276op_and (a, b)
277struct val *a, *b;
278{
279	if (is_zero_or_null (a) || is_zero_or_null (b)) {
280		free_value (a);
281		free_value (b);
282		return (make_integer (0));
283	} else {
284		free_value (b);
285		return (a);
286	}
287}
288
289struct val *
290op_eq (a, b)
291struct val *a, *b;
292{
293	struct val *r;
294
295	/* attempt to coerce both arguments to integers */
296	(void) to_integer (a);
297	(void) to_integer (b);
298
299	/* But if either one of them really is a string, do
300	   a string comparison */
301	if (isstring (a) || isstring (b)) {
302		to_string (a);
303		to_string (b);
304		r = make_integer (strcmp (a->u.s, b->u.s) == 0);
305	} else {
306		r = make_integer (a->u.i == b->u.i);
307	}
308
309	free_value (a);
310	free_value (b);
311	return r;
312}
313
314struct val *
315op_gt (a, b)
316struct val *a, *b;
317{
318	struct val *r;
319
320	/* attempt to coerce both arguments to integers */
321	(void) to_integer (a);
322	(void) to_integer (b);
323
324	/* But if either one of them really is a string, do
325	   a string comparison */
326	if (isstring (a) || isstring (b)) {
327		to_string (a);
328		to_string (b);
329		r = make_integer (strcmp (a->u.s, b->u.s) > 0);
330	} else {
331		r= make_integer (a->u.i > b->u.i);
332	}
333
334	free_value (a);
335	free_value (b);
336	return r;
337}
338
339struct val *
340op_lt (a, b)
341struct val *a, *b;
342{
343	struct val *r;
344
345	/* attempt to coerce both arguments to integers */
346	(void) to_integer (a);
347	(void) to_integer (b);
348
349	/* But if either one of them really is a string, do
350	   a string comparison */
351	if (isstring (a) || isstring (b)) {
352		to_string (a);
353		to_string (b);
354		r = make_integer (strcmp (a->u.s, b->u.s) < 0);
355	} else {
356		r = make_integer (a->u.i < b->u.i);
357	}
358
359	free_value (a);
360	free_value (b);
361	return r;
362}
363
364struct val *
365op_ge (a, b)
366struct val *a, *b;
367{
368	struct val *r;
369
370	/* attempt to coerce both arguments to integers */
371	(void) to_integer (a);
372	(void) to_integer (b);
373
374	/* But if either one of them really is a string, do
375	   a string comparison */
376	if (isstring (a) || isstring (b)) {
377		to_string (a);
378		to_string (b);
379		r = make_integer (strcmp (a->u.s, b->u.s) >= 0);
380	} else {
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_le (a, b)
391struct val *a, *b;
392{
393	struct val *r;
394
395	/* attempt to coerce both arguments to integers */
396	(void) to_integer (a);
397	(void) to_integer (b);
398
399	/* But if either one of them really is a string, do
400	   a string comparison */
401	if (isstring (a) || isstring (b)) {
402		to_string (a);
403		to_string (b);
404		r = make_integer (strcmp (a->u.s, b->u.s) <= 0);
405	} else {
406		r = make_integer (a->u.i <= b->u.i);
407	}
408
409	free_value (a);
410	free_value (b);
411	return r;
412}
413
414struct val *
415op_ne (a, b)
416struct val *a, *b;
417{
418	struct val *r;
419
420	/* attempt to coerce both arguments to integers */
421	(void) to_integer (a);
422	(void) to_integer (b);
423
424	/* But if either one of them really is a string, do
425	   a string comparison */
426	if (isstring (a) || isstring (b)) {
427		to_string (a);
428		to_string (b);
429		r = make_integer (strcmp (a->u.s, b->u.s) != 0);
430	} else {
431		r = make_integer (a->u.i != b->u.i);
432	}
433
434	free_value (a);
435	free_value (b);
436	return r;
437}
438
439struct val *
440op_plus (a, b)
441struct val *a, *b;
442{
443	struct val *r;
444
445	if (!to_integer (a) || !to_integer (b)) {
446		fprintf (stderr, "expr: non-numeric argument\n");
447		exit (2);
448	}
449
450	r = make_integer (a->u.i + b->u.i);
451	free_value (a);
452	free_value (b);
453	return r;
454}
455
456struct val *
457op_minus (a, b)
458struct val *a, *b;
459{
460	struct val *r;
461
462	if (!to_integer (a) || !to_integer (b)) {
463		fprintf (stderr, "expr: non-numeric argument\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_times (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	r = make_integer (a->u.i * b->u.i);
485	free_value (a);
486	free_value (b);
487	return (r);
488}
489
490struct val *
491op_div (a, b)
492struct val *a, *b;
493{
494	struct val *r;
495
496	if (!to_integer (a) || !to_integer (b)) {
497		fprintf (stderr, "expr: non-numeric argument\n");
498		exit (2);
499	}
500
501	if (b->u.i == 0) {
502		fprintf (stderr, "expr: division by zero\n");
503		exit (2);
504	}
505
506	r = make_integer (a->u.i / b->u.i);
507	free_value (a);
508	free_value (b);
509	return r;
510}
511
512struct val *
513op_rem (a, b)
514struct val *a, *b;
515{
516	struct val *r;
517
518	if (!to_integer (a) || !to_integer (b)) {
519		fprintf (stderr, "expr: non-numeric argument\n");
520		exit (2);
521	}
522
523	if (b->u.i == 0) {
524		fprintf (stderr, "expr: division by zero\n");
525		exit (2);
526	}
527
528	r = make_integer (a->u.i % b->u.i);
529	free_value (a);
530	free_value (b);
531	return r;
532}
533
534#include <regex.h>
535#define SE_MAX	30
536
537struct val *
538op_colon (a, b)
539struct val *a, *b;
540{
541	regex_t rp;
542	regmatch_t rm[SE_MAX];
543	char errbuf[256];
544	int eval;
545	char *newpat;
546	struct val *v;
547
548	/* patterns are anchored to the beginning of the line */
549	newpat = malloc (strlen (b->u.s) + 2);
550	strcpy (newpat, "^");
551	strcat (newpat, b->u.s);
552
553	/* compile regular expression */
554	if ((eval = regcomp (&rp, newpat, 0)) != 0) {
555		regerror (eval, &rp, errbuf, sizeof(errbuf));
556		fprintf (stderr, "expr: %s\n", errbuf);
557		exit (2);
558	}
559	free (newpat);
560
561	/* compare string against pattern */
562	if (regexec(&rp, a->u.s, SE_MAX, rm, 0) == 0) {
563		if (rm[1].rm_so >= 0) {
564			*(a->u.s + rm[1].rm_eo) = 0;
565			v = make_str (a->u.s + rm[1].rm_so);
566
567		} else {
568			v = make_integer (rm[0].rm_eo - rm[0].rm_so);
569		}
570	} else {
571		v = make_integer (0);
572	}
573
574	/* free arguments and pattern buffer */
575	free_value (a);
576	free_value (b);
577	regfree (&rp);
578
579	return v;
580}
581