|
|
1.1 ! root 1: /* ! 2: * The Bourne shell. ! 3: * This shell is dedicated to Ciaran Gerald Aidan O'Donnell. ! 4: * May he live a thousand minutes (long enough to fix up YACC). ! 5: * It is also dedicated to Steve Bourne. ! 6: * May he live a thousand seconds. ! 7: */ ! 8: %{ ! 9: #include "sh.h" ! 10: ! 11: #define YYERROR { yyerrflag=1; goto YYerract; } ! 12: ! 13: extern NODE *node(); ! 14: %} ! 15: ! 16: %union { ! 17: NODE *yu_node; ! 18: char *yu_strp; ! 19: int yu_nval; ! 20: } ! 21: ! 22: %token _ANDF ! 23: %token _ASGN ! 24: %token _CASE ! 25: %token _CBRAC ! 26: %token _DO ! 27: %token _DONE ! 28: %token _DSEMI ! 29: %token _ELIF ! 30: %token _ELSE ! 31: %token _ESAC ! 32: %token _FI ! 33: %token _FOR ! 34: %token _IF ! 35: %token _IN ! 36: %token _IORS ! 37: %token _NAME ! 38: %token _NULL ! 39: %token _OBRAC ! 40: %token _ORF ! 41: %token _PARENS ! 42: %token _RET ! 43: %token _THEN ! 44: %token _UNTIL ! 45: %token _WHILE ! 46: ! 47: %type <yu_node> arg arg_list case_line case_list ! 48: %type <yu_node> cmd cmd_line cmd_list cmd_seq ! 49: %type <yu_node> control do_list else_part in_name_list ! 50: %type <yu_node> logical_cmd name_list opt_cmd_seq pattern_list ! 51: %type <yu_node> pipe_cmd sub_shell ! 52: ! 53: %type <yu_node> command simple_command redirect_list cmd_prefix ! 54: %type <yu_node> cmd_word cmd_suffix cmd_name redirect_list ! 55: %type <yu_node> asgn_node redirect_node name_node ! 56: %type <yu_node> function_definition compound_command ! 57: %type <yu_node> non_keyword_name ! 58: ! 59: %type <yu_strp> asgn name redirect ! 60: ! 61: %type <yu_nval> whuntile ! 62: ! 63: %% ! 64: ! 65: session: ! 66: session cmd_line ! 67: | ! 68: ; ! 69: ! 70: cmd_line: ! 71: '\n' { ! 72: sesp->s_node = NULL; ! 73: reset(RCMD); ! 74: NOTREACHED; ! 75: } ! 76: | ! 77: cmd_list '\n' { ! 78: sesp->s_node = $1; ! 79: reset(errflag ? RERR : RCMD); ! 80: NOTREACHED; ! 81: } ! 82: | error '\n' { ! 83: keyflush(); ! 84: keyflag = 1; ! 85: reset(RERR); ! 86: NOTREACHED; ! 87: } ! 88: ; ! 89: ! 90: if: _IF optnls ; ! 91: ! 92: then: _THEN optnls ; ! 93: ! 94: elif: _ELIF optnls ; ! 95: ! 96: else: _ELSE optnls ; ! 97: ! 98: whuntile: _WHILE optnls { $$ = NWHILE; } ! 99: | _UNTIL optnls { $$ = NUNTIL; } ! 100: ; ! 101: ! 102: do: _DO optnls | _DO ';' optnls ; ! 103: ! 104: in: _IN | _IN sep ; ! 105: ! 106: oror: _ORF optnls; ! 107: ! 108: andand: _ANDF optnls; ! 109: ! 110: or: '|' optnls; ! 111: ! 112: oparen: '(' optnls ; ! 113: ! 114: obrack: _OBRAC optnls ; ! 115: ! 116: cparen: ')' optnls ; ! 117: ! 118: dsemi: _DSEMI optnls ; ! 119: ! 120: cmd_list: ! 121: logical_cmd { ! 122: $$ = $1; ! 123: } ! 124: | logical_cmd '&' { ! 125: $$ = node(NBACK, $1, NULL); ! 126: } ! 127: | logical_cmd ';' { ! 128: $$ = $1; ! 129: } ! 130: | logical_cmd '&' cmd_list { ! 131: $$ = node(NBACK, $1, $3); ! 132: } ! 133: | logical_cmd ';' cmd_list { ! 134: $$ = node(NLIST, $1, $3); ! 135: } ! 136: ; ! 137: ! 138: logical_cmd: ! 139: pipe_cmd { ! 140: $$ = $1; ! 141: } ! 142: | pipe_cmd oror logical_cmd { ! 143: $$ = node(NORF, $1, $3); ! 144: } ! 145: | pipe_cmd andand logical_cmd { ! 146: $$ = node(NANDF, $1, $3); ! 147: } ! 148: ; ! 149: ! 150: pipe_cmd: ! 151: cmd or pipe_cmd { ! 152: $$ = node(NPIPE, $1, $3); ! 153: } ! 154: | cmd { ! 155: $$ = $1; ! 156: } ! 157: ; ! 158: ! 159: /* ! 160: * In the original grammar, no distinction between simple command and compound ! 161: * commands was made. This, along with the right-recursive formulation of the ! 162: * command grammar, created a need for lookahead that defeated the complex ! 163: * machinery for context-sensitive lexing that is required. ! 164: */ ! 165: ! 166: cmd: turn_on_keywords command { ! 167: $$ = $2; ! 168: keypop (); ! 169: } ! 170: ; ! 171: ! 172: turn_on_keywords: { ! 173: keypush (); ! 174: keyflag = 1; ! 175: } ! 176: ; ! 177: ! 178: command: ! 179: simple_command { ! 180: $$ = node (NCOMS, $1, NULL); ! 181: } ! 182: | compound_command { ! 183: $$ = node (NCOMS, $1, NULL); ! 184: } ! 185: | compound_command redirect_list { ! 186: $$ = node (NCOMS, $1->n_next = $2, NULL); ! 187: } ! 188: | function_definition { ! 189: $$ = node (NCOMS, $1, NULL); ! 190: } ! 191: | _RET name { ! 192: $$ = node (NRET, $2, NULL); ! 193: } ! 194: | _RET { ! 195: $$ = node (NRET, "", NULL); ! 196: } ! 197: ; ! 198: ! 199: compound_command: ! 200: control { ! 201: $$ = node (NCTRL, $1, NULL); ! 202: } ! 203: ; ! 204: ! 205: function_definition: ! 206: name _PARENS optnls obrack cmd_seq _CBRAC { ! 207: $$ = node (NCTRL, node (NFUNC, $1, $5), NULL); ! 208: } ! 209: ; ! 210: ! 211: redirect_list: ! 212: redirect_node { ! 213: $$ = $1; ! 214: } ! 215: | redirect_list redirect_node { ! 216: ($$ = $1)->n_next = $2; ! 217: } ! 218: ; ! 219: ! 220: simple_command: ! 221: cmd_prefix cmd_word cmd_suffix { ! 222: (($$ = $1)->n_next = $2)->n_next = $3; ! 223: } ! 224: | cmd_prefix cmd_word { ! 225: ($$ = $1)->n_next = $2; ! 226: } ! 227: | cmd_prefix { ! 228: $$ = $1; ! 229: } ! 230: | cmd_name cmd_suffix { ! 231: ($$ = $1)->n_next = $2; ! 232: } ! 233: | cmd_name { ! 234: $$ = $1; ! 235: } ! 236: ; ! 237: ! 238: cmd_prefix: ! 239: redirect_node { ! 240: $$ = $1; ! 241: } ! 242: | redirect_node cmd_prefix { ! 243: ($$ = $1)->n_next = $2; ! 244: } ! 245: | asgn_node { ! 246: $$ = $1; ! 247: } ! 248: | asgn_node cmd_prefix { ! 249: ($$ = $1)->n_next = $2; ! 250: } ! 251: ; ! 252: ! 253: cmd_name: ! 254: name_node { ! 255: $$ = $1; ! 256: keyflag = 0; ! 257: } ! 258: ; ! 259: ! 260: cmd_word: ! 261: name_node { ! 262: $$ = $1; ! 263: keyflag = 0; ! 264: } ! 265: ; ! 266: ! 267: /* ! 268: * The main part of this shell has some silliness with assignments and some ! 269: * flag called '-k'. To support this, we allow assignments after the command ! 270: * name and code elsewhere turns them back into parameters... it seems ! 271: * preferable to do it here, but because of the '-k' thing we'll just ! 272: * accept them. ! 273: */ ! 274: ! 275: cmd_suffix: ! 276: redirect_node { ! 277: $$ = $1; ! 278: } ! 279: | redirect_node cmd_suffix { ! 280: ($$ = $1)->n_next = $2; ! 281: } ! 282: | non_keyword_name { ! 283: $$ = $1; ! 284: } ! 285: | non_keyword_name cmd_suffix { ! 286: ($$ = $1)->n_next = $2; ! 287: } ! 288: | asgn_node { ! 289: $$ = $1; ! 290: } ! 291: | asgn_node cmd_suffix { ! 292: ($$ = $1)->n_next = $2; ! 293: } ! 294: ; ! 295: ! 296: non_keyword_name: ! 297: non_keyword_string { ! 298: $$ = node (NARGS, duplstr (strt, 0), NULL); ! 299: } ! 300: ; ! 301: ! 302: /* ! 303: * Many of the following cause S/R conflicts. This reflects the fact that the ! 304: * decision about whether to recognise a token in a given place needs some ! 305: * extra disambiguation or not. In all cases, the correct result is to shift ! 306: * (treating the reserved word as a normal word), which is the default. ! 307: */ ! 308: non_keyword_string: ! 309: _NAME ! 310: | _CASE ! 311: | _DO ! 312: | _DONE ! 313: | _ELIF ! 314: | _ELSE ! 315: | _ESAC ! 316: | _FI ! 317: | _FOR ! 318: | _IF ! 319: | _IN ! 320: | _RET ! 321: | _THEN ! 322: | _UNTIL ! 323: | _WHILE ! 324: ; ! 325: ! 326: /* ! 327: * Replaced by detailed cases above. ! 328: cmd: ! 329: arg_list_init arg_list { ! 330: $$ = node(NCOMS, $2, NULL); ! 331: keypop(); ! 332: } ! 333: | _RET name { ! 334: $$ = node(NRET, $2, NULL); ! 335: } ! 336: | _RET { ! 337: $$ = node(NRET, "", NULL); ! 338: } ! 339: ; ! 340: ! 341: arg_list_init: ! 342: { ! 343: keypush(); ! 344: keyflag = 1; ! 345: } ! 346: ; ! 347: ! 348: arg_list: ! 349: arg arg_list { ! 350: if (($1->n_type == NCTRL && $2->n_type == NARGS) ! 351: || ($1->n_type == NARGS && $2->n_type == NCTRL)) { ! 352: YYERROR; ! 353: } ! 354: ($$ = $1)->n_next = $2; ! 355: } ! 356: | arg { ! 357: $$ = $1; ! 358: } ! 359: ; ! 360: ! 361: arg: ! 362: redirect_node { ! 363: $$ = $1; ! 364: } ! 365: | name_node { ! 366: $$ = $1; ! 367: keyflag = 0; ! 368: } ! 369: | asgn_node { ! 370: $$ = $1; ! 371: } ! 372: | control { ! 373: if (!keyflag) { ! 374: YYERROR; ! 375: } ! 376: $$ = node(NCTRL, $1, NULL); ! 377: keyflag = 0; ! 378: } ! 379: ; ! 380: */ ! 381: ! 382: /* ! 383: * The form of the following productions arranges for the contents of the ! 384: * global "strt" to be duplicated ASAP, hopefully before lookahead gets ! 385: * involved. ! 386: */ ! 387: ! 388: redirect_node: redirect { ! 389: $$ = node (NIORS, $1, NULL); ! 390: } ! 391: ; ! 392: ! 393: redirect: _IORS { ! 394: $$ = duplstr (strt, 0); ! 395: } ! 396: ; ! 397: ! 398: name_node: name { ! 399: $$ = node (NARGS, $1, NULL); ! 400: } ! 401: ; ! 402: ! 403: name: _NAME { ! 404: $$ = duplstr (strt, 0); ! 405: } ! 406: ; ! 407: ! 408: ! 409: asgn_node: asgn { ! 410: $$ = node (NASSG, $1, NULL); ! 411: } ! 412: ; ! 413: ! 414: asgn: _ASGN { ! 415: $$ = duplstr (strt, 0); ! 416: } ! 417: ; ! 418: ! 419: control: ! 420: _FOR name in_name_list sep do_list _DONE { ! 421: $$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $5, NULL))); ! 422: $$->n_next->n_next->n_next = $$->n_next; ! 423: } ! 424: | _FOR name in_name_list do_list _DONE { ! 425: $$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $4, NULL))); ! 426: $$->n_next->n_next->n_next = $$->n_next; ! 427: } ! 428: | _CASE name sep in case_list _ESAC { ! 429: $$ = node(NCASE, $2, $5); ! 430: } ! 431: | _CASE name in case_list _ESAC { ! 432: $$ = node(NCASE, $2, $4); ! 433: } ! 434: | whuntile cmd_seq do_list _DONE { ! 435: $$ = node($1, $2, node(NLIST, $3, NULL)); ! 436: $$->n_next->n_next = $$; ! 437: } ! 438: | if cmd_seq then opt_cmd_seq else_part _FI { ! 439: $$ = node(NIF, node(NNULL, $2, $4), $5); ! 440: } ! 441: | oparen opt_cmd_seq ')' { ! 442: $$ = node(NPARN, $2, NULL); ! 443: } ! 444: | obrack opt_cmd_seq _CBRAC { ! 445: $$ = node(NBRAC, $2, NULL); ! 446: } ! 447: ; ! 448: ! 449: in_name_list: ! 450: _IN name_list { ! 451: $$ = $2; ! 452: } ! 453: | { ! 454: $$ = node(NARGS, "\"$@\"", NULL); ! 455: } ! 456: ; ! 457: ! 458: name_list: ! 459: name name_list { ! 460: $$ = node(NARGS, $1, $2); ! 461: } ! 462: | { ! 463: $$ = NULL; ! 464: } ! 465: ; ! 466: ! 467: case_list: ! 468: case_line dsemi case_list { ! 469: register NODE *np; ! 470: ! 471: for (np=$1; np->n_next; np=np->n_next) ! 472: ; ! 473: np->n_next = $3; ! 474: $$ = $1; ! 475: } ! 476: | case_line { ! 477: $$ = $1; ! 478: } ! 479: | { ! 480: $$ = NULL; ! 481: } ! 482: ; ! 483: ! 484: case_line: ! 485: pattern_list cparen opt_cmd_seq { ! 486: $$ = node(NCASE2, $3, $1); ! 487: } ! 488: ; ! 489: ! 490: pattern_list: ! 491: name '|' pattern_list { ! 492: $$ = node(NCASE3, $1, $3); ! 493: } ! 494: | name { ! 495: $$ = node(NCASE3, $1, NULL); ! 496: } ! 497: ; ! 498: ! 499: do_list: ! 500: do opt_cmd_seq { ! 501: $$ = $2; ! 502: } ! 503: | { ! 504: $$ = NULL; ! 505: } ! 506: ; ! 507: ! 508: else_part: ! 509: elif cmd_seq then opt_cmd_seq else_part { ! 510: $$ = node(NIF, node(NNULL, $2, $4), $5); ! 511: } ! 512: | else opt_cmd_seq { ! 513: $$ = node(NELSE, $2, NULL); ! 514: } ! 515: | { ! 516: $$ = NULL; ! 517: } ! 518: ; ! 519: ! 520: opt_cmd_seq: ! 521: cmd_seq { ! 522: $$ = $1; ! 523: } ! 524: | ! 525: { ! 526: $$ = NULL; ! 527: } ! 528: ; ! 529: ! 530: cmd_seq: ! 531: cmd_list nls cmd_seq { ! 532: $$ = node(NLIST, $1, $3); ! 533: } ! 534: | cmd_list optnls { ! 535: $$ = $1; ! 536: } ! 537: ; ! 538: ! 539: sep: nls ! 540: | ';' ! 541: | ';' nls ! 542: ; ! 543: ! 544: optnls: nls ! 545: | ! 546: ; ! 547: ! 548: nls: '\n' ! 549: | nls '\n' ! 550: ; ! 551: ! 552: %% ! 553: /* ! 554: * Create a node. ! 555: */ ! 556: NODE * ! 557: node(type, auxp, next) ! 558: NODE *auxp, *next; ! 559: { ! 560: register NODE *np; ! 561: ! 562: np = (NODE *) balloc(sizeof (NODE)); ! 563: np->n_type = type; ! 564: np->n_auxp = auxp; ! 565: np->n_next = next; ! 566: return np; ! 567: } ! 568: ! 569: #define NBPC 8 ! 570: #define NKEY 8 ! 571: static char keys[NKEY] = { 0 }; ! 572: static int keyi = NKEY * NBPC; ! 573: ! 574: keyflush() ! 575: { ! 576: register char *kp; ! 577: ! 578: for (kp = keys+NKEY; kp > keys; *--kp = 0) ! 579: ; ! 580: keyi = NKEY * NBPC; ! 581: } ! 582: ! 583: keypop() ! 584: { ! 585: register char *kp; ! 586: register int km; ! 587: ! 588: if ((km = keyi++) >= NKEY * NBPC) { ! 589: panic(11); ! 590: NOTREACHED; ! 591: } ! 592: kp = keys + (km / NBPC); ! 593: km = 1 << (km %= NBPC); ! 594: keyflag = (*kp & km) ? 1 : 0; ! 595: *kp &= ~km; ! 596: } ! 597: ! 598: keypush() ! 599: { ! 600: register char *kp; ! 601: register int km; ! 602: ! 603: if ((km = --keyi) < 0) { ! 604: panic(12); ! 605: NOTREACHED; ! 606: } ! 607: if (keyflag) { ! 608: kp = keys + (km / NBPC); ! 609: km = 1 << (km %= NBPC); ! 610: *kp |= km; ! 611: } ! 612: } ! 613: /* ! 614: * The following fragments might implement named pipes. ! 615: * The token declaration goes in the header. ! 616: * The nopen production should go with the others of its ilk. ! 617: * The production fragment goes into arg: ! 618: %token _NOPEN _NCLOSE ! 619: nopen: _NOPEN optnls ; ! 620: ! 621: | nopen pipe_cmd ')' { ! 622: $$ = node(NRPIPE, $2, NULL); ! 623: } ! 624: | oparen pipe_cmd _NCLOSE { ! 625: $$ = node(NWPIPE, $2, NULL); ! 626: } ! 627: * ! 628: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.