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