BSD 4_2 release
[unix-history] / usr / src / bin / sh / cmd.c
#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);
}