2 /* Written by Pace Willisson (pace@blitz.com)
3 * and placed in the public domain.
5 * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
7 * $FreeBSD: src/bin/expr/expr.y,v 1.14.2.3 2001/08/01 02:37:46 obrien Exp $
10 #include <sys/types.h>
22 integer
, numeric_string
, string
35 int chk_div
(quad_t
, quad_t
);
36 int chk_minus
(quad_t
, quad_t
, quad_t
);
37 int chk_plus
(quad_t
, quad_t
, quad_t
);
38 int chk_times
(quad_t
, quad_t
, quad_t
);
39 void free_value
(struct val
*);
40 int is_zero_or_null
(struct val
*);
41 int isstring
(struct val
*);
42 int main
(int, char **);
43 struct val
*make_integer
(quad_t
);
44 struct val
*make_str
(const char *);
45 struct val
*op_and
(struct val
*, struct val
*);
46 struct val
*op_colon
(struct val
*, struct val
*);
47 struct val
*op_div
(struct val
*, struct val
*);
48 struct val
*op_eq
(struct val
*, struct val
*);
49 struct val
*op_ge
(struct val
*, struct val
*);
50 struct val
*op_gt
(struct val
*, struct val
*);
51 struct val
*op_le
(struct val
*, struct val
*);
52 struct val
*op_lt
(struct val
*, struct val
*);
53 struct val
*op_minus
(struct val
*, struct val
*);
54 struct val
*op_ne
(struct val
*, struct val
*);
55 struct val
*op_or
(struct val
*, struct val
*);
56 struct val
*op_plus
(struct val
*, struct val
*);
57 struct val
*op_rem
(struct val
*, struct val
*);
58 struct val
*op_times
(struct val
*, struct val
*);
59 quad_t to_integer
(struct val
*);
60 void to_string
(struct val
*);
61 int yyerror (const char *) __dead2
;
74 %left
<val
> '=' '>' '<' GE LE NE
76 %left
<val
> '*' '/' '%'
80 %type
<val
> start expr
84 start: expr
{ result
= $$
; }
87 |
'(' expr
')' { $$
= $2; }
88 | expr
'|' expr
{ $$
= op_or
($1, $3); }
89 | expr
'&' expr
{ $$
= op_and
($1, $3); }
90 | expr
'=' expr
{ $$
= op_eq
($1, $3); }
91 | expr
'>' expr
{ $$
= op_gt
($1, $3); }
92 | expr
'<' expr
{ $$
= op_lt
($1, $3); }
93 | expr GE expr
{ $$
= op_ge
($1, $3); }
94 | expr LE expr
{ $$
= op_le
($1, $3); }
95 | expr NE expr
{ $$
= op_ne
($1, $3); }
96 | expr
'+' expr
{ $$
= op_plus
($1, $3); }
97 | expr
'-' expr
{ $$
= op_minus
($1, $3); }
98 | expr
'*' expr
{ $$
= op_times
($1, $3); }
99 | expr
'/' expr
{ $$
= op_div
($1, $3); }
100 | expr
'%' expr
{ $$
= op_rem
($1, $3); }
101 | expr
':' expr
{ $$
= op_colon
($1, $3); }
108 make_integer
(quad_t i
)
112 vp
= (struct val
*) malloc
(sizeof
(*vp
));
114 errx
(2, "malloc() failed");
123 make_str
(const char *s
)
129 vp
= (struct val
*) malloc
(sizeof
(*vp
));
130 if
(vp
== NULL ||
((vp
->u.s
= strdup
(s
)) == NULL
)) {
131 errx
(2, "malloc() failed");
134 for
(i
= 1, isint
= isdigit
(s
[0]) || s
[0] == '-';
135 isint
&& i
< strlen
(s
);
143 vp
->type
= numeric_string
;
152 free_value
(struct val
*vp
)
154 if
(vp
->type
== string || vp
->type
== numeric_string
)
160 to_integer
(struct val
*vp
)
164 if
(vp
->type
== integer
)
167 if
(vp
->type
== string)
170 /* vp->type == numeric_string, make it numeric */
172 i
= strtoll
(vp
->u.s
, NULL
, 10);
174 errx
(2, "overflow");
183 to_string
(struct val
*vp
)
187 if
(vp
->type
== string || vp
->type
== numeric_string
)
190 tmp
= malloc
((size_t)25);
192 errx
(2, "malloc() failed");
195 sprintf
(tmp
, "%lld", (long long)vp
->u.i
);
202 isstring
(struct val
*vp
)
204 /* only TRUE if this string is not a valid integer */
205 return
(vp
->type
== string);
219 if
(strlen
(p
) == 1) {
220 if
(strchr
("|&=<>+-*/%:()", *p
))
222 } else if
(strlen
(p
) == 2 && p
[1] == '=') {
224 case
'>': return
(GE
);
225 case
'<': return
(LE
);
226 case
'!': return
(NE
);
230 yylval.val
= make_str
(p
);
235 is_zero_or_null
(struct val
*vp
)
237 if
(vp
->type
== integer
) {
238 return
(vp
->u.i
== 0);
240 return
(*vp
->u.s
== 0 ||
(to_integer
(vp
) && vp
->u.i
== 0));
249 "usage: expr expression\n");
254 main
(int argc
, char **argv
)
256 setlocale
(LC_ALL
, "");
258 if
(argc
> 1 && strcmp
(argv
[1], "--"))
267 if
(result
->type
== integer
)
268 printf
("%lld\n", (long long)result
->u.i
);
270 printf
("%s\n", result
->u.s
);
272 return
(is_zero_or_null
(result
));
276 yyerror(const char *s __unused
)
278 errx
(2, "syntax error");
283 op_or
(struct val
*a
, struct val
*b
)
285 if
(is_zero_or_null
(a
)) {
295 op_and
(struct val
*a
, struct val
*b
)
297 if
(is_zero_or_null
(a
) || is_zero_or_null
(b
)) {
300 return
(make_integer
((quad_t
)0));
308 op_eq
(struct val
*a
, struct val
*b
)
312 if
(isstring
(a
) || isstring
(b
)) {
315 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) == 0));
319 r
= make_integer
((quad_t
)(a
->u.i
== b
->u.i
));
328 op_gt
(struct val
*a
, struct val
*b
)
332 if
(isstring
(a
) || isstring
(b
)) {
335 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) > 0));
339 r
= make_integer
((quad_t
)(a
->u.i
> b
->u.i
));
348 op_lt
(struct val
*a
, struct val
*b
)
352 if
(isstring
(a
) || isstring
(b
)) {
355 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) < 0));
359 r
= make_integer
((quad_t
)(a
->u.i
< b
->u.i
));
368 op_ge
(struct val
*a
, struct val
*b
)
372 if
(isstring
(a
) || isstring
(b
)) {
375 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) >= 0));
379 r
= make_integer
((quad_t
)(a
->u.i
>= b
->u.i
));
388 op_le
(struct val
*a
, struct val
*b
)
392 if
(isstring
(a
) || isstring
(b
)) {
395 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) <= 0));
399 r
= make_integer
((quad_t
)(a
->u.i
<= b
->u.i
));
408 op_ne
(struct val
*a
, struct val
*b
)
412 if
(isstring
(a
) || isstring
(b
)) {
415 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) != 0));
419 r
= make_integer
((quad_t
)(a
->u.i
!= b
->u.i
));
428 chk_plus
(quad_t a
, quad_t b
, quad_t r
)
430 /* sum of two positive numbers must be positive */
431 if
(a
> 0 && b
> 0 && r
<= 0)
433 /* sum of two negative numbers must be negative */
434 if
(a
< 0 && b
< 0 && r
>= 0)
436 /* all other cases are OK */
441 op_plus
(struct val
*a
, struct val
*b
)
445 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
446 errx
(2, "non-numeric argument");
449 r
= make_integer
(/*(quad_t)*/(a
->u.i
+ b
->u.i
));
450 if
(chk_plus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
451 errx
(2, "overflow");
459 chk_minus
(quad_t a
, quad_t b
, quad_t r
)
461 /* special case subtraction of QUAD_MIN */
468 /* this is allowed for b != QUAD_MIN */
469 return chk_plus
(a
, -b
, r
);
473 op_minus
(struct val
*a
, struct val
*b
)
477 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
478 errx
(2, "non-numeric argument");
481 r
= make_integer
(/*(quad_t)*/(a
->u.i
- b
->u.i
));
482 if
(chk_minus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
483 errx
(2, "overflow");
491 chk_times
(quad_t a
, quad_t b
, quad_t r
)
493 /* special case: first operand is 0, no overflow possible */
496 /* cerify that result of division matches second operand */
503 op_times
(struct val
*a
, struct val
*b
)
507 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
508 errx
(2, "non-numeric argument");
511 r
= make_integer
(/*(quad_t)*/(a
->u.i
* b
->u.i
));
512 if
(chk_times
(a
->u.i
, b
->u.i
, r
->u.i
)) {
513 errx
(2, "overflow");
521 chk_div
(quad_t a
, quad_t b
)
523 /* div by zero has been taken care of before */
524 /* only QUAD_MIN / -1 causes overflow */
525 if
(a
== QUAD_MIN
&& b
== -1)
527 /* everything else is OK */
532 op_div
(struct val
*a
, struct val
*b
)
536 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
537 errx
(2, "non-numeric argument");
541 errx
(2, "division by zero");
544 r
= make_integer
(/*(quad_t)*/(a
->u.i
/ b
->u.i
));
545 if
(chk_div
(a
->u.i
, b
->u.i
)) {
546 errx
(2, "overflow");
554 op_rem
(struct val
*a
, struct val
*b
)
558 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
559 errx
(2, "non-numeric argument");
563 errx
(2, "division by zero");
566 r
= make_integer
(/*(quad_t)*/(a
->u.i % b
->u.i
));
567 /* chk_rem necessary ??? */
574 op_colon
(struct val
*a
, struct val
*b
)
582 /* coerce to both arguments to strings */
586 /* compile regular expression */
587 if
((eval
= regcomp
(&rp
, b
->u.s
, 0)) != 0) {
588 regerror
(eval
, &rp
, errbuf
, sizeof
(errbuf
));
589 errx
(2, "%s", errbuf
);
592 /* compare string against pattern */
593 /* remember that patterns are anchored to the beginning of the line */
594 if
(regexec
(&rp
, a
->u.s
, (size_t)2, rm
, 0) == 0 && rm
[0].rm_so
== 0) {
595 if
(rm
[1].rm_so
>= 0) {
596 *(a
->u.s
+ rm
[1].rm_eo
) = '\0';
597 v
= make_str
(a
->u.s
+ rm
[1].rm_so
);
600 v
= make_integer
((quad_t
)(rm
[0].rm_eo
- rm
[0].rm_so
));
603 if
(rp.re_nsub
== 0) {
604 v
= make_integer
((quad_t
)0);
610 /* free arguments and pattern buffer */