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