Changeset 3192 in kBuild for trunk/src/kmk/kmkbuiltin/expr.c
- Timestamp:
- Mar 26, 2018 8:25:56 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin/expr.c
r3140 r3192 22 22 #endif 23 23 #include "err.h" 24 #include "getopt.h"25 24 #include "kmkbuiltin.h" 26 25 27 static struct val *make_int(int); 28 static struct val *make_str(char *); 29 static void free_value(struct val *); 26 typedef struct EXPRINSTANCE *PEXPRINSTANCE; 27 28 static struct val *make_int(PEXPRINSTANCE, int); 29 static struct val *make_str(PEXPRINSTANCE, char *); 30 static void free_value(PEXPRINSTANCE, struct val *); 30 31 static int is_integer(struct val *, int *); 31 static int to_integer( struct val *);32 static void to_string( struct val *);33 static int is_zero_or_null( struct val *);34 static void nexttoken( int);35 static struct val *eval6( void);36 static struct val *eval5( void);37 static struct val *eval4( void);38 static struct val *eval3( void);39 static struct val *eval2( void);40 static struct val *eval1( void);41 static struct val *eval0( void);32 static int to_integer(PEXPRINSTANCE, struct val *); 33 static void to_string(PEXPRINSTANCE, struct val *); 34 static int is_zero_or_null(PEXPRINSTANCE, struct val *); 35 static void nexttoken(PEXPRINSTANCE, int); 36 static struct val *eval6(PEXPRINSTANCE); 37 static struct val *eval5(PEXPRINSTANCE); 38 static struct val *eval4(PEXPRINSTANCE); 39 static struct val *eval3(PEXPRINSTANCE); 40 static struct val *eval2(PEXPRINSTANCE); 41 static struct val *eval1(PEXPRINSTANCE); 42 static struct val *eval0(PEXPRINSTANCE); 42 43 43 44 enum token { … … 58 59 }; 59 60 60 static enum token token; 61 static struct val *tokval; 62 static char **av; 63 static jmp_buf g_expr_jmp; 64 static void **recorded_allocations; 65 static int num_recorded_allocations; 66 67 68 static void expr_mem_record_alloc(void *ptr) 69 { 70 if (!(num_recorded_allocations & 31)) { 71 void *newtab = realloc(recorded_allocations, (num_recorded_allocations + 33) * sizeof(void *)); 61 typedef struct EXPRINSTANCE { 62 PKMKBUILTINCTX pCtx; 63 enum token token; 64 struct val *tokval; 65 char **av; 66 jmp_buf g_expr_jmp; 67 void **recorded_allocations; 68 int num_recorded_allocations; 69 } EXPRINSTANCE; 70 71 72 static void expr_mem_record_alloc(PEXPRINSTANCE pThis, void *ptr) 73 { 74 if (!(pThis->num_recorded_allocations & 31)) { 75 void *newtab = realloc(pThis->recorded_allocations, (pThis->num_recorded_allocations + 33) * sizeof(void *)); 72 76 if (!newtab) 73 longjmp( g_expr_jmp, err(3, NULL));74 recorded_allocations = (void **)newtab;75 } 76 recorded_allocations[num_recorded_allocations++] = ptr;77 } 78 79 80 static void expr_mem_record_free( void *ptr)81 { 82 int i = num_recorded_allocations;77 longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL)); 78 pThis->recorded_allocations = (void **)newtab; 79 } 80 pThis->recorded_allocations[pThis->num_recorded_allocations++] = ptr; 81 } 82 83 84 static void expr_mem_record_free(PEXPRINSTANCE pThis, void *ptr) 85 { 86 int i = pThis->num_recorded_allocations; 83 87 while (i-- > 0) 84 if ( recorded_allocations[i] == ptr) {85 num_recorded_allocations--;86 recorded_allocations[i] = recorded_allocations[num_recorded_allocations];88 if (pThis->recorded_allocations[i] == ptr) { 89 pThis->num_recorded_allocations--; 90 pThis->recorded_allocations[i] = pThis->recorded_allocations[pThis->num_recorded_allocations]; 87 91 return; 88 92 } … … 90 94 } 91 95 92 static void expr_mem_init( void)93 { 94 num_recorded_allocations = 0;95 recorded_allocations = NULL;96 } 97 98 static void expr_mem_cleanup( void)99 { 100 if ( recorded_allocations) {101 while ( num_recorded_allocations-- > 0)102 free( recorded_allocations[num_recorded_allocations]);103 free( recorded_allocations);104 recorded_allocations = NULL;105 } 106 } 107 108 109 static struct val * 110 make_int( int i)96 static void expr_mem_init(PEXPRINSTANCE pThis) 97 { 98 pThis->num_recorded_allocations = 0; 99 pThis->recorded_allocations = NULL; 100 } 101 102 static void expr_mem_cleanup(PEXPRINSTANCE pThis) 103 { 104 if (pThis->recorded_allocations) { 105 while (pThis->num_recorded_allocations-- > 0) 106 free(pThis->recorded_allocations[pThis->num_recorded_allocations]); 107 free(pThis->recorded_allocations); 108 pThis->recorded_allocations = NULL; 109 } 110 } 111 112 113 static struct val * 114 make_int(PEXPRINSTANCE pThis, int i) 111 115 { 112 116 struct val *vp; … … 114 118 vp = (struct val *) malloc(sizeof(*vp)); 115 119 if (vp == NULL) 116 longjmp( g_expr_jmp, err(3, NULL));117 expr_mem_record_alloc( vp);120 longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL)); 121 expr_mem_record_alloc(pThis, vp); 118 122 vp->type = integer; 119 123 vp->u.i = i; … … 123 127 124 128 static struct val * 125 make_str( char *s)129 make_str(PEXPRINSTANCE pThis, char *s) 126 130 { 127 131 struct val *vp; … … 129 133 vp = (struct val *) malloc(sizeof(*vp)); 130 134 if (vp == NULL || ((vp->u.s = strdup(s)) == NULL)) 131 longjmp( g_expr_jmp, err(3, NULL));132 expr_mem_record_alloc( vp->u.s);133 expr_mem_record_alloc( vp);135 longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL)); 136 expr_mem_record_alloc(pThis, vp->u.s); 137 expr_mem_record_alloc(pThis, vp); 134 138 vp->type = string; 135 139 return vp; … … 138 142 139 143 static void 140 free_value( struct val *vp)144 free_value(PEXPRINSTANCE pThis, struct val *vp) 141 145 { 142 146 if (vp->type == string) { 143 expr_mem_record_free( vp->u.s);147 expr_mem_record_free(pThis, vp->u.s); 144 148 free(vp->u.s); 145 149 } 146 150 free(vp); 147 expr_mem_record_free( vp);151 expr_mem_record_free(pThis, vp); 148 152 } 149 153 … … 193 197 /* coerce to vp to an integer */ 194 198 static int 195 to_integer( struct val *vp)199 to_integer(PEXPRINSTANCE pThis, struct val *vp) 196 200 { 197 201 int r; … … 201 205 202 206 if (is_integer(vp, &r)) { 203 expr_mem_record_free( vp->u.s);207 expr_mem_record_free(pThis, vp->u.s); 204 208 free(vp->u.s); 205 209 vp->u.i = r; … … 214 218 /* coerce to vp to an string */ 215 219 static void 216 to_string( struct val *vp)220 to_string(PEXPRINSTANCE pThis, struct val *vp) 217 221 { 218 222 char *tmp; … … 222 226 223 227 if (asprintf(&tmp, "%d", vp->u.i) == -1) 224 longjmp( g_expr_jmp, err(3, NULL));225 expr_mem_record_alloc( tmp);228 longjmp(pThis->g_expr_jmp, err(pThis->pCtx, 3, NULL)); 229 expr_mem_record_alloc(pThis, tmp); 226 230 227 231 vp->type = string; … … 230 234 231 235 static int 232 is_zero_or_null( struct val *vp)236 is_zero_or_null(PEXPRINSTANCE pThis, struct val *vp) 233 237 { 234 238 if (vp->type == integer) { 235 239 return (vp->u.i == 0); 236 240 } else { 237 return (*vp->u.s == 0 || (to_integer( vp) && vp->u.i == 0));241 return (*vp->u.s == 0 || (to_integer(pThis, vp) && vp->u.i == 0)); 238 242 } 239 243 /* NOTREACHED */ … … 241 245 242 246 static void 243 nexttoken( int pat)247 nexttoken(PEXPRINSTANCE pThis, int pat) 244 248 { 245 249 char *p; 246 250 247 if ((p = * av) == NULL) {248 token = EOI;251 if ((p = *pThis->av) == NULL) { 252 pThis->token = EOI; 249 253 return; 250 254 } 251 av++;255 pThis->av++; 252 256 253 257 … … 258 262 259 263 if ((i = strchr(x, *p)) != NULL) { 260 token = i - x;264 pThis->token = i - x; 261 265 return; 262 266 } … … 264 268 switch (*p) { 265 269 case '<': 266 token = LE;270 pThis->token = LE; 267 271 return; 268 272 case '>': 269 token = GE;273 pThis->token = GE; 270 274 return; 271 275 case '!': 272 token = NE;276 pThis->token = NE; 273 277 return; 274 278 } 275 279 } 276 280 } 277 tokval = make_str(p);278 token = OPERAND;281 pThis->tokval = make_str(pThis, p); 282 pThis->token = OPERAND; 279 283 return; 280 284 } … … 287 291 #endif 288 292 static void 289 error( void)290 { 291 longjmp( g_expr_jmp, errx(2, "syntax error"));293 error(PEXPRINSTANCE pThis) 294 { 295 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "syntax error")); 292 296 /* NOTREACHED */ 293 297 } 294 298 295 299 static struct val * 296 eval6( void)300 eval6(PEXPRINSTANCE pThis) 297 301 { 298 302 struct val *v; 299 303 300 if ( token == OPERAND) {301 nexttoken( 0);302 return tokval;303 304 } else if ( token == RP) {305 nexttoken( 0);306 v = eval0( );307 308 if ( token != LP) {309 error( );304 if (pThis->token == OPERAND) { 305 nexttoken(pThis, 0); 306 return pThis->tokval; 307 308 } else if (pThis->token == RP) { 309 nexttoken(pThis, 0); 310 v = eval0(pThis); 311 312 if (pThis->token != LP) { 313 error(pThis); 310 314 /* NOTREACHED */ 311 315 } 312 nexttoken( 0);316 nexttoken(pThis, 0); 313 317 return v; 314 318 } else { 315 error( );319 error(pThis); 316 320 } 317 321 /* NOTREACHED */ … … 320 324 /* Parse and evaluate match (regex) expressions */ 321 325 static struct val * 322 eval5( void)326 eval5(PEXPRINSTANCE pThis) 323 327 { 324 328 #ifdef KMK_WITH_REGEX … … 332 336 struct val *l; 333 337 334 l = eval6( );335 while ( token == MATCH) {338 l = eval6(pThis); 339 while (pThis->token == MATCH) { 336 340 #ifdef KMK_WITH_REGEX 337 nexttoken( 1);338 r = eval6( );341 nexttoken(pThis, 1); 342 r = eval6(pThis); 339 343 340 344 /* coerce to both arguments to strings */ 341 to_string( l);342 to_string( r);345 to_string(pThis, l); 346 to_string(pThis, r); 343 347 344 348 /* compile regular expression */ 345 349 if ((eval = regcomp(&rp, r->u.s, 0)) != 0) { 346 350 regerror(eval, &rp, errbuf, sizeof(errbuf)); 347 longjmp( g_expr_jmp, errx(2, "%s", errbuf));351 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "%s", errbuf)); 348 352 } 349 353 … … 353 357 if (rm[1].rm_so >= 0) { 354 358 *(l->u.s + rm[1].rm_eo) = '\0'; 355 v = make_str( l->u.s + rm[1].rm_so);359 v = make_str(pThis, l->u.s + rm[1].rm_so); 356 360 357 361 } else { 358 v = make_int( (int)(rm[0].rm_eo - rm[0].rm_so));362 v = make_int(pThis, (int)(rm[0].rm_eo - rm[0].rm_so)); 359 363 } 360 364 } else { 361 365 if (rp.re_nsub == 0) { 362 v = make_int( 0);366 v = make_int(pThis, 0); 363 367 } else { 364 v = make_str( "");368 v = make_str(pThis, ""); 365 369 } 366 370 } 367 371 368 372 /* free arguments and pattern buffer */ 369 free_value( l);370 free_value( r);373 free_value(pThis, l); 374 free_value(pThis, r); 371 375 regfree(&rp); 372 376 373 377 l = v; 374 378 #else 375 longjmp( g_expr_jmp, errx(2, "regex not supported, sorry."));379 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "regex not supported, sorry.")); 376 380 #endif 377 381 } … … 382 386 /* Parse and evaluate multiplication and division expressions */ 383 387 static struct val * 384 eval4( void)388 eval4(PEXPRINSTANCE pThis) 385 389 { 386 390 struct val *l, *r; 387 391 enum token op; 388 392 389 l = eval5( );390 while ((op = token) == MUL || op == DIV || op == MOD) {391 nexttoken( 0);392 r = eval5( );393 394 if (!to_integer( l) || !to_integer(r)) {395 longjmp( g_expr_jmp, errx(2, "non-numeric argument"));393 l = eval5(pThis); 394 while ((op = pThis->token) == MUL || op == DIV || op == MOD) { 395 nexttoken(pThis, 0); 396 r = eval5(pThis); 397 398 if (!to_integer(pThis, l) || !to_integer(pThis, r)) { 399 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument")); 396 400 } 397 401 … … 400 404 } else { 401 405 if (r->u.i == 0) { 402 longjmp( g_expr_jmp, errx(2, "division by zero"));406 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "division by zero")); 403 407 } 404 408 if (op == DIV) { … … 409 413 } 410 414 411 free_value( r);415 free_value(pThis, r); 412 416 } 413 417 … … 417 421 /* Parse and evaluate addition and subtraction expressions */ 418 422 static struct val * 419 eval3( void)423 eval3(PEXPRINSTANCE pThis) 420 424 { 421 425 struct val *l, *r; 422 426 enum token op; 423 427 424 l = eval4( );425 while ((op = token) == ADD || op == SUB) {426 nexttoken( 0);427 r = eval4( );428 429 if (!to_integer( l) || !to_integer(r)) {430 longjmp( g_expr_jmp, errx(2, "non-numeric argument"));428 l = eval4(pThis); 429 while ((op = pThis->token) == ADD || op == SUB) { 430 nexttoken(pThis, 0); 431 r = eval4(pThis); 432 433 if (!to_integer(pThis, l) || !to_integer(pThis, r)) { 434 longjmp(pThis->g_expr_jmp, errx(pThis->pCtx, 2, "non-numeric argument")); 431 435 } 432 436 … … 437 441 } 438 442 439 free_value( r);443 free_value(pThis, r); 440 444 } 441 445 … … 445 449 /* Parse and evaluate comparison expressions */ 446 450 static struct val * 447 eval2( void)451 eval2(PEXPRINSTANCE pThis) 448 452 { 449 453 struct val *l, *r; … … 451 455 int v = 0, li, ri; 452 456 453 l = eval3( );454 while ((op = token) == EQ || op == NE || op == LT || op == GT ||457 l = eval3(pThis); 458 while ((op = pThis->token) == EQ || op == NE || op == LT || op == GT || 455 459 op == LE || op == GE) { 456 nexttoken( 0);457 r = eval3( );460 nexttoken(pThis, 0); 461 r = eval3(pThis); 458 462 459 463 if (is_integer(l, &li) && is_integer(r, &ri)) { … … 481 485 } 482 486 } else { 483 to_string( l);484 to_string( r);487 to_string(pThis, l); 488 to_string(pThis, r); 485 489 486 490 switch (op) { … … 508 512 } 509 513 510 free_value( l);511 free_value( r);512 l = make_int( v);514 free_value(pThis, l); 515 free_value(pThis, r); 516 l = make_int(pThis, v); 513 517 } 514 518 … … 518 522 /* Parse and evaluate & expressions */ 519 523 static struct val * 520 eval1( void)524 eval1(PEXPRINSTANCE pThis) 521 525 { 522 526 struct val *l, *r; 523 527 524 l = eval2( );525 while ( token == AND) {526 nexttoken( 0);527 r = eval2( );528 529 if (is_zero_or_null( l) || is_zero_or_null(r)) {530 free_value( l);531 free_value( r);532 l = make_int( 0);528 l = eval2(pThis); 529 while (pThis->token == AND) { 530 nexttoken(pThis, 0); 531 r = eval2(pThis); 532 533 if (is_zero_or_null(pThis, l) || is_zero_or_null(pThis, r)) { 534 free_value(pThis, l); 535 free_value(pThis, r); 536 l = make_int(pThis, 0); 533 537 } else { 534 free_value( r);538 free_value(pThis, r); 535 539 } 536 540 } … … 541 545 /* Parse and evaluate | expressions */ 542 546 static struct val * 543 eval0( void)547 eval0(PEXPRINSTANCE pThis) 544 548 { 545 549 struct val *l, *r; 546 550 547 l = eval1( );548 while ( token == OR) {549 nexttoken( 0);550 r = eval1( );551 552 if (is_zero_or_null( l)) {553 free_value( l);551 l = eval1(pThis); 552 while (pThis->token == OR) { 553 nexttoken(pThis, 0); 554 r = eval1(pThis); 555 556 if (is_zero_or_null(pThis, l)) { 557 free_value(pThis, l); 554 558 l = r; 555 559 } else { 556 free_value( r);560 free_value(pThis, r); 557 561 } 558 562 } … … 563 567 564 568 int 565 kmk_builtin_expr(int argc, char *argv[], char **envp) 566 { 567 struct val *vp; 569 kmk_builtin_expr(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx) 570 { 571 EXPRINSTANCE This; 572 struct val *vp; 568 573 int rval; 569 570 /* re-init globals */571 token = 0;572 tokval = 0;573 av = 0;574 expr_mem_init();575 576 #ifdef kmk_builtin_expr /* kmk already does this. */577 (void) setlocale(LC_ALL, "");578 #endif579 574 580 575 if (argc > 1 && !strcmp(argv[1], "--")) 581 576 argv++; 582 577 583 av = argv + 1; 584 585 rval = setjmp(g_expr_jmp); 578 /* Init globals */ 579 This.pCtx = pCtx; 580 This.token = 0; 581 This.tokval = 0; 582 This.av = argv + 1; 583 expr_mem_init(&This); 584 585 rval = setjmp(This.g_expr_jmp); 586 586 if (!rval) { 587 nexttoken( 0);588 vp = eval0( );589 590 if ( token != EOI) {591 error( );587 nexttoken(&This, 0); 588 vp = eval0(&This); 589 590 if (This.token != EOI) { 591 error(&This); 592 592 /* NOTREACHED */ 593 593 } 594 594 595 595 if (vp->type == integer) 596 printf("%d\n", vp->u.i);596 kmk_builtin_ctx_printf(pCtx, 0, "%d\n", vp->u.i); 597 597 else 598 printf("%s\n", vp->u.s);599 600 rval = is_zero_or_null( vp);598 kmk_builtin_ctx_printf(pCtx, 0, "%s\n", vp->u.s); 599 600 rval = is_zero_or_null(&This, vp); 601 601 } 602 602 /* else: longjmp */ 603 603 604 604 /* cleanup */ 605 expr_mem_cleanup( );605 expr_mem_cleanup(&This); 606 606 return rval; 607 607 } 608 609 #ifdef KMK_BUILTIN_STANDALONE 610 int main(int argc, char **argv, char **envp) 611 { 612 KMKBUILTINCTX Ctx = { "kmk_expr", NULL }; 613 (void) setlocale(LC_ALL, ""); 614 return kmk_builtin_expr(argc, argv, envp, &Ctx); 615 } 616 #endif 617
Note:
See TracChangeset
for help on using the changeset viewer.