|
|
1.1 root 1: /*
2: * sh/sh.y
3: * The Bourne shell.
4: * This shell is dedicated to Ciaran Gerald Aidan O'Donnell.
5: * May he live a thousand minutes (long enough to fix up YACC).
6: * It is also dedicated to Steve Bourne.
7: * May he live a thousand seconds.
8: */
9: %{
10: #include "sh.h"
11:
12: #define YYERROR { yyerrflag=1; goto YYerract; }
13:
14: extern NODE *node();
15: %}
16:
17: %union {
18: NODE *yu_node;
19: char *yu_strp;
20: int yu_nval;
21: }
22:
23: %token _ANDF
24: %token _ASGN
25: %token _CASE
26: %token _CBRAC
27: %token _DO
28: %token _DONE
29: %token _DSEMI
30: %token _ELIF
31: %token _ELSE
32: %token _ESAC
33: %token _FI
34: %token _FOR
35: %token _IF
36: %token _IN
37: %token _IORS
38: %token _NAME
39: %token _NULL
40: %token _OBRAC
41: %token _ORF
42: %token _THEN
43: %token _UNTIL
44: %token _WHILE
45:
46: %type <yu_node> arg arg_list case_line case_list
47: %type <yu_node> cmd cmd_line cmd_list cmd_seq
48: %type <yu_node> control do_list else_part in_name_list
49: %type <yu_node> logical_cmd name_list opt_cmd_seq pattern_list
50: %type <yu_node> pipe_cmd sub_shell
51:
52: %type <yu_strp> asgn name redirect
53:
54: %type <yu_nval> whuntile
55:
56: %%
57:
58: session:
59: session cmd_line
60: |
61: ;
62:
63: cmd_line:
64: '\n' {
65: sesp->s_node = NULL;
66: reset(RCMD);
67: NOTREACHED;
68: }
69: |
70: cmd_list '\n' {
71: sesp->s_node = $1;
72: reset(errflag ? RERR : RCMD);
73: NOTREACHED;
74: }
75: | error '\n' {
76: keyflush();
77: keyflag = 1;
78: reset(RERR);
79: NOTREACHED;
80: }
81: ;
82:
83: if: _IF optnls ;
84:
85: then: _THEN optnls ;
86:
87: elif: _ELIF optnls ;
88:
89: else: _ELSE optnls ;
90:
91: whuntile: _WHILE optnls { $$ = NWHILE; }
92: | _UNTIL optnls { $$ = NUNTIL; }
93: ;
94:
95: do: _DO optnls | _DO ';' optnls ;
96:
97: in: _IN | _IN sep ;
98:
99: oror: _ORF optnls;
100:
101: andand: _ANDF optnls;
102:
103: or: '|' optnls;
104:
105: oparen: '(' optnls ;
106:
107: obrack: _OBRAC optnls ;
108:
109: cparen: ')' optnls ;
110:
111: dsemi: _DSEMI optnls ;
112:
113: cmd_list:
114: logical_cmd {
115: $$ = $1;
116: }
117: | logical_cmd '&' {
118: $$ = node(NBACK, $1, NULL);
119: }
120: | logical_cmd ';' {
121: $$ = $1;
122: }
123: | logical_cmd '&' cmd_list {
124: $$ = node(NBACK, $1, $3);
125: }
126: | logical_cmd ';' cmd_list {
127: $$ = node(NLIST, $1, $3);
128: }
129: ;
130:
131: logical_cmd:
132: pipe_cmd {
133: $$ = $1;
134: }
135: | pipe_cmd oror logical_cmd {
136: $$ = node(NORF, $1, $3);
137: }
138: | pipe_cmd andand logical_cmd {
139: $$ = node(NANDF, $1, $3);
140: }
141: ;
142:
143: pipe_cmd:
144: cmd or pipe_cmd {
145: $$ = node(NPIPE, $1, $3);
146: }
147: | cmd {
148: $$ = $1;
149: }
150: ;
151:
152: cmd:
153: arg_list_init arg_list {
154: $$ = node(NCOMS, $2, NULL);
155: keypop();
156: }
157: ;
158:
159: arg_list_init:
160: {
161: keypush();
162: keyflag = 1;
163: }
164: ;
165:
166: arg_list:
167: arg arg_list {
168: if (($1->n_type == NCTRL && $2->n_type == NARGS)
169: || ($1->n_type == NARGS && $2->n_type == NCTRL)) {
170: YYERROR;
171: }
172: ($$ = $1)->n_next = $2;
173: }
174: | arg {
175: $$ = $1;
176: }
177: ;
178:
179: arg:
180: redirect {
181: $$ = node(NIORS, $1, NULL);
182: }
183: | name {
184: $$ = node(NARGS, $1, NULL);
185: keyflag = 0;
186: }
187: | asgn {
188: $$ = node(NASSG, $1, NULL);
189: }
190: | control {
191: if (!keyflag) {
192: YYERROR;
193: }
194: $$ = node(NCTRL, $1, NULL);
195: keyflag = 0;
196: }
197: ;
198:
199: redirect: _IORS {
200: $$ = duplstr(strt, 0);
201: }
202: ;
203:
204: name: _NAME {
205: $$ = duplstr(strt, 0);
206: }
207: ;
208:
209: asgn: _ASGN {
210: $$ = duplstr(strt, 0);
211: }
212: ;
213:
214: control:
215: _FOR name in_name_list sep do_list _DONE {
216: $$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $5, NULL)));
217: $$->n_next->n_next->n_next = $$->n_next;
218: }
219: | _FOR name in_name_list do_list _DONE {
220: $$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $4, NULL)));
221: $$->n_next->n_next->n_next = $$->n_next;
222: }
223: | _CASE name sep in case_list _ESAC {
224: $$ = node(NCASE, $2, $5);
225: }
226: | _CASE name in case_list _ESAC {
227: $$ = node(NCASE, $2, $4);
228: }
229: | whuntile cmd_seq do_list _DONE {
230: $$ = node($1, $2, node(NLIST, $3, NULL));
231: $$->n_next->n_next = $$;
232: }
233: | if cmd_seq then opt_cmd_seq else_part _FI {
234: $$ = node(NIF, node(NNULL, $2, $4), $5);
235: }
236: | oparen opt_cmd_seq ')' {
237: $$ = node(NPARN, $2, NULL);
238: }
239: | obrack opt_cmd_seq _CBRAC {
240: $$ = node(NBRAC, $2, NULL);
241: }
242: ;
243:
244: in_name_list:
245: _IN name_list {
246: $$ = $2;
247: }
248: | {
249: $$ = node(NARGS, "\"$@\"", NULL);
250: }
251: ;
252:
253: name_list:
254: name name_list {
255: $$ = node(NARGS, $1, $2);
256: }
257: | {
258: $$ = NULL;
259: }
260: ;
261:
262: case_list:
263: case_line dsemi case_list {
264: register NODE *np;
265:
266: for (np=$1; np->n_next; np=np->n_next)
267: ;
268: np->n_next = $3;
269: $$ = $1;
270: }
271: | case_line {
272: $$ = $1;
273: }
274: | {
275: $$ = NULL;
276: }
277: ;
278:
279: case_line:
280: pattern_list cparen opt_cmd_seq {
281: $$ = node(NCASE2, $3, $1);
282: }
283: ;
284:
285: pattern_list:
286: name '|' pattern_list {
287: $$ = node(NCASE3, $1, $3);
288: }
289: | name {
290: $$ = node(NCASE3, $1, NULL);
291: }
292: ;
293:
294: do_list:
295: do opt_cmd_seq {
296: $$ = $2;
297: }
298: | {
299: $$ = NULL;
300: }
301: ;
302:
303: else_part:
304: elif cmd_seq then opt_cmd_seq else_part {
305: $$ = node(NIF, node(NNULL, $2, $4), $5);
306: }
307: | else opt_cmd_seq {
308: $$ = node(NELSE, $2, NULL);
309: }
310: | {
311: $$ = NULL;
312: }
313: ;
314:
315: opt_cmd_seq:
316: cmd_seq {
317: $$ = $1;
318: }
319: |
320: {
321: $$ = NULL;
322: }
323: ;
324:
325: cmd_seq:
326: cmd_list nls cmd_seq {
327: $$ = node(NLIST, $1, $3);
328: }
329: | cmd_list optnls {
330: $$ = $1;
331: }
332: ;
333:
334: sep: nls
335: | ';'
336: | ';' nls
337: ;
338:
339: optnls: nls
340: |
341: ;
342:
343: nls: '\n'
344: | nls '\n'
345: ;
346:
347: %%
348: /*
349: * Create a node.
350: */
351: NODE *
352: node(type, auxp, next)
353: NODE *auxp, *next;
354: {
355: register NODE *np;
356:
357: np = (NODE *) balloc(sizeof (NODE));
358: np->n_type = type;
359: np->n_auxp = auxp;
360: np->n_next = next;
361: return np;
362: }
363:
364: #define NBPC 8
365: #define NKEY 8
366: static char keys[NKEY] = { 0 };
367: static int keyi = NKEY * NBPC;
368:
369: keyflush()
370: {
371: register char *kp;
372:
373: for (kp = keys+NKEY; kp > keys; *--kp = 0)
374: ;
375: keyi = NKEY * NBPC;
376: }
377:
378: keypop()
379: {
380: register char *kp;
381: register int km;
382:
383: if ((km = keyi++) >= NKEY * NBPC) {
384: panic(11);
385: NOTREACHED;
386: }
387: kp = keys + (km / NBPC);
388: km = 1 << (km %= NBPC);
389: keyflag = (*kp & km) ? 1 : 0;
390: *kp &= ~km;
391: }
392:
393: keypush()
394: {
395: register char *kp;
396: register int km;
397:
398: if ((km = --keyi) < 0) {
399: panic(12);
400: NOTREACHED;
401: }
402: if (keyflag) {
403: kp = keys + (km / NBPC);
404: km = 1 << (km %= NBPC);
405: *kp |= km;
406: }
407: }
408: /*
409: * The following fragments might implement named pipes.
410: * The token declaration goes in the header.
411: * The nopen production should go with the others of its ilk.
412: * The production fragment goes into arg:
413: %token _NOPEN _NCLOSE
414: nopen: _NOPEN optnls ;
415:
416: | nopen pipe_cmd ')' {
417: $$ = node(NRPIPE, $2, NULL);
418: }
419: | oparen pipe_cmd _NCLOSE {
420: $$ = node(NWPIPE, $2, NULL);
421: }
422: *
423: */
424:
425: /* end of sh/sh.y */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.