home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
pdksh-4.9-src.tgz
/
tar.out
/
contrib
/
pdksh
/
sh
/
syn.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
10KB
|
578 lines
/*
* shell parser (C version)
*/
#ifndef lint
static char *RCSid = "$Id: syn.c,v 1.4 93/05/05 21:17:06 sjg Exp $";
#endif
#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"
static struct op *pipeline ARGS((int cf));
static struct op *andor ARGS((void));
static struct op *c_list ARGS((void));
static struct ioword *synio ARGS((int cf));
static void musthave ARGS((int c, int cf));
static struct op *nested ARGS((int type, int mark));
static struct op *command ARGS((int cf));
static struct op *dogroup ARGS((int onlydone));
static struct op *thenpart ARGS((void));
static struct op *elsepart ARGS((void));
static struct op *caselist ARGS((void));
static struct op *casepart ARGS((void));
static char ** wordlist ARGS((void));
static struct op *block ARGS((int type, struct op *t1, struct op *t2, char **wp));
static struct op *newtp ARGS((int type));
static void zzerr ARGS((void));
static struct op *outtree; /* yyparse output */
static int reject; /* token(cf) gets symbol again */
static int symbol; /* yylex value */
#define REJECT (reject = 1)
#define ACCEPT (reject = 0)
#define token(cf) \
((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
#define tpeek(cf) \
((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
int
yyparse()
{
ACCEPT;
yynerrs = 0;
if ((tpeek(KEYWORD|ALIAS)) == 0) { /* EOF */
outtree = newtp(TEOF);
return 0;
}
outtree = c_list();
musthave('\n', 0);
return (yynerrs != 0);
}
static struct op *
pipeline(cf)
int cf;
{
register struct op *t, *p, *tl = NULL;
register int c;
t = command(cf);
if (t != NULL) {
while ((c = token(0)) == '|') {
if ((p = command(CONTIN)) == NULL)
SYNTAXERR;
if (tl == NULL)
t = tl = block(TPIPE, t, p, NOWORDS);
else
tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
/*t = block(TPIPE, t, p, NOWORDS);*/
}
REJECT;
}
return (t);
}
static struct op *
andor()
{
register struct op *t, *p;
register int c;
t = pipeline(0);
if (t != NULL) {
while ((c = token(0)) == LOGAND || c == LOGOR) {
if ((p = pipeline(CONTIN)) == NULL)
SYNTAXERR;
t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct op *
c_list()
{
register struct op *t, *p, *tl = NULL;
register int c;
t = andor();
if (t != NULL) {
while ((c = token(0)) == ';' || c == '&' ||
((multiline || source->type == SSTRING
|| (source->type == SALIAS)) && c == '\n')) {
if (c == '&') {
if (tl)
tl->right = block(TASYNC, tl->right, NOBLOCK, NOWORDS);
else
t = block(TASYNC, t, NOBLOCK, NOWORDS);
}
if ((p = andor()) == NULL)
return (t);
if (tl == NULL)
t = tl = block(TLIST, t, p, NOWORDS);
else
tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct ioword *
synio(cf)
int cf;
{
register struct ioword *iop;
if (tpeek(cf) != REDIR)
return NULL;
ACCEPT;
iop = yylval.iop;
musthave(LWORD, 0);
iop->name = yylval.cp;
if ((iop->flag&IOTYPE) == IOHERE) {
if (*ident != 0) /* unquoted */
iop->flag |= IOEVAL;
if (herep >= &heres[HERES])
errorf("too many <<'s\n");
*herep++ = iop;
}
return iop;
}
static void
musthave(c, cf)
int c, cf;
{
if ((token(cf)) != c)
SYNTAXERR;
}
static struct op *
nested(type, mark)
int type, mark;
{
register struct op *t;
multiline++;
t = c_list();
musthave(mark, KEYWORD);
multiline--;
return (block(type, t, NOBLOCK, NOWORDS));
}
static struct op *
command(cf)
int cf;
{
register struct op *t;
register int c, iopn = 0;
struct ioword *iop, **iops;
XPtrV args, vars;
iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), ATEMP);
XPinit(args, 16);
XPinit(vars, 16);
if (multiline)
cf = CONTIN;
cf |= KEYWORD|ALIAS;
while ((iop = synio(cf)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many redirections");
iops[iopn++] = iop;
cf &=~ CONTIN;
}
switch (c = token(cf)) {
case 0:
yyerror("unexpected EOF");
return NULL;
default:
REJECT;
if (iopn == 0)
return NULL; /* empty line */
t = newtp(TCOM);
break;
case LWORD:
case MDPAREN:
REJECT;
t = newtp(TCOM);
if (c == MDPAREN) {
ACCEPT;
XPput(args,"let");
musthave(LWORD,LETEXPR);
XPput(args,yylval.cp);
}
while (1)
switch (tpeek(0)) {
case REDIR:
if (iopn >= NUFILE)
yyerror("too many redirections");
iops[iopn++] = synio(0);
break;
case LWORD:
ACCEPT;
if ((XPsize(args) == 0 || flag[FKEYWORD])
&& strchr(ident+1, '='))
{XPput(vars, yylval.cp);}
else
{XPput(args, yylval.cp);}
break;
case MPAREN:
ACCEPT;
if (XPsize(args) != 1)
SYNTAXERR;
if (*ident == 0)
yyerror("invalid function name\n");
t = newtp(TFUNCT);
t->str = strsave(ident, ATEMP);
musthave('{', CONTIN|KEYWORD);
t->left = nested(TBRACE, '}');
return t;
default:
goto Leave;
}
Leave:
break;
case '(':
t = nested(TPAREN, ')');
break;
case '{':
t = nested(TBRACE, '}');
break;
case FOR:
case SELECT:
t = newtp((c == FOR) ? TFOR: TSELECT);
musthave(LWORD, 0);
t->str = strsave(ident, ATEMP);
multiline++;
t->vars = wordlist();
t->left = dogroup(0);
multiline--;
break;
case WHILE:
case UNTIL:
multiline++;
t = newtp((c == WHILE) ? TWHILE: TUNTIL);
t->left = c_list();
t->right = dogroup(1);
multiline--;
break;
case CASE:
t = newtp(TCASE);
musthave(LWORD, 0);
t->str = yylval.cp;
multiline++;
musthave(IN, KEYWORD|CONTIN);
t->left = caselist();
musthave(ESAC, KEYWORD);
multiline--;
break;
case IF:
multiline++;
t = newtp(TIF);
t->left = c_list();
t->right = thenpart();
musthave(FI, KEYWORD);
multiline--;
break;
case TIME:
t = pipeline(CONTIN);
t = block(TTIME, t, NOBLOCK, NOWORDS);
break;
case FUNCTION:
t = newtp(TFUNCT);
musthave(LWORD, 0);
t->str = strsave(ident, ATEMP);
musthave('{', CONTIN|KEYWORD);
t->left = nested(TBRACE, '}');
break;
#if 0
case MDPAREN:
t = newtp(TCOM);
XPput(args, "let");
musthave(LWORD, LETEXPR);
XPput(args, yylval.cp);
while (tpeek(0) == REDIR) {
if (iopn >= NUFILE)
yyerror("too many redirections");
iops[iopn++] = synio(0);
}
break;
#endif
}
while ((iop = synio(0)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many redirections");
iops[iopn++] = iop;
}
if (iopn == 0) {
afree((void*) iops, ATEMP);
t->ioact = NULL;
} else {
iops[iopn++] = NULL;
aresize((void*) iops, sizeofN(struct ioword *, iopn), ATEMP);
t->ioact = iops;
}
if (t->type == TCOM) {
XPput(args, NULL);
t->args = (char **) XPclose(args);
XPput(vars, NULL);
t->vars = (char **) XPclose(vars);
} else {
XPfree(args);
XPfree(vars);
}
return t;
}
static struct op *
dogroup(onlydone)
int onlydone;
{
register int c;
register struct op *list;
c = token(CONTIN|KEYWORD);
if (c == DONE && onlydone)
return NULL;
if (c != DO)
SYNTAXERR;
list = c_list();
musthave(DONE, KEYWORD);
return list;
}
static struct op *
thenpart()
{
register int c;
register struct op *t;
if ((c = token(0)) != THEN) {
REJECT;
return NULL;
}
t = newtp(0);
t->left = c_list();
if (t->left == NULL)
SYNTAXERR;
t->right = elsepart();
return (t);
}
static struct op *
elsepart()
{
register int c;
register struct op *t;
switch (c = token(0)) {
case ELSE:
if ((t = c_list()) == NULL)
SYNTAXERR;
return (t);
case ELIF:
t = newtp(TELIF);
t->left = c_list();
t->right = thenpart();
return (t);
default:
REJECT;
return NULL;
}
}
static struct op *
caselist()
{
register struct op *t, *tl;
t = tl = NULL;
while ((tpeek(CONTIN|KEYWORD)) != ESAC) {
struct op *tc = casepart();
if (tl == NULL)
t = tl = tc, tl->right = NULL;
else
tl->right = tc, tl = tc;
}
return (t);
}
static struct op *
casepart()
{
register struct op *t;
register int c, cf;
XPtrV ptns;
XPinit(ptns, 16);
t = newtp(TPAT);
cf = CONTIN|KEYWORD;
c = token(cf);
if (c != '(')
REJECT;
else
cf = 0;
do {
musthave(LWORD, cf);
XPput(ptns, yylval.cp);
cf = 0;
} while ((c = token(0)) == '|');
REJECT;
XPput(ptns, NULL);
t->vars = (char **) XPclose(ptns);
musthave(')', 0);
t->left = c_list();
if ((tpeek(CONTIN|KEYWORD)) != ESAC)
musthave(BREAK, CONTIN|KEYWORD);
return (t);
}
static char **
wordlist()
{
register int c;
XPtrV args;
XPinit(args, 16);
if ((c = token(CONTIN|KEYWORD)) != IN) {
REJECT;
return NULL;
}
while ((c = token(0)) == LWORD)
XPput(args, yylval.cp);
if (c != '\n' && c != ';')
SYNTAXERR;
if (XPsize(args) == 0) {
XPfree(args);
return NULL;
} else {
XPput(args, NULL);
return (char **) XPclose(args);
}
}
/*
* supporting functions
*/
static struct op *
block(type, t1, t2, wp)
struct op *t1, *t2;
char **wp;
{
register struct op *t;
t = newtp(type);
t->left = t1;
t->right = t2;
t->vars = wp;
return (t);
}
const struct res {
char *name;
int val;
} restab[] = {
"for", FOR,
"select", SELECT,
"case", CASE,
"esac", ESAC,
"while", WHILE,
"do", DO,
"done", DONE,
"if", IF,
"in", IN,
"then", THEN,
"else", ELSE,
"elif", ELIF,
"until", UNTIL,
"fi", FI,
"function", FUNCTION,
"time", TIME,
"{", '{',
"}", '}',
0
};
keywords()
{
register struct res const *rp;
register struct tbl *p;
for (rp = restab; rp->name; rp++) {
p = tenter(&lexicals, rp->name, hash(rp->name));
p->flag |= DEFINED|ISSET;
p->type = CKEYWD;
p->val.i = rp->val;
}
}
static struct op *
newtp(type)
int type;
{
register struct op *t;
t = (struct op *) alloc(sizeof(*t), ATEMP);
t->type = type;
t->args = t->vars = NULL;
t->ioact = NULL;
t->left = t->right = NULL;
t->str = NULL;
return (t);
}
static void
zzerr()
{
yyerror("syntax error");
}
struct op *
compile(s)
Source *s;
{
yynerrs = 0;
multiline = 0;
herep = heres;
source = s;
if (yyparse())
unwind();
if (s->type == STTY || s->type == SFILE || s->type == SHIST)
s->str = null; /* line is not preserved */
return outtree;
}