1 /* $OpenBSD: syn.c,v 1.12 1999/06/15 01:18:36 millert Exp $ */ 2 3 /* 4 * shell parser (C version) 5 */ 6 7 #include "sh.h" 8 #include "c_test.h" 9 10 struct nesting_state { 11 int start_token; /* token than began nesting (eg, FOR) */ 12 int start_line; /* line nesting began on */ 13 }; 14 15 static void yyparse ARGS((void)); 16 static struct op *pipeline ARGS((int cf)); 17 static struct op *andor ARGS((void)); 18 static struct op *c_list ARGS((int multi)); 19 static struct ioword *synio ARGS((int cf)); 20 static void musthave ARGS((int c, int cf)); 21 static struct op *nested ARGS((int type, int smark, int emark)); 22 static struct op *get_command ARGS((int cf)); 23 static struct op *dogroup ARGS((void)); 24 static struct op *thenpart ARGS((void)); 25 static struct op *elsepart ARGS((void)); 26 static struct op *caselist ARGS((void)); 27 static struct op *casepart ARGS((int endtok)); 28 static struct op *function_body ARGS((char *name, int ksh_func)); 29 static char ** wordlist ARGS((void)); 30 static struct op *block ARGS((int type, struct op *t1, struct op *t2, 31 char **wp)); 32 static struct op *newtp ARGS((int type)); 33 static void syntaxerr ARGS((const char *what)) 34 GCC_FUNC_ATTR(noreturn); 35 static void nesting_push ARGS((struct nesting_state *save, int tok)); 36 static void nesting_pop ARGS((struct nesting_state *saved)); 37 static int assign_command ARGS((char *s)); 38 static int inalias ARGS((struct source *s)); 39 #ifdef KSH 40 static int dbtestp_isa ARGS((Test_env *te, Test_meta meta)); 41 static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op, 42 int do_eval)); 43 static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1, 44 const char *opnd2, int do_eval)); 45 static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg)); 46 #endif /* KSH */ 47 48 static struct op *outtree; /* yyparse output */ 49 50 static struct nesting_state nesting; /* \n changed to ; */ 51 52 static int reject; /* token(cf) gets symbol again */ 53 static int symbol; /* yylex value */ 54 55 #define REJECT (reject = 1) 56 #define ACCEPT (reject = 0) 57 #define token(cf) \ 58 ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf))) 59 #define tpeek(cf) \ 60 ((reject) ? (symbol) : (REJECT, symbol = yylex(cf))) 61 62 static void 63 yyparse() 64 { 65 int c; 66 67 ACCEPT; 68 69 outtree = c_list(source->type == SSTRING); 70 c = tpeek(0); 71 if (c == 0 && !outtree) 72 outtree = newtp(TEOF); 73 else if (c != '\n' && c != 0) 74 syntaxerr((char *) 0); 75 } 76 77 static struct op * 78 pipeline(cf) 79 int cf; 80 { 81 register struct op *t, *p, *tl = NULL; 82 83 t = get_command(cf); 84 if (t != NULL) { 85 while (token(0) == '|') { 86 if ((p = get_command(CONTIN)) == NULL) 87 syntaxerr((char *) 0); 88 if (tl == NULL) 89 t = tl = block(TPIPE, t, p, NOWORDS); 90 else 91 tl = tl->right = block(TPIPE, tl->right, p, NOWORDS); 92 } 93 REJECT; 94 } 95 return (t); 96 } 97 98 static struct op * 99 andor() 100 { 101 register struct op *t, *p; 102 register int c; 103 104 t = pipeline(0); 105 if (t != NULL) { 106 while ((c = token(0)) == LOGAND || c == LOGOR) { 107 if ((p = pipeline(CONTIN)) == NULL) 108 syntaxerr((char *) 0); 109 t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); 110 } 111 REJECT; 112 } 113 return (t); 114 } 115 116 static struct op * 117 c_list(multi) 118 int multi; 119 { 120 register struct op *t = NULL, *p, *tl = NULL; 121 register int c; 122 int have_sep; 123 124 while (1) { 125 p = andor(); 126 /* Token has always been read/rejected at this point, so 127 * we don't worry about what flags to pass token() 128 */ 129 c = token(0); 130 have_sep = 1; 131 if (c == '\n' && (multi || inalias(source))) { 132 if (!p) /* ignore blank lines */ 133 continue; 134 } else if (!p) 135 break; 136 else if (c == '&' || c == COPROC) 137 p = block(c == '&' ? TASYNC : TCOPROC, 138 p, NOBLOCK, NOWORDS); 139 else if (c != ';') 140 have_sep = 0; 141 if (!t) 142 t = p; 143 else if (!tl) 144 t = tl = block(TLIST, t, p, NOWORDS); 145 else 146 tl = tl->right = block(TLIST, tl->right, p, NOWORDS); 147 if (!have_sep) 148 break; 149 } 150 REJECT; 151 return t; 152 } 153 154 static struct ioword * 155 synio(cf) 156 int cf; 157 { 158 register struct ioword *iop; 159 int ishere; 160 161 if (tpeek(cf) != REDIR) 162 return NULL; 163 ACCEPT; 164 iop = yylval.iop; 165 ishere = (iop->flag&IOTYPE) == IOHERE; 166 musthave(LWORD, ishere ? HEREDELIM : 0); 167 if (ishere) { 168 iop->delim = yylval.cp; 169 if (*ident != 0) /* unquoted */ 170 iop->flag |= IOEVAL; 171 if (herep >= &heres[HERES]) 172 yyerror("too many <<'s\n"); 173 *herep++ = iop; 174 } else 175 iop->name = yylval.cp; 176 return iop; 177 } 178 179 static void 180 musthave(c, cf) 181 int c, cf; 182 { 183 if ((token(cf)) != c) 184 syntaxerr((char *) 0); 185 } 186 187 static struct op * 188 nested(type, smark, emark) 189 int type, smark, emark; 190 { 191 register struct op *t; 192 struct nesting_state old_nesting; 193 194 nesting_push(&old_nesting, smark); 195 t = c_list(TRUE); 196 musthave(emark, KEYWORD|ALIAS); 197 nesting_pop(&old_nesting); 198 return (block(type, t, NOBLOCK, NOWORDS)); 199 } 200 201 static struct op * 202 get_command(cf) 203 int cf; 204 { 205 register struct op *t; 206 register int c, iopn = 0, syniocf; 207 struct ioword *iop, **iops; 208 XPtrV args, vars; 209 struct nesting_state old_nesting; 210 211 iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), 212 ATEMP); 213 XPinit(args, 16); 214 XPinit(vars, 16); 215 216 syniocf = KEYWORD|ALIAS; 217 switch (c = token(cf|KEYWORD|ALIAS|VARASN)) { 218 default: 219 REJECT; 220 afree((void*) iops, ATEMP); 221 XPfree(args); 222 XPfree(vars); 223 return NULL; /* empty line */ 224 225 case LWORD: 226 case REDIR: 227 REJECT; 228 syniocf &= ~(KEYWORD|ALIAS); 229 t = newtp(TCOM); 230 t->lineno = source->line; 231 while (1) { 232 cf = (t->u.evalflags ? ARRAYVAR : 0) 233 | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); 234 switch (tpeek(cf)) { 235 case REDIR: 236 if (iopn >= NUFILE) 237 yyerror("too many redirections\n"); 238 iops[iopn++] = synio(cf); 239 break; 240 241 case LWORD: 242 ACCEPT; 243 /* the iopn == 0 and XPsize(vars) == 0 are 244 * dubious but at&t ksh acts this way 245 */ 246 if (iopn == 0 && XPsize(vars) == 0 247 && XPsize(args) == 0 248 && assign_command(ident)) 249 t->u.evalflags = DOVACHECK; 250 if ((XPsize(args) == 0 || Flag(FKEYWORD)) 251 && is_wdvarassign(yylval.cp)) 252 XPput(vars, yylval.cp); 253 else 254 XPput(args, yylval.cp); 255 break; 256 257 case '(': 258 /* Check for "> foo (echo hi)", which at&t ksh 259 * allows (not POSIX, but not disallowed) 260 */ 261 afree(t, ATEMP); 262 if (XPsize(args) == 0 && XPsize(vars) == 0) { 263 ACCEPT; 264 goto Subshell; 265 } 266 /* Must be a function */ 267 if (iopn != 0 || XPsize(args) != 1 268 || XPsize(vars) != 0) 269 syntaxerr((char *) 0); 270 ACCEPT; 271 /*(*/ 272 musthave(')', 0); 273 t = function_body(XPptrv(args)[0], FALSE); 274 goto Leave; 275 276 default: 277 goto Leave; 278 } 279 } 280 Leave: 281 break; 282 283 Subshell: 284 case '(': 285 t = nested(TPAREN, '(', ')'); 286 break; 287 288 case '{': /*}*/ 289 t = nested(TBRACE, '{', '}'); 290 break; 291 292 #ifdef KSH 293 case MDPAREN: 294 { 295 static const char let_cmd[] = { CHAR, 'l', CHAR, 'e', 296 CHAR, 't', EOS }; 297 /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */ 298 t = newtp(TCOM); 299 t->lineno = source->line; 300 ACCEPT; 301 XPput(args, wdcopy(let_cmd, ATEMP)); 302 musthave(LWORD,LETEXPR); 303 XPput(args, yylval.cp); 304 break; 305 } 306 #endif /* KSH */ 307 308 #ifdef KSH 309 case DBRACKET: /* [[ .. ]] */ 310 /* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */ 311 t = newtp(TDBRACKET); 312 ACCEPT; 313 { 314 Test_env te; 315 316 te.flags = TEF_DBRACKET; 317 te.pos.av = &args; 318 te.isa = dbtestp_isa; 319 te.getopnd = dbtestp_getopnd; 320 te.eval = dbtestp_eval; 321 te.error = dbtestp_error; 322 323 test_parse(&te); 324 } 325 break; 326 #endif /* KSH */ 327 328 case FOR: 329 case SELECT: 330 t = newtp((c == FOR) ? TFOR : TSELECT); 331 musthave(LWORD, ARRAYVAR); 332 if (!is_wdvarname(yylval.cp, TRUE)) 333 yyerror("%s: bad identifier\n", 334 c == FOR ? "for" : "select"); 335 t->str = str_save(ident, ATEMP); 336 nesting_push(&old_nesting, c); 337 t->vars = wordlist(); 338 t->left = dogroup(); 339 nesting_pop(&old_nesting); 340 break; 341 342 case WHILE: 343 case UNTIL: 344 nesting_push(&old_nesting, c); 345 t = newtp((c == WHILE) ? TWHILE : TUNTIL); 346 t->left = c_list(TRUE); 347 t->right = dogroup(); 348 nesting_pop(&old_nesting); 349 break; 350 351 case CASE: 352 t = newtp(TCASE); 353 musthave(LWORD, 0); 354 t->str = yylval.cp; 355 nesting_push(&old_nesting, c); 356 t->left = caselist(); 357 nesting_pop(&old_nesting); 358 break; 359 360 case IF: 361 nesting_push(&old_nesting, c); 362 t = newtp(TIF); 363 t->left = c_list(TRUE); 364 t->right = thenpart(); 365 musthave(FI, KEYWORD|ALIAS); 366 nesting_pop(&old_nesting); 367 break; 368 369 case BANG: 370 syniocf &= ~(KEYWORD|ALIAS); 371 t = pipeline(0); 372 if (t == (struct op *) 0) 373 syntaxerr((char *) 0); 374 t = block(TBANG, NOBLOCK, t, NOWORDS); 375 break; 376 377 case TIME: 378 syniocf &= ~(KEYWORD|ALIAS); 379 t = pipeline(0); 380 t = block(TTIME, t, NOBLOCK, NOWORDS); 381 break; 382 383 case FUNCTION: 384 musthave(LWORD, 0); 385 t = function_body(yylval.cp, TRUE); 386 break; 387 } 388 389 while ((iop = synio(syniocf)) != NULL) { 390 if (iopn >= NUFILE) 391 yyerror("too many redirections\n"); 392 iops[iopn++] = iop; 393 } 394 395 if (iopn == 0) { 396 afree((void*) iops, ATEMP); 397 t->ioact = NULL; 398 } else { 399 iops[iopn++] = NULL; 400 iops = (struct ioword **) aresize((void*) iops, 401 sizeofN(struct ioword *, iopn), ATEMP); 402 t->ioact = iops; 403 } 404 405 if (t->type == TCOM || t->type == TDBRACKET) { 406 XPput(args, NULL); 407 t->args = (char **) XPclose(args); 408 XPput(vars, NULL); 409 t->vars = (char **) XPclose(vars); 410 } else { 411 XPfree(args); 412 XPfree(vars); 413 } 414 415 return t; 416 } 417 418 static struct op * 419 dogroup() 420 { 421 register int c; 422 register struct op *list; 423 424 c = token(CONTIN|KEYWORD|ALIAS); 425 /* A {...} can be used instead of do...done for for/select loops 426 * but not for while/until loops - we don't need to check if it 427 * is a while loop because it would have been parsed as part of 428 * the conditional command list... 429 */ 430 if (c == DO) 431 c = DONE; 432 else if (c == '{') 433 c = '}'; 434 else 435 syntaxerr((char *) 0); 436 list = c_list(TRUE); 437 musthave(c, KEYWORD|ALIAS); 438 return list; 439 } 440 441 static struct op * 442 thenpart() 443 { 444 register struct op *t; 445 446 musthave(THEN, KEYWORD|ALIAS); 447 t = newtp(0); 448 t->left = c_list(TRUE); 449 if (t->left == NULL) 450 syntaxerr((char *) 0); 451 t->right = elsepart(); 452 return (t); 453 } 454 455 static struct op * 456 elsepart() 457 { 458 register struct op *t; 459 460 switch (token(KEYWORD|ALIAS|VARASN)) { 461 case ELSE: 462 if ((t = c_list(TRUE)) == NULL) 463 syntaxerr((char *) 0); 464 return (t); 465 466 case ELIF: 467 t = newtp(TELIF); 468 t->left = c_list(TRUE); 469 t->right = thenpart(); 470 return (t); 471 472 default: 473 REJECT; 474 } 475 return NULL; 476 } 477 478 static struct op * 479 caselist() 480 { 481 register struct op *t, *tl; 482 int c; 483 484 c = token(CONTIN|KEYWORD|ALIAS); 485 /* A {...} can be used instead of in...esac for case statements */ 486 if (c == IN) 487 c = ESAC; 488 else if (c == '{') 489 c = '}'; 490 else 491 syntaxerr((char *) 0); 492 t = tl = NULL; 493 while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */ 494 struct op *tc = casepart(c); 495 if (tl == NULL) 496 t = tl = tc, tl->right = NULL; 497 else 498 tl->right = tc, tl = tc; 499 } 500 musthave(c, KEYWORD|ALIAS); 501 return (t); 502 } 503 504 static struct op * 505 casepart(endtok) 506 int endtok; 507 { 508 register struct op *t; 509 register int c; 510 XPtrV ptns; 511 512 XPinit(ptns, 16); 513 t = newtp(TPAT); 514 c = token(CONTIN|KEYWORD); /* no ALIAS here */ 515 if (c != '(') 516 REJECT; 517 do { 518 musthave(LWORD, 0); 519 XPput(ptns, yylval.cp); 520 } while ((c = token(0)) == '|'); 521 REJECT; 522 XPput(ptns, NULL); 523 t->vars = (char **) XPclose(ptns); 524 musthave(')', 0); 525 526 t->left = c_list(TRUE); 527 /* Note: Posix requires the ;; */ 528 if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok) 529 musthave(BREAK, CONTIN|KEYWORD|ALIAS); 530 return (t); 531 } 532 533 static struct op * 534 function_body(name, ksh_func) 535 char *name; 536 int ksh_func; /* function foo { ... } vs foo() { .. } */ 537 { 538 char *sname, *p; 539 struct op *t; 540 int old_func_parse; 541 542 sname = wdstrip(name); 543 /* Check for valid characters in name. posix and ksh93 say only 544 * allow [a-zA-Z_0-9] but this allows more as old pdksh's have 545 * allowed more (the following were never allowed: 546 * nul space nl tab $ ' " \ ` ( ) & | ; = < > 547 * C_QUOTE covers all but = and adds # [ ? *) 548 */ 549 for (p = sname; *p; p++) 550 if (ctype(*p, C_QUOTE) || *p == '=') 551 yyerror("%s: invalid function name\n", sname); 552 553 t = newtp(TFUNCT); 554 t->str = sname; 555 t->u.ksh_func = ksh_func; 556 t->lineno = source->line; 557 558 /* Note that POSIX allows only compound statements after foo(), sh and 559 * at&t ksh allow any command, go with the later since it shouldn't 560 * break anything. However, for function foo, at&t ksh only accepts 561 * an open-brace. 562 */ 563 if (ksh_func) { 564 musthave('{', CONTIN|KEYWORD|ALIAS); /* } */ 565 REJECT; 566 } 567 568 old_func_parse = e->flags & EF_FUNC_PARSE; 569 e->flags |= EF_FUNC_PARSE; 570 if ((t->left = get_command(CONTIN)) == (struct op *) 0) { 571 /* 572 * Probably something like foo() followed by eof or ;. 573 * This is accepted by sh and ksh88. 574 * To make "typset -f foo" work reliably (so its output can 575 * be used as input), we pretend there is a colon here. 576 */ 577 t->left = newtp(TCOM); 578 t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP); 579 t->left->args[0] = alloc(sizeof(char) * 3, ATEMP); 580 t->left->args[0][0] = CHAR; 581 t->left->args[0][1] = ':'; 582 t->left->args[0][2] = EOS; 583 t->left->args[1] = (char *) 0; 584 t->left->vars = (char **) alloc(sizeof(char *), ATEMP); 585 t->left->vars[0] = (char *) 0; 586 t->left->lineno = 1; 587 } 588 if (!old_func_parse) 589 e->flags &= ~EF_FUNC_PARSE; 590 591 return t; 592 } 593 594 static char ** 595 wordlist() 596 { 597 register int c; 598 XPtrV args; 599 600 XPinit(args, 16); 601 /* Posix does not do alias expansion here... */ 602 if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) { 603 if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */ 604 REJECT; 605 return NULL; 606 } 607 while ((c = token(0)) == LWORD) 608 XPput(args, yylval.cp); 609 if (c != '\n' && c != ';') 610 syntaxerr((char *) 0); 611 if (XPsize(args) == 0) { 612 XPfree(args); 613 return NULL; 614 } else { 615 XPput(args, NULL); 616 return (char **) XPclose(args); 617 } 618 } 619 620 /* 621 * supporting functions 622 */ 623 624 static struct op * 625 block(type, t1, t2, wp) 626 int type; 627 struct op *t1, *t2; 628 char **wp; 629 { 630 register struct op *t; 631 632 t = newtp(type); 633 t->left = t1; 634 t->right = t2; 635 t->vars = wp; 636 return (t); 637 } 638 639 const struct tokeninfo { 640 const char *name; 641 short val; 642 short reserved; 643 } tokentab[] = { 644 /* Reserved words */ 645 { "if", IF, TRUE }, 646 { "then", THEN, TRUE }, 647 { "else", ELSE, TRUE }, 648 { "elif", ELIF, TRUE }, 649 { "fi", FI, TRUE }, 650 { "case", CASE, TRUE }, 651 { "esac", ESAC, TRUE }, 652 { "for", FOR, TRUE }, 653 #ifdef KSH 654 { "select", SELECT, TRUE }, 655 #endif /* KSH */ 656 { "while", WHILE, TRUE }, 657 { "until", UNTIL, TRUE }, 658 { "do", DO, TRUE }, 659 { "done", DONE, TRUE }, 660 { "in", IN, TRUE }, 661 { "function", FUNCTION, TRUE }, 662 { "time", TIME, TRUE }, 663 { "{", '{', TRUE }, 664 { "}", '}', TRUE }, 665 { "!", BANG, TRUE }, 666 #ifdef KSH 667 { "[[", DBRACKET, TRUE }, 668 #endif /* KSH */ 669 /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */ 670 { "&&", LOGAND, FALSE }, 671 { "||", LOGOR, FALSE }, 672 { ";;", BREAK, FALSE }, 673 #ifdef KSH 674 { "((", MDPAREN, FALSE }, 675 { "|&", COPROC, FALSE }, 676 #endif /* KSH */ 677 /* and some special cases... */ 678 { "newline", '\n', FALSE }, 679 { 0 } 680 }; 681 682 void 683 initkeywords() 684 { 685 register struct tokeninfo const *tt; 686 register struct tbl *p; 687 688 tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */ 689 for (tt = tokentab; tt->name; tt++) { 690 if (tt->reserved) { 691 p = tenter(&keywords, tt->name, hash(tt->name)); 692 p->flag |= DEFINED|ISSET; 693 p->type = CKEYWD; 694 p->val.i = tt->val; 695 } 696 } 697 } 698 699 static void 700 syntaxerr(what) 701 const char *what; 702 { 703 char redir[6]; /* 2<<- is the longest redirection, I think */ 704 const char *s; 705 struct tokeninfo const *tt; 706 int c; 707 708 if (!what) 709 what = "unexpected"; 710 REJECT; 711 c = token(0); 712 Again: 713 switch (c) { 714 case 0: 715 if (nesting.start_token) { 716 c = nesting.start_token; 717 source->errline = nesting.start_line; 718 what = "unmatched"; 719 goto Again; 720 } 721 /* don't quote the EOF */ 722 yyerror("syntax error: unexpected EOF\n"); 723 /*NOTREACHED*/ 724 725 case LWORD: 726 s = snptreef((char *) 0, 32, "%S", yylval.cp); 727 break; 728 729 case REDIR: 730 s = snptreef(redir, sizeof(redir), "%R", yylval.iop); 731 break; 732 733 default: 734 for (tt = tokentab; tt->name; tt++) 735 if (tt->val == c) 736 break; 737 if (tt->name) 738 s = tt->name; 739 else { 740 if (c > 0 && c < 256) { 741 redir[0] = c; 742 redir[1] = '\0'; 743 } else 744 shf_snprintf(redir, sizeof(redir), 745 "?%d", c); 746 s = redir; 747 } 748 } 749 yyerror("syntax error: `%s' %s\n", s, what); 750 } 751 752 static void 753 nesting_push(save, tok) 754 struct nesting_state *save; 755 int tok; 756 { 757 *save = nesting; 758 nesting.start_token = tok; 759 nesting.start_line = source->line; 760 } 761 762 static void 763 nesting_pop(saved) 764 struct nesting_state *saved; 765 { 766 nesting = *saved; 767 } 768 769 static struct op * 770 newtp(type) 771 int type; 772 { 773 register struct op *t; 774 775 t = (struct op *) alloc(sizeof(*t), ATEMP); 776 t->type = type; 777 t->u.evalflags = 0; 778 t->args = t->vars = NULL; 779 t->ioact = NULL; 780 t->left = t->right = NULL; 781 t->str = NULL; 782 return (t); 783 } 784 785 struct op * 786 compile(s) 787 Source *s; 788 { 789 nesting.start_token = 0; 790 nesting.start_line = 0; 791 herep = heres; 792 source = s; 793 yyparse(); 794 return outtree; 795 } 796 797 /* This kludge exists to take care of sh/at&t ksh oddity in which 798 * the arguments of alias/export/readonly/typeset have no field 799 * splitting, file globbing, or (normal) tilde expansion done. 800 * at&t ksh seems to do something similar to this since 801 * $ touch a=a; typeset a=[ab]; echo "$a" 802 * a=[ab] 803 * $ x=typeset; $x a=[ab]; echo "$a" 804 * a=a 805 * $ 806 */ 807 static int 808 assign_command(s) 809 char *s; 810 { 811 char c = *s; 812 813 if (Flag(FPOSIX) || !*s) 814 return 0; 815 return (c == 'a' && strcmp(s, "alias") == 0) 816 || (c == 'e' && strcmp(s, "export") == 0) 817 || (c == 'r' && strcmp(s, "readonly") == 0) 818 || (c == 't' && strcmp(s, "typeset") == 0); 819 } 820 821 /* Check if we are in the middle of reading an alias */ 822 static int 823 inalias(s) 824 struct source *s; 825 { 826 for (; s && s->type == SALIAS; s = s->next) 827 if (!(s->flags & SF_ALIASEND)) 828 return 1; 829 return 0; 830 } 831 832 833 #ifdef KSH 834 /* Order important - indexed by Test_meta values 835 * Note that ||, &&, ( and ) can't appear in as unquoted strings 836 * in normal shell input, so these can be interpreted unambiguously 837 * in the evaluation pass. 838 */ 839 static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS }; 840 static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS }; 841 static const char dbtest_not[] = { CHAR, '!', EOS }; 842 static const char dbtest_oparen[] = { CHAR, '(', EOS }; 843 static const char dbtest_cparen[] = { CHAR, ')', EOS }; 844 const char *const dbtest_tokens[] = { 845 dbtest_or, dbtest_and, dbtest_not, 846 dbtest_oparen, dbtest_cparen 847 }; 848 const char db_close[] = { CHAR, ']', CHAR, ']', EOS }; 849 const char db_lthan[] = { CHAR, '<', EOS }; 850 const char db_gthan[] = { CHAR, '>', EOS }; 851 852 /* Test if the current token is a whatever. Accepts the current token if 853 * it is. Returns 0 if it is not, non-zero if it is (in the case of 854 * TM_UNOP and TM_BINOP, the returned value is a Test_op). 855 */ 856 static int 857 dbtestp_isa(te, meta) 858 Test_env *te; 859 Test_meta meta; 860 { 861 int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); 862 int uqword = 0; 863 char *save = (char *) 0; 864 int ret = 0; 865 866 /* unquoted word? */ 867 uqword = c == LWORD && *ident; 868 869 if (meta == TM_OR) 870 ret = c == LOGOR; 871 else if (meta == TM_AND) 872 ret = c == LOGAND; 873 else if (meta == TM_NOT) 874 ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0; 875 else if (meta == TM_OPAREN) 876 ret = c == '(' /*)*/; 877 else if (meta == TM_CPAREN) 878 ret = c == /*(*/ ')'; 879 else if (meta == TM_UNOP || meta == TM_BINOP) { 880 if (meta == TM_BINOP && c == REDIR 881 && (yylval.iop->flag == IOREAD 882 || yylval.iop->flag == IOWRITE)) 883 { 884 ret = 1; 885 save = wdcopy(yylval.iop->flag == IOREAD ? 886 db_lthan : db_gthan, ATEMP); 887 } else if (uqword && (ret = (int) test_isop(te, meta, ident))) 888 save = yylval.cp; 889 } else /* meta == TM_END */ 890 ret = uqword && strcmp(yylval.cp, db_close) == 0; 891 if (ret) { 892 ACCEPT; 893 if (meta != TM_END) { 894 if (!save) 895 save = wdcopy(dbtest_tokens[(int) meta], ATEMP); 896 XPput(*te->pos.av, save); 897 } 898 } 899 return ret; 900 } 901 902 static const char * 903 dbtestp_getopnd(te, op, do_eval) 904 Test_env *te; 905 Test_op op; 906 int do_eval; 907 { 908 int c = tpeek(ARRAYVAR); 909 910 if (c != LWORD) 911 return (const char *) 0; 912 913 ACCEPT; 914 XPput(*te->pos.av, yylval.cp); 915 916 return null; 917 } 918 919 static int 920 dbtestp_eval(te, op, opnd1, opnd2, do_eval) 921 Test_env *te; 922 Test_op op; 923 const char *opnd1; 924 const char *opnd2; 925 int do_eval; 926 { 927 return 1; 928 } 929 930 static void 931 dbtestp_error(te, offset, msg) 932 Test_env *te; 933 int offset; 934 const char *msg; 935 { 936 te->flags |= TEF_ERROR; 937 938 if (offset < 0) { 939 REJECT; 940 /* Kludgy to say the least... */ 941 symbol = LWORD; 942 yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) 943 + offset); 944 } 945 syntaxerr(msg); 946 } 947 #endif /* KSH */ 948