expr.y (11567B)
1 /* from Unix 7th Edition /usr/src/cmd/expr.y */ 2 /* 3 * Changes by Gunnar Ritter, Freiburg i. Br., Germany, December 2002. 4 */ 5 /* 6 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * Redistributions of source code and documentation must retain the 12 * above copyright notice, this list of conditions and the following 13 * disclaimer. 14 * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed or owned by Caldera 20 * International, Inc. 21 * Neither the name of Caldera International, Inc. nor the names of 22 * other contributors may be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 26 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 30 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 33 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 35 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 36 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 %{ 40 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 41 #define USED __attribute__ ((used)) 42 #elif defined __GNUC__ 43 #define USED __attribute__ ((unused)) 44 #else 45 #define USED 46 #endif 47 #if defined (S42) 48 static const char sccsid[] USED = "@(#)expr_s42.sl 1.28 (gritter) 5/29/05"; 49 static int sus = 0; 50 #elif defined (SU3) 51 static const char sccsid[] USED = "@(#)expr_su3.sl 1.28 (gritter) 5/29/05"; 52 static int sus = 3; 53 #elif defined (SUS) 54 static const char sccsid[] USED = "@(#)expr_sus.sl 1.28 (gritter) 5/29/05"; 55 static int sus = 1; 56 #else 57 static const char sccsid[] USED = "@(#)expr.sl 1.28 (gritter) 5/29/05"; 58 static int sus = 0; 59 #endif 60 61 /* expression command */ 62 #include <stdio.h> 63 #include <string.h> 64 #include <stdlib.h> 65 #include <libgen.h> 66 #include <locale.h> 67 #include <wchar.h> 68 #include <unistd.h> 69 #include <limits.h> 70 #include <ctype.h> 71 #include <inttypes.h> 72 73 #include "atoll.h" 74 75 #define EQL(x,y) !strcmp(x,y) 76 77 #define NUMSZ 25 78 79 static char **Av; 80 static int Ac; 81 static int Argi; 82 static int mb_cur_max; 83 static char *progname; 84 extern int sysv3; 85 86 static char *Mstring[1]; 87 88 int yylex(void); 89 static char *_rel(int op, register char *r1, register char *r2); 90 static char *_arith(int op, char *r1, char *r2); 91 static char *_conj(int op, char *r1, char *r2); 92 static char *match(char *s, char *p); 93 static int ematch(char *s, register char *p); 94 static void errxx(int c); 95 static int yyerror(const char *s); 96 static int numeric(const char *s); 97 static int chars(const char *s, const char *end); 98 static void *srealloc(void *, size_t); 99 static void *smalloc(size_t); 100 static char *numpr(int64_t val); 101 102 static char *substr(char *, const char *, const char *); 103 static char *length(const char *); 104 static char *eindex(const char *, const char *); 105 106 #if defined (SUS) || defined (SU3) || defined (S42) 107 #include <regex.h> 108 static int nbra; 109 #else /* !SUS, !SU3, !S42 */ 110 #include <regexpr.h> 111 #endif /* !SUS, !SU3, !S42 */ 112 %} 113 114 /* Yacc productions for "expr" command: */ 115 116 %union { 117 char *val; 118 } 119 120 %token <val> OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ 121 %token <val> A_STRING SUBSTR LENGTH INDEX NOARG MATCH 122 123 %type <val> expr 124 125 /* operators listed below in increasing precedence: */ 126 %left OR 127 %left AND 128 %left EQ LT GT GEQ LEQ NEQ 129 %left ADD SUBT 130 %left MULT DIV REM 131 %left MCH 132 %left MATCH 133 %left SUBSTR 134 %left LENGTH INDEX 135 %% 136 137 /* a single `expression' is evaluated and printed: */ 138 139 expression: expr NOARG { 140 if (sus && numeric($1)) { 141 int64_t n; 142 n = atoll($1); 143 printf("%lld\n", n); 144 exit(n == 0); 145 } else 146 puts($1); 147 exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0); 148 } 149 ; 150 151 152 expr: '(' expr ')' { $$ = $2; } 153 | expr OR expr { $$ = _conj(OR, $1, $3); } 154 | expr AND expr { $$ = _conj(AND, $1, $3); } 155 | expr EQ expr { $$ = _rel(EQ, $1, $3); } 156 | expr GT expr { $$ = _rel(GT, $1, $3); } 157 | expr GEQ expr { $$ = _rel(GEQ, $1, $3); } 158 | expr LT expr { $$ = _rel(LT, $1, $3); } 159 | expr LEQ expr { $$ = _rel(LEQ, $1, $3); } 160 | expr NEQ expr { $$ = _rel(NEQ, $1, $3); } 161 | expr ADD expr { $$ = _arith(ADD, $1, $3); } 162 | expr SUBT expr { $$ = _arith(SUBT, $1, $3); } 163 | expr MULT expr { $$ = _arith(MULT, $1, $3); } 164 | expr DIV expr { $$ = _arith(DIV, $1, $3); } 165 | expr REM expr { $$ = _arith(REM, $1, $3); } 166 | expr MCH expr { $$ = match($1, $3); } 167 | MATCH expr expr { $$ = match($2, $3); } 168 | SUBSTR expr expr expr { $$ = substr($2, $3, $4); } 169 | LENGTH expr { $$ = length($2); } 170 | INDEX expr expr { $$ = eindex($2, $3); } 171 | A_STRING 172 ; 173 %% 174 175 int 176 main(int argc, char **argv) 177 { 178 extern int yyparse(void); 179 180 Ac = argc; 181 Argi = 1; 182 Av = argv; 183 progname = basename(argv[0]); 184 if (getenv("SYSV3") != NULL) 185 sysv3 = 1; 186 setlocale(LC_COLLATE, ""); 187 setlocale(LC_CTYPE, ""); 188 mb_cur_max = MB_CUR_MAX; 189 if (Av[1] && Av[1][0] == '-' && Av[1][1] == '-' && Av[1][2] == '\0') 190 Argi++; 191 yyparse(); 192 /*NOTREACHED*/ 193 return 0; 194 } 195 196 static const char *operators[] = { 197 "|", "&", "+", "-", "*", "/", "%", ":", 198 "=", "==", "<", "<=", ">", ">=", "!=", 199 "match", "substr", "length", "index", 200 "\0" 201 }; 202 203 static int op[] = { 204 OR, AND, ADD, SUBT, MULT, DIV, REM, MCH, 205 EQ, EQ, LT, LEQ, GT, GEQ, NEQ, 206 MATCH, SUBSTR, LENGTH, INDEX 207 }; 208 209 int 210 yylex(void) 211 { 212 register char *p; 213 register int i; 214 215 if(Argi >= Ac) return NOARG; 216 217 p = Av[Argi++]; 218 219 if((*p == '(' || *p == ')') && p[1] == '\0') 220 return (int)*p; 221 for(i = 0; *operators[i]; ++i) 222 if(EQL(operators[i], p)) 223 return op[i]; 224 225 yylval.val = p; 226 return A_STRING; 227 } 228 229 static char * 230 _rel(int op, register char *r1, register char *r2) 231 { 232 register int64_t i; 233 234 if (numeric(r1) && numeric(r2)) 235 i = atoll(r1) - atoll(r2); 236 else 237 i = strcoll(r1, r2); 238 switch(op) { 239 case EQ: i = i==0; break; 240 case GT: i = i>0; break; 241 case GEQ: i = i>=0; break; 242 case LT: i = i<0; break; 243 case LEQ: i = i<=0; break; 244 case NEQ: i = i!=0; break; 245 } 246 return i? "1": "0"; 247 } 248 249 static char * 250 _arith(int op, char *r1, char *r2) 251 { 252 int64_t i1, i2; 253 register char *rv; 254 255 if (!numeric(r1) || !numeric(r2)) 256 yyerror("non-numeric argument"); 257 i1 = atoll(r1); 258 i2 = atoll(r2); 259 260 switch(op) { 261 case ADD: i1 = i1 + i2; break; 262 case SUBT: i1 = i1 - i2; break; 263 case MULT: i1 = i1 * i2; break; 264 case DIV: 265 if (i2 == 0) yyerror("division by zero"); 266 i1 = i1 / i2; break; 267 case REM: i1 = i1 % i2; break; 268 } 269 rv = numpr(i1); 270 return rv; 271 } 272 273 static char * 274 _conj(int op, char *r1, char *r2) 275 { 276 register char *rv = NULL; 277 278 switch(op) { 279 280 case OR: 281 if(EQL(r1, "0") 282 || EQL(r1, "")) 283 if(EQL(r2, "0") 284 || EQL(r2, "")) 285 rv = "0"; 286 else 287 rv = r2; 288 else 289 rv = r1; 290 break; 291 case AND: 292 if(EQL(r1, "0") 293 || EQL(r1, "")) 294 rv = "0"; 295 else if(EQL(r2, "0") 296 || EQL(r2, "")) 297 rv = "0"; 298 else 299 rv = r1; 300 break; 301 } 302 return rv; 303 } 304 305 static char * 306 match(char *s, char *p) 307 { 308 register char *rv; 309 int gotcha; 310 311 gotcha = ematch(s, p); 312 if(nbra) { 313 if (gotcha) { 314 rv = smalloc(strlen(Mstring[0])+1); 315 strcpy(rv, Mstring[0]); 316 } else 317 rv = ""; 318 } else 319 rv = numpr(gotcha); 320 return rv; 321 } 322 323 #if defined (SUS) || defined (SU3) || defined (S42) 324 static int 325 ematch(char *s, register char *p) 326 { 327 regex_t re; 328 register int num; 329 regmatch_t bralist[2]; 330 int reflags = 0, val; 331 332 #ifdef REG_ANGLES 333 reflags |= REG_ANGLES; 334 #endif 335 #if defined (SU3) && defined (REG_AVOIDNULL) 336 reflags |= REG_AVOIDNULL; 337 #endif 338 if ((num = regcomp(&re, p, reflags)) != 0) 339 errxx(0); 340 nbra = re.re_nsub; 341 if (regexec(&re, s, 2, bralist, 0) == 0 && bralist[0].rm_so == 0) { 342 if (re.re_nsub >= 1) { 343 num = bralist[1].rm_eo - bralist[1].rm_so; 344 Mstring[0] = srealloc(Mstring[0], num + 1); 345 strncpy(Mstring[0], s + bralist[1].rm_so, num); 346 Mstring[0][num] = '\0'; 347 } 348 val = chars(s, &s[bralist[0].rm_eo]); 349 } else 350 val = 0; 351 regfree(&re); 352 return val; 353 } 354 #else /* !SUS, !SU3, !S42 */ 355 static int 356 ematch(char *s, register char *p) 357 { 358 char *expbuf; 359 register int num, val; 360 361 if ((expbuf = compile(p, NULL, NULL)) == NULL) 362 errxx(regerrno); 363 if(nbra > 1) 364 yyerror("Too many '\\('s"); 365 if(advance(s, expbuf)) { 366 if(nbra == 1) { 367 p = braslist[0]; 368 num = braelist[0] ? braelist[0] - p : 0; 369 Mstring[0] = srealloc(Mstring[0], num + 1); 370 strncpy(Mstring[0], p, num); 371 Mstring[0][num] = '\0'; 372 } 373 val = chars(s, loc2); 374 } else 375 val = 0; 376 free(expbuf); 377 return(val); 378 } 379 #endif /* !SUS, !SU3, !S42 */ 380 381 /*ARGSUSED*/ 382 static void 383 errxx(int c) 384 { 385 yyerror("RE error"); 386 } 387 388 static int 389 yyerror(const char *s) 390 { 391 fprintf(stderr, "%s: %s\n", progname, s); 392 exit(2); 393 } 394 395 static int 396 numeric(const char *s) 397 { 398 if (*s == '-') 399 s++; 400 if (!isdigit(*s & 0377)) 401 return 0; 402 do 403 s++; 404 while (isdigit(*s & 0377)); 405 return (*s == '\0'); 406 } 407 408 static int 409 chars(const char *s, const char *end) 410 { 411 int count = 0, n; 412 wchar_t wc; 413 414 if (mb_cur_max > 1) { 415 while (s < end) { 416 if ((n = mbtowc(&wc, s, MB_LEN_MAX)) >= 0) 417 count++; 418 s += n > 0 ? n : 1; 419 } 420 } else 421 count = end - s; 422 return count; 423 } 424 425 static void * 426 srealloc(void *vp, size_t nbytes) 427 { 428 void *p; 429 430 if ((p = realloc(vp, nbytes)) == NULL) { 431 write(2, "no memory\n", 10); 432 exit(077); 433 } 434 return p; 435 } 436 437 static void * 438 smalloc(size_t nbytes) 439 { 440 return srealloc(NULL, nbytes); 441 } 442 443 static char * 444 numpr(int64_t val) 445 { 446 char *rv; 447 int ret; 448 449 rv = smalloc(NUMSZ); 450 ret = snprintf(rv, NUMSZ, "%lld", (long long)val); 451 if (ret < 0 || ret >= NUMSZ) { 452 rv = srealloc(rv, ret + 1); 453 ret = snprintf(rv, ret, "%lld", (long long)val); 454 if (ret < 0) 455 yyerror("illegal number"); 456 } 457 return rv; 458 } 459 460 #define next(wc, s, n) (mb_cur_max > 1 && *(s) & 0200 ? \ 461 ((n) = mbtowc(&(wc), (s), mb_cur_max), \ 462 (n) = ((n) > 0 ? (n) : (n) < 0 ? illseq() : 1)) :\ 463 ((wc) = *(s) & 0377, (n) = 1)) 464 465 static int 466 illseq(void) 467 { 468 yyerror("illegal byte sequence"); 469 /*NOTREACHED*/ 470 return 0; 471 } 472 473 static char * 474 substr(char *v, const char *s, const char *w) 475 { 476 long si, wi; 477 char *res; 478 wchar_t wc; 479 int n; 480 481 #ifndef S42 482 if (sysv3 == 0) 483 yyerror("syntax error"); 484 #endif 485 si = atoll(s); 486 wi = atoll(w); 487 while (--si) 488 if (*v) { 489 next(wc, v, n); 490 v += n; 491 } 492 res = v; 493 while (wi--) 494 if (*v) { 495 next(wc, v, n); 496 v += n; 497 } 498 *v = '\0'; 499 return res; 500 } 501 502 static char * 503 length(const char *s) 504 { 505 long i = 0; 506 char *rv; 507 wchar_t wc; 508 int n; 509 510 #ifndef S42 511 if (sysv3 == 0) 512 yyerror("syntax error"); 513 #endif 514 while (*s) { 515 next(wc, s, n); 516 s += n; 517 ++i; 518 } 519 rv = numpr(i); 520 return rv; 521 } 522 523 static char * 524 eindex(const char *s, const char *t) 525 { 526 long i, j, x; 527 char *rv; 528 wchar_t ws, wt; 529 int ns, nt; 530 531 #ifndef S42 532 if (sysv3 == 0) 533 yyerror("syntax error"); 534 #endif 535 for (i = 0, x = 0; s[i]; x++, i += ns) { 536 next(ws, &s[i], ns); 537 for (j = 0; t[j]; j += nt) { 538 next(wt, &t[j], nt); 539 if (ws == wt) { 540 rv = numpr(++x); 541 return rv; 542 } 543 } 544 } 545 return "0"; 546 }