From 2b37049c221501c6ae77e0308634aebcdb10060d Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Wed, 23 Feb 2000 15:13:27 +0000 Subject: manual/9838 --- Src/parse.c | 2875 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 1266 insertions(+), 1609 deletions(-) (limited to 'Src/parse.c') diff --git a/Src/parse.c b/Src/parse.c index 8d72b4826..2351b1501 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -28,182 +28,6 @@ */ #include "zsh.mdh" - -/********************************/ -/* Definitions for syntax trees */ -/********************************/ - -typedef struct cond *Cond; -typedef struct cmd *Cmd; -typedef struct pline *Pline; -typedef struct sublist *Sublist; -typedef struct list *List; -typedef struct forcmd *Forcmd; -typedef struct autofn *AutoFn; -typedef struct varasg *Varasg; - - -/* struct list, struct sublist, struct pline, etc. all fit the form * - * of this structure and are used interchangably. The ptrs may hold * - * integers or pointers, depending on the type of the node. */ - -/* Generic node structure for syntax trees */ -struct node { - int ntype; /* node type */ -}; - -#define N_LIST 0 -#define N_SUBLIST 1 -#define N_PLINE 2 -#define N_CMD 3 -#define N_REDIR 4 -#define N_COND 5 -#define N_FOR 6 -#define N_CASE 7 -#define N_IF 8 -#define N_WHILE 9 -#define N_VARASG 10 -#define N_AUTOFN 11 -#define N_COUNT 12 - -/* values for types[4] */ - -#define NT_EMPTY 0 -#define NT_NODE 1 -#define NT_STR 2 -#define NT_PAT 3 -#define NT_LIST 4 -#define NT_ARR 8 - -#define NT_TYPE(T) ((T) & 0xff) -#define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf) -#define NT_SET(T0, T1, T2, T3, T4) \ - ((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20)) - -/* tree element for lists */ - -struct list { - int ntype; /* node type */ - int type; - Sublist left; - List right; -}; - -/* tree element for sublists */ - -struct sublist { - int ntype; /* node type */ - int type; - int flags; /* see PFLAGs below */ - Pline left; - Sublist right; -}; - -#define ORNEXT 10 /* || */ -#define ANDNEXT 11 /* && */ - -#define PFLAG_NOT 1 /* ! ... */ -#define PFLAG_COPROC 32 /* coproc ... */ - -/* tree element for pipes */ - -struct pline { - int ntype; /* node type */ - int type; - Cmd left; - Pline right; -}; - -#define END 0 /* pnode *right is null */ -#define PIPE 1 /* pnode *right is the rest of the pipeline */ - -/* tree element for commands */ - -struct cmd { - int ntype; /* node type */ - int type; - int flags; /* see CFLAGs below */ - int lineno; /* lineno of script for command */ - union { - List list; /* for SUBSH/CURSH/SHFUNC */ - Forcmd forcmd; - struct casecmd *casecmd; - struct ifcmd *ifcmd; - struct whilecmd *whilecmd; - Sublist pline; - Cond cond; - AutoFn autofn; - void *generic; - } u; - LinkList args; /* command & argmument List (char *'s) */ - LinkList redir; /* i/o redirections (struct redir *'s) */ - LinkList vars; /* param assignments (struct varasg *'s) */ -}; - -/* cmd types */ -#define SIMPLE 0 -#define SUBSH 1 -#define CURSH 2 -#define ZCTIME 3 -#define FUNCDEF 4 -#define CFOR 5 -#define CWHILE 6 -#define CREPEAT 7 -#define CIF 8 -#define CCASE 9 -#define CSELECT 10 -#define COND 11 -#define CARITH 12 - -/* tree element for conditionals */ - -struct cond { - int ntype; /* node type */ - int type; /* can be cond_type, or a single */ - /* letter (-a, -b, ...) */ - void *left, *right; -}; - -struct forcmd { /* for/select */ -/* Cmd->args contains list of words to loop thru */ - int ntype; /* node type */ - int inflag; /* if there is an in ... clause */ - char *name; /* initializer or parameter name */ - char *condition; /* arithmetic terminating condition */ - char *advance; /* evaluated after each loop */ - List list; /* list to look through for each name */ -}; - -struct casecmd { -/* Cmd->args contains word to test */ - int ntype; /* node type */ - char **pats; /* pattern strings */ - List *lists; /* list to execute */ -}; - -struct ifcmd { - int ntype; /* node type */ - List *ifls; - List *thenls; -}; - -struct whilecmd { - int ntype; /* node type */ - int cond; /* 0 for while, 1 for until */ - List cont; /* condition */ - List loop; /* list to execute until condition met */ -}; - -/* variable assignment tree element */ - -struct varasg { - int ntype; /* node type */ - int type; /* nonzero means array */ - char *name; - char *str; /* should've been a union here. oh well */ - LinkList arr; -}; - #include "parse.pro" /* != 0 if we are about to read a command word */ @@ -241,191 +65,543 @@ int infor; /**/ struct heredocs *hdocs; -/* used in arrays of lists instead of NULL pointers */ - -/**/ -static struct list dummy_list; -#define YYERROR { tok = LEXERR; return NULL; } -#define YYERRORV { tok = LEXERR; return; } +#define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } +#define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } #define COND_ERROR(X,Y) do { \ zwarn(X,Y,0); \ herrflush(); \ if (noerrs != 2) \ errflag = 1; \ - YYERROR \ + YYERROR(ecused) \ } while(0) -#define make_list() allocnode(sizeof(struct list), N_LIST) -#define make_sublist() allocnode(sizeof(struct sublist), N_SUBLIST) -#define make_pline() allocnode(sizeof(struct pline), N_PLINE) -#define make_cmd() allocnode(sizeof(struct cmd), N_CMD) -#define make_forcmd() allocnode(sizeof(struct forcmd), N_FOR) -#define make_casecmd() allocnode(sizeof(struct casecmd), N_CASE) -#define make_ifcmd() allocnode(sizeof(struct ifcmd), N_IF) -#define make_whilecmd() allocnode(sizeof(struct whilecmd), N_WHILE) -#define make_varnode() allocnode(sizeof(struct varasg), N_VARASG) -#define make_cond() allocnode(sizeof(struct cond), N_COND) - -static void * -allocnode(size_t s, int t) -{ - struct node *r = (struct node *) hcalloc(s); - - r->ntype = t; - - return (void *) r; -} -/* - * event : ENDINPUT - * | SEPER - * | sublist [ SEPER | AMPER | AMPERBANG ] +/* + * Word code. + * + * For now we simply post-process the syntax tree produced by the + * parser. We compile it into a struct eprog. Some day the parser + * above should be changed to emit the word code directly. + * + * Word code layout: + * + * WC_END + * - end of program code + * + * WC_LIST + * - data contains type (sync, ...) + * - follwed by code for this list + * - if not (type & Z_END), followed by next WC_LIST + * + * WC_SUBLIST + * - data contains type (&&, ||, END) and flags (coprog, not) + * - followed by code for sublist + * - if not (type == END), followed by next WC_SUBLIST + * + * WC_PIPE + * - data contains type (end, mid) and LINENO + * - if not (type == END), followed by offset to next WC_PIPE + * - followed by command + * - if not (type == END), followed by next WC_PIPE + * + * WC_REDIR + * - must precede command-code (or WC_ASSIGN) + * - data contains type (<, >, ...) + * - followed by fd1 and name from struct redir + * + * WC_ASSIGN + * - data contains type (scalar, array) and number of array-elements + * - followed by name and value + * + * WC_SIMPLE + * - data contains the number of arguments (plus command) + * - followed by strings + * + * WC_SUBSH + * - data unused + * - followed by list + * + * WC_CURSH + * - data unused + * - followed by list + * + * WC_TIMED + * - data contains type (followed by pipe or not) + * - if (type == PIPE), followed by pipe + * + * WC_FUNCDEF + * - data contains offset to after body-strings + * - followed by number of names + * - followed by names + * - followed by number of codes for body + * - followed by number of patterns for body + * - follwoed by codes for body + * - followed by strings for body + * + * WC_FOR + * - data contains type (list, ...) and offset to after body + * - if (type == COND), followed by init, cond, advance expressions + * - else if (type == PPARAM), followed by param name + * - else if (type == LIST), followed by param name, num strings, strings + * - followed by body + * + * WC_SELECT + * - data contains type (list, ...) and offset to after body + * - if (type == PPARAM), followed by param name + * - else if (type == LIST), followed by param name, num strings, strings + * - followed by body + * + * WC_WHILE + * - data contains type (while, until) and ofsset to after body + * - followed by condition + * - followed by body + * + * WC_REPEAT + * - data contains offset to after body + * - followed by number-string + * - followed by body + * + * WC_CASE + * - first CASE is always of type HEAD, data contains offset to esac + * - after that CASEs of type OR (;;) and AND (;&), data is offset to + * next case + * - each OR/AND case is followed by pattern, pattern-number, list + * + * WC_IF + * - first IF is of type HEAD, data contains offset to fi + * - after that IFs of type IF, ELIF, ELSE, data is offset to next + * - each non-HEAD is followed by condition (only IF, ELIF) and body + * + * WC_COND + * - data contains type + * - if (type == AND/OR), data contains offset to after this one, + * followed by two CONDs + * - else if (type == NOT), followed by COND + * - else if (type == MOD), followed by name and strings + * - else if (type == MODI), followed by name, left, right + * - else if (type == STR[N]EQ), followed by left, right, pattern-number + * - else if (has two args) followed by left, right + * - else followed by string + * + * WC_ARITH + * - followed by string (there's only one) + * + * WC_AUTOFN + * - only used by the autoload builtin + * + * Lists and sublists may also be simplified, indicated by the presence + * of the Z_SIMPLE or WC_SUBLIST_SIMPLE flags. In this case they are only + * followed by a slot containing the line number, not by a WC_SUBLIST or + * WC_PIPE, respectively. The real advantage of simplified lists and + * sublists is that they can be executed faster, see exec.c. In the + * parser, the test if a list can be simplified is done quite simply + * by passing a int* around which gets set to non-zero if the thing + * just parsed is `complex', i.e. may need to be run by forking or + * some such. + * + * In each of the above, strings are encoded as one word code. For empty + * strings this is the bit pattern 11x, the lowest bit is non-zero if the + * string contains tokens and zero otherwise (this is true for the other + * ways to encode strings, too). For short strings (one to three + * characters), this is the marker 01x with the 24 bits above that + * containing the characters. Longer strings are encoded as the offset + * into the strs character array stored in the eprog struct shifted by + * two and ored with the bit pattern 0x. + * The ecstr() function that adds the code for a string uses a simple + * list of strings already added so that long strings are encoded only + * once. + * + * Note also that in the eprog struct the pattern, code, and string + * arrays all point to the same memory block. + * + * + * To make things even faster in future versions, we could not only + * test if the strings contain tokens, but instead what kind of + * expansions need to be done on strings. In the execution code we + * could then use these flags for a specialized version of prefork() + * to avoid a lot of string parsing and some more string duplication. */ -/**/ -Eprog -parse_event(void) -{ - List ret; - tok = ENDINPUT; - incmdpos = 1; - yylex(); - return ((ret = par_event()) ? execompile(ret) : NULL); -} /**/ -static List -par_event(void) -{ - Sublist sl; - List l = NULL; +int eclen, ecused, ecfree, ecnpats; +/**/ +Wordcode ecbuf; +/**/ +Eccstr ecstrs; +/**/ +int ecsoffs; - 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(0); - return NULL; - } - yyerror(1); - herrflush(); - if (noerrs != 2) - errflag = 1; - return NULL; - } else { - l->right = par_event(); - } - return l; -} +/* Make at least n bytes free (aligned to sizeof(wordcode)). */ -/**/ -mod_export Eprog -parse_list(void) +static int +ecspace(int n) { - List ret; + n = (n + sizeof(wordcode) - 1) / sizeof(wordcode); - tok = ENDINPUT; - incmdpos = 1; - yylex(); - ret = par_list(); -#if 0 - if (tok == LEXERR) -#endif - if (tok != ENDINPUT) - { - yyerror(0); - return NULL; + if (ecfree < n) { + int a = (n > 256 ? n : 256); + + ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), + (eclen + a) * sizeof(wordcode)); + eclen += a; + ecfree += a; } - return execompile(ret); + ecused += n; + ecfree -= n; + + return ecused - 1; } -/**/ -mod_export Eprog -parse_cond(void) +/* Insert n free code-slots at position p. */ + +static void +ecispace(int p, int n) { - Cond c = par_cond(); + int m; - if (!c) - return NULL; + if (ecfree < n) { + int a = (n > 256 ? n : 256); - return execompile((List) c); + ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), + (eclen + a) * sizeof(wordcode)); + eclen += a; + ecfree += a; + } + if ((m = ecused - p) > 0) + memmove(ecbuf + p + n, ecbuf + p, m * sizeof(wordcode)); + ecused += n; } -/* - * list : { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ] - */ +/* Add one wordcode. */ -/**/ -static List -par_list(void) +static int +ecadd(wordcode c) +{ + if (ecfree < 1) { + ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), + (eclen + 256) * sizeof(wordcode)); + eclen += 256; + ecfree += 256; + } + ecbuf[ecused] = c; + ecused++; + ecfree--; + + return ecused - 1; +} + +/* Delete a wordcode. */ + +static void +ecdel(int p) +{ + int n = ecused - p - 1; + + if (n > 0) + memmove(ecbuf + p, ecbuf + p + 1, n * sizeof(wordcode)); + ecused--; +} + +/* Build the wordcode for a string. */ + +static wordcode +ecstrcode(char *s) +{ + int l, t = has_token(s); + + if ((l = strlen(s) + 1) && l <= 4) { + wordcode c = (t ? 3 : 2); + switch (l) { + case 4: c |= ((wordcode) STOUC(s[2])) << 19; + case 3: c |= ((wordcode) STOUC(s[1])) << 11; + case 2: c |= ((wordcode) STOUC(s[0])) << 3; break; + case 1: c = (t ? 7 : 6); break; + } + return c; + } else { + Eccstr p, q = NULL; + + for (p = ecstrs; p; q = p, p = p->next) + if (!strcmp(s, p->str)) + return p->offs; + + p = (Eccstr) zhalloc(sizeof(*p)); + p->next = NULL; + if (q) + q->next = p; + else + ecstrs = p; + p->offs = (ecsoffs << 2) | (t ? 1 : 0); + p->str = s; + ecsoffs += l; + + return p->offs; + } +} + +static int +ecstr(char *s) +{ + return ecadd(ecstrcode(s)); +} + + +#define par_save_list(C) \ + do { \ + int eu = ecused; \ + par_list(C); \ + if (eu == ecused) ecadd(WCB_END()); \ + } while (0) +#define par_save_list1(C) \ + do { \ + int eu = ecused; \ + par_list1(C); \ + if (eu == ecused) ecadd(WCB_END()); \ + } while (0) + + +/* Initialise wordcode buffer. */ + +static void +init_parse(void) +{ + ecbuf = (Wordcode) zhalloc((eclen = ecfree = 256) * sizeof(wordcode)); + ecused = 0; + ecstrs = NULL; + ecsoffs = ecnpats = 0; +} + +/* Build eprog. */ + +static Eprog +bld_eprog(void) +{ + Eprog ret; + Eccstr p; + char *q; + int l; + + ecadd(WCB_END()); + + ret = (Eprog) zhalloc(sizeof(*ret)); + ret->len = ((ecnpats * sizeof(Patprog)) + + (ecused * sizeof(wordcode)) + + ecsoffs); + ret->npats = ecnpats; + ret->pats = (Patprog *) zhalloc(ret->len); + ret->prog = (Wordcode) (ret->pats + ecnpats); + ret->strs = (char *) (ret->prog + ecused); + ret->shf = NULL; + ret->heap = 1; + for (l = 0; l < ecnpats; l++) + ret->pats[l] = dummy_patprog1; + memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode)); + for (p = ecstrs, q = ret->strs; p; p = p->next, q += l) { + l = strlen(p->str) + 1; + memcpy(q, p->str, l); + } + return ret; +} + +/* + * event : ENDINPUT + * | SEPER + * | sublist [ SEPER | AMPER | AMPERBANG ] + */ + +/**/ +Eprog +parse_event(void) +{ + tok = ENDINPUT; + incmdpos = 1; + yylex(); + init_parse(); + return ((par_event()) ? bld_eprog() : NULL); +} + +/**/ +static int +par_event(void) +{ + int r = 0, p, c = 0; + + while (tok == SEPER) { + if (isnewlin > 0) + return 0; + yylex(); + } + if (tok == ENDINPUT) + return 0; + + p = ecadd(0); + + if (par_sublist(&c)) { + if (tok == ENDINPUT) { + set_list_code(p, Z_SYNC, c); + r = 1; + } else if (tok == SEPER) { + set_list_code(p, Z_SYNC, c); + if (isnewlin <= 0) + yylex(); + r = 1; + } else if (tok == AMPER) { + set_list_code(p, Z_ASYNC, c); + yylex(); + r = 1; + } else if (tok == AMPERBANG) { + set_list_code(p, (Z_ASYNC | Z_DISOWN), c); + yylex(); + r = 1; + } + } + if (!r) { + if (errflag) { + yyerror(0); + ecused--; + return 0; + } + yyerror(1); + herrflush(); + if (noerrs != 2) + errflag = 1; + ecused--; + return 0; + } else { + int oec = ecused; + + par_event(); + if (ecused == oec) + ecbuf[p] |= wc_bdata(Z_END); + } + return 1; +} + +/**/ +mod_export Eprog +parse_list(void) +{ + int c = 0; + + tok = ENDINPUT; + incmdpos = 1; + yylex(); + init_parse(); + par_list(&c); +#if 0 + if (tok == LEXERR) +#endif + if (tok != ENDINPUT) { + yyerror(0); + return NULL; + } + return bld_eprog(); +} + +/**/ +mod_export Eprog +parse_cond(void) { - Sublist sl; - List l = NULL; + init_parse(); + + if (!par_cond()) + return NULL; + + return bld_eprog(); +} + +/* This adds a list wordcode. The important bit about this is that it also + * tries to optimise this to a Z_SIMPLE list code. */ + +/**/ +static void +set_list_code(int p, int type, int complex) +{ + if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) && + WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) { + int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE); + ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p); + ecdel(p + 1); + if (ispipe) + ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); + } else + ecbuf[p] = WCB_LIST(type, 0); +} + +/* The same for sublists. */ + +/**/ +static void +set_sublist_code(int p, int type, int flags, int skip, int complex) +{ + if (complex) + ecbuf[p] = WCB_SUBLIST(type, flags, skip); + else { + ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip); + ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); + } +} + +/* + * list : { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ] + */ + +/**/ +static int +par_list(int *complex) +{ + int p, lp = -1, c; + + rec: while (tok == SEPER) yylex(); - if ((sl = par_sublist())) { + + p = ecadd(0); + c = 0; + + if (par_sublist(&c)) { + *complex |= c; 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; + if (tok != SEPER) + *complex = 1; + set_list_code(p, ((tok == SEPER) ? Z_SYNC : + (tok == AMPER) ? Z_ASYNC : + (Z_ASYNC | Z_DISOWN)), c); incmdpos = 1; do { yylex(); } while (tok == SEPER); - l->right = par_list(); - } else { - l = (List) make_list(); - l->left = sl; - l->type = Z_SYNC; + lp = p; + goto rec; + } else + set_list_code(p, (Z_SYNC | Z_END), c); + return 1; + } else { + ecused--; + if (lp >= 0) { + ecbuf[lp] |= wc_bdata(Z_END); + return 1; } + return 0; } - return l; } /**/ -static List -par_list1(void) +static int +par_list1(int *complex) { - Sublist sl; - List l = NULL; + int p = ecadd(0), c = 0; - if ((sl = par_sublist())) { - l = (List) make_list(); - l->type = Z_SYNC; - l->left = sl; + if (par_sublist(&c)) { + set_list_code(p, (Z_SYNC | Z_END), c); + *complex |= c; + return 1; + } else { + ecused--; + return 0; } - return l; } /* @@ -433,24 +609,37 @@ par_list1(void) */ /**/ -static Sublist -par_sublist(void) +static int +par_sublist(int *complex) { - Sublist sl; + int f, p, c = 0; + + p = ecadd(0); + + if ((f = par_sublist2(&c)) != -1) { + int e = ecused; - if ((sl = par_sublist2())) + *complex |= c; if (tok == DBAR || tok == DAMPER) { - int qtok = tok; + int qtok = tok, sl; cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND); yylex(); while (tok == SEPER) yylex(); - sl->right = par_sublist(); - sl->type = (qtok == DBAR) ? ORNEXT : ANDNEXT; + sl = par_sublist(complex); + set_sublist_code(p, (sl ? (qtok == DBAR ? + WC_SUBLIST_OR : WC_SUBLIST_AND) : + WC_SUBLIST_END), + f, (e - 1 - p), c); cmdpop(); - } - return sl; + } else + set_sublist_code(p, WC_SUBLIST_END, f, (e - 1 - p), c); + return 1; + } else { + ecused--; + return 0; + } } /* @@ -458,24 +647,24 @@ par_sublist(void) */ /**/ -static Sublist -par_sublist2(void) +static int +par_sublist2(int *complex) { - Sublist sl; - Pline p; + int f = 0; - sl = (Sublist) make_sublist(); if (tok == COPROC) { - sl->flags |= PFLAG_COPROC; + *complex = 1; + f |= WC_SUBLIST_COPROC; yylex(); } else if (tok == BANG) { - sl->flags |= PFLAG_NOT; + *complex = 1; + f |= WC_SUBLIST_NOT; yylex(); } - if (!(p = par_pline()) && !sl->flags) - return NULL; - sl->left = p; - return sl; + if (!par_pline(complex) && !f) + return -1; + + return f; } /* @@ -483,51 +672,52 @@ par_sublist2(void) */ /**/ -static Pline -par_pline(void) +static int +par_pline(int *complex) { - Cmd c; - Pline p, p2; + int p, line = lineno; - if (!(c = par_cmd())) - return NULL; + p = ecadd(0); + + if (!par_cmd(complex)) { + ecused--; + return 0; + } if (tok == BAR) { + *complex = 1; cmdpush(CS_PIPE); yylex(); while (tok == SEPER) yylex(); - p2 = par_pline(); + ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); + ecispace(p + 1, 1); + ecbuf[p + 1] = ecused - 1 - p; + par_pline(complex); cmdpop(); - p = (Pline) make_pline(); - p->left = c; - p->right = p2; - p->type = PIPE; - return p; + return 1; } else if (tok == BARAMP) { - struct redir *rdr = (struct redir *) - allocnode(sizeof(struct redir), N_REDIR); + int r; - rdr->type = MERGEOUT; - rdr->fd1 = 2; - rdr->name = dupstring("1"); - if (!c->redir) - c->redir = newlinklist(); - addlinknode(c->redir, rdr); + for (r = p + 1; wc_code(ecbuf[r]) == WC_REDIR; r += 3); + ecispace(r, 3); + p += 3; + ecbuf[r] = WCB_REDIR(MERGEOUT); + ecbuf[r + 1] = 2; + ecbuf[r + 2] = ecstrcode("1"); + + *complex = 1; cmdpush(CS_ERRPIPE); yylex(); - p2 = par_pline(); + ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); + ecispace(p + 1, 1); + ecbuf[p + 1] = ecused - 1 - p; + par_pline(complex); cmdpop(); - p = (Pline) make_pline(); - p->left = c; - p->right = p2; - p->type = PIPE; - return p; + return 1; } else { - p = (Pline) make_pline(); - p->left = c; - p->type = END; - return p; + ecbuf[p] = WCB_PIPE(WC_PIPE_END, (line >= 0 ? line + 1 : 0)); + return 1; } } @@ -537,105 +727,116 @@ par_pline(void) */ /**/ -static Cmd -par_cmd(void) +static int +par_cmd(int *complex) { - Cmd c; + int r, nr = 0; + + r = ecused; - c = (Cmd) make_cmd(); - c->lineno = lineno; - c->args = NULL; - c->vars = NULL; if (IS_REDIROP(tok)) { - c->redir = newlinklist(); - while (IS_REDIROP(tok)) - par_redir(c->redir); - } else - c->redir = NULL; + *complex = 1; + while (IS_REDIROP(tok)) { + nr++; + par_redir(&r); + } + } switch (tok) { case FOR: cmdpush(CS_FOR); - par_for(c); + par_for(complex); cmdpop(); break; case FOREACH: cmdpush(CS_FOREACH); - par_for(c); + par_for(complex); cmdpop(); break; case SELECT: + *complex = 1; cmdpush(CS_SELECT); - par_for(c); + par_for(complex); cmdpop(); break; case CASE: cmdpush(CS_CASE); - par_case(c); + par_case(complex); cmdpop(); break; case IF: - par_if(c); + par_if(complex); break; case WHILE: cmdpush(CS_WHILE); - par_while(c); + par_while(complex); cmdpop(); break; case UNTIL: cmdpush(CS_UNTIL); - par_while(c); + par_while(complex); cmdpop(); break; case REPEAT: cmdpush(CS_REPEAT); - par_repeat(c); + par_repeat(complex); cmdpop(); break; case INPAR: + *complex = 1; cmdpush(CS_SUBSH); - par_subsh(c); + par_subsh(complex); cmdpop(); break; case INBRACE: cmdpush(CS_CURSH); - par_subsh(c); + par_subsh(complex); cmdpop(); break; case FUNC: cmdpush(CS_FUNCDEF); - par_funcdef(c); + par_funcdef(); cmdpop(); break; case TIME: - par_time(c); + *complex = 1; + par_time(); break; case DINBRACK: cmdpush(CS_COND); - par_dinbrack(c); + par_dinbrack(); cmdpop(); break; case DINPAR: - c->type = CARITH; - if (!c->args) - c->args = newlinklist(); - addlinknode(c->args, tokstr); + ecadd(WCB_ARITH()); + ecstr(tokstr); yylex(); break; default: - if (!par_simple(c)) - return NULL; + { + int sr; + + if (!(sr = par_simple(complex, nr))) { + if (!nr) + return 0; + } else { + /* Three codes per redirection. */ + if (sr > 1) { + *complex = 1; + r += (sr - 1) * 3; + } + } + } break; } if (IS_REDIROP(tok)) { - if (!c->redir) - c->redir = newlinklist(); + *complex = 1; while (IS_REDIROP(tok)) - par_redir(c->redir); + par_redir(&r); } incmdpos = 1; incasepat = 0; incond = 0; - return c; + return 1; } /* @@ -646,86 +847,95 @@ par_cmd(void) /**/ static void -par_for(Cmd c) +par_for(int *complex) { - Forcmd f; - int csh = (tok == FOREACH); + int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT); + int type; + + p = ecadd(0); - 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; + YYERRORV(oecused); + ecstr(tokstr); yylex(); if (tok != DINPAR) - YYERRORV; - f->condition = tokstr; + YYERRORV(oecused); + ecstr(tokstr); yylex(); if (tok != DOUTPAR) - YYERRORV; - f->advance = tokstr; + YYERRORV(oecused); + ecstr(tokstr); infor = 0; incmdpos = 1; yylex(); + type = WC_FOR_COND; } else { infor = 0; if (tok != STRING || !isident(tokstr)) - YYERRORV; - f->name = tokstr; + YYERRORV(oecused); + ecstr(tokstr); incmdpos = 1; yylex(); if (tok == STRING && !strcmp(tokstr, "in")) { - f->inflag = 1; + int np, n; + incmdpos = 0; yylex(); - if (!c->args) - c->args = newlinklist(); - c->args = par_wordlist(); + np = ecadd(0); + n = par_wordlist(); if (tok != SEPER) - YYERRORV; + YYERRORV(oecused); + ecbuf[np] = n; + type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); } else if (tok == INPAR) { - f->inflag = 1; + int np, n; + incmdpos = 0; yylex(); - if (!c->args) - c->args = newlinklist(); - c->args = par_nl_wordlist(); + np = ecadd(0); + n = par_nl_wordlist(); if (tok != OUTPAR) - YYERRORV; + YYERRORV(oecused); + ecbuf[np] = n; incmdpos = 1; yylex(); - } + type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); + } else + type = (sel ? WC_SELECT_PPARAM : WC_FOR_PPARAM); } incmdpos = 1; while (tok == SEPER) yylex(); if (tok == DO) { yylex(); - f->list = par_list(); + par_save_list(complex); if (tok != DONE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (tok == INBRACE) { yylex(); - f->list = par_list(); + par_save_list(complex); if (tok != OUTBRACE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (csh || isset(CSHJUNKIELOOPS)) { - f->list = par_list(); + par_save_list(complex); if (tok != ZEND) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (unset(SHORTLOOPS)) { - YYERRORV; + YYERRORV(oecused); } else - f->list = par_list1(); - c->u.forcmd = f; + par_save_list1(complex); + + ecbuf[p] = (sel ? + WCB_SELECT(type, ecused - 1 - p) : + WCB_FOR(type, ecused - 1 - p)); } /* @@ -737,35 +947,29 @@ par_for(Cmd c) /**/ static void -par_case(Cmd c) +par_case(int *complex) { - int brflag; - LinkList pats, lists; - int n = 1; - char **pp; - List *ll; - LinkNode no; - struct casecmd *cc; - - c->type = CCASE; + int oecused = ecused, brflag, p, pp, n = 1, type; + + p = ecadd(0); + incmdpos = 0; yylex(); if (tok != STRING) - YYERRORV; - pats = newlinklist(); - addlinknode(pats, tokstr); + YYERRORV(oecused); + ecstr(tokstr); + incmdpos = 1; yylex(); while (tok == SEPER) yylex(); if (!(tok == STRING && !strcmp(tokstr, "in")) && tok != INBRACE) - YYERRORV; + YYERRORV(oecused); brflag = (tok == INBRACE); incasepat = 1; incmdpos = 0; yylex(); - cc = c->u.casecmd = (struct casecmd *)make_casecmd(); - lists = newlinklist(); + for (;;) { char *str; @@ -774,14 +978,13 @@ par_case(Cmd c) if (tok == OUTBRACE) break; if (tok != STRING) - YYERRORV; + YYERRORV(oecused); if (!strcmp(tokstr, "esac")) break; - str = ncalloc(strlen(tokstr) + 2); - *str = ';'; - strcpy(str + 1, tokstr); + str = dupstring(tokstr); incasepat = 0; incmdpos = 1; + type = WC_CASE_OR; for (;;) { yylex(); if (tok == OUTPAR) { @@ -803,12 +1006,12 @@ par_case(Cmd c) } else { int sl = strlen(str); - if (str[sl - 1] != Bar) { + if (!sl || str[sl - 1] != Bar) { /* POSIX allows (foo*) patterns */ int pct; char *s; - for (s = str + 1, pct = 0; *s; s++) { + for (s = str, pct = 0; *s; s++) { if (*s == Inpar) pct++; if (!pct) @@ -819,26 +1022,26 @@ par_case(Cmd c) chuck(s+1); if (*s == Bar || *s == Outpar) while (iblank(s[-1]) && - (s < str+2 || s[-2] != Meta)) + (s < str + 1 || s[-2] != Meta)) chuck(--s); } if (*s == Outpar) pct--; } - if (*s || pct || s == str + 1) - YYERRORV; + if (*s || pct || s == str) + YYERRORV(oecused); /* Simplify pattern by removing surrounding (...) */ sl = strlen(str); - DPUTS(str[1] != Inpar || str[sl-1] != Outpar, + DPUTS(*str != Inpar || str[sl - 1] != Outpar, "BUG: strange case pattern"); - str[sl-1] = '\0'; - chuck(str+1); + str[sl - 1] = '\0'; + chuck(str); break; } else { char *str2; if (tok != STRING) - YYERRORV; + YYERRORV(oecused); str2 = ncalloc(sl + strlen(tokstr) + 1); strcpy(str2, str); strcpy(str2 + sl, tokstr); @@ -846,35 +1049,26 @@ par_case(Cmd c) } } } - addlinknode(pats, str); - addlinknode(lists, par_list()); + pp = ecadd(0); + ecstr(str); + ecadd(ecnpats++); + par_save_list(complex); n++; + if (tok == SEMIAMP) + type = WC_CASE_AND; + ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp); if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) break; - if(tok == SEMIAMP) - *str = '&'; - else if (tok != DSEMI) - YYERRORV; + if (tok != DSEMI && tok != SEMIAMP) + YYERRORV(oecused); 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; + ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); } /* @@ -886,20 +1080,13 @@ par_case(Cmd c) /**/ static void -par_if(Cmd c) +par_if(int *complex) { - struct ifcmd *i; - int xtok; + int oecused = ecused, xtok, p, pp, type, usebrace = 0; unsigned char nc; - LinkList ifsl, thensl; - LinkNode no; - int ni = 0, nt = 0, usebrace = 0; - List l, *ll; - ifsl = newlinklist(); - thensl = newlinklist(); + p = ecadd(0); - c->type = CIF; for (;;) { xtok = tok; cmdpush(xtok == IF ? CS_IF : CS_ELIF); @@ -912,10 +1099,11 @@ par_if(Cmd c) yylex(); if (!(xtok == IF || xtok == ELIF)) { cmdpop(); - YYERRORV; + YYERRORV(oecused); } - addlinknode(ifsl, par_list()); - ni++; + pp = ecadd(0); + type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF); + par_save_list(complex); incmdpos = 1; while (tok == SEPER) yylex(); @@ -926,79 +1114,63 @@ par_if(Cmd c) cmdpop(); cmdpush(nc); yylex(); - addlinknode(thensl, par_list()); - nt++; + par_save_list(complex); + ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); 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)) { + } else if (tok == INBRACE) { + usebrace = 1; + cmdpop(); + cmdpush(nc); + yylex(); + par_save_list(complex); + if (tok != OUTBRACE) { cmdpop(); - YYERRORV; - } else { - cmdpop(); - cmdpush(nc); - addlinknode(thensl, par_list1()); - nt++; - incmdpos = 1; - break; + YYERRORV(oecused); } + ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); + yylex(); + incmdpos = 1; + if (tok == SEPER) + break; + cmdpop(); + } else if (unset(SHORTLOOPS)) { + cmdpop(); + YYERRORV(oecused); + } else { + cmdpop(); + cmdpush(nc); + par_save_list1(complex); + ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); + incmdpos = 1; + break; } } cmdpop(); if (xtok == ELSE) { + pp = ecadd(0); cmdpush(CS_ELSE); while (tok == SEPER) yylex(); if (tok == INBRACE && usebrace) { yylex(); - l = par_list(); + par_list(complex); if (tok != OUTBRACE) { cmdpop(); - YYERRORV; + YYERRORV(oecused); } } else { - l = par_list(); + par_list(complex); if (tok != FI) { cmdpop(); - YYERRORV; + YYERRORV(oecused); } } - addlinknode(thensl, l); - nt++; + ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp); 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; + ecbuf[p] = WCB_IF(WC_IF_HEAD, ecused - 1 - p); } /* @@ -1008,37 +1180,38 @@ par_if(Cmd c) /**/ static void -par_while(Cmd c) +par_while(int *complex) { - struct whilecmd *w; + int oecused = ecused, p; + int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE); - c->type = CWHILE; - w = c->u.whilecmd = (struct whilecmd *)make_whilecmd(); - w->cond = (tok == UNTIL); + p = ecadd(0); yylex(); - w->cont = par_list(); + par_save_list(complex); incmdpos = 1; while (tok == SEPER) yylex(); if (tok == DO) { yylex(); - w->loop = par_list(); + par_save_list(complex); if (tok != DONE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (tok == INBRACE) { yylex(); - w->loop = par_list(); + par_save_list(complex); if (tok != OUTBRACE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (isset(CSHJUNKIELOOPS)) { - w->loop = par_list(); + par_save_list(complex); if (tok != ZEND) - YYERRORV; + YYERRORV(oecused); yylex(); } else - YYERRORV; + YYERRORV(oecused); + + ecbuf[p] = WCB_WHILE(type, ecused - 1 - p); } /* @@ -1047,41 +1220,44 @@ par_while(Cmd c) /**/ static void -par_repeat(Cmd c) +par_repeat(int *complex) { - c->type = CREPEAT; + int oecused = ecused, p; + + p = ecadd(0); + incmdpos = 0; yylex(); if (tok != STRING) - YYERRORV; - if (!c->args) - c->args = newlinklist(); - addlinknode(c->args, tokstr); + YYERRORV(oecused); + ecstr(tokstr); incmdpos = 1; yylex(); while (tok == SEPER) yylex(); if (tok == DO) { yylex(); - c->u.list = par_list(); + par_save_list(complex); if (tok != DONE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (tok == INBRACE) { yylex(); - c->u.list = par_list(); + par_save_list(complex); if (tok != OUTBRACE) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (isset(CSHJUNKIELOOPS)) { - c->u.list = par_list(); + par_save_list(complex); if (tok != ZEND) - YYERRORV; + YYERRORV(oecused); yylex(); } else if (unset(SHORTLOOPS)) { - YYERRORV; + YYERRORV(oecused); } else - c->u.list = par_list1(); + par_save_list1(complex); + + ecbuf[p] = WCB_REPEAT(ecused - 1 - p); } /* @@ -1090,13 +1266,15 @@ par_repeat(Cmd c) /**/ static void -par_subsh(Cmd c) +par_subsh(int *complex) { - c->type = (tok == INPAR) ? SUBSH : CURSH; + int oecused = ecused, otok = tok; + + ecadd(tok == INPAR ? WCB_SUBSH() : WCB_CURSH()); yylex(); - c->u.list = par_list(); - if (tok != ((c->type == SUBSH) ? OUTPAR : OUTBRACE)) - YYERRORV; + par_save_list(complex); + if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE)) + YYERRORV(oecused); incmdpos = 1; yylex(); } @@ -1108,43 +1286,88 @@ par_subsh(Cmd c) /**/ static void -par_funcdef(Cmd c) +par_funcdef(void) { - int oldlineno = lineno; + int oecused = ecused, oldlineno = lineno, num = 0, sbeg, onp, p, c = 0; + Eccstr ostrs; + lineno = 0; nocorrect = 1; incmdpos = 0; yylex(); - c->type = FUNCDEF; - c->args = newlinklist(); + + p = ecadd(0); + ecadd(0); + incmdpos = 1; while (tok == STRING) { if (*tokstr == Inbrace && !tokstr[1]) { tok = INBRACE; break; } - addlinknode(c->args, tokstr); + ecstr(tokstr); + num++; yylex(); } + ecadd(0); + ecadd(0); + nocorrect = 0; if (tok == INOUTPAR) yylex(); while (tok == SEPER) yylex(); + + sbeg = ecsoffs; + ecsoffs = 0; + ostrs = ecstrs; + ecstrs = NULL; + onp = ecnpats; + ecnpats = 0; + if (tok == INBRACE) { yylex(); - c->u.list = par_list(); + par_save_list(&c); if (tok != OUTBRACE) { lineno += oldlineno; - YYERRORV; + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; + YYERRORV(oecused); } yylex(); } else if (unset(SHORTLOOPS)) { lineno += oldlineno; - YYERRORV; + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; + YYERRORV(oecused); } else - c->u.list = par_list1(); + par_save_list1(&c); + + ecbuf[p + num + 2] = ecused - num - p; + ecbuf[p + num + 3] = ecnpats; + ecbuf[p + 1] = num; + + if (ecsoffs) { + int beg = ecused, l; + Eccstr sp; + char *sq; + + ecspace(ecsoffs); + + for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp; + sp = sp->next, sq += l) { + l = strlen(sp->str) + 1; + memcpy(sq, sp->str, l); + } + } lineno += oldlineno; + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; + + ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); } /* @@ -1153,11 +1376,17 @@ par_funcdef(Cmd c) /**/ static void -par_time(Cmd c) +par_time(void) { + int p, f, c = 0; + yylex(); - c->type = ZCTIME; - c->u.pline = par_sublist2(); + + p = ecadd(0); + ecadd(0); + f = par_sublist2(&c); + ecbuf[p] = WCB_TIMED((p + 1 == ecused) ? WC_TIMED_EMPTY : WC_TIMED_PIPE); + set_sublist_code(p + 1, WC_SUBLIST_END, f, ecused - 2 - p, c); } /* @@ -1166,15 +1395,16 @@ par_time(Cmd c) /**/ static void -par_dinbrack(Cmd c) +par_dinbrack(void) { - c->type = COND; + int oecused = ecused; + incond = 1; incmdpos = 0; yylex(); - c->u.cond = par_cond(); + par_cond(); if (tok != DOUTBRACK) - YYERRORV; + YYERRORV(oecused); incond = 0; incmdpos = 1; yylex(); @@ -1187,293 +1417,157 @@ par_dinbrack(Cmd c) */ /**/ -static Cmd -par_simple(Cmd c) +static int +par_simple(int *complex, int nr) { - int isnull = 1; + int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; + int c = *complex; - c->type = SIMPLE; + r = ecused; for (;;) { - if (tok == NOCORRECT) + if (tok == NOCORRECT) { + *complex = c = 1; nocorrect = 1; - else if (tok == ENVSTRING) { - struct varasg *v = (struct varasg *)make_varnode(); - char *p; + } else if (tok == ENVSTRING) { + char *p, *name, *str; - v->type = PM_SCALAR; - v->name = tokstr; + ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, 0)); + name = tokstr; for (p = tokstr; *p && *p != Inbrack && *p != '='; p++); if (*p == Inbrack && !skipparens(Inbrack, Outbrack, &p) && *p == '=') { *p = '\0'; - v->str = p + 1; + str = p + 1; } else - equalsplit(tokstr, &v->str); - if (!c->vars) - c->vars = newlinklist(); - addlinknode(c->vars, v); + equalsplit(tokstr, &str); + ecstr(name); + ecstr(str); isnull = 0; } else if (tok == ENVARRAY) { - struct varasg *v = (struct varasg *)make_varnode(); - int oldcmdpos = incmdpos; + int oldcmdpos = incmdpos, n; - v->type = PM_ARRAY; + p = ecadd(0); incmdpos = 0; - v->name = tokstr; + ecstr(tokstr); cmdpush(CS_ARRAY); yylex(); - v->arr = par_nl_wordlist(); + n = par_nl_wordlist(); + ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, n); cmdpop(); if (tok != OUTPAR) - YYERROR; + YYERROR(oecused); incmdpos = oldcmdpos; - if (!c->vars) - c->vars = newlinklist(); - addlinknode(c->vars, v); isnull = 0; } else break; yylex(); } if (tok == AMPER || tok == AMPERBANG) - YYERROR; + YYERROR(oecused); + + p = ecadd(WCB_SIMPLE(0)); + for (;;) { if (tok == STRING) { + *complex = 1; incmdpos = 0; - if (!c->args) - c->args = newlinklist(); - addlinknode(c->args, tokstr); + ecstr(tokstr); + argc++; yylex(); } else if (IS_REDIROP(tok)) { - if (!c->redir) - c->redir = newlinklist(); - par_redir(c->redir); + *complex = c = 1; + par_redir(&r); + p += 3; /* 3 codes per redirection */ + sr++; } else if (tok == INOUTPAR) { - int oldlineno = lineno; + int oldlineno = lineno, sbeg, onp; + Eccstr ostrs; + + *complex = c; lineno = 0; incmdpos = 1; cmdpush(CS_FUNCDEF); yylex(); while (tok == SEPER) yylex(); + + ecispace(p + 1, 1); + ecbuf[p + 1] = argc; + ecadd(0); + ecadd(0); + + sbeg = ecsoffs; + ecsoffs = 0; + ostrs = ecstrs; + ecstrs = NULL; + onp = ecnpats; + ecnpats = 0; + if (tok == INBRACE) { + int c = 0; + yylex(); - c->u.list = par_list(); + par_list(&c); if (tok != OUTBRACE) { cmdpop(); lineno += oldlineno; - YYERROR; + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; + YYERROR(oecused); } yylex(); } else { - List l; - Sublist sl; - Pline pl; - - l = (List) allocnode(sizeof(*l), N_LIST); - l->type = Z_SYNC; - l->left = sl = (Sublist) allocnode(sizeof(*sl), N_SUBLIST); - sl->type = END; - sl->left = pl = (Pline) allocnode(sizeof(*pl), N_PLINE); - pl->type = END; - pl->left = par_cmd(); - c->u.list = l; - } - cmdpop(); - c->type = FUNCDEF; - lineno += oldlineno; - } else - break; - isnull = 0; - } - if (isnull && (!c->redir || 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; + int ll, sl, c = 0; -/* - * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ] - */ + ll = ecadd(0); + sl = ecadd(0); -/**/ -static Cond -par_cond(void) -{ - Cond c, c2; + par_cmd(&c); - 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; -} + set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); + set_list_code(ll, (Z_SYNC | Z_END), c); + } + cmdpop(); -/* - * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ] - */ + ecbuf[p + argc + 2] = ecused - argc - p; + ecbuf[p + argc + 3] = ecnpats; -/**/ -static Cond -par_cond_1(void) -{ - Cond c, c2; + if (ecsoffs) { + int beg = ecused, l; + Eccstr sp; + char *sq; - 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; -} + ecspace(ecsoffs); -/* - * cond_2 : BANG cond_2 - | INPAR { SEPER } cond_2 { SEPER } OUTPAR - | STRING STRING STRING - | STRING STRING - | STRING ( INANG | OUTANG ) STRING - */ + for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp; + sp = sp->next, sq += l) { + l = strlen(sp->str) + 1; + memcpy(sq, sp->str, l); + } + } + lineno += oldlineno; + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; -/**/ -static Cond -par_cond_2(void) -{ - Cond c, c2; - char *s1, *s2, *s3; - int dble = 0; + ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); - 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); + isfunc = 1; } 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; + break; + isnull = 0; } - 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; + if (isnull && !(sr + nr)) { + ecused = p; + return 0; } - s2 = tokstr; - incond++; /* parentheses do globbing */ - condlex(); - incond--; /* parentheses do grouping */ - if (tok == STRING && !dble) { - s3 = tokstr; - condlex(); - if (tok == STRING) { - LinkList l = newlinklist(); + incmdpos = 1; - addlinknode(l, s2); - addlinknode(l, s3); + if (!isfunc) + ecbuf[p] = WCB_SIMPLE(argc); - while (tok == STRING) { - addlinknode(l, tokstr); - condlex(); - } - return par_cond_multi(s1, l); - } else - return par_cond_triple(s1, s2, s3); - } else - return par_cond_double(s1, s2); + return sr + 1; } /* @@ -1500,32 +1594,31 @@ static int redirtab[TRINANG - OUTANG + 1] = { /**/ static void -par_redir(LinkList l) +par_redir(int *rp) { - struct redir *fn = (struct redir *) - allocnode(sizeof(struct redir), N_REDIR); - int oldcmdpos, oldnc; + int r = *rp, type, fd1, oldcmdpos, oldnc; + char *name; oldcmdpos = incmdpos; incmdpos = 0; oldnc = nocorrect; if (tok != INANG && tok != INOUTANG) nocorrect = 1; - fn->type = redirtab[tok - OUTANG]; - fn->fd1 = tokfd; + type = redirtab[tok - OUTANG]; + fd1 = tokfd; yylex(); if (tok != STRING && tok != ENVSTRING) - YYERRORV; + YYERRORV(ecused); incmdpos = oldcmdpos; nocorrect = oldnc; /* assign default fd */ - if (fn->fd1 == -1) - fn->fd1 = IS_READFD(fn->type) ? 0 : 1; + if (fd1 == -1) + fd1 = IS_READFD(type) ? 0 : 1; - fn->name = tokstr; + name = tokstr; - switch (fn->type) { + switch (type) { case HEREDOC: case HEREDOCDASH: { /* <<[-] name */ @@ -1534,31 +1627,56 @@ par_redir(LinkList l) for (hd = &hdocs; *hd; hd = &(*hd)->next); *hd = zalloc(sizeof(struct heredocs)); (*hd)->next = NULL; - (*hd)->rd = fn; - break; + (*hd)->pc = ecbuf + r; + (*hd)->str = tokstr; + + /* If we ever need more than three codes (or less), we have to change + * the factors in par_cmd() and par_simple(), too. */ + ecispace(r, 3); + *rp = r + 3; + ecbuf[r] = WCB_REDIR(type); + ecbuf[r + 1] = fd1; + + yylex(); + return; } case WRITE: case WRITENOW: if (tokstr[0] == Outang && tokstr[1] == Inpar) /* > >(...) */ - fn->type = OUTPIPE; + type = OUTPIPE; else if (tokstr[0] == Inang && tokstr[1] == Inpar) - YYERRORV; + YYERRORV(ecused); break; case READ: if (tokstr[0] == Inang && tokstr[1] == Inpar) /* < <(...) */ - fn->type = INPIPE; + type = INPIPE; else if (tokstr[0] == Outang && tokstr[1] == Inpar) - YYERRORV; + YYERRORV(ecused); break; case READWRITE: if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar) - fn->type = tokstr[0] == Inang ? INPIPE : OUTPIPE; + type = tokstr[0] == Inang ? INPIPE : OUTPIPE; break; } yylex(); - addlinknode(l, fn); + + /* If we ever need more than three codes (or less), we have to change + * the factors in par_cmd() and par_simple(), too. */ + ecispace(r, 3); + *rp = r + 3; + ecbuf[r] = WCB_REDIR(type); + ecbuf[r + 1] = fd1; + ecbuf[r + 2] = ecstrcode(name); +} + +/**/ +void +setheredoc(Wordcode pc, int type, char *str) +{ + pc[0] = WCB_REDIR(type); + pc[2] = ecstrcode(str); } /* @@ -1566,17 +1684,16 @@ par_redir(LinkList l) */ /**/ -static LinkList +static int par_wordlist(void) { - LinkList l; - - l = newlinklist(); + int num = 0; while (tok == STRING) { - addlinknode(l, tokstr); + ecstr(tokstr); + num++; yylex(); } - return l; + return num; } /* @@ -1584,788 +1701,309 @@ par_wordlist(void) */ /**/ -static LinkList +static int par_nl_wordlist(void) { - LinkList l; + int num = 0; - l = newlinklist(); while (tok == STRING || tok == SEPER) { - if (tok != SEPER) - addlinknode(l, tokstr); + if (tok != SEPER) { + ecstr(tokstr); + num++; + } yylex(); } - return l; + return num; } -/**/ -static Cond -par_cond_double(char *a, char *b) -{ - Cond n = (Cond) make_cond(); - - n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); - n->left = (void *) b; - if (a[0] != '-' || !a[1]) - COND_ERROR("parse error: condition expected: %s", a); - else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) - n->type = a[1]; - else { - char *d[2]; - - n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0); - n->type = COND_MOD; - n->left = (void *) a; - d[0] = b; - d[1] = NULL; - n->right = (void *) arrdup(d); - } - return n; -} +/* + * condlex is yylex for normal parsing, but is altered to allow + * the test builtin to use par_cond. + */ /**/ -static int -get_cond_num(char *tst) -{ - static char *condstrs[] = - { - "nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL - }; - int t0; +void (*condlex) _((void)) = yylex; - for (t0 = 0; condstrs[t0]; t0++) - if (!strcmp(condstrs[t0], tst)) - return t0; - return -1; -} +/* + * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ] + */ /**/ -static Cond -par_cond_triple(char *a, char *b, char *c) -{ - Cond n = (Cond) make_cond(); - int t0; - - n->left = (void *) a; - n->right = (void *) c; - if ((b[0] == Equals || b[0] == '=') && - (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { - n->ntype = NT_SET(N_COND, NT_STR, NT_STR, NT_PAT, 0); - n->type = COND_STREQ; - } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) { - n->ntype = NT_SET(N_COND, NT_STR, NT_STR, NT_PAT, 0); - n->type = COND_STRNEQ; - } else if (b[0] == '-') { - if ((t0 = get_cond_num(b + 1)) > -1) { - n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); - n->type = t0 + COND_NT; - } else { - char *d[3]; - - n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0); - n->type = COND_MODI; - n->left = (void *) b; - d[0] = a; - d[1] = c; - d[2] = NULL; - n->right = (void *) arrdup(d); - } - } else if (a[0] == '-' && a[1]) { - char *d[3]; - - n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0); - n->type = COND_MOD; - n->left = (void *) a; - d[0] = b; - d[1] = c; - d[2] = NULL; - n->right = (void *) arrdup(d); - } else - COND_ERROR("condition expected: %s", b); - return n; -} - -/**/ -static Cond -par_cond_multi(char *a, LinkList l) -{ - Cond n = (Cond) make_cond(); - - n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0); - if (a[0] != '-' || !a[1]) - COND_ERROR("condition expected: %s", a); - else { - n->type = COND_MOD; - n->left = (void *) a; - n->right = (void *) listarr(l); - } - return n; -} - -/**/ -static void -yyerror(int noerr) -{ - int t0; - - for (t0 = 0; t0 != 20; t0++) - if (!yytext || !yytext[t0] || yytext[t0] == '\n') - break; - if (t0 == 20) - zwarn("parse error near `%l...'", yytext, 20); - else if (t0) - zwarn("parse error near `%l'", yytext, t0); - else - zwarn("parse error", NULL, 0); - if (!noerr && noerrs != 2) - errflag = 1; -} - -/* - * Word code. - * - * For now we simply post-process the syntax tree produced by the - * parser. We compile it into a struct eprog. Some day the parser - * above should be changed to emit the word code directly. - * - * Word code layout: - * - * WC_END - * - end of program code - * - * WC_LIST - * - data contains type (sync, ...) - * - follwed by code for this list - * - if not (type & Z_END), followed by next WC_LIST - * - * WC_SUBLIST - * - data contains type (&&, ||, END) and flags (coprog, not) - * - followed by code for sublist - * - if not (type == END), followed by next WC_SUBLIST - * - * WC_PIPE - * - data contains type (end, mid) and LINENO - * - if not (type == END), followed by offset to next WC_PIPE - * - followed by command - * - if not (type == END), followed by next WC_PIPE - * - * WC_REDIR - * - must precede command-code (or WC_ASSIGN) - * - data contains type (<, >, ...) - * - followed by fd1 and name from struct redir - * - * WC_ASSIGN - * - data contains type (scalar, array) and number of array-elements - * - followed by name and value - * - * WC_SIMPLE - * - data contains the number of arguments (plus command) - * - followed by strings - * - * WC_SUBSH - * - data unused - * - followed by list - * - * WC_CURSH - * - data unused - * - followed by list - * - * WC_TIMED - * - data contains type (followed by pipe or not) - * - if (type == PIPE), followed by pipe - * - * WC_FUNCDEF - * - data contains offset to after body-strings - * - followed by number of names - * - followed by names - * - followed by number of codes for body - * - followed by number of patterns for body - * - follwoed by codes for body - * - followed by strings for body - * - * WC_FOR - * - data contains type (list, ...) and offset to after body - * - if (type == COND), followed by init, cond, advance expressions - * - else if (type == PPARAM), followed by param name - * - else if (type == LIST), followed by param name, num strings, strings - * - followed by body - * - * WC_SELECT - * - data contains type (list, ...) and offset to after body - * - if (type == PPARAM), followed by param name - * - else if (type == LIST), followed by param name, num strings, strings - * - followed by body - * - * WC_WHILE - * - data contains type (while, until) and ofsset to after body - * - followed by condition - * - followed by body - * - * WC_REPEAT - * - data contains offset to after body - * - followed by number-string - * - followed by body - * - * WC_CASE - * - first CASE is always of type HEAD, data contains offset to esac - * - after that CASEs of type OR (;;) and AND (;&), data is offset to - * next case - * - each OR/AND case is followed by pattern, pattern-number, list - * - * WC_IF - * - first IF is of type HEAD, data contains offset to fi - * - after that IFs of type IF, ELIF, ELSE, data is offset to next - * - each non-HEAD is followed by condition (only IF, ELIF) and body - * - * WC_COND - * - data contains type - * - if (type == AND/OR), data contains offset to after this one, - * followed by two CONDs - * - else if (type == NOT), followed by COND - * - else if (type == MOD), followed by name and strings - * - else if (type == MODI), followed by name, left, right - * - else if (type == STR[N]EQ), followed by left, right, pattern-number - * - else if (has two args) followed by left, right - * - else followed by string - * - * WC_ARITH - * - followed by string (there's only one) - * - * WC_AUTOFN - * - only used by the autoload builtin - * - * In each of the above, strings are encoded as one word code. For empty - * strings this is the bit pattern 0xfe000000. For short strings (one to - * three characters), this is the marker 0xff000000 with the lower three - * bytes containing the characters. Longer strings are encoded as the - * offset into the strs character array stored in the eprog struct. - * The ecstr() function that adds the code for a string uses a simple - * list of strings already added so that long strings are encoded only - * once. - * - * Note also that in the eprog struct the pattern, code, and string - * arrays all point to the same memory block. - */ - -static int eclen, ecused, ecfree, ecnpats; -static Wordcode ecbuf; - -typedef struct eccstr *Eccstr; - -struct eccstr { - Eccstr next; - char *str; - wordcode offs; -}; - -static Eccstr ecstrs; -static int ecsoffs; - -/* Make at least n bytes free (aligned to sizeof(wordcode)). */ - static int -ecspace(int n) -{ - n = (n + sizeof(wordcode) - 1) / sizeof(wordcode); - - if (ecfree < n) { - int a = (n > 256 ? n : 256); - - ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), - (eclen + a) * sizeof(wordcode)); - eclen += a; - ecfree += a; - } - ecused += n; - ecfree -= n; - - return ecused - 1; -} - -/* Add one wordcode. */ - -static int -ecadd(wordcode c) -{ - if (ecfree < 1) { - ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), - (eclen + 256) * sizeof(wordcode)); - eclen += 256; - ecfree += 256; - } - ecbuf[ecused] = c; - ecused++; - ecfree--; - - return ecused - 1; -} - -/* Add a string and the wordcode for it. */ - -static int -ecstr(char *s) -{ - int l; - - if ((l = strlen(s) + 1) && l <= 4) { - wordcode c = 0xff000000; - switch (l) { - case 4: c |= ((wordcode) STOUC(s[2])) << 16; - case 3: c |= ((wordcode) STOUC(s[1])) << 8; - case 2: c |= ((wordcode) STOUC(s[0])); break; - case 1: c = 0xfe000000; break; - } - return ecadd(c); - } else { - Eccstr p, q = NULL; - - for (p = ecstrs; p; q = p, p = p->next) - if (!strcmp(s, p->str)) - return ecadd(p->offs); - - p = (Eccstr) zhalloc(sizeof(*p)); - p->next = NULL; - if (q) - q->next = p; - else - ecstrs = p; - p->offs = ecsoffs; - p->str = s; - ecsoffs += l; - - return ecadd(p->offs); - } -} - -#define ec(N) ecomp((struct node *) (N)) -#define ecsave(N) \ - do { int u = ecused; ec(N); if (u == ecused) ecadd(WCB_END()); } while (0) - -#define _Cond(X) ((Cond) (X)) -#define _Cmd(X) ((Cmd) (X)) -#define _Pline(X) ((Pline) (X)) -#define _Sublist(X) ((Sublist) (X)) -#define _List(X) ((List) (X)) -#define _casecmd(X) ((struct casecmd *) (X)) -#define _ifcmd(X) ((struct ifcmd *) (X)) -#define _whilecmd(X) ((struct whilecmd *) (X)) - -#define cont(N) do { n = (struct node *) (N); goto rec; } while (0) - -/* Compile a node. */ - -static void -ecomp(struct node *n) -{ - int p, c; - - rec: - - if (!n || ((List) n) == &dummy_list) - return; - - switch (NT_TYPE(n->ntype)) { - case N_LIST: - ecadd(WCB_LIST(_List(n)->type | (_List(n)->right ? 0 : Z_END))); - if (_List(n)->right) { - ec(_List(n)->left); - cont(_List(n)->right); - } else - cont(_List(n)->left); - break; - case N_SUBLIST: - p = ecadd(0); - ec(_Sublist(n)->left); - ecbuf[p] = WCB_SUBLIST((_Sublist(n)->right ? - ((_Sublist(n)->type == ORNEXT) ? - WC_SUBLIST_OR : WC_SUBLIST_AND) : - WC_SUBLIST_END), - (((_Sublist(n)->flags & PFLAG_NOT) ? - WC_SUBLIST_NOT : 0) | - ((_Sublist(n)->flags & PFLAG_COPROC) ? - WC_SUBLIST_COPROC : 0)), - (ecused - 1 - p)); - if (_Sublist(n)->right) - cont(_Sublist(n)->right); - break; - case N_PLINE: - ecadd(WCB_PIPE((_Pline(n)->right ? WC_PIPE_MID : WC_PIPE_END), - (_Cmd(_Pline(n)->left)->lineno >= 0 ? - _Cmd(_Pline(n)->left)->lineno + 1 : 0))); - if (_Pline(n)->right) { - p = ecadd(0); - ec(_Pline(n)->left); - ecbuf[p] = (wordcode) (ecused - p); - cont(_Pline(n)->right); - } else - cont(_Pline(n)->left); - break; - case N_CMD: - { - Cmd nn = _Cmd(n); - - /* Note that the execution and text code require that the - * redirs and assignments are in exactly this order and that - * they are before the command. */ - - ecredirs(nn->redir); - - switch (nn->type) { - case SIMPLE: - { - int num = 0; - - ecassigns(nn->vars); - p = ecadd(0); - - if (nn->args) { - LinkNode ap; - - for (ap = firstnode(nn->args); ap; - incnode(ap), num++) - ecstr((char *) getdata(ap)); - } - ecbuf[p] = WCB_SIMPLE(num); - } - break; - case SUBSH: - ecadd(WCB_SUBSH()); - ecsave(nn->u.list); - break; - case ZCTIME: - ecadd(WCB_TIMED(nn->u.pline ? WC_TIMED_PIPE : WC_TIMED_EMPTY)); - if (nn->u.pline) - ec(nn->u.pline); - break; - case FUNCDEF: - { - LinkNode np; - int num, sbeg, onp; - Eccstr ostrs; - - /* Defined functions and their strings are stored - * inline. */ - - p = ecadd(0); - ecadd(0); - - for (np = firstnode(nn->args), num = 0; np; - incnode(np), num++) - ecstr((char *) getdata(np)); - - ecadd(0); - ecadd(0); - - sbeg = ecsoffs; - ecsoffs = 0; - ostrs = ecstrs; - ecstrs = NULL; - onp = ecnpats; - ecnpats = 0; - - ecsave(nn->u.list); - - ecbuf[p + num + 2] = ecused - num - p; - ecbuf[p + num + 3] = ecnpats; - ecbuf[p + 1] = num; - - if (ecsoffs) { - int beg = ecused, l; - Eccstr sp; - char *sq; - - ecspace(ecsoffs); - - for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp; - sp = sp->next, sq += l) { - l = strlen(sp->str) + 1; - memcpy(sq, sp->str, l); - } - } - ecsoffs = sbeg; - ecstrs = ostrs; - ecnpats = onp; - - ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); - } - break; - case CURSH: - ecadd(WCB_CURSH()); - ecsave(nn->u.list); - break; - case CFOR: - { - int type; - - p = ecadd(0); - ecstr(nn->u.forcmd->name); - - if (nn->u.forcmd->condition) { - type = WC_FOR_COND; - ecstr(nn->u.forcmd->condition); - ecstr(nn->u.forcmd->advance); - } else { - if (nn->args) { - LinkNode fp; - int num; - - type = WC_FOR_LIST; - - ecadd(0); - - for (fp = firstnode(nn->args), num = 0; fp; - incnode(fp), num++) - ecstr((char *) getdata(fp)); - - ecbuf[p + 2] = num; - } else - type = WC_FOR_PPARAM; - } - ecsave(nn->u.forcmd->list); - - ecbuf[p] = WCB_FOR(type, ecused - 1 - p); - } - break; - case CSELECT: - { - int type; +par_cond(void) +{ + int p = ecused, r; - p = ecadd(0); - ecstr(nn->u.forcmd->name); + r = par_cond_1(); + while (tok == SEPER) + condlex(); + if (tok == DBAR) { + condlex(); + while (tok == SEPER) + condlex(); + ecispace(p, 1); + par_cond(); + ecbuf[p] = WCB_COND(COND_OR, ecused - 1 - p); + return 1; + } + return r; +} - if (nn->args) { - LinkNode fp; - int num; +/* + * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ] + */ - type = WC_SELECT_LIST; - ecadd(0); +/**/ +static int +par_cond_1(void) +{ + int r, p = ecused; - for (fp = firstnode(nn->args), num = 0; fp; - incnode(fp), num++) - ecstr((char *) getdata(fp)); + r = par_cond_2(); + while (tok == SEPER) + condlex(); + if (tok == DAMPER) { + condlex(); + while (tok == SEPER) + condlex(); + ecispace(p, 1); + par_cond_1(); + ecbuf[p] = WCB_COND(COND_AND, ecused - 1 - p); + return 1; + } + return r; +} - ecbuf[p + 2] = num; - } else - type = WC_SELECT_PPARAM; +/* + * cond_2 : BANG cond_2 + | INPAR { SEPER } cond_2 { SEPER } OUTPAR + | STRING STRING STRING + | STRING STRING + | STRING ( INANG | OUTANG ) STRING + */ - ecsave(nn->u.forcmd->list); +/**/ +static int +par_cond_2(void) +{ + char *s1, *s2, *s3; + int dble = 0; - ecbuf[p] = WCB_SELECT(type, ecused - 1 - p); - } - break; - case CIF: - { - List *i, *t; - int type = WC_IF_IF; - - c = ecadd(0); - - for (i = nn->u.ifcmd->ifls, t = nn->u.ifcmd->thenls; - *i; i++, t++) { - p = ecadd(0); - ecsave(*i); - ecsave(*t); - ecbuf[p] = WCB_IF(type, ecused - 1 - p); - type = WC_IF_ELIF; - } - if (*t) { - p = ecadd(0); - ecsave(*t); - ecbuf[p] = WCB_IF(WC_IF_ELSE, ecused - 1 - p); - } - ecbuf[c] = WCB_IF(WC_IF_HEAD, ecused - 1 - c); - } - break; - case CCASE: - { - List *l; - char **pp = nn->u.casecmd->pats; - - p = ecadd(0); - ecstr(*pp++); - - for (l = nn->u.casecmd->lists; l && *l; l++, pp++) { - c = ecadd(0); - ecstr(*pp + 1); - ecadd(ecnpats++); - ecsave(*l); - ecbuf[c] = WCB_CASE((**pp == ';' ? - WC_CASE_OR : WC_CASE_AND), - ecused - 1 - c); - } - ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); - } - break; - case COND: - eccond(nn->u.cond); - break; - case CARITH: - ecadd(WCB_ARITH()); - ecstr((char *) getdata(firstnode(nn->args))); - break; - case CREPEAT: - p = ecadd(0); - ecstr((char *) getdata(firstnode(nn->args))); - ecsave(nn->u.list); - ecbuf[p] = WCB_REPEAT(ecused - 1 - p); - break; - case CWHILE: - p = ecadd(0); - ecsave(nn->u.whilecmd->cont); - ecsave(nn->u.whilecmd->loop); - ecbuf[p] = WCB_WHILE((nn->u.whilecmd->cond ? - WC_WHILE_UNTIL : WC_WHILE_WHILE), - ecused - 1 - p); - break; + 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); } } - break; - case N_COND: - eccond((Cond) n); - break; -#ifdef DEBUG - default: - dputs("BUG: node type not handled in ecomp()."); - break; -#endif } -} + if (tok == BANG) { + condlex(); + ecadd(WCB_COND(COND_NOT, 0)); + return par_cond_2(); + } + if (tok == INPAR) { + int r; -/**/ -static void -ecredirs(LinkList l) -{ - LinkNode n; - Redir f; + condlex(); + while (tok == SEPER) + condlex(); + r = par_cond(); + while (tok == SEPER) + condlex(); + if (tok != OUTPAR) + YYERROR(ecused); + condlex(); + return r; + } + if (tok != STRING) { + if (tok && tok != LEXERR && condlex == testlex) { + s1 = tokstr; + condlex(); + return par_cond_double("-n", s1); + } else + YYERROR(ecused); + } + 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(ecused); + s3 = tokstr; + condlex(); + ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0)); + ecstr(s1); + ecstr(s3); + return 1; + } + 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(ecused); + } + s2 = tokstr; + incond++; /* parentheses do globbing */ + condlex(); + incond--; /* parentheses do grouping */ + if (tok == STRING && !dble) { + s3 = tokstr; + condlex(); + if (tok == STRING) { + LinkList l = newlinklist(); - if (!l) - return; + addlinknode(l, s2); + addlinknode(l, s3); - for (n = firstnode(l); n; incnode(n)) { - f = (Redir) getdata(n); + while (tok == STRING) { + addlinknode(l, tokstr); + condlex(); + } + return par_cond_multi(s1, l); + } else + return par_cond_triple(s1, s2, s3); + } else + return par_cond_double(s1, s2); +} - ecadd(WCB_REDIR(f->type)); - ecadd(f->fd1); - ecstr(f->name); +/**/ +static int +par_cond_double(char *a, char *b) +{ + if (a[0] != '-' || !a[1]) + COND_ERROR("parse error: condition expected: %s", a); + else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) { + ecadd(WCB_COND(a[1], 0)); + ecstr(b); + } else { + ecadd(WCB_COND(COND_MOD, 1)); + ecstr(a); + ecstr(b); } + return 1; } /**/ -static void -ecassigns(LinkList l) +static int +get_cond_num(char *tst) { - int p; - LinkNode n; - Varasg v; - - if (!l) - return; - - for (n = firstnode(l); n; incnode(n)) { - v = (Varasg) getdata(n); + static char *condstrs[] = + { + "nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL + }; + int t0; - p = ecadd(0); - ecstr(v->name); + for (t0 = 0; condstrs[t0]; t0++) + if (!strcmp(condstrs[t0], tst)) + return t0; + return -1; +} - if (PM_TYPE(v->type) == PM_ARRAY) { - LinkNode vp; - int num; +/**/ +static int +par_cond_triple(char *a, char *b, char *c) +{ + int t0; - for (vp = firstnode(v->arr), num = 0; vp; incnode(vp), num++) - ecstr((char *) getdata(vp)); - ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, num); + if ((b[0] == Equals || b[0] == '=') && + (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { + ecadd(WCB_COND(COND_STREQ, 0)); + ecstr(a); + ecstr(c); + ecadd(ecnpats++); + } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) { + ecadd(WCB_COND(COND_STRNEQ, 0)); + ecstr(a); + ecstr(c); + ecadd(ecnpats++); + } else if (b[0] == '-') { + if ((t0 = get_cond_num(b + 1)) > -1) { + ecadd(WCB_COND(t0 + COND_NT, 0)); + ecstr(a); + ecstr(c); } else { - ecstr(v->str); - ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_SCALAR, 0); + ecadd(WCB_COND(COND_MODI, 0)); + ecstr(b); + ecstr(a); + ecstr(c); } - } + } else if (a[0] == '-' && a[1]) { + ecadd(WCB_COND(COND_MOD, 2)); + ecstr(a); + ecstr(b); + ecstr(c); + } else + COND_ERROR("condition expected: %s", b); + + return 1; } /**/ -static void -eccond(Cond c) +static int +par_cond_multi(char *a, LinkList l) { - int p; - - switch (c->type) { - case COND_NOT: - ecadd(WCB_COND(COND_NOT, 0)); - eccond(c->left); - break; - case COND_AND: - case COND_OR: - p = ecadd(0); - eccond(c->left); - eccond(c->right); - ecbuf[p] = WCB_COND(c->type, ecused - 1 - p); - break; - case COND_MOD: - { - char **pp; - int num; + if (a[0] != '-' || !a[1]) + COND_ERROR("condition expected: %s", a); + else { + LinkNode n; - p = ecadd(0); - ecstr((char *) c->left); - for (pp = (char **) c->right, num = 0; *pp; pp++, num++) - ecstr(*pp); - ecbuf[p] = WCB_COND(COND_MOD, num); - } - break; - case COND_MODI: - ecadd(WCB_COND(COND_MODI, 0)); - ecstr((char *) c->left); - ecstr(((char **) c->right)[0]); - ecstr(((char **) c->right)[1]); - break; - default: - ecadd(WCB_COND(c->type, 0)); - ecstr((char *) c->left); - if (c->type <= COND_GE) { - ecstr((char *) c->right); - if (c->type == COND_STREQ || c->type == COND_STRNEQ) - ecadd(ecnpats++); - } - break; + ecadd(WCB_COND(COND_MOD, countlinknodes(l))); + ecstr(a); + for (n = firstnode(l); n; incnode(n)) + ecstr((char *) getdata(n)); } + return 1; } /**/ -static Eprog -execompile(List list) +static void +yyerror(int noerr) { - Eprog ret; - Eccstr p; - char *q; - int l; - - MUSTUSEHEAP("execompile"); - - ecbuf = (Wordcode) zhalloc((eclen = ecfree = 256) * sizeof(wordcode)); - ecused = 0; - ecstrs = NULL; - ecsoffs = ecnpats = 0; + int t0; + char *t; - ec(list); - ecadd(WCB_END()); + if ((t = dupstring(yytext))) + untokenize(t); - ret = (Eprog) zhalloc(sizeof(*ret)); - ret->len = ((ecnpats * sizeof(Patprog)) + - (ecused * sizeof(wordcode)) + - ecsoffs); - ret->npats = ecnpats; - ret->pats = (Patprog *) zhalloc(ret->len); - ret->prog = (Wordcode) (ret->pats + ecnpats); - ret->strs = (char *) (ret->prog + ecused); - ret->shf = NULL; - ret->heap = 1; - for (l = 0; l < ecnpats; l++) - ret->pats[l] = dummy_patprog1; - memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode)); - for (p = ecstrs, q = ret->strs; p; p = p->next, q += l) { - l = strlen(p->str) + 1; - memcpy(q, p->str, l); - } - return ret; + for (t0 = 0; t0 != 20; t0++) + if (!t || !t[t0] || t[t0] == '\n') + break; + if (t0 == 20) + zwarn("parse error near `%l...'", t, 20); + else if (t0) + zwarn("parse error near `%l'", t, t0); + else + zwarn("parse error", NULL, 0); + if (!noerr && noerrs != 2) + errflag = 1; } /**/ @@ -2425,75 +2063,94 @@ freeeprogs(void) /**/ char * -ecgetstr(Estate s, int dup) +ecgetstr(Estate s, int dup, int *tok) { static char buf[4]; wordcode c = *s->pc++; char *r; - if (c == 0xfe000000) + if (c == 6 || c == 7) r = ""; - else if (c >= 0xff000000) { - buf[0] = (char) (c & 0xff); - buf[1] = (char) ((c >> 8) & 0xff); - buf[2] = (char) ((c >> 16) & 0xff); + else if (c & 2) { + buf[0] = (char) ((c >> 3) & 0xff); + buf[1] = (char) ((c >> 11) & 0xff); + buf[2] = (char) ((c >> 19) & 0xff); buf[3] = '\0'; r = dupstring(buf); - dup = 0; - } else - r = s->strs + c; - - return (dup ? dupstring(r) : r); + dup = EC_NODUP; + } else { + r = s->strs + (c >> 2); + } + if (tok) + *tok = (c & 1); + return ((dup == EC_DUP || (dup && (c & 1))) ? dupstring(r) : r); } /**/ char * -ecrawstr(Eprog p, Wordcode pc) +ecrawstr(Eprog p, Wordcode pc, int *tok) { static char buf[4]; wordcode c = *pc; - if (c == 0xfe000000) + if (c == 6 || c == 7) { + if (tok) + *tok = (c & 1); return ""; - else if (c >= 0xff000000) { - buf[0] = (char) (c & 0xff); - buf[1] = (char) ((c >> 8) & 0xff); - buf[2] = (char) ((c >> 16) & 0xff); + } else if (c & 2) { + buf[0] = (char) ((c >> 3) & 0xff); + buf[1] = (char) ((c >> 11) & 0xff); + buf[2] = (char) ((c >> 19) & 0xff); buf[3] = '\0'; + if (tok) + *tok = (c & 1); return buf; - } else - return p->strs + c; + } else { + if (tok) + *tok = (c & 1); + return p->strs + (c >> 2); + } } /**/ char ** -ecgetarr(Estate s, int num, int dup) +ecgetarr(Estate s, int num, int dup, int *tok) { char **ret, **rp; + int tf = 0, tmp = 0; ret = rp = (char **) zhalloc((num + 1) * sizeof(char *)); - while (num--) - *rp++ = ecgetstr(s, dup); + while (num--) { + *rp++ = ecgetstr(s, dup, &tmp); + tf |= tmp; + } *rp = NULL; + if (tok) + *tok = tf; return ret; } /**/ LinkList -ecgetlist(Estate s, int num, int dup) +ecgetlist(Estate s, int num, int dup, int *tok) { if (num) { LinkList ret; + int i, tf = 0, tmp = 0; - ret = newlinklist(); - - while (num--) - addlinknode(ret, ecgetstr(s, dup)); - + ret = newsizedlist(num); + for (i = 0; i < num; i++) { + setsizednode(ret, i, ecgetstr(s, dup, &tmp)); + tf |= tmp; + } + if (tok) + *tok = tf; return ret; } + if (tok) + *tok = 0; return NULL; } @@ -2509,7 +2166,7 @@ ecgetredirs(Estate s) r->type = WC_REDIR_TYPE(code); r->fd1 = *s->pc++; - r->name = ecgetstr(s, 1); + r->name = ecgetstr(s, EC_DUP, NULL); addlinknode(ret, r); -- cgit 1.4.1