#ifndef lint static char sccsid[] = "@(#)cmd.c 4.2 8/11/83"; #endif # /* * UNIX shell * * S. R. Bourne * Bell Telephone Laboratories * */ #include "defs.h" #include "sym.h" PROC IOPTR inout(); PROC VOID chkword(); PROC VOID chksym(); PROC TREPTR term(); PROC TREPTR makelist(); PROC TREPTR list(); PROC REGPTR syncase(); PROC TREPTR item(); PROC VOID skipnl(); PROC VOID prsym(); PROC VOID synbad(); /* ======== command line decoding ========*/ TREPTR makefork(flgs, i) INT flgs; TREPTR i; { REG TREPTR t; t=getstak(FORKTYPE); t->forktyp=flgs|TFORK; t->forktre=i; t->forkio=0; return(t); } LOCAL TREPTR makelist(type,i,r) INT type; TREPTR i, r; { REG TREPTR t; IF i==0 ORF r==0 THEN synbad(); ELSE t = getstak(LSTTYPE); t->lsttyp = type; t->lstlef = i; t->lstrit = r; FI return(t); } /* * cmd * empty * list * list & [ cmd ] * list [ ; cmd ] */ TREPTR cmd(sym,flg) REG INT sym; INT flg; { REG TREPTR i, e; i = list(flg); IF wdval==NL THEN IF flg&NLFLG THEN wdval=';'; chkpr(NL); FI ELIF i==0 ANDF (flg&MTFLG)==0 THEN synbad(); FI SWITCH wdval IN case '&': IF i THEN i = makefork(FINT|FPRS|FAMP, i); ELSE synbad(); FI case ';': IF e=cmd(sym,flg|MTFLG) THEN i=makelist(TLST, i, e); FI break; case EOFSYM: IF sym==NL THEN break; FI default: IF sym THEN chksym(sym); FI ENDSW return(i); } /* * list * term * list && term * list || term */ LOCAL TREPTR list(flg) { REG TREPTR r; REG INT b; r = term(flg); WHILE r ANDF ((b=(wdval==ANDFSYM)) ORF wdval==ORFSYM) DO r = makelist((b ? TAND : TORF), r, term(NLFLG)); OD return(r); } /* * term * item * item |^ term */ LOCAL TREPTR term(flg) { REG TREPTR t; reserv++; IF flg&NLFLG THEN skipnl(); ELSE word(); FI IF (t=item(TRUE)) ANDF (wdval=='^' ORF wdval=='|') THEN return(makelist(TFIL, makefork(FPOU,t), makefork(FPIN|FPCL,term(NLFLG)))); ELSE return(t); FI } LOCAL REGPTR syncase(esym) REG INT esym; { skipnl(); IF wdval==esym THEN return(0); ELSE REG REGPTR r=getstak(REGTYPE); r->regptr=0; LOOP wdarg->argnxt=r->regptr; r->regptr=wdarg; IF wdval ORF ( word()!=')' ANDF wdval!='|' ) THEN synbad(); FI IF wdval=='|' THEN word(); ELSE break; FI POOL r->regcom=cmd(0,NLFLG|MTFLG); IF wdval==ECSYM THEN r->regnxt=syncase(esym); ELSE chksym(esym); r->regnxt=0; FI return(r); FI } /* * item * * ( cmd ) [ < in ] [ > out ] * word word* [ < in ] [ > out ] * if ... then ... else ... fi * for ... while ... do ... done * case ... in ... esac * begin ... end */ LOCAL TREPTR item(flag) BOOL flag; { REG TREPTR t; REG IOPTR io; IF flag THEN io=inout((IOPTR)0); ELSE io=0; FI SWITCH wdval IN case CASYM: BEGIN t=getstak(SWTYPE); chkword(); t->swarg=wdarg->argval; skipnl(); chksym(INSYM|BRSYM); t->swlst=syncase(wdval==INSYM?ESSYM:KTSYM); t->swtyp=TSW; break; END case IFSYM: BEGIN REG INT w; t=getstak(IFTYPE); t->iftyp=TIF; t->iftre=cmd(THSYM,NLFLG); t->thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG); t->eltre=((w=wdval)==ELSYM ? cmd(FISYM,NLFLG) : (w==EFSYM ? (wdval=IFSYM, item(0)) : 0)); IF w==EFSYM THEN return(t) FI break; END case FORSYM: BEGIN t=getstak(FORTYPE); t->fortyp=TFOR; t->forlst=0; chkword(); t->fornam=wdarg->argval; IF skipnl()==INSYM THEN chkword(); t->forlst=item(0); IF wdval!=NL ANDF wdval!=';' THEN synbad(); FI chkpr(wdval); skipnl(); FI chksym(DOSYM|BRSYM); t->fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG); break; END case WHSYM: case UNSYM: BEGIN t=getstak(WHTYPE); t->whtyp=(wdval==WHSYM ? TWH : TUN); t->whtre = cmd(DOSYM,NLFLG); t->dotre = cmd(ODSYM,NLFLG); break; END case BRSYM: t=cmd(KTSYM,NLFLG); break; case '(': BEGIN REG PARPTR p; p=getstak(PARTYPE); p->partre=cmd(')',NLFLG); p->partyp=TPAR; t=makefork(0,p); break; END default: IF io==0 THEN return(0); FI case 0: BEGIN REG ARGPTR argp; REG ARGPTR *argtail; REG ARGPTR *argset=0; INT keywd=1; t=getstak(COMTYPE); t->comio=io; /*initial io chain*/ argtail = &(t->comarg); WHILE wdval==0 DO argp = wdarg; IF wdset ANDF keywd THEN argp->argnxt=argset; argset=argp; ELSE *argtail=argp; argtail = &(argp->argnxt); keywd=flags&keyflg; FI word(); IF flag THEN t->comio=inout(t->comio); FI OD t->comtyp=TCOM; t->comset=argset; *argtail=0; return(t); END ENDSW reserv++; word(); IF io=inout(io) THEN t=makefork(0,t); t->treio=io; FI return(t); } LOCAL VOID skipnl() { WHILE (reserv++, word()==NL) DO chkpr(NL) OD return(wdval); } LOCAL IOPTR inout(lastio) IOPTR lastio; { REG INT iof; REG IOPTR iop; REG CHAR c; iof=wdnum; SWITCH wdval IN case DOCSYM: iof |= IODOC; break; case APPSYM: case '>': IF wdnum==0 THEN iof |= 1 FI iof |= IOPUT; IF wdval==APPSYM THEN iof |= IOAPP; break; FI case '<': IF (c=nextc(0))=='&' THEN iof |= IOMOV; ELIF c=='>' THEN iof |= IORDW; ELSE peekc=c|MARK; FI break; default: return(lastio); ENDSW chkword(); iop=getstak(IOTYPE); iop->ioname=wdarg->argval; iop->iofile=iof; IF iof&IODOC THEN iop->iolst=iopend; iopend=iop; FI word(); iop->ionxt=inout(lastio); return(iop); } LOCAL VOID chkword() { IF word() THEN synbad(); FI } LOCAL VOID chksym(sym) { REG INT x = sym&wdval; IF ((x&SYMFLG) ? x : sym) != wdval THEN synbad(); FI } LOCAL VOID prsym(sym) { IF sym&SYMFLG THEN REG SYSPTR sp=reserved; WHILE sp->sysval ANDF sp->sysval!=sym DO sp++ OD prs(sp->sysnam); ELIF sym==EOFSYM THEN prs(endoffile); ELSE IF sym&SYMREP THEN prc(sym) FI IF sym==NL THEN prs("newline"); ELSE prc(sym); FI FI } LOCAL VOID synbad() { prp(); prs(synmsg); IF (flags&ttyflg)==0 THEN prs(atline); prn(standin->flin); FI prs(colon); prc(LQ); IF wdval THEN prsym(wdval); ELSE prs(wdarg->argval); FI prc(RQ); prs(unexpected); newline(); exitsh(SYNBAD); }