diff options
author | Tanaka Akira <akr@users.sourceforge.net> | 1999-04-15 18:05:38 +0000 |
---|---|---|
committer | Tanaka Akira <akr@users.sourceforge.net> | 1999-04-15 18:05:38 +0000 |
commit | e74702b467171dbdafb56dfe354794a212e020d9 (patch) | |
tree | c295b3e9b2e93e2de10331877442615b0f37e779 /Src/parse.c | |
parent | c175751b501a3a4cb40ad4787340a597ea769be4 (diff) | |
download | zsh-e74702b467171dbdafb56dfe354794a212e020d9.tar.gz zsh-e74702b467171dbdafb56dfe354794a212e020d9.tar.xz zsh-e74702b467171dbdafb56dfe354794a212e020d9.zip |
Initial revision
Diffstat (limited to 'Src/parse.c')
-rw-r--r-- | Src/parse.c | 1379 |
1 files changed, 1379 insertions, 0 deletions
diff --git a/Src/parse.c b/Src/parse.c new file mode 100644 index 000000000..d42be2f2f --- /dev/null +++ b/Src/parse.c @@ -0,0 +1,1379 @@ +/* + * parse.c - parser + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "zsh.mdh" +#include "parse.pro" + +/* != 0 if we are about to read a command word */ + +/**/ +int incmdpos; + +/* != 0 if we are in the middle of a [[ ... ]] */ + +/**/ +int incond; + +/* != 0 if we are after a redirection (for ctxtlex only) */ + +/**/ +int inredir; + +/* != 0 if we are about to read a case pattern */ + +/**/ +int incasepat; + +/* != 0 if we just read a newline */ + +/**/ +int isnewlin; + +/* != 0 if we are after a for keyword */ + +/**/ +int infor; + +/* list of here-documents */ + +/**/ +struct heredocs *hdocs; + +/* used in arrays of lists instead of NULL pointers */ + +/**/ +struct list dummy_list; + +#define YYERROR { tok = LEXERR; return NULL; } +#define YYERRORV { tok = LEXERR; return; } +#define COND_ERROR(X,Y) do{herrflush();zerr(X,Y,0);YYERROR}while(0) + +#define make_list() allocnode(N_LIST) +#define make_sublist() allocnode(N_SUBLIST) +#define make_pline() allocnode(N_PLINE) +#define make_cmd() allocnode(N_CMD) +#define make_forcmd() allocnode(N_FOR) +#define make_casecmd() allocnode(N_CASE) +#define make_ifcmd() allocnode(N_IF) +#define make_whilecmd() allocnode(N_WHILE) +#define make_varnode() allocnode(N_VARASG) +#define make_cond() allocnode(N_COND) + +/* + * event : ENDINPUT + * | SEPER + * | sublist [ SEPER | AMPER | AMPERBANG ] + */ +/**/ +List +parse_event(void) +{ + tok = ENDINPUT; + incmdpos = 1; + yylex(); + return par_event(); +} + +/**/ +static List +par_event(void) +{ + Sublist sl; + List l = NULL; + + while (tok == SEPER) { + if (isnewlin > 0) + return NULL; + yylex(); + } + if (tok == ENDINPUT) + return NULL; + if ((sl = par_sublist())) + if (tok == ENDINPUT) { + l = (List) make_list(); + l->type = Z_SYNC; + l->left = sl; + } else if (tok == SEPER) { + l = (List) make_list(); + l->type = Z_SYNC; + l->left = sl; + if (isnewlin <= 0) + yylex(); + } else if (tok == AMPER) { + l = (List) make_list(); + l->type = Z_ASYNC; + l->left = sl; + yylex(); + } else if (tok == AMPERBANG) { + l = (List) make_list(); + l->type = Z_ASYNC | Z_DISOWN; + l->left = sl; + yylex(); + } else + l = NULL; + if (!l) { + if (errflag) { + yyerror(); + return NULL; + } + herrflush(); + yyerror(); + return NULL; + } else { + l->right = par_event(); + } + return l; +} + +/**/ +List +parse_list(void) +{ + List ret; + + tok = ENDINPUT; + incmdpos = 1; + yylex(); + ret = par_list(); + if (tok == LEXERR) { + yyerror(); + return NULL; + } + return ret; +} + +/* + * list : { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ] + */ + +/**/ +static List +par_list(void) +{ + Sublist sl; + List l = NULL; + + while (tok == SEPER) + yylex(); + if ((sl = par_sublist())) + if (tok == SEPER || tok == AMPER || tok == AMPERBANG) { + l = (List) make_list(); + l->left = sl; + l->type = (tok == SEPER) ? Z_SYNC : + (tok == AMPER) ? Z_ASYNC : Z_ASYNC | Z_DISOWN; + incmdpos = 1; + do { + yylex(); + } while (tok == SEPER); + l->right = par_list(); + } else { + l = (List) make_list(); + l->left = sl; + l->type = Z_SYNC; + } + return l; +} + +/**/ +static List +par_list1(void) +{ + Sublist sl; + List l = NULL; + + if ((sl = par_sublist())) { + l = (List) make_list(); + l->type = Z_SYNC; + l->left = sl; + } + return l; +} + +/* + * sublist : sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ] + */ + +/**/ +static Sublist +par_sublist(void) +{ + Sublist sl; + + if ((sl = par_sublist2())) + if (tok == DBAR || tok == DAMPER) { + int qtok = tok; + + cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND); + yylex(); + while (tok == SEPER) + yylex(); + sl->right = par_sublist(); + sl->type = (qtok == DBAR) ? ORNEXT : ANDNEXT; + cmdpop(); + } + return sl; +} + +/* + * sublist2 : [ COPROC | BANG ] pline + */ + +/**/ +static Sublist +par_sublist2(void) +{ + Sublist sl; + Pline p; + + sl = (Sublist) make_sublist(); + if (tok == COPROC) { + sl->flags |= PFLAG_COPROC; + yylex(); + } else if (tok == BANG) { + sl->flags |= PFLAG_NOT; + yylex(); + } + if (!(p = par_pline()) && !sl->flags) + return NULL; + sl->left = p; + return sl; +} + +/* + * pline : cmd [ ( BAR | BARAMP ) { SEPER } pline ] + */ + +/**/ +static Pline +par_pline(void) +{ + Cmd c; + Pline p, p2; + + if (!(c = par_cmd())) + return NULL; + if (tok == BAR) { + cmdpush(CS_PIPE); + yylex(); + while (tok == SEPER) + yylex(); + p2 = par_pline(); + cmdpop(); + p = (Pline) make_pline(); + p->left = c; + p->right = p2; + p->type = PIPE; + return p; + } else if (tok == BARAMP) { + struct redir *rdr = (struct redir *)allocnode(N_REDIR); + + rdr->type = MERGEOUT; + rdr->fd1 = 2; + rdr->name = dupstring("1"); + addlinknode(c->redir, rdr); + + cmdpush(CS_ERRPIPE); + yylex(); + p2 = par_pline(); + cmdpop(); + p = (Pline) make_pline(); + p->left = c; + p->right = p2; + p->type = PIPE; + return p; + } else { + p = (Pline) make_pline(); + p->left = c; + p->type = END; + return p; + } +} + +/* + * cmd : { redir } ( for | case | if | while | repeat | + * subsh | funcdef | time | dinbrack | dinpar | simple ) { redir } + */ + +/**/ +static Cmd +par_cmd(void) +{ + Cmd c; + + c = (Cmd) make_cmd(); + c->lineno = lineno; + c->args = newlinklist(); + c->redir = newlinklist(); + c->vars = newlinklist(); + while (IS_REDIROP(tok)) + par_redir(c->redir); + switch (tok) { + case FOR: + cmdpush(CS_FOR); + par_for(c); + cmdpop(); + break; + case FOREACH: + cmdpush(CS_FOREACH); + par_for(c); + cmdpop(); + break; + case SELECT: + cmdpush(CS_SELECT); + par_for(c); + cmdpop(); + break; + case CASE: + cmdpush(CS_CASE); + par_case(c); + cmdpop(); + break; + case IF: + par_if(c); + break; + case WHILE: + cmdpush(CS_WHILE); + par_while(c); + cmdpop(); + break; + case UNTIL: + cmdpush(CS_UNTIL); + par_while(c); + cmdpop(); + break; + case REPEAT: + cmdpush(CS_REPEAT); + par_repeat(c); + cmdpop(); + break; + case INPAR: + cmdpush(CS_SUBSH); + par_subsh(c); + cmdpop(); + break; + case INBRACE: + cmdpush(CS_CURSH); + par_subsh(c); + cmdpop(); + break; + case FUNC: + cmdpush(CS_FUNCDEF); + par_funcdef(c); + cmdpop(); + break; + case TIME: + par_time(c); + break; + case DINBRACK: + cmdpush(CS_COND); + par_dinbrack(c); + cmdpop(); + break; + case DINPAR: + c->type = CARITH; + addlinknode(c->args, tokstr); + yylex(); + break; + default: + if (!par_simple(c)) + return NULL; + break; + } + while (IS_REDIROP(tok)) + par_redir(c->redir); + incmdpos = 1; + incasepat = 0; + incond = 0; + return c; +} + +/* + * for : ( FOR DINPAR expr SEMI expr SEMI expr DOUTPAR | + * ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR ) ) + * { SEPER } ( DO list DONE | INBRACE list OUTBRACE | list ZEND | list1 ) + */ + +/**/ +static void +par_for(Cmd c) +{ + Forcmd f; + int csh = (tok == FOREACH); + + f = (Forcmd) make_forcmd(); + c->type = (tok == SELECT) ? CSELECT : CFOR; + incmdpos = 0; + infor = tok == FOR ? 2 : 0; + yylex(); + if (tok == DINPAR) { + yylex(); + if (tok != DINPAR) + YYERRORV; + f->name = tokstr; + yylex(); + if (tok != DINPAR) + YYERRORV; + f->condition = tokstr; + yylex(); + if (tok != DOUTPAR) + YYERRORV; + f->advance = tokstr; + infor = 0; + incmdpos = 1; + yylex(); + } else { + infor = 0; + if (tok != STRING || !isident(tokstr)) + YYERRORV; + f->name = tokstr; + incmdpos = 1; + yylex(); + if (tok == STRING && !strcmp(tokstr, "in")) { + f->inflag = 1; + incmdpos = 0; + yylex(); + c->args = par_wordlist(); + if (tok != SEPER) + YYERRORV; + } else if (tok == INPAR) { + f->inflag = 1; + incmdpos = 0; + yylex(); + c->args = par_nl_wordlist(); + if (tok != OUTPAR) + YYERRORV; + incmdpos = 1; + yylex(); + } + } + incmdpos = 1; + while (tok == SEPER) + yylex(); + if (tok == DO) { + yylex(); + f->list = par_list(); + if (tok != DONE) + YYERRORV; + yylex(); + } else if (tok == INBRACE) { + yylex(); + f->list = par_list(); + if (tok != OUTBRACE) + YYERRORV; + yylex(); + } else if (csh || isset(CSHJUNKIELOOPS)) { + f->list = par_list(); + if (tok != ZEND) + YYERRORV; + yylex(); + } else if (unset(SHORTLOOPS)) { + YYERRORV; + } else + f->list = par_list1(); + c->u.forcmd = f; +} + +/* + * case : CASE STRING { SEPER } ( "in" | INBRACE ) + { { SEPER } STRING { BAR STRING } OUTPAR + list [ DSEMI | SEMIAMP ] } + { SEPER } ( "esac" | OUTBRACE ) + */ + +/**/ +static void +par_case(Cmd c) +{ + int brflag; + LinkList pats, lists; + int n = 1; + char **pp; + List *ll; + LinkNode no; + struct casecmd *cc; + + c->type = CCASE; + incmdpos = 0; + yylex(); + if (tok != STRING) + YYERRORV; + pats = newlinklist(); + addlinknode(pats, tokstr); + incmdpos = 1; + yylex(); + while (tok == SEPER) + yylex(); + if (!(tok == STRING && !strcmp(tokstr, "in")) && tok != INBRACE) + YYERRORV; + brflag = (tok == INBRACE); + incasepat = 1; + incmdpos = 0; + yylex(); + cc = c->u.casecmd = (struct casecmd *)make_casecmd(); + lists = newlinklist(); + for (;;) { + char *str; + + while (tok == SEPER) + yylex(); + if (tok == OUTBRACE) + break; + if (tok != STRING) + YYERRORV; + if (!strcmp(tokstr, "esac")) + break; + str = ncalloc(strlen(tokstr) + 2); + *str = ';'; + strcpy(str + 1, tokstr); + incasepat = 0; + incmdpos = 1; + for (;;) { + yylex(); + if (tok == OUTPAR) { + incasepat = 0; + incmdpos = 1; + yylex(); + break; + } else if (tok == BAR) { + char *str2; + int sl = strlen(str); + + incasepat = 1; + incmdpos = 0; + str2 = ncalloc(sl + 2); + strcpy(str2, str); + str2[sl] = Bar; + str2[sl+1] = '\0'; + str = str2; + } else { + int sl = strlen(str); + + if (str[sl - 1] != Bar) { + /* POSIX allows (foo*) patterns */ + int pct; + char *s; + + for (s = str + 1, pct = 0; *s; s++) { + if (*s == Inpar) + pct++; + if (!pct) + break; + if (pct == 1) { + if (*s == Bar || *s == Inpar) + while (iblank(s[1])) + chuck(s+1); + if (*s == Bar || *s == Outpar) + while (iblank(s[-1]) && + (s < str+2 || s[-2] != Meta)) + chuck(--s); + } + if (*s == Outpar) + pct--; + } + if (*s || pct || s == str + 1) + YYERRORV; + break; + } else { + char *str2; + + if (tok != STRING) + YYERRORV; + str2 = ncalloc(sl + strlen(tokstr) + 1); + strcpy(str2, str); + strcpy(str2 + sl, tokstr); + str = str2; + } + } + } + addlinknode(pats, str); + addlinknode(lists, par_list()); + n++; + if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) + break; + if(tok == SEMIAMP) + *str = '&'; + else if (tok != DSEMI) + YYERRORV; + incasepat = 1; + incmdpos = 0; + yylex(); + } + + incmdpos = 1; + yylex(); + + cc->pats = (char **)alloc((n + 1) * sizeof(char *)); + + for (pp = cc->pats, no = firstnode(pats); no; incnode(no)) + *pp++ = (char *)getdata(no); + *pp = NULL; + cc->lists = (List *) alloc((n + 1) * sizeof(List)); + for (ll = cc->lists, no = firstnode(lists); no; incnode(no), ll++) + if (!(*ll = (List) getdata(no))) + *ll = &dummy_list; + *ll = NULL; +} + +/* + * if : { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list ) + { SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) } + [ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ] + (you get the idea...?) + */ + +/**/ +static void +par_if(Cmd c) +{ + struct ifcmd *i; + int xtok; + unsigned char nc; + LinkList ifsl, thensl; + LinkNode no; + int ni = 0, nt = 0, usebrace = 0; + List l, *ll; + + ifsl = newlinklist(); + thensl = newlinklist(); + + c->type = CIF; + for (;;) { + xtok = tok; + cmdpush(xtok == IF ? CS_IF : CS_ELIF); + yylex(); + if (xtok == FI) + break; + if (xtok == ELSE) + break; + while (tok == SEPER) + yylex(); + if (!(xtok == IF || xtok == ELIF)) { + cmdpop(); + YYERRORV; + } + addlinknode(ifsl, par_list()); + ni++; + incmdpos = 1; + while (tok == SEPER) + yylex(); + xtok = FI; + nc = cmdstack[cmdsp - 1] == CS_IF ? CS_IFTHEN : CS_ELIFTHEN; + if (tok == THEN) { + usebrace = 0; + cmdpop(); + cmdpush(nc); + yylex(); + addlinknode(thensl, par_list()); + nt++; + incmdpos = 1; + cmdpop(); + } else { + if (tok == INBRACE) { + usebrace = 1; + cmdpop(); + cmdpush(nc); + yylex(); + l = par_list(); + if (tok != OUTBRACE) { + cmdpop(); + YYERRORV; + } + addlinknode(thensl, l); + nt++; + yylex(); + incmdpos = 1; + if (tok == SEPER) + break; + cmdpop(); + } else if (unset(SHORTLOOPS)) { + cmdpop(); + YYERRORV; + } else { + cmdpop(); + cmdpush(nc); + addlinknode(thensl, par_list1()); + nt++; + incmdpos = 1; + break; + } + } + } + cmdpop(); + if (xtok == ELSE) { + cmdpush(CS_ELSE); + while (tok == SEPER) + yylex(); + if (tok == INBRACE && usebrace) { + yylex(); + l = par_list(); + if (tok != OUTBRACE) { + cmdpop(); + YYERRORV; + } + } else { + l = par_list(); + if (tok != FI) { + cmdpop(); + YYERRORV; + } + } + addlinknode(thensl, l); + nt++; + yylex(); + cmdpop(); + } + i = (struct ifcmd *)make_ifcmd(); + i->ifls = (List *) alloc((ni + 1) * sizeof(List)); + i->thenls = (List *) alloc((nt + 1) * sizeof(List)); + + for (ll = i->ifls, no = firstnode(ifsl); no; incnode(no), ll++) + if (!(*ll = (List) getdata(no))) + *ll = &dummy_list; + *ll = NULL; + for (ll = i->thenls, no = firstnode(thensl); no; incnode(no), ll++) + if (!(*ll = (List) getdata(no))) + *ll = &dummy_list; + *ll = NULL; + + c->u.ifcmd = i; +} + +/* + * while : ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER } + ( DO list DONE | INBRACE list OUTBRACE | list ZEND ) + */ + +/**/ +static void +par_while(Cmd c) +{ + struct whilecmd *w; + + c->type = CWHILE; + w = c->u.whilecmd = (struct whilecmd *)make_whilecmd(); + w->cond = (tok == UNTIL); + yylex(); + w->cont = par_list(); + incmdpos = 1; + while (tok == SEPER) + yylex(); + if (tok == DO) { + yylex(); + w->loop = par_list(); + if (tok != DONE) + YYERRORV; + yylex(); + } else if (tok == INBRACE) { + yylex(); + w->loop = par_list(); + if (tok != OUTBRACE) + YYERRORV; + yylex(); + } else if (isset(CSHJUNKIELOOPS)) { + w->loop = par_list(); + if (tok != ZEND) + YYERRORV; + yylex(); + } else + YYERRORV; +} + +/* + * repeat : REPEAT STRING { SEPER } ( DO list DONE | list1 ) + */ + +/**/ +static void +par_repeat(Cmd c) +{ + c->type = CREPEAT; + incmdpos = 0; + yylex(); + if (tok != STRING) + YYERRORV; + addlinknode(c->args, tokstr); + incmdpos = 1; + yylex(); + while (tok == SEPER) + yylex(); + if (tok == DO) { + yylex(); + c->u.list = par_list(); + if (tok != DONE) + YYERRORV; + yylex(); + } else if (tok == INBRACE) { + yylex(); + c->u.list = par_list(); + if (tok != OUTBRACE) + YYERRORV; + yylex(); + } else if (isset(CSHJUNKIELOOPS)) { + c->u.list = par_list(); + if (tok != ZEND) + YYERRORV; + yylex(); + } else if (unset(SHORTLOOPS)) { + YYERRORV; + } else + c->u.list = par_list1(); +} + +/* + * subsh : ( INPAR | INBRACE ) list ( OUTPAR | OUTBRACE ) + */ + +/**/ +static void +par_subsh(Cmd c) +{ + c->type = (tok == INPAR) ? SUBSH : CURSH; + yylex(); + c->u.list = par_list(); + if (tok != ((c->type == SUBSH) ? OUTPAR : OUTBRACE)) + YYERRORV; + incmdpos = 1; + yylex(); +} + +/* + * funcdef : FUNCTION wordlist [ INOUTPAR ] { SEPER } + * ( list1 | INBRACE list OUTBRACE ) + */ + +/**/ +static void +par_funcdef(Cmd c) +{ + nocorrect = 1; + incmdpos = 0; + yylex(); + c->type = FUNCDEF; + c->args = newlinklist(); + incmdpos = 1; + while (tok == STRING) { + if (*tokstr == Inbrace && !tokstr[1]) { + tok = INBRACE; + break; + } + addlinknode(c->args, tokstr); + yylex(); + } + nocorrect = 0; + if (tok == INOUTPAR) + yylex(); + while (tok == SEPER) + yylex(); + if (tok == INBRACE) { + yylex(); + c->u.list = par_list(); + if (tok != OUTBRACE) + YYERRORV; + yylex(); + } else if (unset(SHORTLOOPS)) { + YYERRORV; + } else + c->u.list = par_list1(); +} + +/* + * time : TIME sublist2 + */ + +/**/ +static void +par_time(Cmd c) +{ + yylex(); + c->type = ZCTIME; + c->u.pline = par_sublist2(); +} + +/* + * dinbrack : DINBRACK cond DOUTBRACK + */ + +/**/ +static void +par_dinbrack(Cmd c) +{ + c->type = COND; + incond = 1; + incmdpos = 0; + yylex(); + c->u.cond = par_cond(); + if (tok != DOUTBRACK) + YYERRORV; + incond = 0; + incmdpos = 1; + yylex(); +} + +/* + * simple : { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH } + { STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir } + [ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ] + */ + +/**/ +static Cmd +par_simple(Cmd c) +{ + int isnull = 1; + + c->type = SIMPLE; + for (;;) { + if (tok == NOCORRECT) + nocorrect = 1; + else if (tok == ENVSTRING) { + struct varasg *v = (struct varasg *)make_varnode(); + + v->type = PM_SCALAR; + equalsplit(v->name = tokstr, &v->str); + addlinknode(c->vars, v); + isnull = 0; + } else if (tok == ENVARRAY) { + struct varasg *v = (struct varasg *)make_varnode(); + int oldcmdpos = incmdpos; + + v->type = PM_ARRAY; + incmdpos = 0; + v->name = tokstr; + cmdpush(CS_ARRAY); + yylex(); + v->arr = par_nl_wordlist(); + cmdpop(); + if (tok != OUTPAR) + YYERROR; + incmdpos = oldcmdpos; + addlinknode(c->vars, v); + isnull = 0; + } else + break; + yylex(); + } + if (tok == AMPER || tok == AMPERBANG) + YYERROR; + for (;;) { + if (tok == STRING) { + incmdpos = 0; + addlinknode(c->args, tokstr); + yylex(); + } else if (IS_REDIROP(tok)) { + par_redir(c->redir); + } else if (tok == INOUTPAR) { + incmdpos = 1; + cmdpush(CS_FUNCDEF); + yylex(); + while (tok == SEPER) + yylex(); + if (tok == INBRACE) { + yylex(); + c->u.list = par_list(); + if (tok != OUTBRACE) { + cmdpop(); + YYERROR; + } + yylex(); + } else + c->u.list = (List) expandstruct((struct node *) par_cmd(), N_LIST); + cmdpop(); + c->type = FUNCDEF; + } else + break; + isnull = 0; + } + if (isnull && empty(c->redir)) + return NULL; + incmdpos = 1; + return c; +} + +/* + * condlex is yylex for normal parsing, but is altered to allow + * the test builtin to use par_cond. + */ + +/**/ +void (*condlex) _((void)) = yylex; + +/* + * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ] + */ + +/**/ +Cond +par_cond(void) +{ + Cond c, c2; + + c = par_cond_1(); + while (tok == SEPER) + condlex(); + if (tok == DBAR) { + condlex(); + while (tok == SEPER) + condlex(); + c2 = (Cond) make_cond(); + c2->left = (void *) c; + c2->right = (void *) par_cond(); + c2->type = COND_OR; + return c2; + } + return c; +} + +/* + * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ] + */ + +/**/ +static Cond +par_cond_1(void) +{ + Cond c, c2; + + c = par_cond_2(); + while (tok == SEPER) + condlex(); + if (tok == DAMPER) { + condlex(); + while (tok == SEPER) + condlex(); + c2 = (Cond) make_cond(); + c2->left = (void *) c; + c2->right = (void *) par_cond_1(); + c2->type = COND_AND; + return c2; + } + return c; +} + +/* + * cond_2 : BANG cond_2 + | INPAR { SEPER } cond_2 { SEPER } OUTPAR + | STRING STRING STRING + | STRING STRING + | STRING ( INANG | OUTANG ) STRING + */ + +/**/ +static Cond +par_cond_2(void) +{ + Cond c, c2; + char *s1, *s2, *s3; + int dble = 0; + + if (condlex == testlex) { + /* See the description of test in POSIX 1003.2 */ + if (tok == NULLTOK) + /* no arguments: false */ + return par_cond_double(dupstring("-n"), dupstring("")); + if (!*testargs) { + /* one argument: [ foo ] is equivalent to [ -n foo ] */ + s1 = tokstr; + condlex(); + return par_cond_double(dupstring("-n"), s1); + } + if (testargs[1] && !testargs[2]) { + /* three arguments: if the second argument is a binary operator, * + * perform that binary test on the first and the trird argument */ + if (!strcmp(*testargs, "=") || + !strcmp(*testargs, "==") || + !strcmp(*testargs, "!=") || + (**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { + s1 = tokstr; + condlex(); + s2 = tokstr; + condlex(); + s3 = tokstr; + condlex(); + return par_cond_triple(s1, s2, s3); + } + } + } + if (tok == BANG) { + condlex(); + c = par_cond_2(); + c2 = (Cond) make_cond(); + c2->left = (void *) c; + c2->type = COND_NOT; + return c2; + } + if (tok == INPAR) { + condlex(); + while (tok == SEPER) + condlex(); + c = par_cond(); + while (tok == SEPER) + condlex(); + if (tok != OUTPAR) + YYERROR; + condlex(); + return c; + } + if (tok != STRING) + if (tok && tok != LEXERR && condlex == testlex) { + s1 = tokstr; + condlex(); + return par_cond_double("-n", s1); + } else + YYERROR; + s1 = tokstr; + if (condlex == testlex) + dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1 + && !s1[2]); + condlex(); + if (tok == INANG || tok == OUTANG) { + int xtok = tok; + condlex(); + if (tok != STRING) + YYERROR; + s3 = tokstr; + condlex(); + c = (Cond) make_cond(); + c->left = (void *) s1; + c->right = (void *) s3; + c->type = (xtok == INANG) ? COND_STRLT : COND_STRGTR; + c->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); + return c; + } + if (tok != STRING) + if (tok != LEXERR && condlex == testlex) { + if (!dble) + return par_cond_double("-n", s1); + else if (!strcmp(s1, "-t")) + return par_cond_double(s1, "1"); + } else + YYERROR; + s2 = tokstr; + incond++; /* parentheses do globbing */ + condlex(); + incond--; /* parentheses do grouping */ + if (tok == STRING && !dble) { + s3 = tokstr; + condlex(); + return par_cond_triple(s1, s2, s3); + } else + return par_cond_double(s1, s2); +} + +/* + * redir : ( OUTANG | ... | TRINANG ) STRING + */ + +static int redirtab[TRINANG - OUTANG + 1] = { + WRITE, + WRITENOW, + APP, + APPNOW, + READ, + READWRITE, + HEREDOC, + HEREDOCDASH, + MERGEIN, + MERGEOUT, + ERRWRITE, + ERRWRITENOW, + ERRAPP, + ERRAPPNOW, + HERESTR, +}; + +/**/ +static void +par_redir(LinkList l) +{ + struct redir *fn = (struct redir *)allocnode(N_REDIR); + int oldcmdpos, oldnc; + + oldcmdpos = incmdpos; + incmdpos = 0; + oldnc = nocorrect; + if (tok != INANG && tok != INOUTANG) + nocorrect = 1; + fn->type = redirtab[tok - OUTANG]; + fn->fd1 = tokfd; + yylex(); + if (tok != STRING && tok != ENVSTRING) + YYERRORV; + incmdpos = oldcmdpos; + nocorrect = oldnc; + + /* assign default fd */ + if (fn->fd1 == -1) + fn->fd1 = IS_READFD(fn->type) ? 0 : 1; + + fn->name = tokstr; + + switch (fn->type) { + case HEREDOC: + case HEREDOCDASH: { + /* <<[-] name */ + struct heredocs **hd; + + for (hd = &hdocs; *hd; hd = &(*hd)->next); + *hd = zalloc(sizeof(struct heredocs)); + (*hd)->next = NULL; + (*hd)->rd = fn; + break; + } + case WRITE: + case WRITENOW: + if (tokstr[0] == Outang && tokstr[1] == Inpar) + /* > >(...) */ + fn->type = OUTPIPE; + else if (tokstr[0] == Inang && tokstr[1] == Inpar) + YYERRORV; + break; + case READ: + if (tokstr[0] == Inang && tokstr[1] == Inpar) + /* < <(...) */ + fn->type = INPIPE; + else if (tokstr[0] == Outang && tokstr[1] == Inpar) + YYERRORV; + break; + case READWRITE: + if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar) + fn->type = tokstr[0] == Inang ? INPIPE : OUTPIPE; + break; + } + yylex(); + addlinknode(l, fn); +} + +/* + * wordlist : { STRING } + */ + +/**/ +static LinkList +par_wordlist(void) +{ + LinkList l; + + l = newlinklist(); + while (tok == STRING) { + addlinknode(l, tokstr); + yylex(); + } + return l; +} + +/* + * nl_wordlist : { STRING | SEPER } + */ + +/**/ +static LinkList +par_nl_wordlist(void) +{ + LinkList l; + + l = newlinklist(); + while (tok == STRING || tok == SEPER) { + if (tok != SEPER) + addlinknode(l, tokstr); + yylex(); + } + return l; +} + +/**/ +static Cond +par_cond_double(char *a, char *b) +{ + Cond n = (Cond) make_cond(); + + if (a[0] != '-' || !a[1] || a[2]) + COND_ERROR("parse error: condition expected: %s", a); + n->left = (void *) b; + n->type = a[1]; + n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); + return n; +} + +/**/ +static int +get_cond_num(char *tst) +{ + static char *condstrs[] = + { + "nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL + }; + int t0; + + for (t0 = 0; condstrs[t0]; t0++) + if (!strcmp(condstrs[t0], tst)) + return t0; + return -1; +} + +/**/ +static Cond +par_cond_triple(char *a, char *b, char *c) +{ + Cond n = (Cond) make_cond(); + int t0; + + if ((b[0] == Equals || b[0] == '=') && + (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) + n->type = COND_STREQ; + else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) + n->type = COND_STRNEQ; + else if (b[0] == '-') { + if ((t0 = get_cond_num(b + 1)) > -1) + n->type = t0 + COND_NT; + else + COND_ERROR("unrecognized condition: %s", b); + } else + COND_ERROR("condition expected: %s", b); + n->left = (void *) a; + n->right = (void *) c; + n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); + return n; +} + +/**/ +static void +yyerror(void) +{ + int t0; + + for (t0 = 0; t0 != 20; t0++) + if (!yytext || !yytext[t0] || yytext[t0] == '\n') + break; + if (t0 == 20) + zerr("parse error near `%l...'", yytext, 20); + else if (t0) + zerr("parse error near `%l'", yytext, t0); + else + zerr("parse error", NULL, 0); +} |