summaryrefslogtreecommitdiffstats
path: root/Src/parse.c
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>2000-02-23 15:13:27 +0000
committerTanaka Akira <akr@users.sourceforge.net>2000-02-23 15:13:27 +0000
commit2b37049c221501c6ae77e0308634aebcdb10060d (patch)
tree29c3604e4a9b5e9da1ff2c2d80be81f8d06f44a3 /Src/parse.c
parentzsh-workers/9840 (diff)
downloadzsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar.gz
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar.bz2
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar.lz
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar.xz
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.tar.zst
zsh-2b37049c221501c6ae77e0308634aebcdb10060d.zip
manual/9838
Diffstat (limited to 'Src/parse.c')
-rw-r--r--Src/parse.c2607
1 files changed, 1132 insertions, 1475 deletions
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,40 +65,343 @@ 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)
+/*
+ * 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.
+ */
+
+/**/
+int eclen, ecused, ecfree, ecnpats;
+/**/
+Wordcode ecbuf;
+/**/
+Eccstr ecstrs;
+/**/
+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;
+}
+
+/* Insert n free code-slots at position p. */
+
+static void
+ecispace(int p, int n)
+{
+ int m;
+
+ 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;
+ }
+ if ((m = ecused - p) > 0)
+ memmove(ecbuf + p + n, ecbuf + p, m * sizeof(wordcode));
+ ecused += n;
+}
+
+/* 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;
+}
+
+/* Delete a wordcode. */
+
+static void
+ecdel(int p)
{
- struct node *r = (struct node *) hcalloc(s);
+ int n = ecused - p - 1;
- r->ntype = t;
+ if (n > 0)
+ memmove(ecbuf + p, ecbuf + p + 1, n * sizeof(wordcode));
+ ecused--;
+}
- return (void *) r;
+/* 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;
}
/*
@@ -282,102 +409,138 @@ allocnode(size_t s, int t)
* | SEPER
* | sublist [ SEPER | AMPER | AMPERBANG ]
*/
+
/**/
Eprog
parse_event(void)
{
- List ret;
tok = ENDINPUT;
incmdpos = 1;
yylex();
- return ((ret = par_event()) ? execompile(ret) : NULL);
+ init_parse();
+ return ((par_event()) ? bld_eprog() : NULL);
}
/**/
-static List
+static int
par_event(void)
{
- Sublist sl;
- List l = NULL;
+ int r = 0, p, c = 0;
while (tok == SEPER) {
if (isnewlin > 0)
- return NULL;
+ return 0;
yylex();
}
if (tok == ENDINPUT)
- return NULL;
- if ((sl = par_sublist())) {
+ return 0;
+
+ p = ecadd(0);
+
+ if (par_sublist(&c)) {
if (tok == ENDINPUT) {
- l = (List) make_list();
- l->type = Z_SYNC;
- l->left = sl;
+ set_list_code(p, Z_SYNC, c);
+ r = 1;
} else if (tok == SEPER) {
- l = (List) make_list();
- l->type = Z_SYNC;
- l->left = sl;
+ set_list_code(p, Z_SYNC, c);
if (isnewlin <= 0)
yylex();
+ r = 1;
} else if (tok == AMPER) {
- l = (List) make_list();
- l->type = Z_ASYNC;
- l->left = sl;
+ set_list_code(p, Z_ASYNC, c);
yylex();
+ r = 1;
} else if (tok == AMPERBANG) {
- l = (List) make_list();
- l->type = Z_ASYNC | Z_DISOWN;
- l->left = sl;
+ set_list_code(p, (Z_ASYNC | Z_DISOWN), c);
yylex();
- } else
- l = NULL;
+ r = 1;
+ }
}
- if (!l) {
+ if (!r) {
if (errflag) {
yyerror(0);
- return NULL;
+ ecused--;
+ return 0;
}
yyerror(1);
herrflush();
if (noerrs != 2)
errflag = 1;
- return NULL;
+ ecused--;
+ return 0;
} else {
- l->right = par_event();
+ int oec = ecused;
+
+ par_event();
+ if (ecused == oec)
+ ecbuf[p] |= wc_bdata(Z_END);
}
- return l;
+ return 1;
}
/**/
mod_export Eprog
parse_list(void)
{
- List ret;
+ int c = 0;
tok = ENDINPUT;
incmdpos = 1;
yylex();
- ret = par_list();
-#if 0
- if (tok == LEXERR)
+ init_parse();
+ par_list(&c);
+#if 0
+ if (tok == LEXERR)
#endif
- if (tok != ENDINPUT)
- {
+ if (tok != ENDINPUT) {
yyerror(0);
return NULL;
}
- return execompile(ret);
+ return bld_eprog();
}
/**/
mod_export Eprog
parse_cond(void)
{
- Cond c = par_cond();
+ init_parse();
- if (!c)
+ if (!par_cond())
return NULL;
- return execompile((List) c);
+ 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]);
+ }
}
/*
@@ -385,47 +548,60 @@ parse_cond(void)
*/
/**/
-static List
-par_list(void)
+static int
+par_list(int *complex)
{
- Sublist sl;
- List l = NULL;
+ 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;
+ int oecused = ecused, brflag, p, pp, n = 1, type;
+
+ p = ecadd(0);
- c->type = CCASE;
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)) {
- cmdpop();
- YYERRORV;
- } else {
+ } else if (tok == INBRACE) {
+ usebrace = 1;
+ cmdpop();
+ cmdpush(nc);
+ yylex();
+ par_save_list(complex);
+ if (tok != OUTBRACE) {
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,109 +1417,303 @@ 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;
+ int ll, sl, c = 0;
+
+ ll = ecadd(0);
+ sl = ecadd(0);
+
+ par_cmd(&c);
- 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;
+ set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c);
+ set_list_code(ll, (Z_SYNC | Z_END), c);
}
cmdpop();
- c->type = FUNCDEF;
+
+ ecbuf[p + argc + 2] = ecused - argc - p;
+ ecbuf[p + argc + 3] = ecnpats;
+
+ 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);
+
+ isfunc = 1;
} else
break;
isnull = 0;
}
- if (isnull && (!c->redir || empty(c->redir)))
- return NULL;
+ if (isnull && !(sr + nr)) {
+ ecused = p;
+ return 0;
+ }
incmdpos = 1;
- return c;
+
+ if (!isfunc)
+ ecbuf[p] = WCB_SIMPLE(argc);
+
+ return sr + 1;
+}
+
+/*
+ * 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(int *rp)
+{
+ int r = *rp, type, fd1, oldcmdpos, oldnc;
+ char *name;
+
+ oldcmdpos = incmdpos;
+ incmdpos = 0;
+ oldnc = nocorrect;
+ if (tok != INANG && tok != INOUTANG)
+ nocorrect = 1;
+ type = redirtab[tok - OUTANG];
+ fd1 = tokfd;
+ yylex();
+ if (tok != STRING && tok != ENVSTRING)
+ YYERRORV(ecused);
+ incmdpos = oldcmdpos;
+ nocorrect = oldnc;
+
+ /* assign default fd */
+ if (fd1 == -1)
+ fd1 = IS_READFD(type) ? 0 : 1;
+
+ name = tokstr;
+
+ switch (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)->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)
+ /* > >(...) */
+ type = OUTPIPE;
+ else if (tokstr[0] == Inang && tokstr[1] == Inpar)
+ YYERRORV(ecused);
+ break;
+ case READ:
+ if (tokstr[0] == Inang && tokstr[1] == Inpar)
+ /* < <(...) */
+ type = INPIPE;
+ else if (tokstr[0] == Outang && tokstr[1] == Inpar)
+ YYERRORV(ecused);
+ break;
+ case READWRITE:
+ if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar)
+ type = tokstr[0] == Inang ? INPIPE : OUTPIPE;
+ break;
+ }
+ yylex();
+
+ /* 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);
+}
+
+/*
+ * wordlist : { STRING }
+ */
+
+/**/
+static int
+par_wordlist(void)
+{
+ int num = 0;
+ while (tok == STRING) {
+ ecstr(tokstr);
+ num++;
+ yylex();
+ }
+ return num;
+}
+
+/*
+ * nl_wordlist : { STRING | SEPER }
+ */
+
+/**/
+static int
+par_nl_wordlist(void)
+{
+ int num = 0;
+
+ while (tok == STRING || tok == SEPER) {
+ if (tok != SEPER) {
+ ecstr(tokstr);
+ num++;
+ }
+ yylex();
+ }
+ return num;
}
/*
@@ -1305,25 +1729,24 @@ void (*condlex) _((void)) = yylex;
*/
/**/
-static Cond
+static int
par_cond(void)
{
- Cond c, c2;
+ int p = ecused, r;
- c = par_cond_1();
+ r = 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;
+ ecispace(p, 1);
+ par_cond();
+ ecbuf[p] = WCB_COND(COND_OR, ecused - 1 - p);
+ return 1;
}
- return c;
+ return r;
}
/*
@@ -1331,25 +1754,24 @@ par_cond(void)
*/
/**/
-static Cond
+static int
par_cond_1(void)
{
- Cond c, c2;
+ int r, p = ecused;
- c = par_cond_2();
+ r = 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;
+ ecispace(p, 1);
+ par_cond_1();
+ ecbuf[p] = WCB_COND(COND_AND, ecused - 1 - p);
+ return 1;
}
- return c;
+ return r;
}
/*
@@ -1361,10 +1783,9 @@ par_cond_1(void)
*/
/**/
-static Cond
+static int
par_cond_2(void)
{
- Cond c, c2;
char *s1, *s2, *s3;
int dble = 0;
@@ -1398,23 +1819,22 @@ par_cond_2(void)
}
if (tok == BANG) {
condlex();
- c = par_cond_2();
- c2 = (Cond) make_cond();
- c2->left = (void *) c;
- c2->type = COND_NOT;
- return c2;
+ ecadd(WCB_COND(COND_NOT, 0));
+ return par_cond_2();
}
if (tok == INPAR) {
+ int r;
+
condlex();
while (tok == SEPER)
condlex();
- c = par_cond();
+ r = par_cond();
while (tok == SEPER)
condlex();
if (tok != OUTPAR)
- YYERROR;
+ YYERROR(ecused);
condlex();
- return c;
+ return r;
}
if (tok != STRING) {
if (tok && tok != LEXERR && condlex == testlex) {
@@ -1422,7 +1842,7 @@ par_cond_2(void)
condlex();
return par_cond_double("-n", s1);
} else
- YYERROR;
+ YYERROR(ecused);
}
s1 = tokstr;
if (condlex == testlex)
@@ -1433,15 +1853,13 @@ par_cond_2(void)
int xtok = tok;
condlex();
if (tok != STRING)
- YYERROR;
+ YYERROR(ecused);
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;
+ ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0));
+ ecstr(s1);
+ ecstr(s3);
+ return 1;
}
if (tok != STRING) {
if (tok != LEXERR && condlex == testlex) {
@@ -1450,7 +1868,7 @@ par_cond_2(void)
else if (!strcmp(s1, "-t"))
return par_cond_double(s1, "1");
} else
- YYERROR;
+ YYERROR(ecused);
}
s2 = tokstr;
incond++; /* parentheses do globbing */
@@ -1476,151 +1894,21 @@ par_cond_2(void)
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(sizeof(struct redir), 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
+static int
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);
+ 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 n;
+ return 1;
}
/**/
@@ -1640,66 +1928,59 @@ get_cond_num(char *tst)
}
/**/
-static Cond
+static int
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;
+ ecadd(WCB_COND(COND_STREQ, 0));
+ ecstr(a);
+ ecstr(c);
+ ecadd(ecnpats++);
} 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;
+ ecadd(WCB_COND(COND_STRNEQ, 0));
+ ecstr(a);
+ ecstr(c);
+ ecadd(ecnpats++);
} 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;
+ ecadd(WCB_COND(t0 + COND_NT, 0));
+ ecstr(a);
+ ecstr(c);
} 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);
+ ecadd(WCB_COND(COND_MODI, 0));
+ ecstr(b);
+ ecstr(a);
+ ecstr(c);
}
} 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);
+ ecadd(WCB_COND(COND_MOD, 2));
+ ecstr(a);
+ ecstr(b);
+ ecstr(c);
} else
COND_ERROR("condition expected: %s", b);
- return n;
+
+ return 1;
}
/**/
-static Cond
+static int
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);
+ LinkNode n;
+
+ ecadd(WCB_COND(COND_MOD, countlinknodes(l)));
+ ecstr(a);
+ for (n = firstnode(l); n; incnode(n))
+ ecstr((char *) getdata(n));
}
- return n;
+ return 1;
}
/**/
@@ -1707,667 +1988,24 @@ static void
yyerror(int noerr)
{
int t0;
+ char *t;
+
+ if ((t = dupstring(yytext)))
+ untokenize(t);
for (t0 = 0; t0 != 20; t0++)
- if (!yytext || !yytext[t0] || yytext[t0] == '\n')
+ if (!t || !t[t0] || t[t0] == '\n')
break;
if (t0 == 20)
- zwarn("parse error near `%l...'", yytext, 20);
+ zwarn("parse error near `%l...'", t, 20);
else if (t0)
- zwarn("parse error near `%l'", yytext, t0);
+ zwarn("parse error near `%l'", t, 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;
-
- p = ecadd(0);
- ecstr(nn->u.forcmd->name);
-
- if (nn->args) {
- LinkNode fp;
- int num;
-
- type = WC_SELECT_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_SELECT_PPARAM;
-
- ecsave(nn->u.forcmd->list);
-
- 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;
- }
- }
- break;
- case N_COND:
- eccond((Cond) n);
- break;
-#ifdef DEBUG
- default:
- dputs("BUG: node type not handled in ecomp().");
- break;
-#endif
- }
-}
-
-/**/
-static void
-ecredirs(LinkList l)
-{
- LinkNode n;
- Redir f;
-
- if (!l)
- return;
-
- for (n = firstnode(l); n; incnode(n)) {
- f = (Redir) getdata(n);
-
- ecadd(WCB_REDIR(f->type));
- ecadd(f->fd1);
- ecstr(f->name);
- }
-}
-
-/**/
-static void
-ecassigns(LinkList l)
-{
- int p;
- LinkNode n;
- Varasg v;
-
- if (!l)
- return;
-
- for (n = firstnode(l); n; incnode(n)) {
- v = (Varasg) getdata(n);
-
- p = ecadd(0);
- ecstr(v->name);
-
- if (PM_TYPE(v->type) == PM_ARRAY) {
- LinkNode vp;
- int num;
-
- for (vp = firstnode(v->arr), num = 0; vp; incnode(vp), num++)
- ecstr((char *) getdata(vp));
- ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, num);
- } else {
- ecstr(v->str);
- ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_SCALAR, 0);
- }
- }
-}
-
-/**/
-static void
-eccond(Cond c)
-{
- 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;
-
- 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;
- }
-}
-
-/**/
-static Eprog
-execompile(List list)
-{
- 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;
-
- ec(list);
- 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;
-}
-
/**/
mod_export Eprog
dupeprog(Eprog p)
@@ -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);