|
|
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.