1 /* $OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 5 * Thorsten Glaser <tg (at) mirbsd.org> 6 * 7 * Provided that these terms and disclaimer and all copyright notices 8 * are retained or reproduced in an accompanying document, permission 9 * is granted to deal in this work without restriction, including un- 10 * limited rights to use, publicly perform, distribute, sell, modify, 11 * merge, give away, or sublicence. 12 * 13 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 14 * the utmost extent permitted by applicable law, neither express nor 15 * implied; without malicious intent or gross negligence. In no event 16 * may a licensor, author or contributor be held liable for indirect, 17 * direct, other damage, loss, or other issues arising in any way out 18 * of dealing in the work, even if advised of the possibility of such 19 * damage or existence of a defect, except proven that it results out 20 * of said person's immediate fault when using the work as intended. 21 */ 22 23 #include "sh.h" 24 25 __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.69 2011/09/07 15:24:21 tg Exp $"); 26 27 extern short subshell_nesting_level; 28 extern void yyskiputf8bom(void); 29 30 struct nesting_state { 31 int start_token; /* token than began nesting (eg, FOR) */ 32 int start_line; /* line nesting began on */ 33 }; 34 35 static void yyparse(void); 36 static struct op *pipeline(int); 37 static struct op *andor(void); 38 static struct op *c_list(bool); 39 static struct ioword *synio(int); 40 static struct op *nested(int, int, int); 41 static struct op *get_command(int); 42 static struct op *dogroup(void); 43 static struct op *thenpart(void); 44 static struct op *elsepart(void); 45 static struct op *caselist(void); 46 static struct op *casepart(int); 47 static struct op *function_body(char *, bool); 48 static char **wordlist(void); 49 static struct op *block(int, struct op *, struct op *, char **); 50 static struct op *newtp(int); 51 static void syntaxerr(const char *) MKSH_A_NORETURN; 52 static void nesting_push(struct nesting_state *, int); 53 static void nesting_pop(struct nesting_state *); 54 static int assign_command(char *); 55 static int inalias(struct source *); 56 static Test_op dbtestp_isa(Test_env *, Test_meta); 57 static const char *dbtestp_getopnd(Test_env *, Test_op, bool); 58 static int dbtestp_eval(Test_env *, Test_op, const char *, 59 const char *, bool); 60 static void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN; 61 62 static struct op *outtree; /* yyparse output */ 63 static struct nesting_state nesting; /* \n changed to ; */ 64 65 static bool reject; /* token(cf) gets symbol again */ 66 static int symbol; /* yylex value */ 67 68 #define REJECT (reject = true) 69 #define ACCEPT (reject = false) 70 #define token(cf) ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf))) 71 #define tpeek(cf) ((reject) ? (symbol) : (REJECT, symbol = yylex(cf))) 72 #define musthave(c,cf) do { if (token(cf) != (c)) syntaxerr(NULL); } while (/* CONSTCOND */ 0) 73 74 static void 75 yyparse(void) 76 { 77 int c; 78 79 ACCEPT; 80 81 outtree = c_list(source->type == SSTRING); 82 c = tpeek(0); 83 if (c == 0 && !outtree) 84 outtree = newtp(TEOF); 85 else if (c != '\n' && c != 0) 86 syntaxerr(NULL); 87 } 88 89 static struct op * 90 pipeline(int cf) 91 { 92 struct op *t, *p, *tl = NULL; 93 94 t = get_command(cf); 95 if (t != NULL) { 96 while (token(0) == '|') { 97 if ((p = get_command(CONTIN)) == NULL) 98 syntaxerr(NULL); 99 if (tl == NULL) 100 t = tl = block(TPIPE, t, p, NOWORDS); 101 else 102 tl = tl->right = block(TPIPE, tl->right, p, NOWORDS); 103 } 104 REJECT; 105 } 106 return (t); 107 } 108 109 static struct op * 110 andor(void) 111 { 112 struct op *t, *p; 113 int c; 114 115 t = pipeline(0); 116 if (t != NULL) { 117 while ((c = token(0)) == LOGAND || c == LOGOR) { 118 if ((p = pipeline(CONTIN)) == NULL) 119 syntaxerr(NULL); 120 t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); 121 } 122 REJECT; 123 } 124 return (t); 125 } 126 127 static struct op * 128 c_list(bool multi) 129 { 130 struct op *t = NULL, *p, *tl = NULL; 131 int c; 132 bool have_sep; 133 134 while (/* CONSTCOND */ 1) { 135 p = andor(); 136 /* 137 * Token has always been read/rejected at this point, so 138 * we don't worry about what flags to pass token() 139 */ 140 c = token(0); 141 have_sep = true; 142 if (c == '\n' && (multi || inalias(source))) { 143 if (!p) 144 /* ignore blank lines */ 145 continue; 146 } else if (!p) 147 break; 148 else if (c == '&' || c == COPROC) 149 p = block(c == '&' ? TASYNC : TCOPROC, 150 p, NOBLOCK, NOWORDS); 151 else if (c != ';') 152 have_sep = false; 153 if (!t) 154 t = p; 155 else if (!tl) 156 t = tl = block(TLIST, t, p, NOWORDS); 157 else 158 tl = tl->right = block(TLIST, tl->right, p, NOWORDS); 159 if (!have_sep) 160 break; 161 } 162 REJECT; 163 return (t); 164 } 165 166 static struct ioword * 167 synio(int cf) 168 { 169 struct ioword *iop; 170 static struct ioword *nextiop; 171 bool ishere; 172 173 if (nextiop != NULL) { 174 iop = nextiop; 175 nextiop = NULL; 176 return (iop); 177 } 178 179 if (tpeek(cf) != REDIR) 180 return (NULL); 181 ACCEPT; 182 iop = yylval.iop; 183 if (iop->flag & IONDELIM) 184 goto gotnulldelim; 185 ishere = (iop->flag & IOTYPE) == IOHERE; 186 musthave(LWORD, ishere ? HEREDELIM : 0); 187 if (ishere) { 188 iop->delim = yylval.cp; 189 if (*ident != 0) 190 /* unquoted */ 191 gotnulldelim: 192 iop->flag |= IOEVAL; 193 if (herep > &heres[HERES - 1]) 194 yyerror("too many %ss\n", "<<"); 195 *herep++ = iop; 196 } else 197 iop->name = yylval.cp; 198 199 if (iop->flag & IOBASH) { 200 char *cp; 201 202 nextiop = alloc(sizeof(*iop), ATEMP); 203 nextiop->name = cp = alloc(5, ATEMP); 204 205 if (iop->unit > 9) { 206 *cp++ = CHAR; 207 *cp++ = '0' + (iop->unit / 10); 208 } 209 *cp++ = CHAR; 210 *cp++ = '0' + (iop->unit % 10); 211 *cp = EOS; 212 213 iop->flag &= ~IOBASH; 214 nextiop->unit = 2; 215 nextiop->flag = IODUP; 216 nextiop->delim = NULL; 217 nextiop->heredoc = NULL; 218 } 219 return (iop); 220 } 221 222 static struct op * 223 nested(int type, int smark, int emark) 224 { 225 struct op *t; 226 struct nesting_state old_nesting; 227 228 nesting_push(&old_nesting, smark); 229 t = c_list(true); 230 musthave(emark, KEYWORD|ALIAS); 231 nesting_pop(&old_nesting); 232 return (block(type, t, NOBLOCK, NOWORDS)); 233 } 234 235 static struct op * 236 get_command(int cf) 237 { 238 struct op *t; 239 int c, iopn = 0, syniocf; 240 struct ioword *iop, **iops; 241 XPtrV args, vars; 242 struct nesting_state old_nesting; 243 244 /* NUFILE is small enough to leave this addition unchecked */ 245 iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP); 246 XPinit(args, 16); 247 XPinit(vars, 16); 248 249 syniocf = KEYWORD|ALIAS; 250 switch (c = token(cf|KEYWORD|ALIAS|VARASN)) { 251 default: 252 REJECT; 253 afree(iops, ATEMP); 254 XPfree(args); 255 XPfree(vars); 256 /* empty line */ 257 return (NULL); 258 259 case LWORD: 260 case REDIR: 261 REJECT; 262 syniocf &= ~(KEYWORD|ALIAS); 263 t = newtp(TCOM); 264 t->lineno = source->line; 265 while (/* CONSTCOND */ 1) { 266 cf = (t->u.evalflags ? ARRAYVAR : 0) | 267 (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); 268 switch (tpeek(cf)) { 269 case REDIR: 270 while ((iop = synio(cf)) != NULL) { 271 if (iopn >= NUFILE) 272 yyerror("too many %ss\n", 273 "redirection"); 274 iops[iopn++] = iop; 275 } 276 break; 277 278 case LWORD: 279 ACCEPT; 280 /* 281 * the iopn == 0 and XPsize(vars) == 0 are 282 * dubious but AT&T ksh acts this way 283 */ 284 if (iopn == 0 && XPsize(vars) == 0 && 285 XPsize(args) == 0 && 286 assign_command(ident)) 287 t->u.evalflags = DOVACHECK; 288 if ((XPsize(args) == 0 || Flag(FKEYWORD)) && 289 is_wdvarassign(yylval.cp)) 290 XPput(vars, yylval.cp); 291 else 292 XPput(args, yylval.cp); 293 break; 294 295 case '(': 296 #ifndef MKSH_SMALL 297 if ((XPsize(args) == 0 || Flag(FKEYWORD)) && 298 XPsize(vars) == 1 && is_wdvarassign(yylval.cp)) 299 goto is_wdarrassign; 300 #endif 301 /* 302 * Check for "> foo (echo hi)" which AT&T ksh 303 * allows (not POSIX, but not disallowed) 304 */ 305 afree(t, ATEMP); 306 if (XPsize(args) == 0 && XPsize(vars) == 0) { 307 ACCEPT; 308 goto Subshell; 309 } 310 311 /* must be a function */ 312 if (iopn != 0 || XPsize(args) != 1 || 313 XPsize(vars) != 0) 314 syntaxerr(NULL); 315 ACCEPT; 316 musthave(/*(*/')', 0); 317 t = function_body(XPptrv(args)[0], false); 318 goto Leave; 319 #ifndef MKSH_SMALL 320 is_wdarrassign: 321 { 322 static const char set_cmd0[] = { 323 CHAR, 's', CHAR, 'e', 324 CHAR, 't', EOS 325 }; 326 static const char set_cmd1[] = { 327 CHAR, '-', CHAR, 'A', EOS 328 }; 329 static const char set_cmd2[] = { 330 CHAR, '-', CHAR, '-', EOS 331 }; 332 char *tcp; 333 334 ACCEPT; 335 336 /* manipulate the vars string */ 337 tcp = *(--vars.cur); 338 /* 'varname=' -> 'varname' */ 339 tcp[wdscan(tcp, EOS) - tcp - 3] = EOS; 340 341 /* construct new args strings */ 342 XPput(args, wdcopy(set_cmd0, ATEMP)); 343 XPput(args, wdcopy(set_cmd1, ATEMP)); 344 XPput(args, tcp); 345 XPput(args, wdcopy(set_cmd2, ATEMP)); 346 347 /* slurp in words till closing paren */ 348 while (token(CONTIN) == LWORD) 349 XPput(args, yylval.cp); 350 if (symbol != /*(*/ ')') 351 syntaxerr(NULL); 352 353 goto Leave; 354 } 355 #endif 356 357 default: 358 goto Leave; 359 } 360 } 361 Leave: 362 break; 363 364 case '(': 365 Subshell: 366 ++subshell_nesting_level; 367 t = nested(TPAREN, '(', ')'); 368 --subshell_nesting_level; 369 break; 370 371 case '{': /*}*/ 372 t = nested(TBRACE, '{', '}'); 373 break; 374 375 case MDPAREN: { 376 int lno; 377 static const char let_cmd[] = { 378 CHAR, 'l', CHAR, 'e', 379 CHAR, 't', EOS 380 }; 381 382 /* leave KEYWORD in syniocf (allow if (( 1 )) then ...) */ 383 lno = source->line; 384 ACCEPT; 385 switch (token(LETEXPR)) { 386 case LWORD: 387 break; 388 case '(': /*)*/ 389 goto Subshell; 390 default: 391 syntaxerr(NULL); 392 } 393 t = newtp(TCOM); 394 t->lineno = lno; 395 XPput(args, wdcopy(let_cmd, ATEMP)); 396 XPput(args, yylval.cp); 397 break; 398 } 399 400 case DBRACKET: /* [[ .. ]] */ 401 /* leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */ 402 t = newtp(TDBRACKET); 403 ACCEPT; 404 { 405 Test_env te; 406 407 te.flags = TEF_DBRACKET; 408 te.pos.av = &args; 409 te.isa = dbtestp_isa; 410 te.getopnd = dbtestp_getopnd; 411 te.eval = dbtestp_eval; 412 te.error = dbtestp_error; 413 414 test_parse(&te); 415 } 416 break; 417 418 case FOR: 419 case SELECT: 420 t = newtp((c == FOR) ? TFOR : TSELECT); 421 musthave(LWORD, ARRAYVAR); 422 if (!is_wdvarname(yylval.cp, true)) 423 yyerror("%s: %s\n", c == FOR ? "for" : Tselect, 424 "bad identifier"); 425 strdupx(t->str, ident, ATEMP); 426 nesting_push(&old_nesting, c); 427 t->vars = wordlist(); 428 t->left = dogroup(); 429 nesting_pop(&old_nesting); 430 break; 431 432 case WHILE: 433 case UNTIL: 434 nesting_push(&old_nesting, c); 435 t = newtp((c == WHILE) ? TWHILE : TUNTIL); 436 t->left = c_list(true); 437 t->right = dogroup(); 438 nesting_pop(&old_nesting); 439 break; 440 441 case CASE: 442 t = newtp(TCASE); 443 musthave(LWORD, 0); 444 t->str = yylval.cp; 445 nesting_push(&old_nesting, c); 446 t->left = caselist(); 447 nesting_pop(&old_nesting); 448 break; 449 450 case IF: 451 nesting_push(&old_nesting, c); 452 t = newtp(TIF); 453 t->left = c_list(true); 454 t->right = thenpart(); 455 musthave(FI, KEYWORD|ALIAS); 456 nesting_pop(&old_nesting); 457 break; 458 459 case BANG: 460 syniocf &= ~(KEYWORD|ALIAS); 461 t = pipeline(0); 462 if (t == NULL) 463 syntaxerr(NULL); 464 t = block(TBANG, NOBLOCK, t, NOWORDS); 465 break; 466 467 case TIME: 468 syniocf &= ~(KEYWORD|ALIAS); 469 t = pipeline(0); 470 if (t) { 471 t->str = alloc(2, ATEMP); 472 /* TF_* flags */ 473 t->str[0] = '\0'; 474 t->str[1] = '\0'; 475 } 476 t = block(TTIME, t, NOBLOCK, NOWORDS); 477 break; 478 479 case FUNCTION: 480 musthave(LWORD, 0); 481 t = function_body(yylval.cp, true); 482 break; 483 } 484 485 while ((iop = synio(syniocf)) != NULL) { 486 if (iopn >= NUFILE) 487 yyerror("too many %ss\n", "redirection"); 488 iops[iopn++] = iop; 489 } 490 491 if (iopn == 0) { 492 afree(iops, ATEMP); 493 t->ioact = NULL; 494 } else { 495 iops[iopn++] = NULL; 496 iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP); 497 t->ioact = iops; 498 } 499 500 if (t->type == TCOM || t->type == TDBRACKET) { 501 XPput(args, NULL); 502 t->args = (const char **)XPclose(args); 503 XPput(vars, NULL); 504 t->vars = (char **) XPclose(vars); 505 } else { 506 XPfree(args); 507 XPfree(vars); 508 } 509 510 return (t); 511 } 512 513 static struct op * 514 dogroup(void) 515 { 516 int c; 517 struct op *list; 518 519 c = token(CONTIN|KEYWORD|ALIAS); 520 /* 521 * A {...} can be used instead of do...done for for/select loops 522 * but not for while/until loops - we don't need to check if it 523 * is a while loop because it would have been parsed as part of 524 * the conditional command list... 525 */ 526 if (c == DO) 527 c = DONE; 528 else if (c == '{') 529 c = '}'; 530 else 531 syntaxerr(NULL); 532 list = c_list(true); 533 musthave(c, KEYWORD|ALIAS); 534 return (list); 535 } 536 537 static struct op * 538 thenpart(void) 539 { 540 struct op *t; 541 542 musthave(THEN, KEYWORD|ALIAS); 543 t = newtp(0); 544 t->left = c_list(true); 545 if (t->left == NULL) 546 syntaxerr(NULL); 547 t->right = elsepart(); 548 return (t); 549 } 550 551 static struct op * 552 elsepart(void) 553 { 554 struct op *t; 555 556 switch (token(KEYWORD|ALIAS|VARASN)) { 557 case ELSE: 558 if ((t = c_list(true)) == NULL) 559 syntaxerr(NULL); 560 return (t); 561 562 case ELIF: 563 t = newtp(TELIF); 564 t->left = c_list(true); 565 t->right = thenpart(); 566 return (t); 567 568 default: 569 REJECT; 570 } 571 return (NULL); 572 } 573 574 static struct op * 575 caselist(void) 576 { 577 struct op *t, *tl; 578 int c; 579 580 c = token(CONTIN|KEYWORD|ALIAS); 581 /* A {...} can be used instead of in...esac for case statements */ 582 if (c == IN) 583 c = ESAC; 584 else if (c == '{') 585 c = '}'; 586 else 587 syntaxerr(NULL); 588 t = tl = NULL; 589 /* no ALIAS here */ 590 while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { 591 struct op *tc = casepart(c); 592 if (tl == NULL) 593 t = tl = tc, tl->right = NULL; 594 else 595 tl->right = tc, tl = tc; 596 } 597 musthave(c, KEYWORD|ALIAS); 598 return (t); 599 } 600 601 static struct op * 602 casepart(int endtok) 603 { 604 struct op *t; 605 XPtrV ptns; 606 607 XPinit(ptns, 16); 608 t = newtp(TPAT); 609 /* no ALIAS here */ 610 if (token(CONTIN | KEYWORD) != '(') 611 REJECT; 612 do { 613 musthave(LWORD, 0); 614 XPput(ptns, yylval.cp); 615 } while (token(0) == '|'); 616 REJECT; 617 XPput(ptns, NULL); 618 t->vars = (char **) XPclose(ptns); 619 musthave(')', 0); 620 621 t->left = c_list(true); 622 /* Note: POSIX requires the ;; */ 623 if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok) 624 switch (symbol) { 625 default: 626 syntaxerr(NULL); 627 case BREAK: 628 case BRKEV: 629 case BRKFT: 630 t->u.charflag = 631 (symbol == BRKEV) ? '|' : 632 (symbol == BRKFT) ? '&' : ';'; 633 ACCEPT; 634 } 635 return (t); 636 } 637 638 static struct op * 639 function_body(char *name, 640 /* function foo { ... } vs foo() { .. } */ 641 bool ksh_func) 642 { 643 char *sname, *p; 644 struct op *t; 645 bool old_func_parse; 646 647 sname = wdstrip(name, 0); 648 /*- 649 * Check for valid characters in name. POSIX and AT&T ksh93 say 650 * only allow [a-zA-Z_0-9] but this allows more as old pdkshs 651 * have allowed more; the following were never allowed: 652 * NUL TAB NL SP " $ & ' ( ) ; < = > \ ` | 653 * C_QUOTE covers all but adds # * ? [ ] 654 */ 655 for (p = sname; *p; p++) 656 if (ctype(*p, C_QUOTE)) 657 yyerror("%s: %s\n", sname, "invalid function name"); 658 659 /* 660 * Note that POSIX allows only compound statements after foo(), 661 * sh and AT&T ksh allow any command, go with the later since it 662 * shouldn't break anything. However, for function foo, AT&T ksh 663 * only accepts an open-brace. 664 */ 665 if (ksh_func) { 666 if (tpeek(CONTIN|KEYWORD|ALIAS) == '(' /*)*/) { 667 /* function foo () { */ 668 ACCEPT; 669 musthave(')', 0); 670 /* degrade to POSIX function */ 671 ksh_func = false; 672 } 673 musthave('{' /*}*/, CONTIN|KEYWORD|ALIAS); 674 REJECT; 675 } 676 677 t = newtp(TFUNCT); 678 t->str = sname; 679 t->u.ksh_func = tobool(ksh_func); 680 t->lineno = source->line; 681 682 old_func_parse = e->flags & EF_FUNC_PARSE; 683 e->flags |= EF_FUNC_PARSE; 684 if ((t->left = get_command(CONTIN)) == NULL) { 685 char *tv; 686 /* 687 * Probably something like foo() followed by EOF or ';'. 688 * This is accepted by sh and ksh88. 689 * To make "typeset -f foo" work reliably (so its output can 690 * be used as input), we pretend there is a colon here. 691 */ 692 t->left = newtp(TCOM); 693 /* (2 * sizeof(char *)) is small enough */ 694 t->left->args = alloc(2 * sizeof(char *), ATEMP); 695 t->left->args[0] = tv = alloc(3, ATEMP); 696 tv[0] = CHAR; 697 tv[1] = ':'; 698 tv[2] = EOS; 699 t->left->args[1] = NULL; 700 t->left->vars = alloc(sizeof(char *), ATEMP); 701 t->left->vars[0] = NULL; 702 t->left->lineno = 1; 703 } 704 if (!old_func_parse) 705 e->flags &= ~EF_FUNC_PARSE; 706 707 return (t); 708 } 709 710 static char ** 711 wordlist(void) 712 { 713 int c; 714 XPtrV args; 715 716 XPinit(args, 16); 717 /* POSIX does not do alias expansion here... */ 718 if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) { 719 if (c != ';') 720 /* non-POSIX, but AT&T ksh accepts a ; here */ 721 REJECT; 722 return (NULL); 723 } 724 while ((c = token(0)) == LWORD) 725 XPput(args, yylval.cp); 726 if (c != '\n' && c != ';') 727 syntaxerr(NULL); 728 if (XPsize(args) == 0) { 729 XPfree(args); 730 return (NULL); 731 } else { 732 XPput(args, NULL); 733 return ((char **)XPclose(args)); 734 } 735 } 736 737 /* 738 * supporting functions 739 */ 740 741 static struct op * 742 block(int type, struct op *t1, struct op *t2, char **wp) 743 { 744 struct op *t; 745 746 t = newtp(type); 747 t->left = t1; 748 t->right = t2; 749 t->vars = wp; 750 return (t); 751 } 752 753 const struct tokeninfo { 754 const char *name; 755 short val; 756 short reserved; 757 } tokentab[] = { 758 /* Reserved words */ 759 { "if", IF, true }, 760 { "then", THEN, true }, 761 { "else", ELSE, true }, 762 { "elif", ELIF, true }, 763 { "fi", FI, true }, 764 { "case", CASE, true }, 765 { "esac", ESAC, true }, 766 { "for", FOR, true }, 767 { Tselect, SELECT, true }, 768 { "while", WHILE, true }, 769 { "until", UNTIL, true }, 770 { "do", DO, true }, 771 { "done", DONE, true }, 772 { "in", IN, true }, 773 { Tfunction, FUNCTION, true }, 774 { "time", TIME, true }, 775 { "{", '{', true }, 776 { "}", '}', true }, 777 { "!", BANG, true }, 778 { "[[", DBRACKET, true }, 779 /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */ 780 { "&&", LOGAND, false }, 781 { "||", LOGOR, false }, 782 { ";;", BREAK, false }, 783 { ";|", BRKEV, false }, 784 { ";&", BRKFT, false }, 785 { "((", MDPAREN, false }, 786 { "|&", COPROC, false }, 787 /* and some special cases... */ 788 { "newline", '\n', false }, 789 { NULL, 0, false } 790 }; 791 792 void 793 initkeywords(void) 794 { 795 struct tokeninfo const *tt; 796 struct tbl *p; 797 798 ktinit(APERM, &keywords, 799 /* currently 28 keywords -> 80% of 64 (2^6) */ 800 6); 801 for (tt = tokentab; tt->name; tt++) { 802 if (tt->reserved) { 803 p = ktenter(&keywords, tt->name, hash(tt->name)); 804 p->flag |= DEFINED|ISSET; 805 p->type = CKEYWD; 806 p->val.i = tt->val; 807 } 808 } 809 } 810 811 static void 812 syntaxerr(const char *what) 813 { 814 /* 2<<- is the longest redirection, I think */ 815 char redir[6]; 816 const char *s; 817 struct tokeninfo const *tt; 818 int c; 819 820 if (!what) 821 what = "unexpected"; 822 REJECT; 823 c = token(0); 824 Again: 825 switch (c) { 826 case 0: 827 if (nesting.start_token) { 828 c = nesting.start_token; 829 source->errline = nesting.start_line; 830 what = "unmatched"; 831 goto Again; 832 } 833 /* don't quote the EOF */ 834 yyerror("%s: %s %s\n", Tsynerr, "unexpected", "EOF"); 835 /* NOTREACHED */ 836 837 case LWORD: 838 s = snptreef(NULL, 32, "%S", yylval.cp); 839 break; 840 841 case REDIR: 842 s = snptreef(redir, sizeof(redir), "%R", yylval.iop); 843 break; 844 845 default: 846 for (tt = tokentab; tt->name; tt++) 847 if (tt->val == c) 848 break; 849 if (tt->name) 850 s = tt->name; 851 else { 852 if (c > 0 && c < 256) { 853 redir[0] = c; 854 redir[1] = '\0'; 855 } else 856 shf_snprintf(redir, sizeof(redir), 857 "?%d", c); 858 s = redir; 859 } 860 } 861 yyerror("%s: '%s' %s\n", Tsynerr, s, what); 862 } 863 864 static void 865 nesting_push(struct nesting_state *save, int tok) 866 { 867 *save = nesting; 868 nesting.start_token = tok; 869 nesting.start_line = source->line; 870 } 871 872 static void 873 nesting_pop(struct nesting_state *saved) 874 { 875 nesting = *saved; 876 } 877 878 static struct op * 879 newtp(int type) 880 { 881 struct op *t; 882 883 t = alloc(sizeof(struct op), ATEMP); 884 t->type = type; 885 t->u.evalflags = 0; 886 t->args = NULL; 887 t->vars = NULL; 888 t->ioact = NULL; 889 t->left = t->right = NULL; 890 t->str = NULL; 891 return (t); 892 } 893 894 struct op * 895 compile(Source *s, bool skiputf8bom) 896 { 897 nesting.start_token = 0; 898 nesting.start_line = 0; 899 herep = heres; 900 source = s; 901 if (skiputf8bom) 902 yyskiputf8bom(); 903 yyparse(); 904 return (outtree); 905 } 906 907 /*- 908 * This kludge exists to take care of sh/AT&T ksh oddity in which 909 * the arguments of alias/export/readonly/typeset have no field 910 * splitting, file globbing, or (normal) tilde expansion done. 911 * AT&T ksh seems to do something similar to this since 912 * $ touch a=a; typeset a=[ab]; echo "$a" 913 * a=[ab] 914 * $ x=typeset; $x a=[ab]; echo "$a" 915 * a=a 916 * $ 917 */ 918 static int 919 assign_command(char *s) 920 { 921 if (!*s) 922 return (0); 923 return ((strcmp(s, Talias) == 0) || 924 (strcmp(s, "export") == 0) || 925 (strcmp(s, "readonly") == 0) || 926 (strcmp(s, Ttypeset) == 0)); 927 } 928 929 /* Check if we are in the middle of reading an alias */ 930 static int 931 inalias(struct source *s) 932 { 933 for (; s && s->type == SALIAS; s = s->next) 934 if (!(s->flags & SF_ALIASEND)) 935 return (1); 936 return (0); 937 } 938 939 940 /* 941 * Order important - indexed by Test_meta values 942 * Note that ||, &&, ( and ) can't appear in as unquoted strings 943 * in normal shell input, so these can be interpreted unambiguously 944 * in the evaluation pass. 945 */ 946 static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS }; 947 static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS }; 948 static const char dbtest_not[] = { CHAR, '!', EOS }; 949 static const char dbtest_oparen[] = { CHAR, '(', EOS }; 950 static const char dbtest_cparen[] = { CHAR, ')', EOS }; 951 const char *const dbtest_tokens[] = { 952 dbtest_or, dbtest_and, dbtest_not, 953 dbtest_oparen, dbtest_cparen 954 }; 955 const char db_close[] = { CHAR, ']', CHAR, ']', EOS }; 956 const char db_lthan[] = { CHAR, '<', EOS }; 957 const char db_gthan[] = { CHAR, '>', EOS }; 958 959 /* 960 * Test if the current token is a whatever. Accepts the current token if 961 * it is. Returns 0 if it is not, non-zero if it is (in the case of 962 * TM_UNOP and TM_BINOP, the returned value is a Test_op). 963 */ 964 static Test_op 965 dbtestp_isa(Test_env *te, Test_meta meta) 966 { 967 int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); 968 int uqword; 969 char *save = NULL; 970 Test_op ret = TO_NONOP; 971 972 /* unquoted word? */ 973 uqword = c == LWORD && *ident; 974 975 if (meta == TM_OR) 976 ret = c == LOGOR ? TO_NONNULL : TO_NONOP; 977 else if (meta == TM_AND) 978 ret = c == LOGAND ? TO_NONNULL : TO_NONOP; 979 else if (meta == TM_NOT) 980 ret = (uqword && !strcmp(yylval.cp, 981 dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP; 982 else if (meta == TM_OPAREN) 983 ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP; 984 else if (meta == TM_CPAREN) 985 ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP; 986 else if (meta == TM_UNOP || meta == TM_BINOP) { 987 if (meta == TM_BINOP && c == REDIR && 988 (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) { 989 ret = TO_NONNULL; 990 save = wdcopy(yylval.iop->flag == IOREAD ? 991 db_lthan : db_gthan, ATEMP); 992 } else if (uqword && (ret = test_isop(meta, ident))) 993 save = yylval.cp; 994 } else 995 /* meta == TM_END */ 996 ret = (uqword && !strcmp(yylval.cp, 997 db_close)) ? TO_NONNULL : TO_NONOP; 998 if (ret != TO_NONOP) { 999 ACCEPT; 1000 if (meta < NELEM(dbtest_tokens)) 1001 save = wdcopy(dbtest_tokens[(int)meta], ATEMP); 1002 if (save) 1003 XPput(*te->pos.av, save); 1004 } 1005 return (ret); 1006 } 1007 1008 static const char * 1009 dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED, 1010 bool do_eval MKSH_A_UNUSED) 1011 { 1012 int c = tpeek(ARRAYVAR); 1013 1014 if (c != LWORD) 1015 return (NULL); 1016 1017 ACCEPT; 1018 XPput(*te->pos.av, yylval.cp); 1019 1020 return (null); 1021 } 1022 1023 static int 1024 dbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED, 1025 const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED, 1026 bool do_eval MKSH_A_UNUSED) 1027 { 1028 return (1); 1029 } 1030 1031 static void 1032 dbtestp_error(Test_env *te, int offset, const char *msg) 1033 { 1034 te->flags |= TEF_ERROR; 1035 1036 if (offset < 0) { 1037 REJECT; 1038 /* Kludgy to say the least... */ 1039 symbol = LWORD; 1040 yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) + 1041 offset); 1042 } 1043 syntaxerr(msg); 1044 } 1045 1046 #if HAVE_SELECT 1047 1048 #ifndef EOVERFLOW 1049 #ifdef ERANGE 1050 #define EOVERFLOW ERANGE 1051 #else 1052 #define EOVERFLOW EINVAL 1053 #endif 1054 #endif 1055 1056 bool 1057 parse_usec(const char *s, struct timeval *tv) 1058 { 1059 struct timeval tt; 1060 int i; 1061 1062 tv->tv_sec = 0; 1063 /* parse integral part */ 1064 while (ksh_isdigit(*s)) { 1065 tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0'); 1066 if (tt.tv_sec / 10 != tv->tv_sec) { 1067 errno = EOVERFLOW; 1068 return (true); 1069 } 1070 tv->tv_sec = tt.tv_sec; 1071 } 1072 1073 tv->tv_usec = 0; 1074 if (!*s) 1075 /* no decimal fraction */ 1076 return (false); 1077 else if (*s++ != '.') { 1078 /* junk after integral part */ 1079 errno = EINVAL; 1080 return (true); 1081 } 1082 1083 /* parse decimal fraction */ 1084 i = 100000; 1085 while (ksh_isdigit(*s)) { 1086 tv->tv_usec += i * (*s++ - '0'); 1087 if (i == 1) 1088 break; 1089 i /= 10; 1090 } 1091 /* check for junk after fractional part */ 1092 while (ksh_isdigit(*s)) 1093 ++s; 1094 if (*s) { 1095 errno = EINVAL; 1096 return (true); 1097 } 1098 1099 /* end of input string reached, no errors */ 1100 return (false); 1101 } 1102 #endif 1103 1104 /* 1105 * Helper function called from within lex.c:yylex() to parse 1106 * a COMSUB recursively using the main shell parser and lexer 1107 */ 1108 char * 1109 yyrecursive(void) 1110 { 1111 struct op *t; 1112 char *cp; 1113 bool old_reject; 1114 int old_symbol; 1115 struct ioword **old_herep; 1116 1117 /* tell the lexer to accept a closing parenthesis as EOD */ 1118 ++subshell_nesting_level; 1119 1120 /* push reject state, parse recursively, pop reject state */ 1121 old_reject = reject; 1122 old_symbol = symbol; 1123 ACCEPT; 1124 old_herep = herep; 1125 /* we use TPAREN as a helper container here */ 1126 t = nested(TPAREN, '(', ')'); 1127 herep = old_herep; 1128 reject = old_reject; 1129 symbol = old_symbol; 1130 1131 /* t->left because nested(TPAREN, ...) hides our goodies there */ 1132 cp = snptreef(NULL, 0, "%T", t->left); 1133 tfree(t, ATEMP); 1134 1135 --subshell_nesting_level; 1136 return (cp); 1137 } 1138