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