1 #ifndef lint
2 static char sccsid[] = "@(#)cmd.c 4.3 04/24/88";
3 #endif
4
5 #
6 /*
7 * UNIX shell
8 *
9 * S. R. Bourne
10 * Bell Telephone Laboratories
11 *
12 */
13
14 #include "defs.h"
15 #include "sym.h"
16
17 PROC IOPTR inout();
18 PROC VOID chkword();
19 PROC VOID chksym();
20 PROC TREPTR term();
21 PROC TREPTR makelist();
22 PROC TREPTR list();
23 PROC REGPTR syncase();
24 PROC TREPTR item();
25 PROC VOID skipnl();
26 PROC VOID prsym();
27 PROC VOID synbad();
28
29
30 /* ======== command line decoding ========*/
31
32
33
34
makefork(flgs,i)35 TREPTR makefork(flgs, i)
36 INT flgs;
37 TREPTR i;
38 {
39 REG TREPTR t;
40
41 t=getstak(FORKTYPE);
42 t->forknod.forktyp=flgs|TFORK;
43 t->forknod.forktre=i;
44 t->forknod.forkio=0;
45 return(t);
46 }
47
makelist(type,i,r)48 LOCAL TREPTR makelist(type,i,r)
49 INT type;
50 TREPTR i, r;
51 {
52 REG TREPTR t;
53
54 IF i==0 ORF r==0
55 THEN synbad();
56 ELSE t = getstak(LSTTYPE);
57 t->lstnod.lsttyp = type;
58 t->lstnod.lstlef = i;
59 t->lstnod.lstrit = r;
60 FI
61 return(t);
62 }
63
64 /*
65 * cmd
66 * empty
67 * list
68 * list & [ cmd ]
69 * list [ ; cmd ]
70 */
71
cmd(sym,flg)72 TREPTR cmd(sym,flg)
73 REG INT sym;
74 INT flg;
75 {
76 REG TREPTR i, e;
77
78 i = list(flg);
79
80 IF wdval==NL
81 THEN IF flg&NLFLG
82 THEN wdval=';'; chkpr(NL);
83 FI
84 ELIF i==0 ANDF (flg&MTFLG)==0
85 THEN synbad();
86 FI
87
88 SWITCH wdval IN
89
90 case '&':
91 IF i
92 THEN i = makefork(FINT|FPRS|FAMP, i);
93 ELSE synbad();
94 FI
95
96 case ';':
97 IF e=cmd(sym,flg|MTFLG)
98 THEN i=makelist(TLST, i, e);
99 FI
100 break;
101
102 case EOFSYM:
103 IF sym==NL
104 THEN break;
105 FI
106
107 default:
108 IF sym
109 THEN chksym(sym);
110 FI
111
112 ENDSW
113 return(i);
114 }
115
116 /*
117 * list
118 * term
119 * list && term
120 * list || term
121 */
122
list(flg)123 LOCAL TREPTR list(flg)
124 {
125 REG TREPTR r;
126 REG INT b;
127
128 r = term(flg);
129 WHILE r ANDF ((b=(wdval==ANDFSYM)) ORF wdval==ORFSYM)
130 DO r = makelist((b ? TAND : TORF), r, term(NLFLG));
131 OD
132 return(r);
133 }
134
135 /*
136 * term
137 * item
138 * item |^ term
139 */
140
term(flg)141 LOCAL TREPTR term(flg)
142 {
143 REG TREPTR t;
144
145 reserv++;
146 IF flg&NLFLG
147 THEN skipnl();
148 ELSE word();
149 FI
150
151 IF (t=item(TRUE)) ANDF (wdval=='^' ORF wdval=='|')
152 THEN return(makelist(TFIL, makefork(FPOU,t), makefork(FPIN|FPCL,term(NLFLG))));
153 ELSE return(t);
154 FI
155 }
156
syncase(esym)157 LOCAL REGPTR syncase(esym)
158 REG INT esym;
159 {
160 skipnl();
161 IF wdval==esym
162 THEN return(0);
163 ELSE REG REGPTR r=getstak(REGTYPE);
164 r->regptr=0;
165 LOOP wdarg->argnxt=r->regptr;
166 r->regptr=wdarg;
167 IF wdval ORF ( word()!=')' ANDF wdval!='|' )
168 THEN synbad();
169 FI
170 IF wdval=='|'
171 THEN word();
172 ELSE break;
173 FI
174 POOL
175 r->regcom=cmd(0,NLFLG|MTFLG);
176 IF wdval==ECSYM
177 THEN r->regnxt=syncase(esym);
178 ELSE chksym(esym);
179 r->regnxt=0;
180 FI
181 return(r);
182 FI
183 }
184
185 /*
186 * item
187 *
188 * ( cmd ) [ < in ] [ > out ]
189 * word word* [ < in ] [ > out ]
190 * if ... then ... else ... fi
191 * for ... while ... do ... done
192 * case ... in ... esac
193 * begin ... end
194 */
195
item(flag)196 LOCAL TREPTR item(flag)
197 BOOL flag;
198 {
199 REG TREPTR t;
200 REG IOPTR io;
201
202 IF flag
203 THEN io=inout((IOPTR)0);
204 ELSE io=0;
205 FI
206
207 SWITCH wdval IN
208
209 case CASYM:
210 BEGIN
211 t=getstak(SWTYPE);
212 chkword();
213 t->swnod.swarg=wdarg->argval;
214 skipnl(); chksym(INSYM|BRSYM);
215 t->swnod.swlst=syncase(wdval==INSYM?ESSYM:KTSYM);
216 t->swnod.swtyp=TSW;
217 break;
218 END
219
220 case IFSYM:
221 BEGIN
222 REG INT w;
223 t=getstak(IFTYPE);
224 t->ifnod.iftyp=TIF;
225 t->ifnod.iftre=cmd(THSYM,NLFLG);
226 t->ifnod.thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG);
227 t->ifnod.eltre=((w=wdval)==ELSYM ? cmd(FISYM,NLFLG) : (w==EFSYM ? (wdval=IFSYM, item(0)) : 0));
228 IF w==EFSYM THEN return(t) FI
229 break;
230 END
231
232 case FORSYM:
233 BEGIN
234 t=getstak(FORTYPE);
235 t->fornod.fortyp=TFOR;
236 t->fornod.forlst=0;
237 chkword();
238 t->fornod.fornam=wdarg->argval;
239 IF skipnl()==INSYM
240 THEN chkword();
241 t->fornod.forlst=item(0);
242 IF wdval!=NL ANDF wdval!=';'
243 THEN synbad();
244 FI
245 chkpr(wdval); skipnl();
246 FI
247 chksym(DOSYM|BRSYM);
248 t->fornod.fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG);
249 break;
250 END
251
252 case WHSYM:
253 case UNSYM:
254 BEGIN
255 t=getstak(WHTYPE);
256 t->whnod.whtyp=(wdval==WHSYM ? TWH : TUN);
257 t->whnod.whtre = cmd(DOSYM,NLFLG);
258 t->whnod.dotre = cmd(ODSYM,NLFLG);
259 break;
260 END
261
262 case BRSYM:
263 t=cmd(KTSYM,NLFLG);
264 break;
265
266 case '(':
267 BEGIN
268 REG PARPTR p;
269 p=getstak(PARTYPE);
270 p->partre=cmd(')',NLFLG);
271 p->partyp=TPAR;
272 t=makefork(0,p);
273 break;
274 END
275
276 default:
277 IF io==0
278 THEN return(0);
279 FI
280
281 case 0:
282 BEGIN
283 REG ARGPTR argp;
284 REG ARGPTR *argtail;
285 REG ARGPTR *argset=0;
286 INT keywd=1;
287 t=getstak(COMTYPE);
288 t->comnod.comio=io; /*initial io chain*/
289 argtail = &(t->comnod.comarg);
290 WHILE wdval==0
291 DO argp = wdarg;
292 IF wdset ANDF keywd
293 THEN argp->argnxt=argset; argset=argp;
294 ELSE *argtail=argp; argtail = &(argp->argnxt); keywd=flags&keyflg;
295 FI
296 word();
297 IF flag
298 THEN t->comnod.comio=inout(t->comnod.comio);
299 FI
300 OD
301
302 t->comnod.comtyp=TCOM; t->comnod.comset=argset; *argtail=0;
303 return(t);
304 END
305
306 ENDSW
307 reserv++; word();
308 IF io=inout(io)
309 THEN t=makefork(0,t); t->treio.treio=io;
310 FI
311 return(t);
312 }
313
314
skipnl()315 LOCAL VOID skipnl()
316 {
317 WHILE (reserv++, word()==NL) DO chkpr(NL) OD
318 return(wdval);
319 }
320
inout(lastio)321 LOCAL IOPTR inout(lastio)
322 IOPTR lastio;
323 {
324 REG INT iof;
325 REG IOPTR iop;
326 REG CHAR c;
327
328 iof=wdnum;
329
330 SWITCH wdval IN
331
332 case DOCSYM:
333 iof |= IODOC; break;
334
335 case APPSYM:
336 case '>':
337 IF wdnum==0 THEN iof |= 1 FI
338 iof |= IOPUT;
339 IF wdval==APPSYM
340 THEN iof |= IOAPP; break;
341 FI
342
343 case '<':
344 IF (c=nextc(0))=='&'
345 THEN iof |= IOMOV;
346 ELIF c=='>'
347 THEN iof |= IORDW;
348 ELSE peekc=c|MARK;
349 FI
350 break;
351
352 default:
353 return(lastio);
354 ENDSW
355
356 chkword();
357 iop=getstak(IOTYPE); iop->ioname=wdarg->argval; iop->iofile=iof;
358 IF iof&IODOC
359 THEN iop->iolst=iopend; iopend=iop;
360 FI
361 word(); iop->ionxt=inout(lastio);
362 return(iop);
363 }
364
chkword()365 LOCAL VOID chkword()
366 {
367 IF word()
368 THEN synbad();
369 FI
370 }
371
chksym(sym)372 LOCAL VOID chksym(sym)
373 {
374 REG INT x = sym&wdval;
375 IF ((x&SYMFLG) ? x : sym) != wdval
376 THEN synbad();
377 FI
378 }
379
prsym(sym)380 LOCAL VOID prsym(sym)
381 {
382 IF sym&SYMFLG
383 THEN REG SYSPTR sp=reserved;
384 WHILE sp->sysval
385 ANDF sp->sysval!=sym
386 DO sp++ OD
387 prs(sp->sysnam);
388 ELIF sym==EOFSYM
389 THEN prs(endoffile);
390 ELSE IF sym&SYMREP THEN prc(sym) FI
391 IF sym==NL
392 THEN prs("newline");
393 ELSE prc(sym);
394 FI
395 FI
396 }
397
synbad()398 LOCAL VOID synbad()
399 {
400 prp(); prs(synmsg);
401 IF (flags&ttyflg)==0
402 THEN prs(atline); prn(standin->flin);
403 FI
404 prs(colon);
405 prc(LQ);
406 IF wdval
407 THEN prsym(wdval);
408 ELSE prs(wdarg->argval);
409 FI
410 prc(RQ); prs(unexpected);
411 newline();
412 exitsh(SYNBAD);
413 }
414