xref: /freebsd/bin/expr/expr.y (revision fa717604a42dff3416a3e299da0abf01d9f8521e)
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)
755c497bfSJ.T. Conklin  *
82a456239SPeter Wemm  * $FreeBSD$
95b81b6b3SRodney W. Grimes  */
104cf61abaSJ.T. Conklin 
1164867286SStefan Eßer #include <sys/types.h>
12f07e4247SGarrett Wollman 
135b81b6b3SRodney W. Grimes #include <ctype.h>
1455c497bfSJ.T. Conklin #include <err.h>
15915198b4SStefan Eßer #include <errno.h>
16f07e4247SGarrett Wollman #include <inttypes.h>
17915198b4SStefan Eßer #include <limits.h>
18f07e4247SGarrett Wollman #include <locale.h>
19f07e4247SGarrett Wollman #include <stdio.h>
20f07e4247SGarrett Wollman #include <stdlib.h>
21f07e4247SGarrett Wollman #include <string.h>
22f07e4247SGarrett Wollman #include <regex.h>
23f07e4247SGarrett Wollman #include <unistd.h>
24f07e4247SGarrett Wollman 
25f07e4247SGarrett Wollman /*
26f07e4247SGarrett Wollman  * POSIX specifies a specific error code for syntax errors.  We exit
27f07e4247SGarrett Wollman  * with this code for all errors.
28f07e4247SGarrett Wollman  */
29f07e4247SGarrett Wollman #define	ERR_EXIT	2
305b81b6b3SRodney W. Grimes 
315b81b6b3SRodney W. Grimes enum valtype {
32717252eaSJoerg Wunsch 	integer, numeric_string, string
335b81b6b3SRodney W. Grimes } ;
345b81b6b3SRodney W. Grimes 
355b81b6b3SRodney W. Grimes struct val {
365b81b6b3SRodney W. Grimes 	enum valtype type;
375b81b6b3SRodney W. Grimes 	union {
385b81b6b3SRodney W. Grimes 		char *s;
39f07e4247SGarrett Wollman 		intmax_t i;
405b81b6b3SRodney W. Grimes 	} u;
415b81b6b3SRodney W. Grimes } ;
425b81b6b3SRodney W. Grimes 
435b81b6b3SRodney W. Grimes struct val *result;
443d06e95dSKris Kennaway 
45*fa717604SStefan Eßer void		assert_to_integer(struct val *);
46f07e4247SGarrett Wollman int		chk_div(intmax_t, intmax_t);
47f07e4247SGarrett Wollman int		chk_minus(intmax_t, intmax_t, intmax_t);
48f07e4247SGarrett Wollman int		chk_plus(intmax_t, intmax_t, intmax_t);
49f07e4247SGarrett Wollman int		chk_times(intmax_t, intmax_t, intmax_t);
507669d0fcSWarner Losh void		free_value(struct val *);
51*fa717604SStefan Eßer int		is_integer(const char *);
527669d0fcSWarner Losh int		isstring(struct val *);
53*fa717604SStefan Eßer int		is_zero_or_null(struct val *);
54f07e4247SGarrett Wollman struct val	*make_integer(intmax_t);
557669d0fcSWarner Losh struct val	*make_str(const char *);
567669d0fcSWarner Losh struct val	*op_and(struct val *, struct val *);
577669d0fcSWarner Losh struct val	*op_colon(struct val *, struct val *);
587669d0fcSWarner Losh struct val	*op_div(struct val *, struct val *);
597669d0fcSWarner Losh struct val	*op_eq(struct val *, struct val *);
607669d0fcSWarner Losh struct val	*op_ge(struct val *, struct val *);
617669d0fcSWarner Losh struct val	*op_gt(struct val *, struct val *);
627669d0fcSWarner Losh struct val	*op_le(struct val *, struct val *);
637669d0fcSWarner Losh struct val	*op_lt(struct val *, struct val *);
647669d0fcSWarner Losh struct val	*op_minus(struct val *, struct val *);
657669d0fcSWarner Losh struct val	*op_ne(struct val *, struct val *);
667669d0fcSWarner Losh struct val	*op_or(struct val *, struct val *);
677669d0fcSWarner Losh struct val	*op_plus(struct val *, struct val *);
687669d0fcSWarner Losh struct val	*op_rem(struct val *, struct val *);
697669d0fcSWarner Losh struct val	*op_times(struct val *, struct val *);
70*fa717604SStefan Eßer int		to_integer(struct val *);
717669d0fcSWarner Losh void		to_string(struct val *);
727669d0fcSWarner Losh int		yyerror(const char *);
737669d0fcSWarner Losh int		yylex(void);
747669d0fcSWarner Losh int		yyparse(void);
755b81b6b3SRodney W. Grimes 
76*fa717604SStefan Eßer static int	nonposix;
775b81b6b3SRodney W. Grimes char **av;
785b81b6b3SRodney W. Grimes %}
795b81b6b3SRodney W. Grimes 
805b81b6b3SRodney W. Grimes %union
815b81b6b3SRodney W. Grimes {
825b81b6b3SRodney W. Grimes 	struct val *val;
835b81b6b3SRodney W. Grimes }
845b81b6b3SRodney W. Grimes 
855b81b6b3SRodney W. Grimes %left <val> '|'
865b81b6b3SRodney W. Grimes %left <val> '&'
875b81b6b3SRodney W. Grimes %left <val> '=' '>' '<' GE LE NE
885b81b6b3SRodney W. Grimes %left <val> '+' '-'
895b81b6b3SRodney W. Grimes %left <val> '*' '/' '%'
905b81b6b3SRodney W. Grimes %left <val> ':'
915b81b6b3SRodney W. Grimes 
925b81b6b3SRodney W. Grimes %token <val> TOKEN
935b81b6b3SRodney W. Grimes %type <val> start expr
945b81b6b3SRodney W. Grimes 
955b81b6b3SRodney W. Grimes %%
965b81b6b3SRodney W. Grimes 
975b81b6b3SRodney W. Grimes start: expr { result = $$; }
985b81b6b3SRodney W. Grimes 
995b81b6b3SRodney W. Grimes expr:	TOKEN
1005b81b6b3SRodney W. Grimes 	| '(' expr ')' { $$ = $2; }
1015b81b6b3SRodney W. Grimes 	| expr '|' expr { $$ = op_or ($1, $3); }
1025b81b6b3SRodney W. Grimes 	| expr '&' expr { $$ = op_and ($1, $3); }
1035b81b6b3SRodney W. Grimes 	| expr '=' expr { $$ = op_eq ($1, $3); }
1045b81b6b3SRodney W. Grimes 	| expr '>' expr { $$ = op_gt ($1, $3); }
1055b81b6b3SRodney W. Grimes 	| expr '<' expr { $$ = op_lt ($1, $3); }
1065b81b6b3SRodney W. Grimes 	| expr GE expr  { $$ = op_ge ($1, $3); }
1075b81b6b3SRodney W. Grimes 	| expr LE expr  { $$ = op_le ($1, $3); }
1085b81b6b3SRodney W. Grimes 	| expr NE expr  { $$ = op_ne ($1, $3); }
1095b81b6b3SRodney W. Grimes 	| expr '+' expr { $$ = op_plus ($1, $3); }
1105b81b6b3SRodney W. Grimes 	| expr '-' expr { $$ = op_minus ($1, $3); }
1115b81b6b3SRodney W. Grimes 	| expr '*' expr { $$ = op_times ($1, $3); }
1125b81b6b3SRodney W. Grimes 	| expr '/' expr { $$ = op_div ($1, $3); }
1135b81b6b3SRodney W. Grimes 	| expr '%' expr { $$ = op_rem ($1, $3); }
1145b81b6b3SRodney W. Grimes 	| expr ':' expr { $$ = op_colon ($1, $3); }
1155b81b6b3SRodney W. Grimes 	;
1165b81b6b3SRodney W. Grimes 
1175b81b6b3SRodney W. Grimes 
1185b81b6b3SRodney W. Grimes %%
1195b81b6b3SRodney W. Grimes 
1205b81b6b3SRodney W. Grimes struct val *
121f07e4247SGarrett Wollman make_integer(intmax_t i)
1225b81b6b3SRodney W. Grimes {
1235b81b6b3SRodney W. Grimes 	struct val *vp;
1245b81b6b3SRodney W. Grimes 
1255b81b6b3SRodney W. Grimes 	vp = (struct val *) malloc (sizeof (*vp));
1265b81b6b3SRodney W. Grimes 	if (vp == NULL) {
127f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
1285b81b6b3SRodney W. Grimes 	}
1295b81b6b3SRodney W. Grimes 
1305b81b6b3SRodney W. Grimes 	vp->type = integer;
1315b81b6b3SRodney W. Grimes 	vp->u.i  = i;
1325b81b6b3SRodney W. Grimes 	return vp;
1335b81b6b3SRodney W. Grimes }
1345b81b6b3SRodney W. Grimes 
1355b81b6b3SRodney W. Grimes struct val *
1367669d0fcSWarner Losh make_str(const char *s)
1375b81b6b3SRodney W. Grimes {
1385b81b6b3SRodney W. Grimes 	struct val *vp;
1395b81b6b3SRodney W. Grimes 
1405b81b6b3SRodney W. Grimes 	vp = (struct val *) malloc (sizeof (*vp));
1415b81b6b3SRodney W. Grimes 	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
142f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
1435b81b6b3SRodney W. Grimes 	}
1445b81b6b3SRodney W. Grimes 
145*fa717604SStefan Eßer 	if (is_integer(s))
146f07e4247SGarrett Wollman 		vp->type = numeric_string;
147*fa717604SStefan Eßer 	else
148*fa717604SStefan Eßer 		vp->type = string;
1492a353a9fSJoerg Wunsch 
1505b81b6b3SRodney W. Grimes 	return vp;
1515b81b6b3SRodney W. Grimes }
1525b81b6b3SRodney W. Grimes 
1535b81b6b3SRodney W. Grimes 
1545b81b6b3SRodney W. Grimes void
1557669d0fcSWarner Losh free_value(struct val *vp)
1565b81b6b3SRodney W. Grimes {
157717252eaSJoerg Wunsch 	if (vp->type == string || vp->type == numeric_string)
1585b81b6b3SRodney W. Grimes 		free (vp->u.s);
1595b81b6b3SRodney W. Grimes }
1605b81b6b3SRodney W. Grimes 
1615b81b6b3SRodney W. Grimes 
162*fa717604SStefan Eßer int
1637669d0fcSWarner Losh to_integer(struct val *vp)
1645b81b6b3SRodney W. Grimes {
165f07e4247SGarrett Wollman 	intmax_t i;
1665b81b6b3SRodney W. Grimes 
167*fa717604SStefan Eßer 	/* we can only convert numeric_string to integer, here */
168*fa717604SStefan Eßer 	if (vp->type == numeric_string) {
169915198b4SStefan Eßer 		errno = 0;
170f07e4247SGarrett Wollman 		i  = strtoimax(vp->u.s, (char **)NULL, 10);
171*fa717604SStefan Eßer 		/* just keep as numeric_string, if the conversion fails */
172*fa717604SStefan Eßer 		if (errno != ERANGE) {
1735b81b6b3SRodney W. Grimes 			free (vp->u.s);
1745b81b6b3SRodney W. Grimes 			vp->u.i = i;
175717252eaSJoerg Wunsch 			vp->type = integer;
176*fa717604SStefan Eßer 		}
177*fa717604SStefan Eßer 	}
178*fa717604SStefan Eßer 	return (vp->type == integer);
179*fa717604SStefan Eßer }
180*fa717604SStefan Eßer 
181*fa717604SStefan Eßer 
182*fa717604SStefan Eßer void
183*fa717604SStefan Eßer assert_to_integer(struct val *vp)
184*fa717604SStefan Eßer {
185*fa717604SStefan Eßer 	if (vp->type == string)
186*fa717604SStefan Eßer 		errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
187*fa717604SStefan Eßer 	if (!to_integer(vp))
188*fa717604SStefan Eßer 		errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
1895b81b6b3SRodney W. Grimes }
1905b81b6b3SRodney W. Grimes 
1915b81b6b3SRodney W. Grimes void
1927669d0fcSWarner Losh to_string(struct val *vp)
1935b81b6b3SRodney W. Grimes {
1945b81b6b3SRodney W. Grimes 	char *tmp;
1955b81b6b3SRodney W. Grimes 
196717252eaSJoerg Wunsch 	if (vp->type == string || vp->type == numeric_string)
1975b81b6b3SRodney W. Grimes 		return;
1985b81b6b3SRodney W. Grimes 
199f07e4247SGarrett Wollman 	/*
200f07e4247SGarrett Wollman 	 * log_10(x) ~= 0.3 * log_2(x).  Rounding up gives the number
201f07e4247SGarrett Wollman 	 * of digits; add one each for the sign and terminating null
202f07e4247SGarrett Wollman 	 * character, respectively.
203f07e4247SGarrett Wollman 	 */
204f07e4247SGarrett Wollman #define	NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
205f07e4247SGarrett Wollman 	tmp = malloc(NDIGITS(vp->u.i));
206f07e4247SGarrett Wollman 	if (tmp == NULL)
207f07e4247SGarrett Wollman 		errx(ERR_EXIT, "malloc() failed");
2085b81b6b3SRodney W. Grimes 
209f07e4247SGarrett Wollman 	sprintf(tmp, "%jd", vp->u.i);
2105b81b6b3SRodney W. Grimes 	vp->type = string;
2115b81b6b3SRodney W. Grimes 	vp->u.s  = tmp;
2125b81b6b3SRodney W. Grimes }
2135b81b6b3SRodney W. Grimes 
2145b81b6b3SRodney W. Grimes 
2155b81b6b3SRodney W. Grimes int
216*fa717604SStefan Eßer is_integer(const char *s)
217*fa717604SStefan Eßer {
218*fa717604SStefan Eßer 	if (nonposix) {
219*fa717604SStefan Eßer 		if (*s == '\0')
220*fa717604SStefan Eßer 			return (1);
221*fa717604SStefan Eßer 		while (isspace((unsigned char)*s))
222*fa717604SStefan Eßer 			s++;
223*fa717604SStefan Eßer 	}
224*fa717604SStefan Eßer 	if (*s == '-' || (nonposix && *s == '+'))
225*fa717604SStefan Eßer 		s++;
226*fa717604SStefan Eßer 	if (*s == '\0')
227*fa717604SStefan Eßer 		return (0);
228*fa717604SStefan Eßer 	while (isdigit((unsigned char)*s))
229*fa717604SStefan Eßer 		s++;
230*fa717604SStefan Eßer 	return (*s == '\0');
231*fa717604SStefan Eßer }
232*fa717604SStefan Eßer 
233*fa717604SStefan Eßer 
234*fa717604SStefan Eßer int
2357669d0fcSWarner Losh isstring(struct val *vp)
2365b81b6b3SRodney W. Grimes {
237717252eaSJoerg Wunsch 	/* only TRUE if this string is not a valid integer */
2385b81b6b3SRodney W. Grimes 	return (vp->type == string);
2395b81b6b3SRodney W. Grimes }
2405b81b6b3SRodney W. Grimes 
2415b81b6b3SRodney W. Grimes 
2425b81b6b3SRodney W. Grimes int
2437669d0fcSWarner Losh yylex(void)
2445b81b6b3SRodney W. Grimes {
2455b81b6b3SRodney W. Grimes 	char *p;
2465b81b6b3SRodney W. Grimes 
2475b81b6b3SRodney W. Grimes 	if (*av == NULL)
2485b81b6b3SRodney W. Grimes 		return (0);
2495b81b6b3SRodney W. Grimes 
2505b81b6b3SRodney W. Grimes 	p = *av++;
2515b81b6b3SRodney W. Grimes 
2525b81b6b3SRodney W. Grimes 	if (strlen (p) == 1) {
2535b81b6b3SRodney W. Grimes 		if (strchr ("|&=<>+-*/%:()", *p))
2545b81b6b3SRodney W. Grimes 			return (*p);
2555b81b6b3SRodney W. Grimes 	} else if (strlen (p) == 2 && p[1] == '=') {
2565b81b6b3SRodney W. Grimes 		switch (*p) {
2575b81b6b3SRodney W. Grimes 		case '>': return (GE);
2585b81b6b3SRodney W. Grimes 		case '<': return (LE);
2595b81b6b3SRodney W. Grimes 		case '!': return (NE);
2605b81b6b3SRodney W. Grimes 		}
2615b81b6b3SRodney W. Grimes 	}
2625b81b6b3SRodney W. Grimes 
2635b81b6b3SRodney W. Grimes 	yylval.val = make_str (p);
2645b81b6b3SRodney W. Grimes 	return (TOKEN);
2655b81b6b3SRodney W. Grimes }
2665b81b6b3SRodney W. Grimes 
2675b81b6b3SRodney W. Grimes int
2687669d0fcSWarner Losh is_zero_or_null(struct val *vp)
2695b81b6b3SRodney W. Grimes {
2705b81b6b3SRodney W. Grimes 	if (vp->type == integer) {
2715b81b6b3SRodney W. Grimes 		return (vp->u.i == 0);
2725b81b6b3SRodney W. Grimes 	} else {
273c9fe00dcSJ.T. Conklin 		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
2745b81b6b3SRodney W. Grimes 	}
2755b81b6b3SRodney W. Grimes 	/* NOTREACHED */
2765b81b6b3SRodney W. Grimes }
2775b81b6b3SRodney W. Grimes 
278717252eaSJoerg Wunsch int
279f07e4247SGarrett Wollman main(int argc, char *argv[])
2805b81b6b3SRodney W. Grimes {
281f07e4247SGarrett Wollman 	int c;
2824cf61abaSJ.T. Conklin 
283f07e4247SGarrett Wollman 	setlocale (LC_ALL, "");
284c9885518SGarrett Wollman 	if (getenv("EXPR_COMPAT") != NULL
285c9885518SGarrett Wollman 	    || check_utility_compat("expr")) {
28696ab7da3SGarrett Wollman 		av = argv + 1;
287*fa717604SStefan Eßer 		nonposix = 1;
28896ab7da3SGarrett Wollman 	} else {
2891393277eSGarrett Wollman 		while ((c = getopt(argc, argv, "e")) != -1)
290f07e4247SGarrett Wollman 			switch (c) {
2911393277eSGarrett Wollman 			case 'e':
292*fa717604SStefan Eßer 				nonposix = 1;
2931393277eSGarrett Wollman 				break;
2941393277eSGarrett Wollman 
295f07e4247SGarrett Wollman 			default:
2961393277eSGarrett Wollman 				fprintf(stderr,
2971393277eSGarrett Wollman 				    "usage: expr [-e] expression\n");
298f07e4247SGarrett Wollman 				exit(ERR_EXIT);
299f07e4247SGarrett Wollman 			}
300f07e4247SGarrett Wollman 		av = argv + optind;
30196ab7da3SGarrett Wollman 	}
3025b81b6b3SRodney W. Grimes 
3035b81b6b3SRodney W. Grimes 	yyparse();
3045b81b6b3SRodney W. Grimes 
3055b81b6b3SRodney W. Grimes 	if (result->type == integer)
306f07e4247SGarrett Wollman 		printf("%jd\n", result->u.i);
3075b81b6b3SRodney W. Grimes 	else
3085b81b6b3SRodney W. Grimes 		printf("%s\n", result->u.s);
3095b81b6b3SRodney W. Grimes 
310717252eaSJoerg Wunsch 	return (is_zero_or_null(result));
3115b81b6b3SRodney W. Grimes }
3125b81b6b3SRodney W. Grimes 
3135b81b6b3SRodney W. Grimes int
3147669d0fcSWarner Losh yyerror(const char *s __unused)
3155b81b6b3SRodney W. Grimes {
316f07e4247SGarrett Wollman 	errx(ERR_EXIT, "syntax error");
3175b81b6b3SRodney W. Grimes }
3185b81b6b3SRodney W. Grimes 
3195b81b6b3SRodney W. Grimes 
3205b81b6b3SRodney W. Grimes struct val *
3217669d0fcSWarner Losh op_or(struct val *a, struct val *b)
3225b81b6b3SRodney W. Grimes {
323*fa717604SStefan Eßer 	if (!is_zero_or_null(a)) {
3245b81b6b3SRodney W. Grimes 		free_value(b);
3255b81b6b3SRodney W. Grimes 		return (a);
3265b81b6b3SRodney W. Grimes 	}
327*fa717604SStefan Eßer 	free_value(a);
328*fa717604SStefan Eßer 	if (!is_zero_or_null(b))
329*fa717604SStefan Eßer 		return (b);
330*fa717604SStefan Eßer 	free_value(b);
331*fa717604SStefan Eßer 	return (make_integer((intmax_t)0));
3325b81b6b3SRodney W. Grimes }
3335b81b6b3SRodney W. Grimes 
3345b81b6b3SRodney W. Grimes struct val *
3357669d0fcSWarner Losh op_and(struct val *a, struct val *b)
3365b81b6b3SRodney W. Grimes {
3375b81b6b3SRodney W. Grimes 	if (is_zero_or_null (a) || is_zero_or_null (b)) {
3385b81b6b3SRodney W. Grimes 		free_value (a);
3395b81b6b3SRodney W. Grimes 		free_value (b);
340f07e4247SGarrett Wollman 		return (make_integer ((intmax_t)0));
3415b81b6b3SRodney W. Grimes 	} else {
3425b81b6b3SRodney W. Grimes 		free_value (b);
3435b81b6b3SRodney W. Grimes 		return (a);
3445b81b6b3SRodney W. Grimes 	}
3455b81b6b3SRodney W. Grimes }
3465b81b6b3SRodney W. Grimes 
3475b81b6b3SRodney W. Grimes struct val *
3487669d0fcSWarner Losh op_eq(struct val *a, struct val *b)
3495b81b6b3SRodney W. Grimes {
3505b81b6b3SRodney W. Grimes 	struct val *r;
3515b81b6b3SRodney W. Grimes 
3525b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
3535b81b6b3SRodney W. Grimes 		to_string (a);
3545b81b6b3SRodney W. Grimes 		to_string (b);
355f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) == 0));
3565b81b6b3SRodney W. Grimes 	} else {
357*fa717604SStefan Eßer 		assert_to_integer(a);
358*fa717604SStefan Eßer 		assert_to_integer(b);
359f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i == b->u.i));
3605b81b6b3SRodney W. Grimes 	}
3615b81b6b3SRodney W. Grimes 
3625b81b6b3SRodney W. Grimes 	free_value (a);
3635b81b6b3SRodney W. Grimes 	free_value (b);
3645b81b6b3SRodney W. Grimes 	return r;
3655b81b6b3SRodney W. Grimes }
3665b81b6b3SRodney W. Grimes 
3675b81b6b3SRodney W. Grimes struct val *
3687669d0fcSWarner Losh op_gt(struct val *a, struct val *b)
3695b81b6b3SRodney W. Grimes {
3705b81b6b3SRodney W. Grimes 	struct val *r;
3715b81b6b3SRodney W. Grimes 
3725b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
3735b81b6b3SRodney W. Grimes 		to_string (a);
3745b81b6b3SRodney W. Grimes 		to_string (b);
375f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) > 0));
3765b81b6b3SRodney W. Grimes 	} else {
377*fa717604SStefan Eßer 		assert_to_integer(a);
378*fa717604SStefan Eßer 		assert_to_integer(b);
379f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i > b->u.i));
3805b81b6b3SRodney W. Grimes 	}
3815b81b6b3SRodney W. Grimes 
3825b81b6b3SRodney W. Grimes 	free_value (a);
3835b81b6b3SRodney W. Grimes 	free_value (b);
3845b81b6b3SRodney W. Grimes 	return r;
3855b81b6b3SRodney W. Grimes }
3865b81b6b3SRodney W. Grimes 
3875b81b6b3SRodney W. Grimes struct val *
3887669d0fcSWarner Losh op_lt(struct val *a, struct val *b)
3895b81b6b3SRodney W. Grimes {
3905b81b6b3SRodney W. Grimes 	struct val *r;
3915b81b6b3SRodney W. Grimes 
3925b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
3935b81b6b3SRodney W. Grimes 		to_string (a);
3945b81b6b3SRodney W. Grimes 		to_string (b);
395f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) < 0));
3965b81b6b3SRodney W. Grimes 	} else {
397*fa717604SStefan Eßer 		assert_to_integer(a);
398*fa717604SStefan Eßer 		assert_to_integer(b);
399f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i < b->u.i));
4005b81b6b3SRodney W. Grimes 	}
4015b81b6b3SRodney W. Grimes 
4025b81b6b3SRodney W. Grimes 	free_value (a);
4035b81b6b3SRodney W. Grimes 	free_value (b);
4045b81b6b3SRodney W. Grimes 	return r;
4055b81b6b3SRodney W. Grimes }
4065b81b6b3SRodney W. Grimes 
4075b81b6b3SRodney W. Grimes struct val *
4087669d0fcSWarner Losh op_ge(struct val *a, struct val *b)
4095b81b6b3SRodney W. Grimes {
4105b81b6b3SRodney W. Grimes 	struct val *r;
4115b81b6b3SRodney W. Grimes 
4125b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
4135b81b6b3SRodney W. Grimes 		to_string (a);
4145b81b6b3SRodney W. Grimes 		to_string (b);
415f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) >= 0));
4165b81b6b3SRodney W. Grimes 	} else {
417*fa717604SStefan Eßer 		assert_to_integer(a);
418*fa717604SStefan Eßer 		assert_to_integer(b);
419f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i >= b->u.i));
4205b81b6b3SRodney W. Grimes 	}
4215b81b6b3SRodney W. Grimes 
4225b81b6b3SRodney W. Grimes 	free_value (a);
4235b81b6b3SRodney W. Grimes 	free_value (b);
4245b81b6b3SRodney W. Grimes 	return r;
4255b81b6b3SRodney W. Grimes }
4265b81b6b3SRodney W. Grimes 
4275b81b6b3SRodney W. Grimes struct val *
4287669d0fcSWarner Losh op_le(struct val *a, struct val *b)
4295b81b6b3SRodney W. Grimes {
4305b81b6b3SRodney W. Grimes 	struct val *r;
4315b81b6b3SRodney W. Grimes 
4325b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
4335b81b6b3SRodney W. Grimes 		to_string (a);
4345b81b6b3SRodney W. Grimes 		to_string (b);
435f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) <= 0));
4365b81b6b3SRodney W. Grimes 	} else {
437*fa717604SStefan Eßer 		assert_to_integer(a);
438*fa717604SStefan Eßer 		assert_to_integer(b);
439f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i <= b->u.i));
4405b81b6b3SRodney W. Grimes 	}
4415b81b6b3SRodney W. Grimes 
4425b81b6b3SRodney W. Grimes 	free_value (a);
4435b81b6b3SRodney W. Grimes 	free_value (b);
4445b81b6b3SRodney W. Grimes 	return r;
4455b81b6b3SRodney W. Grimes }
4465b81b6b3SRodney W. Grimes 
4475b81b6b3SRodney W. Grimes struct val *
4487669d0fcSWarner Losh op_ne(struct val *a, struct val *b)
4495b81b6b3SRodney W. Grimes {
4505b81b6b3SRodney W. Grimes 	struct val *r;
4515b81b6b3SRodney W. Grimes 
4525b81b6b3SRodney W. Grimes 	if (isstring (a) || isstring (b)) {
4535b81b6b3SRodney W. Grimes 		to_string (a);
4545b81b6b3SRodney W. Grimes 		to_string (b);
455f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) != 0));
4565b81b6b3SRodney W. Grimes 	} else {
457*fa717604SStefan Eßer 		assert_to_integer(a);
458*fa717604SStefan Eßer 		assert_to_integer(b);
459f07e4247SGarrett Wollman 		r = make_integer ((intmax_t)(a->u.i != b->u.i));
4605b81b6b3SRodney W. Grimes 	}
4615b81b6b3SRodney W. Grimes 
4625b81b6b3SRodney W. Grimes 	free_value (a);
4635b81b6b3SRodney W. Grimes 	free_value (b);
4645b81b6b3SRodney W. Grimes 	return r;
4655b81b6b3SRodney W. Grimes }
4665b81b6b3SRodney W. Grimes 
467915198b4SStefan Eßer int
468f07e4247SGarrett Wollman chk_plus(intmax_t a, intmax_t b, intmax_t r)
469915198b4SStefan Eßer {
4701393277eSGarrett Wollman 
471915198b4SStefan Eßer 	/* sum of two positive numbers must be positive */
472915198b4SStefan Eßer 	if (a > 0 && b > 0 && r <= 0)
473915198b4SStefan Eßer 		return 1;
474915198b4SStefan Eßer 	/* sum of two negative numbers must be negative */
475915198b4SStefan Eßer 	if (a < 0 && b < 0 && r >= 0)
476915198b4SStefan Eßer 		return 1;
477915198b4SStefan Eßer 	/* all other cases are OK */
478915198b4SStefan Eßer 	return 0;
479915198b4SStefan Eßer }
480915198b4SStefan Eßer 
4815b81b6b3SRodney W. Grimes struct val *
4827669d0fcSWarner Losh op_plus(struct val *a, struct val *b)
4835b81b6b3SRodney W. Grimes {
4845b81b6b3SRodney W. Grimes 	struct val *r;
4855b81b6b3SRodney W. Grimes 
486*fa717604SStefan Eßer 	assert_to_integer(a);
487*fa717604SStefan Eßer 	assert_to_integer(b);
4885b81b6b3SRodney W. Grimes 
4891393277eSGarrett Wollman 	r = make_integer(a->u.i + b->u.i);
490915198b4SStefan Eßer 	if (chk_plus(a->u.i, b->u.i, r->u.i)) {
491f07e4247SGarrett Wollman 		errx(ERR_EXIT, "overflow");
492915198b4SStefan Eßer 	}
4931393277eSGarrett Wollman 
4945b81b6b3SRodney W. Grimes 	free_value (a);
4955b81b6b3SRodney W. Grimes 	free_value (b);
4965b81b6b3SRodney W. Grimes 	return r;
4975b81b6b3SRodney W. Grimes }
4985b81b6b3SRodney W. Grimes 
499915198b4SStefan Eßer int
500f07e4247SGarrett Wollman chk_minus(intmax_t a, intmax_t b, intmax_t r)
501915198b4SStefan Eßer {
5021393277eSGarrett Wollman 
503f07e4247SGarrett Wollman 	/* special case subtraction of INTMAX_MIN */
504f07e4247SGarrett Wollman 	if (b == INTMAX_MIN) {
505915198b4SStefan Eßer 		if (a >= 0)
506915198b4SStefan Eßer 			return 1;
507915198b4SStefan Eßer 		else
508915198b4SStefan Eßer 			return 0;
509915198b4SStefan Eßer 	}
510f07e4247SGarrett Wollman 	/* this is allowed for b != INTMAX_MIN */
511915198b4SStefan Eßer 	return chk_plus (a, -b, r);
512915198b4SStefan Eßer }
513915198b4SStefan Eßer 
5145b81b6b3SRodney W. Grimes struct val *
5157669d0fcSWarner Losh op_minus(struct val *a, struct val *b)
5165b81b6b3SRodney W. Grimes {
5175b81b6b3SRodney W. Grimes 	struct val *r;
5185b81b6b3SRodney W. Grimes 
519*fa717604SStefan Eßer 	assert_to_integer(a);
520*fa717604SStefan Eßer 	assert_to_integer(b);
5215b81b6b3SRodney W. Grimes 
5221393277eSGarrett Wollman 	r = make_integer(a->u.i - b->u.i);
523915198b4SStefan Eßer 	if (chk_minus(a->u.i, b->u.i, r->u.i)) {
524f07e4247SGarrett Wollman 		errx(ERR_EXIT, "overflow");
525915198b4SStefan Eßer 	}
5261393277eSGarrett Wollman 
5275b81b6b3SRodney W. Grimes 	free_value (a);
5285b81b6b3SRodney W. Grimes 	free_value (b);
5295b81b6b3SRodney W. Grimes 	return r;
5305b81b6b3SRodney W. Grimes }
5315b81b6b3SRodney W. Grimes 
532915198b4SStefan Eßer int
533f07e4247SGarrett Wollman chk_times(intmax_t a, intmax_t b, intmax_t r)
534915198b4SStefan Eßer {
535915198b4SStefan Eßer 	/* special case: first operand is 0, no overflow possible */
536915198b4SStefan Eßer 	if (a == 0)
537915198b4SStefan Eßer 		return 0;
538e1854a84SCeri Davies 	/* verify that result of division matches second operand */
539915198b4SStefan Eßer 	if (r / a != b)
540915198b4SStefan Eßer 		return 1;
541915198b4SStefan Eßer 	return 0;
542915198b4SStefan Eßer }
543915198b4SStefan Eßer 
5445b81b6b3SRodney W. Grimes struct val *
5457669d0fcSWarner Losh op_times(struct val *a, struct val *b)
5465b81b6b3SRodney W. Grimes {
5475b81b6b3SRodney W. Grimes 	struct val *r;
5485b81b6b3SRodney W. Grimes 
549*fa717604SStefan Eßer 	assert_to_integer(a);
550*fa717604SStefan Eßer 	assert_to_integer(b);
5515b81b6b3SRodney W. Grimes 
5521393277eSGarrett Wollman 	r = make_integer(a->u.i * b->u.i);
553915198b4SStefan Eßer 	if (chk_times(a->u.i, b->u.i, r->u.i)) {
554f07e4247SGarrett Wollman 		errx(ERR_EXIT, "overflow");
555915198b4SStefan Eßer 	}
5561393277eSGarrett Wollman 
5575b81b6b3SRodney W. Grimes 	free_value (a);
5585b81b6b3SRodney W. Grimes 	free_value (b);
5595b81b6b3SRodney W. Grimes 	return (r);
5605b81b6b3SRodney W. Grimes }
5615b81b6b3SRodney W. Grimes 
562915198b4SStefan Eßer int
563f07e4247SGarrett Wollman chk_div(intmax_t a, intmax_t b)
564915198b4SStefan Eßer {
565915198b4SStefan Eßer 	/* div by zero has been taken care of before */
566f07e4247SGarrett Wollman 	/* only INTMAX_MIN / -1 causes overflow */
567f07e4247SGarrett Wollman 	if (a == INTMAX_MIN && b == -1)
568915198b4SStefan Eßer 		return 1;
569915198b4SStefan Eßer 	/* everything else is OK */
570915198b4SStefan Eßer 	return 0;
571915198b4SStefan Eßer }
572915198b4SStefan Eßer 
5735b81b6b3SRodney W. Grimes struct val *
5747669d0fcSWarner Losh op_div(struct val *a, struct val *b)
5755b81b6b3SRodney W. Grimes {
5765b81b6b3SRodney W. Grimes 	struct val *r;
5775b81b6b3SRodney W. Grimes 
578*fa717604SStefan Eßer 	assert_to_integer(a);
579*fa717604SStefan Eßer 	assert_to_integer(b);
5805b81b6b3SRodney W. Grimes 
5815b81b6b3SRodney W. Grimes 	if (b->u.i == 0) {
582f07e4247SGarrett Wollman 		errx(ERR_EXIT, "division by zero");
5835b81b6b3SRodney W. Grimes 	}
5843d06e95dSKris Kennaway 	if (chk_div(a->u.i, b->u.i)) {
585f07e4247SGarrett Wollman 		errx(ERR_EXIT, "overflow");
586915198b4SStefan Eßer 	}
587*fa717604SStefan Eßer 	r = make_integer(a->u.i / b->u.i);
5881393277eSGarrett Wollman 
5895b81b6b3SRodney W. Grimes 	free_value (a);
5905b81b6b3SRodney W. Grimes 	free_value (b);
5915b81b6b3SRodney W. Grimes 	return r;
5925b81b6b3SRodney W. Grimes }
5935b81b6b3SRodney W. Grimes 
5945b81b6b3SRodney W. Grimes struct val *
5957669d0fcSWarner Losh op_rem(struct val *a, struct val *b)
5965b81b6b3SRodney W. Grimes {
5975b81b6b3SRodney W. Grimes 	struct val *r;
5985b81b6b3SRodney W. Grimes 
599*fa717604SStefan Eßer 	assert_to_integer(a);
600*fa717604SStefan Eßer 	assert_to_integer(b);
6015b81b6b3SRodney W. Grimes 	if (b->u.i == 0) {
602f07e4247SGarrett Wollman 		errx(ERR_EXIT, "division by zero");
6035b81b6b3SRodney W. Grimes 	}
6041393277eSGarrett Wollman 	r = make_integer(a->u.i % b->u.i);
6051393277eSGarrett Wollman 
6065b81b6b3SRodney W. Grimes 	free_value (a);
6075b81b6b3SRodney W. Grimes 	free_value (b);
6085b81b6b3SRodney W. Grimes 	return r;
6095b81b6b3SRodney W. Grimes }
6105b81b6b3SRodney W. Grimes 
6115b81b6b3SRodney W. Grimes struct val *
6127669d0fcSWarner Losh op_colon(struct val *a, struct val *b)
6135b81b6b3SRodney W. Grimes {
6144ba5f298SAndrew Moore 	regex_t rp;
6154cf61abaSJ.T. Conklin 	regmatch_t rm[2];
6164ba5f298SAndrew Moore 	char errbuf[256];
6174ba5f298SAndrew Moore 	int eval;
6184ba5f298SAndrew Moore 	struct val *v;
619c9fe00dcSJ.T. Conklin 
620e1854a84SCeri Davies 	/* coerce both arguments to strings */
621c9fe00dcSJ.T. Conklin 	to_string(a);
622c9fe00dcSJ.T. Conklin 	to_string(b);
6235b81b6b3SRodney W. Grimes 
6244ba5f298SAndrew Moore 	/* compile regular expression */
6254a13ab7cSJ.T. Conklin 	if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
6264ba5f298SAndrew Moore 		regerror (eval, &rp, errbuf, sizeof(errbuf));
627f07e4247SGarrett Wollman 		errx(ERR_EXIT, "%s", errbuf);
6285b81b6b3SRodney W. Grimes 	}
6294ba5f298SAndrew Moore 
6304ba5f298SAndrew Moore 	/* compare string against pattern */
6314a13ab7cSJ.T. Conklin 	/* remember that patterns are anchored to the beginning of the line */
6323d06e95dSKris Kennaway 	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
6334ba5f298SAndrew Moore 		if (rm[1].rm_so >= 0) {
63455c497bfSJ.T. Conklin 			*(a->u.s + rm[1].rm_eo) = '\0';
6354ba5f298SAndrew Moore 			v = make_str (a->u.s + rm[1].rm_so);
6364ba5f298SAndrew Moore 
6374ba5f298SAndrew Moore 		} else {
638f07e4247SGarrett Wollman 			v = make_integer ((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
6394ba5f298SAndrew Moore 		}
6404ba5f298SAndrew Moore 	} else {
64155c497bfSJ.T. Conklin 		if (rp.re_nsub == 0) {
642f07e4247SGarrett Wollman 			v = make_integer ((intmax_t)0);
64355c497bfSJ.T. Conklin 		} else {
64455c497bfSJ.T. Conklin 			v = make_str ("");
64555c497bfSJ.T. Conklin 		}
6464ba5f298SAndrew Moore 	}
6474ba5f298SAndrew Moore 
6484ba5f298SAndrew Moore 	/* free arguments and pattern buffer */
6494ba5f298SAndrew Moore 	free_value (a);
6504ba5f298SAndrew Moore 	free_value (b);
6514ba5f298SAndrew Moore 	regfree (&rp);
6524ba5f298SAndrew Moore 
6534ba5f298SAndrew Moore 	return v;
6544ba5f298SAndrew Moore }
655