hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

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 }