xref: /freebsd/bin/expr/expr.y (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
15b81b6b3SRodney W. Grimes %{
29ddb49cbSWarner Losh /*-
39ddb49cbSWarner Losh  * Written by Pace Willisson (pace@blitz.com)
455c497bfSJ.T. Conklin  * and placed in the public domain.
55b81b6b3SRodney W. Grimes  *
655c497bfSJ.T. Conklin  * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
75b81b6b3SRodney W. Grimes  */
84cf61abaSJ.T. Conklin 
964867286SStefan Eßer #include <sys/types.h>
10f07e4247SGarrett Wollman 
115b81b6b3SRodney W. Grimes #include <ctype.h>
1255c497bfSJ.T. Conklin #include <err.h>
13915198b4SStefan Eßer #include <errno.h>
14f07e4247SGarrett Wollman #include <inttypes.h>
15915198b4SStefan Eßer #include <limits.h>
16f07e4247SGarrett Wollman #include <locale.h>
17f07e4247SGarrett Wollman #include <stdio.h>
18f07e4247SGarrett Wollman #include <stdlib.h>
19f07e4247SGarrett Wollman #include <string.h>
20f07e4247SGarrett Wollman #include <regex.h>
21f07e4247SGarrett Wollman #include <unistd.h>
22f07e4247SGarrett Wollman 
23f07e4247SGarrett Wollman /*
24f07e4247SGarrett Wollman  * POSIX specifies a specific error code for syntax errors.  We exit
25f07e4247SGarrett Wollman  * with this code for all errors.
26f07e4247SGarrett Wollman  */
27f07e4247SGarrett Wollman #define	ERR_EXIT	2
285b81b6b3SRodney W. Grimes 
295b81b6b3SRodney W. Grimes enum valtype {
30717252eaSJoerg Wunsch 	integer, numeric_string, string
315b81b6b3SRodney W. Grimes } ;
325b81b6b3SRodney W. Grimes 
335b81b6b3SRodney W. Grimes struct val {
345b81b6b3SRodney W. Grimes 	enum valtype type;
355b81b6b3SRodney W. Grimes 	union {
365b81b6b3SRodney W. Grimes 		char *s;
37f07e4247SGarrett Wollman 		intmax_t i;
385b81b6b3SRodney W. Grimes 	} u;
395b81b6b3SRodney W. Grimes } ;
405b81b6b3SRodney W. Grimes 
416fbe7bf4SStefan Eßer char		**av;
426fbe7bf4SStefan Eßer int		nonposix;
435b81b6b3SRodney W. Grimes struct val	*result;
443d06e95dSKris Kennaway 
45fa717604SStefan Eßer void		assert_to_integer(struct val *);
466fbe7bf4SStefan Eßer void		assert_div(intmax_t, intmax_t);
476fbe7bf4SStefan Eßer void		assert_minus(intmax_t, intmax_t, intmax_t);
486fbe7bf4SStefan Eßer void		assert_plus(intmax_t, intmax_t, intmax_t);
496fbe7bf4SStefan Eßer void		assert_times(intmax_t, intmax_t, intmax_t);
506fbe7bf4SStefan Eßer int		compare_vals(struct val *, struct val *);
517669d0fcSWarner Losh void		free_value(struct val *);
52fa717604SStefan Eßer int		is_integer(const char *);
5369759f08SStefan Eßer int		is_string(struct val *);
54fa717604SStefan Eßer int		is_zero_or_null(struct val *);
55f07e4247SGarrett Wollman struct val	*make_integer(intmax_t);
567669d0fcSWarner Losh struct val	*make_str(const char *);
577669d0fcSWarner Losh struct val	*op_and(struct val *, struct val *);
587669d0fcSWarner Losh struct val	*op_colon(struct val *, struct val *);
597669d0fcSWarner Losh struct val	*op_div(struct val *, struct val *);
607669d0fcSWarner Losh struct val	*op_eq(struct val *, struct val *);
617669d0fcSWarner Losh struct val	*op_ge(struct val *, struct val *);
627669d0fcSWarner Losh struct val	*op_gt(struct val *, struct val *);
637669d0fcSWarner Losh struct val	*op_le(struct val *, struct val *);
647669d0fcSWarner Losh struct val	*op_lt(struct val *, struct val *);
657669d0fcSWarner Losh struct val	*op_minus(struct val *, struct val *);
667669d0fcSWarner Losh struct val	*op_ne(struct val *, struct val *);
677669d0fcSWarner Losh struct val	*op_or(struct val *, struct val *);
687669d0fcSWarner Losh struct val	*op_plus(struct val *, struct val *);
697669d0fcSWarner Losh struct val	*op_rem(struct val *, struct val *);
707669d0fcSWarner Losh struct val	*op_times(struct val *, struct val *);
71fa717604SStefan Eßer int		to_integer(struct val *);
727669d0fcSWarner Losh void		to_string(struct val *);
737669d0fcSWarner Losh int		yyerror(const char *);
747669d0fcSWarner Losh int		yylex(void);
755b81b6b3SRodney W. Grimes 
765b81b6b3SRodney W. Grimes %}
775b81b6b3SRodney W. Grimes 
785b81b6b3SRodney W. Grimes %union
795b81b6b3SRodney W. Grimes {
805b81b6b3SRodney W. Grimes 	struct val *val;
815b81b6b3SRodney W. Grimes }
825b81b6b3SRodney W. Grimes 
835b81b6b3SRodney W. Grimes %left <val> '|'
845b81b6b3SRodney W. Grimes %left <val> '&'
855b81b6b3SRodney W. Grimes %left <val> '=' '>' '<' GE LE NE
865b81b6b3SRodney W. Grimes %left <val> '+' '-'
875b81b6b3SRodney W. Grimes %left <val> '*' '/' '%'
885b81b6b3SRodney W. Grimes %left <val> ':'
895b81b6b3SRodney W. Grimes 
905b81b6b3SRodney W. Grimes %token <val> TOKEN
915b81b6b3SRodney W. Grimes %type <val> start expr
925b81b6b3SRodney W. Grimes 
935b81b6b3SRodney W. Grimes %%
945b81b6b3SRodney W. Grimes 
955b81b6b3SRodney W. Grimes start: expr { result = $$; }
965b81b6b3SRodney W. Grimes 
975b81b6b3SRodney W. Grimes expr:	TOKEN
985b81b6b3SRodney W. Grimes 	| '(' expr ')' { $$ = $2; }
995b81b6b3SRodney W. Grimes 	| expr '|' expr { $$ = op_or($1, $3); }
1005b81b6b3SRodney W. Grimes 	| expr '&' expr { $$ = op_and($1, $3); }
1015b81b6b3SRodney W. Grimes 	| expr '=' expr { $$ = op_eq($1, $3); }
1025b81b6b3SRodney W. Grimes 	| expr '>' expr { $$ = op_gt($1, $3); }
1035b81b6b3SRodney W. Grimes 	| expr '<' expr { $$ = op_lt($1, $3); }
1045b81b6b3SRodney W. Grimes 	| expr GE expr  { $$ = op_ge($1, $3); }
1055b81b6b3SRodney W. Grimes 	| expr LE expr  { $$ = op_le($1, $3); }
1065b81b6b3SRodney W. Grimes 	| expr NE expr  { $$ = op_ne($1, $3); }
1075b81b6b3SRodney W. Grimes 	| expr '+' expr { $$ = op_plus($1, $3); }
1085b81b6b3SRodney W. Grimes 	| expr '-' expr { $$ = op_minus($1, $3); }
1095b81b6b3SRodney W. Grimes 	| expr '*' expr { $$ = op_times($1, $3); }
1105b81b6b3SRodney W. Grimes 	| expr '/' expr { $$ = op_div($1, $3); }
1115b81b6b3SRodney W. Grimes 	| expr '%' expr { $$ = op_rem($1, $3); }
1125b81b6b3SRodney W. Grimes 	| expr ':' expr { $$ = op_colon($1, $3); }
1135b81b6b3SRodney W. Grimes 	;
1145b81b6b3SRodney W. Grimes 
1155b81b6b3SRodney W. Grimes %%
1165b81b6b3SRodney W. Grimes 
1175b81b6b3SRodney W. Grimes struct val *
118f07e4247SGarrett Wollman make_integer(intmax_t i)
1195b81b6b3SRodney W. Grimes {
1205b81b6b3SRodney W. Grimes 	struct val *vp;
1215b81b6b3SRodney W. Grimes 
1225b81b6b3SRodney W. Grimes 	vp = (struct val *)malloc(sizeof(*vp));
12369759f08SStefan Eßer 	if (vp == NULL)
124f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
1255b81b6b3SRodney W. Grimes 
1265b81b6b3SRodney W. Grimes 	vp->type = integer;
1275b81b6b3SRodney W. Grimes 	vp->u.i  = i;
12869759f08SStefan Eßer 	return (vp);
1295b81b6b3SRodney W. Grimes }
1305b81b6b3SRodney W. Grimes 
1315b81b6b3SRodney W. Grimes struct val *
make_str(const char * s)1327669d0fcSWarner Losh make_str(const char *s)
1335b81b6b3SRodney W. Grimes {
1345b81b6b3SRodney W. Grimes 	struct val *vp;
1355b81b6b3SRodney W. Grimes 
1365b81b6b3SRodney W. Grimes 	vp = (struct val *)malloc(sizeof(*vp));
13769759f08SStefan Eßer 	if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
138f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
1395b81b6b3SRodney W. Grimes 
140fa717604SStefan Eßer 	if (is_integer(s))
141f07e4247SGarrett Wollman 		vp->type = numeric_string;
142fa717604SStefan Eßer 	else
143fa717604SStefan Eßer 		vp->type = string;
1442a353a9fSJoerg Wunsch 
14569759f08SStefan Eßer 	return (vp);
1465b81b6b3SRodney W. Grimes }
1475b81b6b3SRodney W. Grimes 
1485b81b6b3SRodney W. Grimes void
free_value(struct val * vp)1497669d0fcSWarner Losh free_value(struct val *vp)
1505b81b6b3SRodney W. Grimes {
151717252eaSJoerg Wunsch 	if (vp->type == string || vp->type == numeric_string)
1525b81b6b3SRodney W. Grimes 		free(vp->u.s);
1535b81b6b3SRodney W. Grimes }
1545b81b6b3SRodney W. Grimes 
155fa717604SStefan Eßer int
to_integer(struct val * vp)1567669d0fcSWarner Losh to_integer(struct val *vp)
1575b81b6b3SRodney W. Grimes {
158f07e4247SGarrett Wollman 	intmax_t i;
1595b81b6b3SRodney W. Grimes 
160fa717604SStefan Eßer 	/* we can only convert numeric_string to integer, here */
161fa717604SStefan Eßer 	if (vp->type == numeric_string) {
162915198b4SStefan Eßer 		errno = 0;
163f07e4247SGarrett Wollman 		i  = strtoimax(vp->u.s, (char **)NULL, 10);
164fa717604SStefan Eßer 		/* just keep as numeric_string, if the conversion fails */
165fa717604SStefan Eßer 		if (errno != ERANGE) {
1665b81b6b3SRodney W. Grimes 			free(vp->u.s);
1675b81b6b3SRodney W. Grimes 			vp->u.i = i;
168717252eaSJoerg Wunsch 			vp->type = integer;
169fa717604SStefan Eßer 		}
170fa717604SStefan Eßer 	}
171fa717604SStefan Eßer 	return (vp->type == integer);
172fa717604SStefan Eßer }
173fa717604SStefan Eßer 
174fa717604SStefan Eßer void
assert_to_integer(struct val * vp)175fa717604SStefan Eßer assert_to_integer(struct val *vp)
176fa717604SStefan Eßer {
177fa717604SStefan Eßer 	if (vp->type == string)
178fa717604SStefan Eßer 		errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
179fa717604SStefan Eßer 	if (!to_integer(vp))
180fa717604SStefan Eßer 		errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
1815b81b6b3SRodney W. Grimes }
1825b81b6b3SRodney W. Grimes 
1835b81b6b3SRodney W. Grimes void
to_string(struct val * vp)1847669d0fcSWarner Losh to_string(struct val *vp)
1855b81b6b3SRodney W. Grimes {
1865b81b6b3SRodney W. Grimes 	char *tmp;
1875b81b6b3SRodney W. Grimes 
188717252eaSJoerg Wunsch 	if (vp->type == string || vp->type == numeric_string)
1895b81b6b3SRodney W. Grimes 		return;
1905b81b6b3SRodney W. Grimes 
191f07e4247SGarrett Wollman 	/*
192f07e4247SGarrett Wollman 	 * log_10(x) ~= 0.3 * log_2(x).  Rounding up gives the number
193f07e4247SGarrett Wollman 	 * of digits; add one each for the sign and terminating null
194f07e4247SGarrett Wollman 	 * character, respectively.
195f07e4247SGarrett Wollman 	 */
196f07e4247SGarrett Wollman #define	NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
197f07e4247SGarrett Wollman 	tmp = malloc(NDIGITS(vp->u.i));
198f07e4247SGarrett Wollman 	if (tmp == NULL)
199f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
2005b81b6b3SRodney W. Grimes 
201f07e4247SGarrett Wollman 	sprintf(tmp, "%jd", vp->u.i);
2025b81b6b3SRodney W. Grimes 	vp->type = string;
2035b81b6b3SRodney W. Grimes 	vp->u.s  = tmp;
2045b81b6b3SRodney W. Grimes }
2055b81b6b3SRodney W. Grimes 
2065b81b6b3SRodney W. Grimes int
is_integer(const char * s)207fa717604SStefan Eßer is_integer(const char *s)
208fa717604SStefan Eßer {
209fa717604SStefan Eßer 	if (nonposix) {
210fa717604SStefan Eßer 		if (*s == '\0')
211fa717604SStefan Eßer 			return (1);
212fa717604SStefan Eßer 		while (isspace((unsigned char)*s))
213fa717604SStefan Eßer 			s++;
214fa717604SStefan Eßer 	}
215fa717604SStefan Eßer 	if (*s == '-' || (nonposix && *s == '+'))
216fa717604SStefan Eßer 		s++;
217fa717604SStefan Eßer 	if (*s == '\0')
218fa717604SStefan Eßer 		return (0);
219fa717604SStefan Eßer 	while (isdigit((unsigned char)*s))
220fa717604SStefan Eßer 		s++;
221fa717604SStefan Eßer 	return (*s == '\0');
222fa717604SStefan Eßer }
223fa717604SStefan Eßer 
224fa717604SStefan Eßer int
is_string(struct val * vp)22569759f08SStefan Eßer is_string(struct val *vp)
2265b81b6b3SRodney W. Grimes {
227717252eaSJoerg Wunsch 	/* only TRUE if this string is not a valid integer */
2285b81b6b3SRodney W. Grimes 	return (vp->type == string);
2295b81b6b3SRodney W. Grimes }
2305b81b6b3SRodney W. Grimes 
2315b81b6b3SRodney W. Grimes int
yylex(void)2327669d0fcSWarner Losh yylex(void)
2335b81b6b3SRodney W. Grimes {
2345b81b6b3SRodney W. Grimes 	char *p;
2355b81b6b3SRodney W. Grimes 
2365b81b6b3SRodney W. Grimes 	if (*av == NULL)
2375b81b6b3SRodney W. Grimes 		return (0);
2385b81b6b3SRodney W. Grimes 
2395b81b6b3SRodney W. Grimes 	p = *av++;
2405b81b6b3SRodney W. Grimes 
2415b81b6b3SRodney W. Grimes 	if (strlen(p) == 1) {
2425b81b6b3SRodney W. Grimes 		if (strchr("|&=<>+-*/%:()", *p))
2435b81b6b3SRodney W. Grimes 			return (*p);
2445b81b6b3SRodney W. Grimes 	} else if (strlen(p) == 2 && p[1] == '=') {
2455b81b6b3SRodney W. Grimes 		switch (*p) {
2465b81b6b3SRodney W. Grimes 		case '>': return (GE);
2475b81b6b3SRodney W. Grimes 		case '<': return (LE);
2485b81b6b3SRodney W. Grimes 		case '!': return (NE);
2495b81b6b3SRodney W. Grimes 		}
2505b81b6b3SRodney W. Grimes 	}
2515b81b6b3SRodney W. Grimes 
2525b81b6b3SRodney W. Grimes 	yylval.val = make_str(p);
2535b81b6b3SRodney W. Grimes 	return (TOKEN);
2545b81b6b3SRodney W. Grimes }
2555b81b6b3SRodney W. Grimes 
2565b81b6b3SRodney W. Grimes int
is_zero_or_null(struct val * vp)2577669d0fcSWarner Losh is_zero_or_null(struct val *vp)
2585b81b6b3SRodney W. Grimes {
25969759f08SStefan Eßer 	if (vp->type == integer)
2605b81b6b3SRodney W. Grimes 		return (vp->u.i == 0);
26169759f08SStefan Eßer 
262c9fe00dcSJ.T. Conklin 	return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
2635b81b6b3SRodney W. Grimes }
2645b81b6b3SRodney W. Grimes 
265717252eaSJoerg Wunsch int
main(int argc,char * argv[])266f07e4247SGarrett Wollman main(int argc, char *argv[])
2675b81b6b3SRodney W. Grimes {
268f07e4247SGarrett Wollman 	int c;
2694cf61abaSJ.T. Conklin 
270f07e4247SGarrett Wollman 	setlocale(LC_ALL, "");
271c9885518SGarrett Wollman 	if (getenv("EXPR_COMPAT") != NULL
272c9885518SGarrett Wollman 	    || check_utility_compat("expr")) {
27396ab7da3SGarrett Wollman 		av = argv + 1;
274fa717604SStefan Eßer 		nonposix = 1;
27596ab7da3SGarrett Wollman 	} else {
27669759f08SStefan Eßer 		while ((c = getopt(argc, argv, "e")) != -1) {
277f07e4247SGarrett Wollman 			switch (c) {
2781393277eSGarrett Wollman 			case 'e':
279fa717604SStefan Eßer 				nonposix = 1;
2801393277eSGarrett Wollman 				break;
281f07e4247SGarrett Wollman 			default:
28269759f08SStefan Eßer 				errx(ERR_EXIT,
2831393277eSGarrett Wollman 				    "usage: expr [-e] expression\n");
28469759f08SStefan Eßer 			}
285f07e4247SGarrett Wollman 		}
286f07e4247SGarrett Wollman 		av = argv + optind;
28796ab7da3SGarrett Wollman 	}
2885b81b6b3SRodney W. Grimes 
2895b81b6b3SRodney W. Grimes 	yyparse();
2905b81b6b3SRodney W. Grimes 
2915b81b6b3SRodney W. Grimes 	if (result->type == integer)
292f07e4247SGarrett Wollman 		printf("%jd\n", result->u.i);
2935b81b6b3SRodney W. Grimes 	else
2945b81b6b3SRodney W. Grimes 		printf("%s\n", result->u.s);
2955b81b6b3SRodney W. Grimes 
296717252eaSJoerg Wunsch 	return (is_zero_or_null(result));
2975b81b6b3SRodney W. Grimes }
2985b81b6b3SRodney W. Grimes 
2995b81b6b3SRodney W. Grimes int
yyerror(const char * s __unused)3007669d0fcSWarner Losh yyerror(const char *s __unused)
3015b81b6b3SRodney W. Grimes {
302f07e4247SGarrett Wollman 	errx(ERR_EXIT, "syntax error");
3035b81b6b3SRodney W. Grimes }
3045b81b6b3SRodney W. Grimes 
3055b81b6b3SRodney W. Grimes struct val *
op_or(struct val * a,struct val * b)3067669d0fcSWarner Losh op_or(struct val *a, struct val *b)
3075b81b6b3SRodney W. Grimes {
308fa717604SStefan Eßer 	if (!is_zero_or_null(a)) {
3095b81b6b3SRodney W. Grimes 		free_value(b);
3105b81b6b3SRodney W. Grimes 		return (a);
3115b81b6b3SRodney W. Grimes 	}
312fa717604SStefan Eßer 	free_value(a);
313fa717604SStefan Eßer 	if (!is_zero_or_null(b))
314fa717604SStefan Eßer 		return (b);
315fa717604SStefan Eßer 	free_value(b);
316fa717604SStefan Eßer 	return (make_integer((intmax_t)0));
3175b81b6b3SRodney W. Grimes }
3185b81b6b3SRodney W. Grimes 
3195b81b6b3SRodney W. Grimes struct val *
op_and(struct val * a,struct val * b)3207669d0fcSWarner Losh op_and(struct val *a, struct val *b)
3215b81b6b3SRodney W. Grimes {
3225b81b6b3SRodney W. Grimes 	if (is_zero_or_null(a) || is_zero_or_null(b)) {
3235b81b6b3SRodney W. Grimes 		free_value(a);
3245b81b6b3SRodney W. Grimes 		free_value(b);
325f07e4247SGarrett Wollman 		return (make_integer((intmax_t)0));
3265b81b6b3SRodney W. Grimes 	} else {
3275b81b6b3SRodney W. Grimes 		free_value(b);
3285b81b6b3SRodney W. Grimes 		return (a);
3295b81b6b3SRodney W. Grimes 	}
3305b81b6b3SRodney W. Grimes }
3315b81b6b3SRodney W. Grimes 
3326fbe7bf4SStefan Eßer int
compare_vals(struct val * a,struct val * b)3336fbe7bf4SStefan Eßer compare_vals(struct val *a, struct val *b)
3345b81b6b3SRodney W. Grimes {
3356fbe7bf4SStefan Eßer 	int r;
3365b81b6b3SRodney W. Grimes 
33769759f08SStefan Eßer 	if (is_string(a) || is_string(b)) {
3385b81b6b3SRodney W. Grimes 		to_string(a);
3395b81b6b3SRodney W. Grimes 		to_string(b);
3406fbe7bf4SStefan Eßer 		r = strcoll(a->u.s, b->u.s);
3415b81b6b3SRodney W. Grimes 	} else {
342fa717604SStefan Eßer 		assert_to_integer(a);
343fa717604SStefan Eßer 		assert_to_integer(b);
3446fbe7bf4SStefan Eßer 		if (a->u.i > b->u.i)
3456fbe7bf4SStefan Eßer 			r = 1;
3466fbe7bf4SStefan Eßer 		else if (a->u.i < b->u.i)
3476fbe7bf4SStefan Eßer 			r = -1;
3486fbe7bf4SStefan Eßer 		else
3496fbe7bf4SStefan Eßer 			r = 0;
3505b81b6b3SRodney W. Grimes 	}
3515b81b6b3SRodney W. Grimes 
3525b81b6b3SRodney W. Grimes 	free_value(a);
3535b81b6b3SRodney W. Grimes 	free_value(b);
3546fbe7bf4SStefan Eßer 	return (r);
3556fbe7bf4SStefan Eßer }
3566fbe7bf4SStefan Eßer 
3576fbe7bf4SStefan Eßer struct val *
op_eq(struct val * a,struct val * b)3586fbe7bf4SStefan Eßer op_eq(struct val *a, struct val *b)
3596fbe7bf4SStefan Eßer {
3606fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) == 0)));
3615b81b6b3SRodney W. Grimes }
3625b81b6b3SRodney W. Grimes 
3635b81b6b3SRodney W. Grimes struct val *
op_gt(struct val * a,struct val * b)3647669d0fcSWarner Losh op_gt(struct val *a, struct val *b)
3655b81b6b3SRodney W. Grimes {
3666fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) > 0)));
3675b81b6b3SRodney W. Grimes }
3685b81b6b3SRodney W. Grimes 
3695b81b6b3SRodney W. Grimes struct val *
op_lt(struct val * a,struct val * b)3707669d0fcSWarner Losh op_lt(struct val *a, struct val *b)
3715b81b6b3SRodney W. Grimes {
3726fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) < 0)));
3735b81b6b3SRodney W. Grimes }
3745b81b6b3SRodney W. Grimes 
3755b81b6b3SRodney W. Grimes struct val *
op_ge(struct val * a,struct val * b)3767669d0fcSWarner Losh op_ge(struct val *a, struct val *b)
3775b81b6b3SRodney W. Grimes {
3786fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) >= 0)));
3795b81b6b3SRodney W. Grimes }
3805b81b6b3SRodney W. Grimes 
3815b81b6b3SRodney W. Grimes struct val *
op_le(struct val * a,struct val * b)3827669d0fcSWarner Losh op_le(struct val *a, struct val *b)
3835b81b6b3SRodney W. Grimes {
3846fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) <= 0)));
3855b81b6b3SRodney W. Grimes }
3865b81b6b3SRodney W. Grimes 
3875b81b6b3SRodney W. Grimes struct val *
op_ne(struct val * a,struct val * b)3887669d0fcSWarner Losh op_ne(struct val *a, struct val *b)
3895b81b6b3SRodney W. Grimes {
3906fbe7bf4SStefan Eßer 	return (make_integer((intmax_t)(compare_vals(a, b) != 0)));
3915b81b6b3SRodney W. Grimes }
3925b81b6b3SRodney W. Grimes 
3936fbe7bf4SStefan Eßer void
assert_plus(intmax_t a,intmax_t b,intmax_t r)3946fbe7bf4SStefan Eßer assert_plus(intmax_t a, intmax_t b, intmax_t r)
395915198b4SStefan Eßer {
3966fbe7bf4SStefan Eßer 	/*
3976fbe7bf4SStefan Eßer 	 * sum of two positive numbers must be positive,
3986fbe7bf4SStefan Eßer 	 * sum of two negative numbers must be negative
3996fbe7bf4SStefan Eßer 	 */
4006fbe7bf4SStefan Eßer 	if ((a > 0 && b > 0 && r <= 0) ||
4016fbe7bf4SStefan Eßer 	    (a < 0 && b < 0 && r >= 0))
4026fbe7bf4SStefan Eßer 		errx(ERR_EXIT, "overflow");
403915198b4SStefan Eßer }
404915198b4SStefan Eßer 
4055b81b6b3SRodney W. Grimes struct val *
op_plus(struct val * a,struct val * b)4067669d0fcSWarner Losh op_plus(struct val *a, struct val *b)
4075b81b6b3SRodney W. Grimes {
4085b81b6b3SRodney W. Grimes 	struct val *r;
4095b81b6b3SRodney W. Grimes 
410fa717604SStefan Eßer 	assert_to_integer(a);
411fa717604SStefan Eßer 	assert_to_integer(b);
4121393277eSGarrett Wollman 	r = make_integer(a->u.i + b->u.i);
4136fbe7bf4SStefan Eßer 	assert_plus(a->u.i, b->u.i, r->u.i);
4141393277eSGarrett Wollman 
4155b81b6b3SRodney W. Grimes 	free_value(a);
4165b81b6b3SRodney W. Grimes 	free_value(b);
41769759f08SStefan Eßer 	return (r);
4185b81b6b3SRodney W. Grimes }
4195b81b6b3SRodney W. Grimes 
4206fbe7bf4SStefan Eßer void
assert_minus(intmax_t a,intmax_t b,intmax_t r)4216fbe7bf4SStefan Eßer assert_minus(intmax_t a, intmax_t b, intmax_t r)
422915198b4SStefan Eßer {
423*41bd31e6SConrad Meyer 	if ((a >= 0 && b < 0 && r <= 0) ||
424*41bd31e6SConrad Meyer 	    (a < 0 && b > 0 && r >= 0))
4256fbe7bf4SStefan Eßer 		errx(ERR_EXIT, "overflow");
426915198b4SStefan Eßer }
427915198b4SStefan Eßer 
4285b81b6b3SRodney W. Grimes struct val *
op_minus(struct val * a,struct val * b)4297669d0fcSWarner Losh op_minus(struct val *a, struct val *b)
4305b81b6b3SRodney W. Grimes {
4315b81b6b3SRodney W. Grimes 	struct val *r;
4325b81b6b3SRodney W. Grimes 
433fa717604SStefan Eßer 	assert_to_integer(a);
434fa717604SStefan Eßer 	assert_to_integer(b);
4351393277eSGarrett Wollman 	r = make_integer(a->u.i - b->u.i);
4366fbe7bf4SStefan Eßer 	assert_minus(a->u.i, b->u.i, r->u.i);
4371393277eSGarrett Wollman 
4385b81b6b3SRodney W. Grimes 	free_value(a);
4395b81b6b3SRodney W. Grimes 	free_value(b);
44069759f08SStefan Eßer 	return (r);
4415b81b6b3SRodney W. Grimes }
4425b81b6b3SRodney W. Grimes 
4438da97f00SStefan Eßer /*
4448da97f00SStefan Eßer  * We depend on undefined behaviour giving a result (in r).
4458da97f00SStefan Eßer  * To test this result, pass it as volatile.  This prevents
4468da97f00SStefan Eßer  * optimizing away of the test based on the undefined behaviour.
4478da97f00SStefan Eßer  */
4486fbe7bf4SStefan Eßer void
assert_times(intmax_t a,intmax_t b,volatile intmax_t r)4498da97f00SStefan Eßer assert_times(intmax_t a, intmax_t b, volatile intmax_t r)
450915198b4SStefan Eßer {
4516fbe7bf4SStefan Eßer 	/*
4528da97f00SStefan Eßer 	 * If the first operand is 0, no overflow is possible,
4538da97f00SStefan Eßer 	 * else the result of the division test must match the
4548da97f00SStefan Eßer 	 * second operand.
4558da97f00SStefan Eßer 	 *
4568da97f00SStefan Eßer 	 * Be careful to avoid overflow in the overflow test, as
4578da97f00SStefan Eßer 	 * in assert_div().  Overflow in division would kill us
4588da97f00SStefan Eßer 	 * with a SIGFPE before getting the test wrong.  In old
4598da97f00SStefan Eßer 	 * buggy versions, optimization used to give a null test
4608da97f00SStefan Eßer 	 * instead of a SIGFPE.
4616fbe7bf4SStefan Eßer 	 */
4628da97f00SStefan Eßer 	if ((a == -1 && b == INTMAX_MIN) || (a != 0 && r / a != b))
4636fbe7bf4SStefan Eßer 		errx(ERR_EXIT, "overflow");
464915198b4SStefan Eßer }
465915198b4SStefan Eßer 
4665b81b6b3SRodney W. Grimes struct val *
op_times(struct val * a,struct val * b)4677669d0fcSWarner Losh op_times(struct val *a, struct val *b)
4685b81b6b3SRodney W. Grimes {
4695b81b6b3SRodney W. Grimes 	struct val *r;
4705b81b6b3SRodney W. Grimes 
471fa717604SStefan Eßer 	assert_to_integer(a);
472fa717604SStefan Eßer 	assert_to_integer(b);
4731393277eSGarrett Wollman 	r = make_integer(a->u.i * b->u.i);
4746fbe7bf4SStefan Eßer 	assert_times(a->u.i, b->u.i, r->u.i);
4751393277eSGarrett Wollman 
4765b81b6b3SRodney W. Grimes 	free_value(a);
4775b81b6b3SRodney W. Grimes 	free_value(b);
4785b81b6b3SRodney W. Grimes 	return (r);
4795b81b6b3SRodney W. Grimes }
4805b81b6b3SRodney W. Grimes 
4816fbe7bf4SStefan Eßer void
assert_div(intmax_t a,intmax_t b)4826fbe7bf4SStefan Eßer assert_div(intmax_t a, intmax_t b)
483915198b4SStefan Eßer {
4846fbe7bf4SStefan Eßer 	if (b == 0)
4856fbe7bf4SStefan Eßer 		errx(ERR_EXIT, "division by zero");
486f07e4247SGarrett Wollman 	/* only INTMAX_MIN / -1 causes overflow */
487f07e4247SGarrett Wollman 	if (a == INTMAX_MIN && b == -1)
4886fbe7bf4SStefan Eßer 		errx(ERR_EXIT, "overflow");
489915198b4SStefan Eßer }
490915198b4SStefan Eßer 
4915b81b6b3SRodney W. Grimes struct val *
op_div(struct val * a,struct val * b)4927669d0fcSWarner Losh op_div(struct val *a, struct val *b)
4935b81b6b3SRodney W. Grimes {
4945b81b6b3SRodney W. Grimes 	struct val *r;
4955b81b6b3SRodney W. Grimes 
496fa717604SStefan Eßer 	assert_to_integer(a);
497fa717604SStefan Eßer 	assert_to_integer(b);
4986fbe7bf4SStefan Eßer 	/* assert based on operands only, not on result */
4996fbe7bf4SStefan Eßer 	assert_div(a->u.i, b->u.i);
500fa717604SStefan Eßer 	r = make_integer(a->u.i / b->u.i);
5011393277eSGarrett Wollman 
5025b81b6b3SRodney W. Grimes 	free_value(a);
5035b81b6b3SRodney W. Grimes 	free_value(b);
50469759f08SStefan Eßer 	return (r);
5055b81b6b3SRodney W. Grimes }
5065b81b6b3SRodney W. Grimes 
5075b81b6b3SRodney W. Grimes struct val *
op_rem(struct val * a,struct val * b)5087669d0fcSWarner Losh op_rem(struct val *a, struct val *b)
5095b81b6b3SRodney W. Grimes {
5105b81b6b3SRodney W. Grimes 	struct val *r;
5115b81b6b3SRodney W. Grimes 
512fa717604SStefan Eßer 	assert_to_integer(a);
513fa717604SStefan Eßer 	assert_to_integer(b);
5146fbe7bf4SStefan Eßer 	/* pass a=1 to only check for div by zero */
5156fbe7bf4SStefan Eßer 	assert_div(1, b->u.i);
5161393277eSGarrett Wollman 	r = make_integer(a->u.i % b->u.i);
5171393277eSGarrett Wollman 
5185b81b6b3SRodney W. Grimes 	free_value(a);
5195b81b6b3SRodney W. Grimes 	free_value(b);
52069759f08SStefan Eßer 	return (r);
5215b81b6b3SRodney W. Grimes }
5225b81b6b3SRodney W. Grimes 
5235b81b6b3SRodney W. Grimes struct val *
op_colon(struct val * a,struct val * b)5247669d0fcSWarner Losh op_colon(struct val *a, struct val *b)
5255b81b6b3SRodney W. Grimes {
5264ba5f298SAndrew Moore 	regex_t rp;
5274cf61abaSJ.T. Conklin 	regmatch_t rm[2];
5284ba5f298SAndrew Moore 	char errbuf[256];
5294ba5f298SAndrew Moore 	int eval;
5304ba5f298SAndrew Moore 	struct val *v;
531c9fe00dcSJ.T. Conklin 
532e1854a84SCeri Davies 	/* coerce both arguments to strings */
533c9fe00dcSJ.T. Conklin 	to_string(a);
534c9fe00dcSJ.T. Conklin 	to_string(b);
5355b81b6b3SRodney W. Grimes 
5364ba5f298SAndrew Moore 	/* compile regular expression */
5374a13ab7cSJ.T. Conklin 	if ((eval = regcomp(&rp, b->u.s, 0)) != 0) {
5384ba5f298SAndrew Moore 		regerror(eval, &rp, errbuf, sizeof(errbuf));
539f07e4247SGarrett Wollman 		errx(ERR_EXIT, "%s", errbuf);
5405b81b6b3SRodney W. Grimes 	}
5414ba5f298SAndrew Moore 
5424ba5f298SAndrew Moore 	/* compare string against pattern */
5434a13ab7cSJ.T. Conklin 	/* remember that patterns are anchored to the beginning of the line */
54469759f08SStefan Eßer 	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0)
5454ba5f298SAndrew Moore 		if (rm[1].rm_so >= 0) {
54655c497bfSJ.T. Conklin 			*(a->u.s + rm[1].rm_eo) = '\0';
5474ba5f298SAndrew Moore 			v = make_str(a->u.s + rm[1].rm_so);
5484ba5f298SAndrew Moore 
54969759f08SStefan Eßer 		} else
5508c3bbba8SEitan Adler 			v = make_integer((intmax_t)(rm[0].rm_eo));
55169759f08SStefan Eßer 	else
55269759f08SStefan Eßer 		if (rp.re_nsub == 0)
553f07e4247SGarrett Wollman 			v = make_integer((intmax_t)0);
55469759f08SStefan Eßer 		else
55555c497bfSJ.T. Conklin 			v = make_str("");
5564ba5f298SAndrew Moore 
5574ba5f298SAndrew Moore 	/* free arguments and pattern buffer */
5584ba5f298SAndrew Moore 	free_value(a);
5594ba5f298SAndrew Moore 	free_value(b);
5604ba5f298SAndrew Moore 	regfree(&rp);
5614ba5f298SAndrew Moore 
56269759f08SStefan Eßer 	return (v);
5634ba5f298SAndrew Moore }
564