Home | History | Annotate | Line # | Download | only in expr
expr.y revision 1.2
      1 %{
      2 /* Written by Pace Willisson (pace (at) blitz.com)
      3  * and placed in the public domain
      4  *
      5  * $Id: expr.y,v 1.2 1993/03/22 08:04:00 cgd Exp $
      6  */
      7 #include <stdio.h>
      8 #include <ctype.h>
      9 
     10 char *malloc ();
     11 char *calloc ();
     12 
     13 struct val {
     14 	char *sval;
     15 	int ival;
     16 	int iflag;
     17 };
     18 
     19 struct val *result;
     20 
     21 struct val *op_or ();
     22 struct val *op_and ();
     23 struct val *op_eq ();
     24 struct val *op_gt ();
     25 struct val *op_lt ();
     26 struct val *op_ge ();
     27 struct val *op_le ();
     28 struct val *op_ne ();
     29 struct val *op_plus ();
     30 struct val *op_minus ();
     31 struct val *op_times ();
     32 struct val *op_div ();
     33 struct val *op_rem ();
     34 struct val *op_colon ();
     35 
     36 char **av;
     37 %}
     38 
     39 %union
     40 {
     41 	struct val *val;
     42 }
     43 
     44 %left <val> '|'
     45 %left <val> '&'
     46 %left <val> '=' '>' '<' GE LE NE
     47 %left <val> '+' '-'
     48 %left <val> '*' '/' '%'
     49 %left <val> ':'
     50 %left UNARY
     51 
     52 %token <val> TOKEN
     53 %type <val> start expr
     54 
     55 %%
     56 
     57 start: expr { result = $$; }
     58 
     59 expr:	TOKEN
     60 	| '(' expr ')' { $$ = $2; }
     61 	| expr '|' expr { $$ = op_or ($1, $3); }
     62 	| expr '&' expr { $$ = op_and ($1, $3); }
     63 	| expr '=' expr { $$ = op_eq ($1, $3); }
     64 	| expr '>' expr { $$ = op_gt ($1, $3); }
     65 	| expr '<' expr { $$ = op_lt ($1, $3); }
     66 	| expr GE expr  { $$ = op_ge ($1, $3); }
     67 	| expr LE expr  { $$ = op_le ($1, $3); }
     68 	| expr NE expr  { $$ = op_ne ($1, $3); }
     69 	| expr '+' expr { $$ = op_plus ($1, $3); }
     70 	| expr '-' expr { $$ = op_minus ($1, $3); }
     71 	| expr '*' expr { $$ = op_times ($1, $3); }
     72 	| expr '/' expr { $$ = op_div ($1, $3); }
     73 	| expr '%' expr { $$ = op_rem ($1, $3); }
     74 	| expr ':' expr { $$ = op_colon ($1, $3); }
     75 	| '-' expr %prec UNARY { $$ = op_minus (NULL, $2); }
     76 	;
     77 
     78 
     79 %%
     80 
     81 struct val *
     82 make_val (sval)
     83 char *sval;
     84 {
     85 	struct val *vp;
     86 	char *p;
     87 
     88 	if ((vp = (struct val *)calloc (1, sizeof *vp)) == NULL
     89 	    || (vp->sval = malloc (strlen (sval) + 1)) == NULL) {
     90 		fprintf (stderr, "out of memory\n");
     91 		exit (2);
     92 	}
     93 
     94 	strcpy (vp->sval, sval);
     95 
     96 	p = sval;
     97 
     98 	if (*p == '-')
     99 		p++;
    100 	while (isdigit (*p))
    101 		p++;
    102 	if (*p == 0) {
    103 		vp->iflag = 1;
    104 		vp->ival = atoi (sval);
    105 	}
    106 
    107 	return (vp);
    108 }
    109 
    110 struct val *
    111 make_integer (ival)
    112 int ival;
    113 {
    114 	char buf[25];
    115 
    116 	sprintf (buf, "%d", ival);
    117 	return (make_val (buf));
    118 }
    119 
    120 int
    121 yylex ()
    122 {
    123 	struct val *vp;
    124 	char *p;
    125 
    126 	if (*av == NULL)
    127 		return (0);
    128 
    129 	p = *av++;
    130 
    131 	if (strlen (p) == 1) {
    132 		if (strchr ("|&=<>+-*/%:", *p))
    133 			return (*p);
    134 	} else if (strlen (p) == 2 && p[1] == '=') {
    135 		switch (*p) {
    136 		case '>': return (GE);
    137 		case '<': return (LE);
    138 		case '!': return (NE);
    139 		}
    140 	}
    141 
    142 	yylval.val = make_val (p);
    143 	return (TOKEN);
    144 }
    145 
    146 int
    147 is_zero_or_null (vp)
    148 struct val *vp;
    149 {
    150 	if (vp->iflag && vp->ival == 0)
    151 		return (1);
    152 
    153 	if (*vp->sval == 0)
    154 		return (1);
    155 
    156 	return (0);
    157 }
    158 
    159 void
    160 main (argc, argv)
    161 int argc;
    162 char **argv;
    163 {
    164 	av = argv + 1;
    165 
    166 	yyparse ();
    167 
    168 	if (result->iflag)
    169 		printf ("%d\n", result->ival);
    170 	else
    171 		printf ("%s\n", result->sval);
    172 
    173 	if (is_zero_or_null (result))
    174 		exit (1);
    175 	else
    176 		exit (0);
    177 }
    178 
    179 int
    180 yyerror (s)
    181 char *s;
    182 {
    183 	fprintf (stderr, "syntax error\n");
    184 	exit (2);
    185 }
    186 
    187 void
    188 check_integers (a, b)
    189 struct val *a, *b;
    190 {
    191 	if (!a->iflag || !b->iflag) {
    192 		fprintf (stderr, "expr: non-numeric argument\n");
    193 		exit (2);
    194 	}
    195 }
    196 
    197 struct val *
    198 op_or (a, b)
    199 struct val *a, *b;
    200 {
    201 	if (is_zero_or_null (a))
    202 		return (b);
    203 	else
    204 		return (a);
    205 }
    206 
    207 struct val *
    208 op_and (a, b)
    209 struct val *a, *b;
    210 {
    211 	if (is_zero_or_null (a) || is_zero_or_null (b))
    212 		return (make_integer (0));
    213 	else
    214 		return (a);
    215 }
    216 
    217 struct val *
    218 op_eq (a, b)
    219 struct val *a, *b;
    220 {
    221 	if (a->iflag && b->iflag)
    222 		return (make_integer (a->ival == b->ival));
    223 	else
    224 		return (make_integer (strcmp (a->sval, b->sval) == 0));
    225 }
    226 
    227 struct val *
    228 op_gt (a, b)
    229 struct val *a, *b;
    230 {
    231 	if (a->iflag && b->iflag)
    232 		return (make_integer (a->ival > b->ival));
    233 	else
    234 		return (make_integer (strcmp (a->sval, b->sval) > 0));
    235 }
    236 
    237 struct val *
    238 op_lt (a, b)
    239 struct val *a, *b;
    240 {
    241 	if (a->iflag && b->iflag)
    242 		return (make_integer (a->ival < b->ival));
    243 	else
    244 		return (make_integer (strcmp (a->sval, b->sval) < 0));
    245 }
    246 
    247 struct val *
    248 op_ge (a, b)
    249 struct val *a, *b;
    250 {
    251 	if (a->iflag && b->iflag)
    252 		return (make_integer (a->ival >= b->ival));
    253 	else
    254 		return (make_integer (strcmp (a->sval, b->sval) >= 0));
    255 }
    256 
    257 struct val *
    258 op_le (a, b)
    259 struct val *a, *b;
    260 {
    261 	if (a->iflag && b->iflag)
    262 		return (make_integer (a->ival <= b->ival));
    263 	else
    264 		return (make_integer (strcmp (a->sval, b->sval) <= 0));
    265 }
    266 
    267 struct val *
    268 op_ne (a, b)
    269 struct val *a, *b;
    270 {
    271 	if (a->iflag && b->iflag)
    272 		return (make_integer (a->ival != b->ival));
    273 	else
    274 		return (make_integer (strcmp (a->sval, b->sval) != 0));
    275 }
    276 
    277 struct val *
    278 op_plus (a, b)
    279 struct val *a, *b;
    280 {
    281 	check_integers (a, b);
    282 
    283 	return (make_integer (a->ival + b->ival));
    284 }
    285 
    286 struct val *
    287 op_minus (a, b)
    288 struct val *a, *b;
    289 {
    290 	check_integers (a, b);
    291 
    292 	return (make_integer (a->ival - b->ival));
    293 }
    294 
    295 struct val *
    296 op_times (a, b)
    297 struct val *a, *b;
    298 {
    299 	check_integers (a, b);
    300 
    301 	return (make_integer (a->ival * b->ival));
    302 }
    303 
    304 struct val *
    305 op_div (a, b)
    306 struct val *a, *b;
    307 {
    308 	check_integers (a, b);
    309 
    310 	return (make_integer (a->ival / b->ival));
    311 }
    312 
    313 struct val *
    314 op_rem (a, b)
    315 struct val *a, *b;
    316 {
    317 	check_integers (a, b);
    318 
    319 	return (make_integer (a->ival % b->ival));
    320 }
    321 
    322 #include <regexp.h>
    323 
    324 struct val *
    325 op_colon (a, b)
    326 struct val *a, *b;
    327 {
    328 	regexp *rp;
    329 	char *newexp;
    330 	char *p;
    331 	char *q;
    332 
    333 	newexp = malloc (3 * strlen (b->sval));
    334 	p = b->sval;
    335 	q = newexp;
    336 
    337 	*q++ = '^';
    338 	while (*p) {
    339 		if (*p == '\\') {
    340 			p++;
    341 			if (*p == '(' || *p == ')') {
    342 				*q++ = *p++;
    343 			} else {
    344 				*q++ = '\\';
    345 				*q++ = *p++;
    346 			}
    347 		} else if (*p == '(' || *p == ')') {
    348 			*q++ = '\\';
    349 			*q++ = *p++;
    350 		} else {
    351 			*q++ = *p++;
    352 		}
    353 	}
    354 	*q = 0;
    355 
    356 	if ((rp = regcomp (newexp)) == NULL)
    357 		yyerror ("invalid regular expression");
    358 
    359 	if (regexec (rp, a->sval)) {
    360 		if (rp->startp[1]) {
    361 			rp->endp[1][0] = 0;
    362 			return (make_val (rp->startp[1]));
    363 		} else {
    364 			return (make_integer (rp->endp[0] - rp->startp[0]));
    365 		}
    366 	} else {
    367 		return (make_integer (0));
    368 	}
    369 }
    370