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