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