Home | History | Annotate | Line # | Download | only in expr
expr.y revision 1.5
      1 %{
      2 /* Written by Pace Willisson (pace (at) blitz.com)
      3  * and placed in the public domain
      4  *
      5  * $Header: /tank/opengrok/rsync2/NetBSD/src/bin/expr/expr.y,v 1.5 1993/06/05 22:25:44 cgd Exp $
      6  */
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <ctype.h>
     11 
     12 enum valtype {
     13 	integer, string
     14 } ;
     15 
     16 struct val {
     17 	enum valtype type;
     18 	union {
     19 		char *s;
     20 		int   i;
     21 	} u;
     22 } ;
     23 
     24 struct val *result;
     25 struct val *op_or ();
     26 struct val *op_and ();
     27 struct val *op_eq ();
     28 struct val *op_gt ();
     29 struct val *op_lt ();
     30 struct val *op_ge ();
     31 struct val *op_le ();
     32 struct val *op_ne ();
     33 struct val *op_plus ();
     34 struct val *op_minus ();
     35 struct val *op_times ();
     36 struct val *op_div ();
     37 struct val *op_rem ();
     38 struct val *op_colon ();
     39 
     40 char **av;
     41 %}
     42 
     43 %union
     44 {
     45 	struct val *val;
     46 }
     47 
     48 %left <val> '|'
     49 %left <val> '&'
     50 %left <val> '=' '>' '<' GE LE NE
     51 %left <val> '+' '-'
     52 %left <val> '*' '/' '%'
     53 %left <val> ':'
     54 %left UNARY
     55 
     56 %token <val> TOKEN
     57 %type <val> start expr
     58 
     59 %%
     60 
     61 start: expr { result = $$; }
     62 
     63 expr:	TOKEN
     64 	| '(' expr ')' { $$ = $2; }
     65 	| expr '|' expr { $$ = op_or ($1, $3); }
     66 	| expr '&' expr { $$ = op_and ($1, $3); }
     67 	| expr '=' expr { $$ = op_eq ($1, $3); }
     68 	| expr '>' expr { $$ = op_gt ($1, $3); }
     69 	| expr '<' expr { $$ = op_lt ($1, $3); }
     70 	| expr GE expr  { $$ = op_ge ($1, $3); }
     71 	| expr LE expr  { $$ = op_le ($1, $3); }
     72 	| expr NE expr  { $$ = op_ne ($1, $3); }
     73 	| expr '+' expr { $$ = op_plus ($1, $3); }
     74 	| expr '-' expr { $$ = op_minus ($1, $3); }
     75 	| expr '*' expr { $$ = op_times ($1, $3); }
     76 	| expr '/' expr { $$ = op_div ($1, $3); }
     77 	| expr '%' expr { $$ = op_rem ($1, $3); }
     78 	| expr ':' expr { $$ = op_colon ($1, $3); }
     79 	| '-' expr %prec UNARY { $$ = op_minus (NULL, $2); }
     80 	;
     81 
     82 
     83 %%
     84 
     85 struct val *
     86 make_integer (i)
     87 int i;
     88 {
     89 	struct val *vp;
     90 
     91 	vp = (struct val *) malloc (sizeof (*vp));
     92 	if (vp == NULL) {
     93 		fprintf (stderr, "expr: out of memory\n");
     94 		exit (2);
     95 	}
     96 
     97 	vp->type = integer;
     98 	vp->u.i  = i;
     99 	return vp;
    100 }
    101 
    102 struct val *
    103 make_str (s)
    104 char *s;
    105 {
    106 	struct val *vp;
    107 
    108 	vp = (struct val *) malloc (sizeof (*vp));
    109 	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
    110 		fprintf (stderr, "expr: out of memory\n");
    111 		exit (2);
    112 	}
    113 
    114 	vp->type = string;
    115 	return vp;
    116 }
    117 
    118 
    119 void
    120 free_value (vp)
    121 struct val *vp;
    122 {
    123 	if (vp->type == string)
    124 		free (vp->u.s);
    125 }
    126 
    127 
    128 int
    129 to_integer (vp)
    130 struct val *vp;
    131 {
    132 	char *s;
    133 	int neg;
    134 	int i;
    135 
    136 	if (vp->type == integer)
    137 		return 1;
    138 
    139 	s = vp->u.s;
    140 	i = 0;
    141 
    142 	neg = (*s == '-');
    143 	if (neg)
    144 		s++;
    145 
    146 	for (;*s; s++) {
    147 		if (!isdigit (*s))
    148 			return 0;
    149 
    150 		i *= 10;
    151 		i += *s - '0';
    152 	}
    153 
    154 	free (vp->u.s);
    155 	if (neg)
    156 		i *= -1;
    157 
    158 	vp->type = integer;
    159 	vp->u.i  = i;
    160 	return 1;
    161 }
    162 
    163 void
    164 to_string (vp)
    165 struct val *vp;
    166 {
    167 	char *tmp;
    168 
    169 	if (vp->type == string)
    170 		return;
    171 
    172 	tmp = malloc (25);
    173 	if (tmp == NULL) {
    174 		fprintf (stderr, "expr: out of memory\n");
    175 		exit (2);
    176 	}
    177 
    178 	sprintf (tmp, "%d", vp->u.i);
    179 	vp->type = string;
    180 	vp->u.s  = tmp;
    181 }
    182 
    183 
    184 int
    185 isstring (vp)
    186 struct val *vp;
    187 {
    188 	return (vp->type == string);
    189 }
    190 
    191 
    192 int
    193 yylex ()
    194 {
    195 	struct val *vp;
    196 	char *p;
    197 
    198 	if (*av == NULL)
    199 		return (0);
    200 
    201 	p = *av++;
    202 
    203 	if (strlen (p) == 1) {
    204 		if (strchr ("|&=<>+-*/%:()", *p))
    205 			return (*p);
    206 	} else if (strlen (p) == 2 && p[1] == '=') {
    207 		switch (*p) {
    208 		case '>': return (GE);
    209 		case '<': return (LE);
    210 		case '!': return (NE);
    211 		}
    212 	}
    213 
    214 	yylval.val = make_str (p);
    215 	return (TOKEN);
    216 }
    217 
    218 int
    219 is_zero_or_null (vp)
    220 struct val *vp;
    221 {
    222 	/* Like most other versions of expr, this version will return
    223 	   false for a string value of multiple zeros.*/
    224 
    225 	if (vp->type == integer) {
    226 		return (vp->u.i == 0);
    227 	} else {
    228 		return (*vp->u.s == 0 || strcmp (vp->u.s, "0") == 0);
    229 	}
    230 	/* NOTREACHED */
    231 }
    232 
    233 void
    234 main (argc, argv)
    235 int argc;
    236 char **argv;
    237 {
    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 
    247 	if (is_zero_or_null (result))
    248 		exit (1);
    249 	else
    250 		exit (0);
    251 }
    252 
    253 int
    254 yyerror (s)
    255 char *s;
    256 {
    257 	fprintf (stderr, "expr: syntax error\n");
    258 	exit (2);
    259 }
    260 
    261 
    262 struct val *
    263 op_or (a, b)
    264 struct val *a, *b;
    265 {
    266 	if (is_zero_or_null (a)) {
    267 		free_value (a);
    268 		return (b);
    269 	} else {
    270 		free_value (b);
    271 		return (a);
    272 	}
    273 }
    274 
    275 struct val *
    276 op_and (a, b)
    277 struct val *a, *b;
    278 {
    279 	if (is_zero_or_null (a) || is_zero_or_null (b)) {
    280 		free_value (a);
    281 		free_value (b);
    282 		return (make_integer (0));
    283 	} else {
    284 		free_value (b);
    285 		return (a);
    286 	}
    287 }
    288 
    289 struct val *
    290 op_eq (a, b)
    291 struct val *a, *b;
    292 {
    293 	struct val *r;
    294 
    295 	/* attempt to coerce both arguments to integers */
    296 	(void) to_integer (a);
    297 	(void) to_integer (b);
    298 
    299 	/* But if either one of them really is a string, do
    300 	   a string comparison */
    301 	if (isstring (a) || isstring (b)) {
    302 		to_string (a);
    303 		to_string (b);
    304 		r = make_integer (strcmp (a->u.s, b->u.s) == 0);
    305 	} else {
    306 		r = make_integer (a->u.i == b->u.i);
    307 	}
    308 
    309 	free_value (a);
    310 	free_value (b);
    311 	return r;
    312 }
    313 
    314 struct val *
    315 op_gt (a, b)
    316 struct val *a, *b;
    317 {
    318 	struct val *r;
    319 
    320 	/* attempt to coerce both arguments to integers */
    321 	(void) to_integer (a);
    322 	(void) to_integer (b);
    323 
    324 	/* But if either one of them really is a string, do
    325 	   a string comparison */
    326 	if (isstring (a) || isstring (b)) {
    327 		to_string (a);
    328 		to_string (b);
    329 		r = make_integer (strcmp (a->u.s, b->u.s) > 0);
    330 	} else {
    331 		r= make_integer (a->u.i > b->u.i);
    332 	}
    333 
    334 	free_value (a);
    335 	free_value (b);
    336 	return r;
    337 }
    338 
    339 struct val *
    340 op_lt (a, b)
    341 struct val *a, *b;
    342 {
    343 	struct val *r;
    344 
    345 	/* attempt to coerce both arguments to integers */
    346 	(void) to_integer (a);
    347 	(void) to_integer (b);
    348 
    349 	/* But if either one of them really is a string, do
    350 	   a string comparison */
    351 	if (isstring (a) || isstring (b)) {
    352 		to_string (a);
    353 		to_string (b);
    354 		r = make_integer (strcmp (a->u.s, b->u.s) < 0);
    355 	} else {
    356 		r = make_integer (a->u.i < b->u.i);
    357 	}
    358 
    359 	free_value (a);
    360 	free_value (b);
    361 	return r;
    362 }
    363 
    364 struct val *
    365 op_ge (a, b)
    366 struct val *a, *b;
    367 {
    368 	struct val *r;
    369 
    370 	/* attempt to coerce both arguments to integers */
    371 	(void) to_integer (a);
    372 	(void) to_integer (b);
    373 
    374 	/* But if either one of them really is a string, do
    375 	   a string comparison */
    376 	if (isstring (a) || isstring (b)) {
    377 		to_string (a);
    378 		to_string (b);
    379 		r = make_integer (strcmp (a->u.s, b->u.s) >= 0);
    380 	} else {
    381 		r = make_integer (a->u.i >= b->u.i);
    382 	}
    383 
    384 	free_value (a);
    385 	free_value (b);
    386 	return r;
    387 }
    388 
    389 struct val *
    390 op_le (a, b)
    391 struct val *a, *b;
    392 {
    393 	struct val *r;
    394 
    395 	/* attempt to coerce both arguments to integers */
    396 	(void) to_integer (a);
    397 	(void) to_integer (b);
    398 
    399 	/* But if either one of them really is a string, do
    400 	   a string comparison */
    401 	if (isstring (a) || isstring (b)) {
    402 		to_string (a);
    403 		to_string (b);
    404 		r = make_integer (strcmp (a->u.s, b->u.s) <= 0);
    405 	} else {
    406 		r = make_integer (a->u.i <= b->u.i);
    407 	}
    408 
    409 	free_value (a);
    410 	free_value (b);
    411 	return r;
    412 }
    413 
    414 struct val *
    415 op_ne (a, b)
    416 struct val *a, *b;
    417 {
    418 	struct val *r;
    419 
    420 	/* attempt to coerce both arguments to integers */
    421 	(void) to_integer (a);
    422 	(void) to_integer (b);
    423 
    424 	/* But if either one of them really is a string, do
    425 	   a string comparison */
    426 	if (isstring (a) || isstring (b)) {
    427 		to_string (a);
    428 		to_string (b);
    429 		r = make_integer (strcmp (a->u.s, b->u.s) != 0);
    430 	} else {
    431 		r = make_integer (a->u.i != b->u.i);
    432 	}
    433 
    434 	free_value (a);
    435 	free_value (b);
    436 	return r;
    437 }
    438 
    439 struct val *
    440 op_plus (a, b)
    441 struct val *a, *b;
    442 {
    443 	struct val *r;
    444 
    445 	if (!to_integer (a) || !to_integer (b)) {
    446 		fprintf (stderr, "expr: non-numeric argument\n");
    447 		exit (2);
    448 	}
    449 
    450 	r = make_integer (a->u.i + b->u.i);
    451 	free_value (a);
    452 	free_value (b);
    453 	return r;
    454 }
    455 
    456 struct val *
    457 op_minus (a, b)
    458 struct val *a, *b;
    459 {
    460 	struct val *r;
    461 
    462 	if (!to_integer (a) || !to_integer (b)) {
    463 		fprintf (stderr, "expr: non-numeric argument\n");
    464 		exit (2);
    465 	}
    466 
    467 	r = make_integer (a->u.i - b->u.i);
    468 	free_value (a);
    469 	free_value (b);
    470 	return r;
    471 }
    472 
    473 struct val *
    474 op_times (a, b)
    475 struct val *a, *b;
    476 {
    477 	struct val *r;
    478 
    479 	if (!to_integer (a) || !to_integer (b)) {
    480 		fprintf (stderr, "expr: non-numeric argument\n");
    481 		exit (2);
    482 	}
    483 
    484 	r = make_integer (a->u.i * b->u.i);
    485 	free_value (a);
    486 	free_value (b);
    487 	return (r);
    488 }
    489 
    490 struct val *
    491 op_div (a, b)
    492 struct val *a, *b;
    493 {
    494 	struct val *r;
    495 
    496 	if (!to_integer (a) || !to_integer (b)) {
    497 		fprintf (stderr, "expr: non-numeric argument\n");
    498 		exit (2);
    499 	}
    500 
    501 	if (b->u.i == 0) {
    502 		fprintf (stderr, "expr: division by zero\n");
    503 		exit (2);
    504 	}
    505 
    506 	r = make_integer (a->u.i / b->u.i);
    507 	free_value (a);
    508 	free_value (b);
    509 	return r;
    510 }
    511 
    512 struct val *
    513 op_rem (a, b)
    514 struct val *a, *b;
    515 {
    516 	struct val *r;
    517 
    518 	if (!to_integer (a) || !to_integer (b)) {
    519 		fprintf (stderr, "expr: non-numeric argument\n");
    520 		exit (2);
    521 	}
    522 
    523 	if (b->u.i == 0) {
    524 		fprintf (stderr, "expr: division by zero\n");
    525 		exit (2);
    526 	}
    527 
    528 	r = make_integer (a->u.i % b->u.i);
    529 	free_value (a);
    530 	free_value (b);
    531 	return r;
    532 }
    533 
    534 #include <regexp.h>
    535 
    536 struct val *
    537 op_colon (a, b)
    538 struct val *a, *b;
    539 {
    540 	regexp *rp;
    541 	char *newexp;
    542 	char *p;
    543 	char *q;
    544 
    545 	newexp = malloc (3 * strlen (b->u.s));
    546 	p = b->u.s;
    547 	q = newexp;
    548 
    549 	*q++ = '^';
    550 	while (*p) {
    551 		if (*p == '\\') {
    552 			p++;
    553 			if (*p == '(' || *p == ')') {
    554 				*q++ = *p++;
    555 			} else {
    556 				*q++ = '\\';
    557 				*q++ = *p++;
    558 			}
    559 		} else if (*p == '(' || *p == ')') {
    560 			*q++ = '\\';
    561 			*q++ = *p++;
    562 		} else {
    563 			*q++ = *p++;
    564 		}
    565 	}
    566 	*q = 0;
    567 
    568 	if ((rp = regcomp (newexp)) == NULL)
    569 		yyerror ("invalid regular expression");
    570 
    571 	if (regexec (rp, a->u.s)) {
    572 		if (rp->startp[1]) {
    573 			rp->endp[1][0] = 0;
    574 			return (make_str (rp->startp[1]));
    575 		} else {
    576 			return (make_integer (rp->endp[0] - rp->startp[0]));
    577 		}
    578 	} else {
    579 		return (make_integer (0));
    580 	}
    581 }
    582 
    583 void
    584 regerror (s)
    585 const char *s;
    586 {
    587 	fprintf (stderr, "expr: %s\n", s);
    588 	exit (2);
    589 }
    590