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 $
8 * $DragonFly: src/bin/expr/expr.y,v 1.6 2005/11/06 11:44:02 swildner Exp $
11 #include <sys/types.h>
23 integer
, numeric_string
, string
36 int chk_div
(quad_t
, quad_t
);
37 int chk_minus
(quad_t
, quad_t
, quad_t
);
38 int chk_plus
(quad_t
, quad_t
, quad_t
);
39 int chk_times
(quad_t
, quad_t
, quad_t
);
40 void free_value
(struct val
*);
41 int is_zero_or_null
(struct val
*);
42 int isstring
(struct val
*);
43 int main
(int, char **);
44 struct val
*make_integer
(quad_t
);
45 struct val
*make_str
(const char *);
46 struct val
*op_and
(struct val
*, struct val
*);
47 struct val
*op_colon
(struct val
*, struct val
*);
48 struct val
*op_div
(struct val
*, struct val
*);
49 struct val
*op_eq
(struct val
*, struct val
*);
50 struct val
*op_ge
(struct val
*, struct val
*);
51 struct val
*op_gt
(struct val
*, struct val
*);
52 struct val
*op_le
(struct val
*, struct val
*);
53 struct val
*op_lt
(struct val
*, struct val
*);
54 struct val
*op_minus
(struct val
*, struct val
*);
55 struct val
*op_ne
(struct val
*, struct val
*);
56 struct val
*op_or
(struct val
*, struct val
*);
57 struct val
*op_plus
(struct val
*, struct val
*);
58 struct val
*op_rem
(struct val
*, struct val
*);
59 struct val
*op_times
(struct val
*, struct val
*);
60 quad_t to_integer
(struct val
*);
61 void to_string
(struct val
*);
62 int yyerror (const char *);
75 %left
<val
> '=' '>' '<' GE LE NE
77 %left
<val
> '*' '/' '%'
81 %type
<val
> start expr
85 start: expr
{ result
= $$
; }
88 |
'(' expr
')' { $$
= $2; }
89 | expr
'|' expr
{ $$
= op_or
($1, $3); }
90 | expr
'&' expr
{ $$
= op_and
($1, $3); }
91 | expr
'=' expr
{ $$
= op_eq
($1, $3); }
92 | expr
'>' expr
{ $$
= op_gt
($1, $3); }
93 | expr
'<' expr
{ $$
= op_lt
($1, $3); }
94 | expr GE expr
{ $$
= op_ge
($1, $3); }
95 | expr LE expr
{ $$
= op_le
($1, $3); }
96 | expr NE expr
{ $$
= op_ne
($1, $3); }
97 | expr
'+' expr
{ $$
= op_plus
($1, $3); }
98 | expr
'-' expr
{ $$
= op_minus
($1, $3); }
99 | expr
'*' expr
{ $$
= op_times
($1, $3); }
100 | expr
'/' expr
{ $$
= op_div
($1, $3); }
101 | expr
'%' expr
{ $$
= op_rem
($1, $3); }
102 | expr
':' expr
{ $$
= op_colon
($1, $3); }
109 make_integer
(quad_t i
)
113 vp
= (struct val
*) malloc
(sizeof
(*vp
));
115 errx
(2, "malloc() failed");
124 make_str
(const char *s
)
130 vp
= (struct val
*) malloc
(sizeof
(*vp
));
131 if
(vp
== NULL ||
((vp
->u.s
= strdup
(s
)) == NULL
)) {
132 errx
(2, "malloc() failed");
135 for
(i
= 1, isint
= isdigit
(s
[0]) || s
[0] == '-';
136 isint
&& i
< strlen
(s
);
144 vp
->type
= numeric_string
;
153 free_value
(struct val
*vp
)
155 if
(vp
->type
== string || vp
->type
== numeric_string
)
161 to_integer
(struct val
*vp
)
165 if
(vp
->type
== integer
)
168 if
(vp
->type
== string)
171 /* vp->type == numeric_string, make it numeric */
173 i
= strtoll
(vp
->u.s
, NULL
, 10);
175 errx
(2, "overflow");
184 to_string
(struct val
*vp
)
188 if
(vp
->type
== string || vp
->type
== numeric_string
)
191 tmp
= malloc
((size_t)25);
193 errx
(2, "malloc() failed");
196 sprintf
(tmp
, "%lld", (long long)vp
->u.i
);
203 isstring
(struct val
*vp
)
205 /* only TRUE if this string is not a valid integer */
206 return
(vp
->type
== string);
220 if
(strlen
(p
) == 1) {
221 if
(strchr
("|&=<>+-*/%:()", *p
))
223 } else if
(strlen
(p
) == 2 && p
[1] == '=') {
225 case
'>': return
(GE
);
226 case
'<': return
(LE
);
227 case
'!': return
(NE
);
231 yylval.val
= make_str
(p
);
236 is_zero_or_null
(struct val
*vp
)
238 if
(vp
->type
== integer
) {
239 return
(vp
->u.i
== 0);
241 return
(*vp
->u.s
== 0 ||
(to_integer
(vp
) && vp
->u.i
== 0));
250 "usage: expr expression\n");
255 main
(int argc
, char **argv
)
257 setlocale
(LC_ALL
, "");
259 if
(argc
> 1 && strcmp
(argv
[1], "--"))
268 if
(result
->type
== integer
)
269 printf
("%lld\n", (long long)result
->u.i
);
271 printf
("%s\n", result
->u.s
);
273 return
(is_zero_or_null
(result
));
277 yyerror(const char *s __unused
)
279 errx
(2, "syntax error");
284 op_or
(struct val
*a
, struct val
*b
)
286 if
(is_zero_or_null
(a
)) {
296 op_and
(struct val
*a
, struct val
*b
)
298 if
(is_zero_or_null
(a
) || is_zero_or_null
(b
)) {
301 return
(make_integer
((quad_t
)0));
309 op_eq
(struct val
*a
, struct val
*b
)
313 if
(isstring
(a
) || isstring
(b
)) {
316 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) == 0));
320 r
= make_integer
((quad_t
)(a
->u.i
== b
->u.i
));
329 op_gt
(struct val
*a
, struct val
*b
)
333 if
(isstring
(a
) || isstring
(b
)) {
336 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) > 0));
340 r
= make_integer
((quad_t
)(a
->u.i
> b
->u.i
));
349 op_lt
(struct val
*a
, struct val
*b
)
353 if
(isstring
(a
) || isstring
(b
)) {
356 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) < 0));
360 r
= make_integer
((quad_t
)(a
->u.i
< b
->u.i
));
369 op_ge
(struct val
*a
, struct val
*b
)
373 if
(isstring
(a
) || isstring
(b
)) {
376 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) >= 0));
380 r
= make_integer
((quad_t
)(a
->u.i
>= b
->u.i
));
389 op_le
(struct val
*a
, struct val
*b
)
393 if
(isstring
(a
) || isstring
(b
)) {
396 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) <= 0));
400 r
= make_integer
((quad_t
)(a
->u.i
<= b
->u.i
));
409 op_ne
(struct val
*a
, struct val
*b
)
413 if
(isstring
(a
) || isstring
(b
)) {
416 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) != 0));
420 r
= make_integer
((quad_t
)(a
->u.i
!= b
->u.i
));
429 chk_plus
(quad_t a
, quad_t b
, quad_t r
)
431 /* sum of two positive numbers must be positive */
432 if
(a
> 0 && b
> 0 && r
<= 0)
434 /* sum of two negative numbers must be negative */
435 if
(a
< 0 && b
< 0 && r
>= 0)
437 /* all other cases are OK */
442 op_plus
(struct val
*a
, struct val
*b
)
446 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
447 errx
(2, "non-numeric argument");
450 r
= make_integer
(/*(quad_t)*/(a
->u.i
+ b
->u.i
));
451 if
(chk_plus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
452 errx
(2, "overflow");
460 chk_minus
(quad_t a
, quad_t b
, quad_t r
)
462 /* special case subtraction of QUAD_MIN */
469 /* this is allowed for b != QUAD_MIN */
470 return chk_plus
(a
, -b
, r
);
474 op_minus
(struct val
*a
, struct val
*b
)
478 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
479 errx
(2, "non-numeric argument");
482 r
= make_integer
(/*(quad_t)*/(a
->u.i
- b
->u.i
));
483 if
(chk_minus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
484 errx
(2, "overflow");
492 chk_times
(quad_t a
, quad_t b
, quad_t r
)
494 /* special case: first operand is 0, no overflow possible */
497 /* cerify that result of division matches second operand */
504 op_times
(struct val
*a
, struct val
*b
)
508 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
509 errx
(2, "non-numeric argument");
512 r
= make_integer
(/*(quad_t)*/(a
->u.i
* b
->u.i
));
513 if
(chk_times
(a
->u.i
, b
->u.i
, r
->u.i
)) {
514 errx
(2, "overflow");
522 chk_div
(quad_t a
, quad_t b
)
524 /* div by zero has been taken care of before */
525 /* only QUAD_MIN / -1 causes overflow */
526 if
(a
== QUAD_MIN
&& b
== -1)
528 /* everything else is OK */
533 op_div
(struct val
*a
, struct val
*b
)
537 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
538 errx
(2, "non-numeric argument");
542 errx
(2, "division by zero");
545 r
= make_integer
(/*(quad_t)*/(a
->u.i
/ b
->u.i
));
546 if
(chk_div
(a
->u.i
, b
->u.i
)) {
547 errx
(2, "overflow");
555 op_rem
(struct val
*a
, struct val
*b
)
559 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
560 errx
(2, "non-numeric argument");
564 errx
(2, "division by zero");
567 r
= make_integer
(/*(quad_t)*/(a
->u.i % b
->u.i
));
568 /* chk_rem necessary ??? */
575 op_colon
(struct val
*a
, struct val
*b
)
583 /* coerce to both arguments to strings */
587 /* compile regular expression */
588 if
((eval
= regcomp
(&rp
, b
->u.s
, 0)) != 0) {
589 regerror
(eval
, &rp
, errbuf
, sizeof
(errbuf
));
590 errx
(2, "%s", errbuf
);
593 /* compare string against pattern */
594 /* remember that patterns are anchored to the beginning of the line */
595 if
(regexec
(&rp
, a
->u.s
, (size_t)2, rm
, 0) == 0 && rm
[0].rm_so
== 0) {
596 if
(rm
[1].rm_so
>= 0) {
597 *(a
->u.s
+ rm
[1].rm_eo
) = '\0';
598 v
= make_str
(a
->u.s
+ rm
[1].rm_so
);
601 v
= make_integer
((quad_t
)(rm
[0].rm_eo
- rm
[0].rm_so
));
604 if
(rp.re_nsub
== 0) {
605 v
= make_integer
((quad_t
)0);
611 /* free arguments and pattern buffer */