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