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