minix/commands/sh/sh2.c

801 lines
12 KiB
C
Raw Normal View History

2005-04-21 16:53:53 +02:00
#define Extern extern
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
/* -------- csyn.c -------- */
/*
* shell: syntax (C version)
*/
typedef union {
char *cp;
char **wp;
int i;
struct op *o;
} YYSTYPE;
#define WORD 256
#define LOGAND 257
#define LOGOR 258
#define BREAK 259
#define IF 260
#define THEN 261
#define ELSE 262
#define ELIF 263
#define FI 264
#define CASE 265
#define ESAC 266
#define FOR 267
#define WHILE 268
#define UNTIL 269
#define DO 270
#define DONE 271
#define IN 272
#define YYERRCODE 300
/* flags to yylex */
#define CONTIN 01 /* skip new lines to complete command */
/* #include "sh.h" */
#define SYNTAXERR zzerr()
static int startl;
static int peeksym;
static int nlseen;
static int iounit = IODEFAULT;
static YYSTYPE yylval;
_PROTOTYPE(static struct op *pipeline, (int cf ));
_PROTOTYPE(static struct op *andor, (void));
_PROTOTYPE(static struct op *c_list, (void));
_PROTOTYPE(static int synio, (int cf ));
_PROTOTYPE(static void musthave, (int c, int cf ));
_PROTOTYPE(static struct op *simple, (void));
_PROTOTYPE(static struct op *nested, (int type, int mark ));
_PROTOTYPE(static struct op *command, (int cf ));
_PROTOTYPE(static struct op *dogroup, (int onlydone ));
_PROTOTYPE(static struct op *thenpart, (void));
_PROTOTYPE(static struct op *elsepart, (void));
_PROTOTYPE(static struct op *caselist, (void));
_PROTOTYPE(static struct op *casepart, (void));
_PROTOTYPE(static char **pattern, (void));
_PROTOTYPE(static char **wordlist, (void));
_PROTOTYPE(static struct op *list, (struct op *t1, struct op *t2 ));
_PROTOTYPE(static struct op *block, (int type, struct op *t1, struct op *t2, char **wp ));
_PROTOTYPE(static struct op *newtp, (void));
_PROTOTYPE(static struct op *namelist, (struct op *t ));
_PROTOTYPE(static char **copyw, (void));
_PROTOTYPE(static void word, (char *cp ));
_PROTOTYPE(static struct ioword **copyio, (void));
_PROTOTYPE(static struct ioword *io, (int u, int f, char *cp ));
_PROTOTYPE(static void zzerr, (void));
_PROTOTYPE(void yyerror, (char *s ));
_PROTOTYPE(static int yylex, (int cf ));
_PROTOTYPE(int collect, (int c, int c1 ));
_PROTOTYPE(int dual, (int c ));
_PROTOTYPE(static void diag, (int ec ));
_PROTOTYPE(static char *tree, (unsigned size ));
_PROTOTYPE(void printf, (char *s ));
int
yyparse()
{
startl = 1;
peeksym = 0;
yynerrs = 0;
outtree = c_list();
musthave('\n', 0);
return(yynerrs!=0);
}
static struct op *
pipeline(cf)
int cf;
{
register struct op *t, *p;
register int c;
t = command(cf);
if (t != NULL) {
while ((c = yylex(0)) == '|') {
if ((p = command(CONTIN)) == NULL)
SYNTAXERR;
if (t->type != TPAREN && t->type != TCOM) {
/* shell statement */
t = block(TPAREN, t, NOBLOCK, NOWORDS);
}
t = block(TPIPE, t, p, NOWORDS);
}
peeksym = c;
}
return(t);
}
static struct op *
andor()
{
register struct op *t, *p;
register int c;
t = pipeline(0);
if (t != NULL) {
while ((c = yylex(0)) == LOGAND || c == LOGOR) {
if ((p = pipeline(CONTIN)) == NULL)
SYNTAXERR;
t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
}
peeksym = c;
}
return(t);
}
static struct op *
c_list()
{
register struct op *t, *p;
register int c;
t = andor();
if (t != NULL) {
if((peeksym = yylex(0)) == '&')
t = block(TASYNC, t, NOBLOCK, NOWORDS);
while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) {
if ((p = andor()) == NULL)
return(t);
if((peeksym = yylex(0)) == '&')
p = block(TASYNC, p, NOBLOCK, NOWORDS);
t = list(t, p);
}
peeksym = c;
}
return(t);
}
static int
synio(cf)
int cf;
{
register struct ioword *iop;
register int i;
register int c;
if ((c = yylex(cf)) != '<' && c != '>') {
peeksym = c;
return(0);
}
i = yylval.i;
musthave(WORD, 0);
iop = io(iounit, i, yylval.cp);
iounit = IODEFAULT;
if (i & IOHERE)
markhere(yylval.cp, iop);
return(1);
}
static void
musthave(c, cf)
int c, cf;
{
if ((peeksym = yylex(cf)) != c)
SYNTAXERR;
peeksym = 0;
}
static struct op *
simple()
{
register struct op *t;
t = NULL;
for (;;) {
switch (peeksym = yylex(0)) {
case '<':
case '>':
(void) synio(0);
break;
case WORD:
if (t == NULL) {
t = newtp();
t->type = TCOM;
}
peeksym = 0;
word(yylval.cp);
break;
default:
return(t);
}
}
}
static struct op *
nested(type, mark)
int type, mark;
{
register struct op *t;
multiline++;
t = c_list();
musthave(mark, 0);
multiline--;
return(block(type, t, NOBLOCK, NOWORDS));
}
static struct op *
command(cf)
int cf;
{
register struct op *t;
struct wdblock *iosave;
register int c;
iosave = iolist;
iolist = NULL;
if (multiline)
cf |= CONTIN;
while (synio(cf))
cf = 0;
switch (c = yylex(cf)) {
default:
peeksym = c;
if ((t = simple()) == NULL) {
if (iolist == NULL)
return((struct op *)NULL);
t = newtp();
t->type = TCOM;
}
break;
case '(':
t = nested(TPAREN, ')');
break;
case '{':
t = nested(TBRACE, '}');
break;
case FOR:
t = newtp();
t->type = TFOR;
musthave(WORD, 0);
startl = 1;
t->str = yylval.cp;
multiline++;
t->words = wordlist();
if ((c = yylex(0)) != '\n' && c != ';')
peeksym = c;
t->left = dogroup(0);
multiline--;
break;
case WHILE:
case UNTIL:
multiline++;
t = newtp();
t->type = c == WHILE? TWHILE: TUNTIL;
t->left = c_list();
t->right = dogroup(1);
t->words = NULL;
multiline--;
break;
case CASE:
t = newtp();
t->type = TCASE;
musthave(WORD, 0);
t->str = yylval.cp;
startl++;
multiline++;
musthave(IN, CONTIN);
startl++;
t->left = caselist();
musthave(ESAC, 0);
multiline--;
break;
case IF:
multiline++;
t = newtp();
t->type = TIF;
t->left = c_list();
t->right = thenpart();
musthave(FI, 0);
multiline--;
break;
}
while (synio(0))
;
t = namelist(t);
iolist = iosave;
return(t);
}
static struct op *
dogroup(onlydone)
int onlydone;
{
register int c;
register struct op *list;
c = yylex(CONTIN);
if (c == DONE && onlydone)
return((struct op *)NULL);
if (c != DO)
SYNTAXERR;
list = c_list();
musthave(DONE, 0);
return(list);
}
static struct op *
thenpart()
{
register int c;
register struct op *t;
if ((c = yylex(0)) != THEN) {
peeksym = c;
return((struct op *)NULL);
}
t = newtp();
t->type = 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 = yylex(0)) {
case ELSE:
if ((t = c_list()) == NULL)
SYNTAXERR;
return(t);
case ELIF:
t = newtp();
t->type = TELIF;
t->left = c_list();
t->right = thenpart();
return(t);
default:
peeksym = c;
return((struct op *)NULL);
}
}
static struct op *
caselist()
{
register struct op *t;
t = NULL;
while ((peeksym = yylex(CONTIN)) != ESAC)
t = list(t, casepart());
return(t);
}
static struct op *
casepart()
{
register struct op *t;
t = newtp();
t->type = TPAT;
t->words = pattern();
musthave(')', 0);
t->left = c_list();
if ((peeksym = yylex(CONTIN)) != ESAC)
musthave(BREAK, CONTIN);
return(t);
}
static char **
pattern()
{
register int c, cf;
cf = CONTIN;
do {
musthave(WORD, cf);
word(yylval.cp);
cf = 0;
} while ((c = yylex(0)) == '|');
peeksym = c;
word(NOWORD);
return(copyw());
}
static char **
wordlist()
{
register int c;
if ((c = yylex(0)) != IN) {
peeksym = c;
return((char **)NULL);
}
startl = 0;
while ((c = yylex(0)) == WORD)
word(yylval.cp);
word(NOWORD);
peeksym = c;
return(copyw());
}
/*
* supporting functions
*/
static struct op *
list(t1, t2)
register struct op *t1, *t2;
{
if (t1 == NULL)
return(t2);
if (t2 == NULL)
return(t1);
return(block(TLIST, t1, t2, NOWORDS));
}
static struct op *
block(type, t1, t2, wp)
int type;
struct op *t1, *t2;
char **wp;
{
register struct op *t;
t = newtp();
t->type = type;
t->left = t1;
t->right = t2;
t->words = wp;
return(t);
}
struct res {
char *r_name;
int r_val;
} restab[] = {
"for", FOR,
"case", CASE,
"esac", ESAC,
"while", WHILE,
"do", DO,
"done", DONE,
"if", IF,
"in", IN,
"then", THEN,
"else", ELSE,
"elif", ELIF,
"until", UNTIL,
"fi", FI,
";;", BREAK,
"||", LOGOR,
"&&", LOGAND,
"{", '{',
"}", '}',
0,
};
int
rlookup(n)
register char *n;
{
register struct res *rp;
for (rp = restab; rp->r_name; rp++)
if (strcmp(rp->r_name, n) == 0)
return(rp->r_val);
return(0);
}
static struct op *
newtp()
{
register struct op *t;
t = (struct op *)tree(sizeof(*t));
t->type = 0;
t->words = NULL;
t->ioact = NULL;
t->left = NULL;
t->right = NULL;
t->str = NULL;
return(t);
}
static struct op *
namelist(t)
register struct op *t;
{
if (iolist) {
iolist = addword((char *)NULL, iolist);
t->ioact = copyio();
} else
t->ioact = NULL;
if (t->type != TCOM) {
if (t->type != TPAREN && t->ioact != NULL) {
t = block(TPAREN, t, NOBLOCK, NOWORDS);
t->ioact = t->left->ioact;
t->left->ioact = NULL;
}
return(t);
}
word(NOWORD);
t->words = copyw();
return(t);
}
static char **
copyw()
{
register char **wd;
wd = getwords(wdlist);
wdlist = 0;
return(wd);
}
static void
word(cp)
char *cp;
{
wdlist = addword(cp, wdlist);
}
static struct ioword **
copyio()
{
register struct ioword **iop;
iop = (struct ioword **) getwords(iolist);
iolist = 0;
return(iop);
}
static struct ioword *
io(u, f, cp)
int u;
int f;
char *cp;
{
register struct ioword *iop;
iop = (struct ioword *) tree(sizeof(*iop));
iop->io_unit = u;
iop->io_flag = f;
iop->io_name = cp;
iolist = addword((char *)iop, iolist);
return(iop);
}
static void
zzerr()
{
yyerror("syntax error");
}
void
yyerror(s)
char *s;
{
yynerrs++;
if (talking && e.iop <= iostack) {
multiline = 0;
while (eofc() == 0 && yylex(0) != '\n')
;
}
err(s);
fail();
}
static int
yylex(cf)
int cf;
{
register int c, c1;
int atstart;
if ((c = peeksym) > 0) {
peeksym = 0;
if (c == '\n')
startl = 1;
return(c);
}
nlseen = 0;
e.linep = line;
atstart = startl;
startl = 0;
yylval.i = 0;
loop:
while ((c = getc(0)) == ' ' || c == '\t')
;
switch (c) {
default:
if (any(c, "0123456789")) {
unget(c1 = getc(0));
if (c1 == '<' || c1 == '>') {
iounit = c - '0';
goto loop;
}
*e.linep++ = c;
c = c1;
}
break;
case '#':
while ((c = getc(0)) != 0 && c != '\n')
;
unget(c);
goto loop;
case 0:
return(c);
case '$':
*e.linep++ = c;
if ((c = getc(0)) == '{') {
if ((c = collect(c, '}')) != '\0')
return(c);
goto pack;
}
break;
case '`':
case '\'':
case '"':
if ((c = collect(c, c)) != '\0')
return(c);
goto pack;
case '|':
case '&':
case ';':
if ((c1 = dual(c)) != '\0') {
startl = 1;
return(c1);
}
startl = 1;
return(c);
case '^':
startl = 1;
return('|');
case '>':
case '<':
diag(c);
return(c);
case '\n':
nlseen++;
gethere();
startl = 1;
if (multiline || cf & CONTIN) {
if (talking && e.iop <= iostack)
prs(cprompt->value);
if (cf & CONTIN)
goto loop;
}
return(c);
case '(':
case ')':
startl = 1;
return(c);
}
unget(c);
pack:
while ((c = getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
if (e.linep >= elinep)
err("word too long");
else
*e.linep++ = c;
unget(c);
if(any(c, "\"'`$"))
goto loop;
*e.linep++ = '\0';
if (atstart && (c = rlookup(line))!=0) {
startl = 1;
return(c);
}
yylval.cp = strsave(line, areanum);
return(WORD);
}
int
collect(c, c1)
register c, c1;
{
char s[2];
*e.linep++ = c;
while ((c = getc(c1)) != c1) {
if (c == 0) {
unget(c);
s[0] = c1;
s[1] = 0;
prs("no closing "); yyerror(s);
return(YYERRCODE);
}
if (talking && c == '\n' && e.iop <= iostack)
prs(cprompt->value);
*e.linep++ = c;
}
*e.linep++ = c;
return(0);
}
int
dual(c)
register c;
{
char s[3];
register char *cp = s;
*cp++ = c;
*cp++ = getc(0);
*cp = 0;
if ((c = rlookup(s)) == 0)
unget(*--cp);
return(c);
}
static void
diag(ec)
register int ec;
{
register int c;
c = getc(0);
if (c == '>' || c == '<') {
if (c != ec)
zzerr();
yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE;
c = getc(0);
} else
yylval.i = ec == '>'? IOWRITE: IOREAD;
if (c != '&' || yylval.i == IOHERE)
unget(c);
else
yylval.i |= IODUP;
}
static char *
tree(size)
unsigned size;
{
register char *t;
if ((t = getcell(size)) == NULL) {
prs("command line too complicated\n");
fail();
/* NOTREACHED */
}
return(t);
}
/* VARARGS1 */
/* ARGSUSED */
void
printf(s) /* yyparse calls it */
char *s;
{
}