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