* PATCH: 4.1: multi-parameter for loop @ 2001-06-20 14:45 Peter Stephenson 2001-06-20 16:11 ` Peter Stephenson ` (2 more replies) 0 siblings, 3 replies; 18+ messages in thread From: Peter Stephenson @ 2001-06-20 14:45 UTC (permalink / raw) To: Zsh hackers list This is meddling with things one probably shouldn't touch, unless one's working on a particularly annoying and sporadic bug in something else. This extends the for syntax to take multiple parameters after it; they take multiple words from the argument list. The main intended use of this is for imitating perl's `each' feature: typeset -A assoc assoc=(key1 val1 key2 val2) for key value in ${(kv)assoc}; do print $key $value done prints key1 val1 key2 val2 (though ordering of elements isn't guaranteed, of course). My main worry is that the wordcode stuff is as clear as mud to me. In particular, I don't know what WC_FOR_SKIP is doing, why it divides the data size(?) by 4, and whether it needs changing when there's more stuff in the for structure. I probably won't be committing this for a while, if at all. All tests still pass, though. Index: Src/loop.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/loop.c,v retrieving revision 1.4 diff -u -r1.4 loop.c --- Src/loop.c 2000/06/17 17:05:53 1.4 +++ Src/loop.c 2001/06/20 14:34:48 @@ -52,15 +52,15 @@ Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; + int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; - LinkList args = NULL; + LinkList vars = NULL, args = NULL; - name = ecgetstr(state, EC_NODUP, NULL); end = state->pc + WC_FOR_SKIP(code); if (iscond) { - str = dupstring(name); + str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); @@ -77,28 +77,32 @@ } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); - } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) { - int htok = 0; - - if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { - state->pc = end; - return 0; - } - if (htok) - execsubst(args); } else { - char **x; + vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); + + if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + int htok = 0; + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; + return 0; + } + if (htok) + execsubst(args); + } else { + char **x; - args = newlinklist(); - for (x = pparams; *x; x++) - addlinknode(args, dupstring(*x)); + args = newlinklist(); + for (x = pparams; *x; x++) + addlinknode(args, dupstring(*x)); + } } lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; - for (;;) { + while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); @@ -127,14 +131,29 @@ if (!val) break; } else { - if (!args || !(str = (char *) ugetnode(args))) - break; - if (isset(XTRACE)) { - printprompt4(); - fprintf(xtrerr, "%s=%s\n", name, str); - fflush(xtrerr); + LinkNode node; + int count = 0; + for (node = firstnode(vars); node; incnode(node)) + { + name = (char *)getdata(node); + if (!args || !(str = (char *) ugetnode(args))) + { + if (count) { + str = ""; + last = 1; + } else + break; + } + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s=%s\n", name, str); + fflush(xtrerr); + } + setsparam(name, ztrdup(str)); + count++; } - setsparam(name, ztrdup(str)); + if (!count) + break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); Index: Src/parse.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/parse.c,v retrieving revision 1.23 diff -u -r1.23 parse.c --- Src/parse.c 2001/06/18 07:34:34 1.23 +++ Src/parse.c 2001/06/20 14:34:49 @@ -903,15 +903,25 @@ yylex(); type = WC_FOR_COND; } else { + int np, n, isin = 0; infor = 0; if (tok != STRING || !isident(tokstr)) YYERRORV(oecused); - ecstr(tokstr); + np = ecadd(0); + n = 0; incmdpos = 1; - yylex(); - if (tok == STRING && !strcmp(tokstr, "in")) { - int np, n; + for (;;) { + n++; + ecstr(tokstr); + yylex(); + if (tok != STRING || (isin = !strcmp(tokstr, "in")) || sel) + break; + if (!isident(tokstr)) + YYERRORV(oecused); + } + ecbuf[np] = n; + if (isin) { incmdpos = 0; yylex(); np = ecadd(0); @@ -921,8 +931,6 @@ ecbuf[np] = n; type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); } else if (tok == INPAR) { - int np, n; - incmdpos = 0; yylex(); np = ecadd(0); Index: Doc/Zsh/grammar.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/grammar.yo,v retrieving revision 1.4 diff -u -r1.4 grammar.yo --- Doc/Zsh/grammar.yo 2000/08/29 06:35:40 1.4 +++ Doc/Zsh/grammar.yo 2001/06/20 14:34:49 @@ -149,12 +149,20 @@ findex(for) cindex(for loops) cindex(loops, for) -item(tt(for) var(name) [ tt(in) var(word) ... var(term) ] tt(do) var(list) tt(done))( +item(tt(for) var(name) ... [ tt(in) var(word) ... ] var(term) tt(do) var(list) tt(done))( where var(term) is at least one newline or tt(;). Expand the list of var(word)s, and set the parameter var(name) to each of them in turn, executing var(list) each time. If the tt(in) var(word) is omitted, use the positional parameters instead of the var(word)s. + +More than one parameter var(name) can appear before the list of +var(word)s. If var(N) var(name)s are given, then on each execution of the +loop the next tt(N) var(word)s are assigned to the corresponding +parameters. If there are more var(name)s than remaining var(word)s, the +remaining parameters are each set to the empty string. Execution of the +loop ends when there is no remaining var(word) to assign to the first +var(name). ) item(tt(for LPAR()LPAR()) [var(expr1)] tt(;) [var(expr2)] tt(;) [var(expr3)] tt(RPAR()RPAR() do) var(list) tt(done))( The arithmetic expression var(expr1) is evaluated first (see -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 14:45 PATCH: 4.1: multi-parameter for loop Peter Stephenson @ 2001-06-20 16:11 ` Peter Stephenson 2001-06-20 18:01 ` Andrej Borsenkow 2001-06-21 8:33 ` Sven Wischnowsky 2 siblings, 0 replies; 18+ messages in thread From: Peter Stephenson @ 2001-06-20 16:11 UTC (permalink / raw) To: Zsh hackers list Peter Stephenson wrote: > This extends the for syntax to take multiple parameters after it; they take > multiple words from the argument list. Sorry, I didn't send the text.c chunk, without which this will crash horribly. Here's the complete thing. Index: Doc/Zsh/grammar.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/grammar.yo,v retrieving revision 1.4 diff -u -r1.4 grammar.yo --- Doc/Zsh/grammar.yo 2000/08/29 06:35:40 1.4 +++ Doc/Zsh/grammar.yo 2001/06/20 16:09:33 @@ -149,12 +149,20 @@ findex(for) cindex(for loops) cindex(loops, for) -item(tt(for) var(name) [ tt(in) var(word) ... var(term) ] tt(do) var(list) tt(done))( +item(tt(for) var(name) ... [ tt(in) var(word) ... ] var(term) tt(do) var(list) tt(done))( where var(term) is at least one newline or tt(;). Expand the list of var(word)s, and set the parameter var(name) to each of them in turn, executing var(list) each time. If the tt(in) var(word) is omitted, use the positional parameters instead of the var(word)s. + +More than one parameter var(name) can appear before the list of +var(word)s. If var(N) var(name)s are given, then on each execution of the +loop the next tt(N) var(word)s are assigned to the corresponding +parameters. If there are more var(name)s than remaining var(word)s, the +remaining parameters are each set to the empty string. Execution of the +loop ends when there is no remaining var(word) to assign to the first +var(name). ) item(tt(for LPAR()LPAR()) [var(expr1)] tt(;) [var(expr2)] tt(;) [var(expr3)] tt(RPAR()RPAR() do) var(list) tt(done))( The arithmetic expression var(expr1) is evaluated first (see Index: Src/loop.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/loop.c,v retrieving revision 1.4 diff -u -r1.4 loop.c --- Src/loop.c 2000/06/17 17:05:53 1.4 +++ Src/loop.c 2001/06/20 16:09:33 @@ -52,15 +52,15 @@ Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; + int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; - LinkList args = NULL; + LinkList vars = NULL, args = NULL; - name = ecgetstr(state, EC_NODUP, NULL); end = state->pc + WC_FOR_SKIP(code); if (iscond) { - str = dupstring(name); + str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); @@ -77,28 +77,32 @@ } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); - } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) { - int htok = 0; - - if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { - state->pc = end; - return 0; - } - if (htok) - execsubst(args); } else { - char **x; + vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); + + if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + int htok = 0; + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; + return 0; + } + if (htok) + execsubst(args); + } else { + char **x; - args = newlinklist(); - for (x = pparams; *x; x++) - addlinknode(args, dupstring(*x)); + args = newlinklist(); + for (x = pparams; *x; x++) + addlinknode(args, dupstring(*x)); + } } lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; - for (;;) { + while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); @@ -127,14 +131,29 @@ if (!val) break; } else { - if (!args || !(str = (char *) ugetnode(args))) - break; - if (isset(XTRACE)) { - printprompt4(); - fprintf(xtrerr, "%s=%s\n", name, str); - fflush(xtrerr); + LinkNode node; + int count = 0; + for (node = firstnode(vars); node; incnode(node)) + { + name = (char *)getdata(node); + if (!args || !(str = (char *) ugetnode(args))) + { + if (count) { + str = ""; + last = 1; + } else + break; + } + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s=%s\n", name, str); + fflush(xtrerr); + } + setsparam(name, ztrdup(str)); + count++; } - setsparam(name, ztrdup(str)); + if (!count) + break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); Index: Src/parse.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/parse.c,v retrieving revision 1.23 diff -u -r1.23 parse.c --- Src/parse.c 2001/06/18 07:34:34 1.23 +++ Src/parse.c 2001/06/20 16:09:34 @@ -903,15 +903,25 @@ yylex(); type = WC_FOR_COND; } else { + int np, n, isin = 0; infor = 0; if (tok != STRING || !isident(tokstr)) YYERRORV(oecused); - ecstr(tokstr); + np = ecadd(0); + n = 0; incmdpos = 1; - yylex(); - if (tok == STRING && !strcmp(tokstr, "in")) { - int np, n; + for (;;) { + n++; + ecstr(tokstr); + yylex(); + if (tok != STRING || (isin = !strcmp(tokstr, "in")) || sel) + break; + if (!isident(tokstr)) + YYERRORV(oecused); + } + ecbuf[np] = n; + if (isin) { incmdpos = 0; yylex(); np = ecadd(0); @@ -921,8 +931,6 @@ ecbuf[np] = n; type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); } else if (tok == INPAR) { - int np, n; - incmdpos = 0; yylex(); np = ecadd(0); Index: Src/text.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/text.c,v retrieving revision 1.5 diff -u -r1.5 text.c --- Src/text.c 2000/12/05 10:34:23 1.5 +++ Src/text.c 2001/06/20 16:09:34 @@ -415,7 +415,7 @@ taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr(")) do"); } else { - taddstr(ecgetstr(state, EC_NODUP, NULL)); + taddlist(state, *state->pc++); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { taddstr(" in "); taddlist(state, *state->pc++); -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 14:45 PATCH: 4.1: multi-parameter for loop Peter Stephenson 2001-06-20 16:11 ` Peter Stephenson @ 2001-06-20 18:01 ` Andrej Borsenkow 2001-06-20 18:20 ` Bart Schaefer 2001-06-21 8:33 ` Sven Wischnowsky 2 siblings, 1 reply; 18+ messages in thread From: Andrej Borsenkow @ 2001-06-20 18:01 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh hackers list On Wed, 20 Jun 2001, Peter Stephenson wrote: > > This extends the for syntax to take multiple parameters after it; they take > multiple words from the argument list. The main intended use of this is > for imitating perl's `each' feature: > > typeset -A assoc > assoc=(key1 val1 key2 val2) > for key value in ${(kv)assoc}; do > print $key $value > done > This for sure is incompatible with POSIX and all known shells. It does not make legal scripts fail, but it makes illegal scripts legal. Should we care about it? -andrej ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 18:01 ` Andrej Borsenkow @ 2001-06-20 18:20 ` Bart Schaefer 2001-06-20 18:39 ` Peter Stephenson 0 siblings, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2001-06-20 18:20 UTC (permalink / raw) To: Andrej Borsenkow; +Cc: Zsh hackers list On Jun 20, 10:01pm, Andrej Borsenkow wrote: } Subject: Re: PATCH: 4.1: multi-parameter for loop } } On Wed, 20 Jun 2001, Peter Stephenson wrote: } } > This extends the for syntax to take multiple parameters after it } } This for sure is incompatible with POSIX and all known shells. It } does not make legal scripts fail, but it makes illegal scripts legal. } Should we care about it? In general we've taken the position that this is OK. Consider the "foreach" form, or "if [[ test ]] { command }", etc. -- Bart Schaefer Brass Lantern Enterprises http://www.well.com/user/barts http://www.brasslantern.com Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 18:20 ` Bart Schaefer @ 2001-06-20 18:39 ` Peter Stephenson 2001-06-20 18:55 ` Bart Schaefer 0 siblings, 1 reply; 18+ messages in thread From: Peter Stephenson @ 2001-06-20 18:39 UTC (permalink / raw) To: Zsh hackers list "Bart Schaefer" wrote: > On Jun 20, 10:01pm, Andrej Borsenkow wrote: > } Subject: Re: PATCH: 4.1: multi-parameter for loop > } > } On Wed, 20 Jun 2001, Peter Stephenson wrote: > } > } > This extends the for syntax to take multiple parameters after it > } > } This for sure is incompatible with POSIX and all known shells. It > } does not make legal scripts fail, but it makes illegal scripts legal. > } Should we care about it? > > In general we've taken the position that this is OK. Consider the > "foreach" form, or "if [[ test ]] { command }", etc. I've always considered the shell is already riddled with this sort of extension. I much more concerned that there's some valid POSIXy case I've missed that this screws up. I'm perfectly happy to attach it to some relevant option, but I don't think there is a good one; NO_KSH_ARRAYS would be very marginal, probably too unexpected. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 18:39 ` Peter Stephenson @ 2001-06-20 18:55 ` Bart Schaefer 2001-06-20 19:12 ` Peter Stephenson 2001-06-22 23:49 ` PATCH: 4.1: multi-parameter for loop Zefram 0 siblings, 2 replies; 18+ messages in thread From: Bart Schaefer @ 2001-06-20 18:55 UTC (permalink / raw) To: Peter Stephenson, Zsh hackers list On Jun 20, 7:39pm, Peter Stephenson wrote: } Subject: Re: PATCH: 4.1: multi-parameter for loop } } I much more concerned that there's some valid POSIXy case I've missed } that this screws up. Well, there's this: for in in in in; do echo $in; done I haven't applied your patch yet, so I don't know whether it fouls up the above, but clearly a parameter named "in" can only appear in the first position, and everything else has to be taken as a keyword first and only a parameter name otherwise. } I'm perfectly happy to attach it to some } relevant option, but I don't think there is a good one; What if you attached it to the "foreach" keyword, but not "for"? So then one would have to write foreach x y z (p d q) ... Just a thought. -- Bart Schaefer Brass Lantern Enterprises http://www.well.com/user/barts http://www.brasslantern.com Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 18:55 ` Bart Schaefer @ 2001-06-20 19:12 ` Peter Stephenson 2001-06-20 22:56 ` Danek Duvall 2001-06-22 23:49 ` PATCH: 4.1: multi-parameter for loop Zefram 1 sibling, 1 reply; 18+ messages in thread From: Peter Stephenson @ 2001-06-20 19:12 UTC (permalink / raw) To: Zsh hackers list "Bart Schaefer" wrote: > Well, there's this: > > for in in in in; do echo $in; done > > I haven't applied your patch yet, so I don't know whether it fouls up > the above, but clearly a parameter named "in" can only appear in the first > position, and everything else has to be taken as a keyword first and only > a parameter name otherwise. It will stop reading parameters when it reaches the second `in'. I meant to document this, although it should be pretty obvious. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 19:12 ` Peter Stephenson @ 2001-06-20 22:56 ` Danek Duvall 2001-06-21 7:19 ` Andrej Borsenkow 0 siblings, 1 reply; 18+ messages in thread From: Danek Duvall @ 2001-06-20 22:56 UTC (permalink / raw) To: Zsh hackers list On Wed, Jun 20, 2001 at 08:12:09PM +0100, Peter Stephenson wrote: > "Bart Schaefer" wrote: > > Well, there's this: > > > > for in in in in; do echo $in; done > > It will stop reading parameters when it reaches the second `in'. I meant > to document this, although it should be pretty obvious. Right. That lacks ambiguity because multiple distinct parameters can't have the same name. But that ambiguity is missing in for i in in in; do .... Do you set $i to "in" and "in" or do you set $i and $in set to "in" and ""? Posix presumably would simply use the first interpretation, and if you want something like the second, just don't use a parameter named in? Or am I missing the disambiguation? Danek ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: PATCH: 4.1: multi-parameter for loop 2001-06-20 22:56 ` Danek Duvall @ 2001-06-21 7:19 ` Andrej Borsenkow 2001-06-21 9:52 ` Peter Stephenson 2001-06-21 9:55 ` PATCH: POSIX " Bart Schaefer 0 siblings, 2 replies; 18+ messages in thread From: Andrej Borsenkow @ 2001-06-21 7:19 UTC (permalink / raw) To: Danek Duvall, Zsh hackers list > > On Wed, Jun 20, 2001 at 08:12:09PM +0100, Peter Stephenson wrote: > > > "Bart Schaefer" wrote: > > > Well, there's this: > > > > > > for in in in in; do echo $in; done > > > > It will stop reading parameters when it reaches the second > `in'. I meant > > to document this, although it should be pretty obvious. > > Right. That lacks ambiguity because multiple distinct parameters can't > have the same name. But that ambiguity is missing in > > for i in in in; do .... > > Do you set $i to "in" and "in" or do you set $i and $in set to > "in" and ""? Which opens up a question of odd number of list elements. It is invalid in assignment to hash - shuld it be invalid here as well? > Posix presumably would simply use the first interpretation, Yes. Here are grammar rules: for_clause : For name linebreak do_group | For name linebreak in wordlist sequential_sep do_group name : NAME /* Apply rule 5 */ ; in : In /* Apply rule 6 */ 5. [NAME in for] When the TOKEN meets the requirements for a name (see name in the XBD specification, Glossary ), the token identifier NAME will result. Otherwise, the token WORD will be returned. 6. [Third word of for and case] When the TOKEN is exactly the reserved word In, the token identifier for In will result. Otherwise, the token WORD will be returned. (As indicated in the grammar, a linebreak precedes the token In. If newline characters are present at the indicated location, it is the token after them that is treated in this fashion.) Note linebreak here. Definition is: linebreak : newline_list | /* empty */ ; It means, that the following is valid: fot i in a b c do ... it is currently does not work in zsh: bor@itsrm2% for i for> in a b c bor@itsrm2% ^^^^^^^^^^^^^^^ Oops! as opposed to sh: $ for i > in a b c > do > echo $i > done a b c and > if you want > something like the second, just don't use a parameter named in? Or am I > missing the disambiguation? > I guess, Bart suggestion (use foreach) is better. And more Perlish :-) Is there any feasible way to do something like foreach key val hash or even foreach val array i.e. do *not* expand $hash/%array value? For large arrays it may result in significant speedup. -andrej ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-21 7:19 ` Andrej Borsenkow @ 2001-06-21 9:52 ` Peter Stephenson 2001-06-21 10:34 ` PATCH (redux): POSIX `for' syntax Bart Schaefer 2001-06-21 9:55 ` PATCH: POSIX " Bart Schaefer 1 sibling, 1 reply; 18+ messages in thread From: Peter Stephenson @ 2001-06-21 9:52 UTC (permalink / raw) To: Zsh hackers list "Andrej Borsenkow" wrote: > Which opens up a question of odd number of list elements. It is invalid in > assignment to hash - shuld it be invalid here as well? This is covered in the manual page. for p1 p2 in foo bar something else rubbish; do print $p1 $p2 done prints (I cut and pasted this from actually trying it out): foo bar something else rubbish and you get an empty string for the final $p2. I didn't thing there was any point in doing too many sums --- particularly since you can use more than two parameters; here's a way of naming a set of function arguments: fn() { local nam cmd val dsc for nam cmd val dsc; do; break; done; print "$nam, $cmd, $val, $dsc" } Then `fn Me nothing none dunno' prints `Me, nothing, none, dunno'. With regard to `in', the standard interpretation is the one taken in all the suggestions I've seen so far. I should make this clear in the manual, though. > bor@itsrm2% for i > for> in a b c > bor@itsrm2% > ^^^^^^^^^^^^^^^ Oops! That shouldn't be too hard to fix, and wouldn't affect the new syntax: we just terminate the argument list at the end of the first line. Currently it thinks the newline means you're not going to give an `in' and are using positional parameters. I don't know why there's no syntax error, though, but you get one if you set NO_SHORT_LOOPS. > I guess, Bart suggestion (use foreach) is better. And more Perlish :-) I'm not so convinced, since `for' and `foreach' currently do the same thing, and I don't really like dividing the syntax to make people use the non-standard variant just for one use. foreach is automatically handled at the moment, as well as for, by the way. > foreach key val hash > > or even > > foreach val array > > i.e. do *not* expand $hash/%array value? For large arrays it may result in > significant speedup. It's possible, but actually not that effective for hashes, since to iterate through them they have to be flattened, and that only happens once in the current system anyway. By the way, I discovered a problem: alias expansion is turned on for parameter names after the first; alias h='history -f' for g h in foo bar; do; done turns `h' into `history -f' and the -f causes an unexpected parse error. This is because of the csh-style syntax --- the shell is looking for a `(' which it needs to parse as a single token, so it uses the parsing rules for command position. But now I know about it I can turn alias expansion off explicitly for that bit. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* PATCH (redux): POSIX `for' syntax 2001-06-21 9:52 ` Peter Stephenson @ 2001-06-21 10:34 ` Bart Schaefer 2001-06-21 15:31 ` PATCH (redux): non-POSIX " Peter Stephenson 0 siblings, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2001-06-21 10:34 UTC (permalink / raw) To: Zsh hackers list On Jun 21, 10:52am, Peter Stephenson wrote: } Subject: Re: PATCH: 4.1: multi-parameter for loop } } > I guess, Bart suggestion (use foreach) is better. And more Perlish :-) } } I'm not so convinced, since `for' and `foreach' currently do the same } thing, and I don't really like dividing the syntax to make people use the } non-standard variant just for one use. foreach is automatically handled at } the moment, as well as for, by the way. Hrm. The patch I just sent makes for x (a b c) behave as `for x (a b c)' used to, but foreach x (a b c) is taken as a short-loop to run the command "a b c" in a subshell once for each positional parameter. I think they should both behave that way; so the change to parse.c has to be fractionally more complicated. This goes on top of the last one. --- zsh-forge/current/Src/parse.c Thu Jun 21 03:06:36 2001 +++ zsh-4.0/Src/parse.c Thu Jun 21 03:31:04 2001 @@ -903,13 +903,15 @@ yylex(); type = WC_FOR_COND; } else { + int posix_in; infor = 0; if (tok != STRING || !isident(tokstr)) YYERRORV(oecused); ecstr(tokstr); incmdpos = 1; yylex(); - while (isnewlin && !csh) + posix_in = isnewlin; + while (isnewlin) yylex(); if (tok == STRING && !strcmp(tokstr, "in")) { int np, n; @@ -922,7 +924,7 @@ YYERRORV(oecused); ecbuf[np] = n; type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); - } else if (tok == INPAR) { + } else if (!posix_in && tok == INPAR) { int np, n; incmdpos = 0; -- Bart Schaefer Brass Lantern Enterprises http://www.well.com/user/barts http://www.brasslantern.com Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net ^ permalink raw reply [flat|nested] 18+ messages in thread
* PATCH (redux): non-POSIX `for' syntax 2001-06-21 10:34 ` PATCH (redux): POSIX `for' syntax Bart Schaefer @ 2001-06-21 15:31 ` Peter Stephenson 2001-06-25 16:05 ` Peter Stephenson 0 siblings, 1 reply; 18+ messages in thread From: Peter Stephenson @ 2001-06-21 15:31 UTC (permalink / raw) To: Zsh hackers list "Bart Schaefer" wrote: > This goes on top of the last one. This is my patch relative to the foregoing. It improves the documentation, and adds the fix not to expand aliases in parameter names after the first. Index: Doc/Zsh/grammar.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/grammar.yo,v retrieving revision 1.4 diff -u -r1.4 grammar.yo --- Doc/Zsh/grammar.yo 2000/08/29 06:35:40 1.4 +++ Doc/Zsh/grammar.yo 2001/06/21 15:27:31 @@ -149,12 +149,21 @@ findex(for) cindex(for loops) cindex(loops, for) -item(tt(for) var(name) [ tt(in) var(word) ... var(term) ] tt(do) var(list) tt(done))( +item(tt(for) var(name) ... [ tt(in) var(word) ... ] var(term) tt(do) var(list) tt(done))( where var(term) is at least one newline or tt(;). Expand the list of var(word)s, and set the parameter var(name) to each of them in turn, executing var(list) each time. If the tt(in) var(word) is omitted, use the positional parameters instead of the var(word)s. + +More than one parameter var(name) can appear before the list of +var(word)s. If var(N) var(name)s are given, then on each execution of the +loop the next tt(N) var(word)s are assigned to the corresponding +parameters. If there are more var(name)s than remaining var(word)s, the +remaining parameters are each set to the empty string. Execution of the +loop ends when there is no remaining var(word) to assign to the first +var(name). It is only possible for tt(in) to appear as the first var(name) +in the list, else it will be treated as marking the end of the list. ) item(tt(for LPAR()LPAR()) [var(expr1)] tt(;) [var(expr2)] tt(;) [var(expr3)] tt(RPAR()RPAR() do) var(list) tt(done))( The arithmetic expression var(expr1) is evaluated first (see @@ -289,17 +298,17 @@ item(tt(if) var(list) var(sublist))( A short form of the alternate `if'. ) -item(tt(for) var(name) tt(LPAR()) var(word) ... tt(RPAR()) var(sublist))( +item(tt(for) var(name) ... tt(LPAR()) var(word) ... tt(RPAR()) var(sublist))( A short form of tt(for). ) -item(tt(for) var(name) [ tt(in) var(word) ... var(term) ] var(sublist))( +item(tt(for) var(name) ... [ tt(in) var(word) ... ] var(term) var(sublist))( where var(term) is at least one newline or tt(;). Another short form of tt(for). ) item(tt(for LPAR()LPAR()) [var(expr1)] tt(;) [var(expr2)] tt(;) [var(expr3)] tt(RPAR()RPAR()) var(sublist))( A short form of the arithmetic tt(for) command. ) -item(tt(foreach) var(name) tt(LPAR()) var(word) ... tt(RPAR()) var(list) tt(end))( +item(tt(foreach) var(name) ... tt(LPAR()) var(word) ... tt(RPAR()) var(list) tt(end))( Another form of tt(for). ) item(tt(while) var(list) tt({) var(list) tt(}))( Index: Src/loop.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/loop.c,v retrieving revision 1.4 diff -u -r1.4 loop.c --- Src/loop.c 2000/06/17 17:05:53 1.4 +++ Src/loop.c 2001/06/21 15:27:31 @@ -52,15 +52,15 @@ Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; + int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; - LinkList args = NULL; + LinkList vars = NULL, args = NULL; - name = ecgetstr(state, EC_NODUP, NULL); end = state->pc + WC_FOR_SKIP(code); if (iscond) { - str = dupstring(name); + str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); @@ -77,28 +77,32 @@ } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); - } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) { - int htok = 0; - - if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { - state->pc = end; - return 0; - } - if (htok) - execsubst(args); } else { - char **x; + vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); + + if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + int htok = 0; + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; + return 0; + } + if (htok) + execsubst(args); + } else { + char **x; - args = newlinklist(); - for (x = pparams; *x; x++) - addlinknode(args, dupstring(*x)); + args = newlinklist(); + for (x = pparams; *x; x++) + addlinknode(args, dupstring(*x)); + } } lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; - for (;;) { + while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); @@ -127,14 +131,29 @@ if (!val) break; } else { - if (!args || !(str = (char *) ugetnode(args))) - break; - if (isset(XTRACE)) { - printprompt4(); - fprintf(xtrerr, "%s=%s\n", name, str); - fflush(xtrerr); + LinkNode node; + int count = 0; + for (node = firstnode(vars); node; incnode(node)) + { + name = (char *)getdata(node); + if (!args || !(str = (char *) ugetnode(args))) + { + if (count) { + str = ""; + last = 1; + } else + break; + } + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s=%s\n", name, str); + fflush(xtrerr); + } + setsparam(name, ztrdup(str)); + count++; } - setsparam(name, ztrdup(str)); + if (!count) + break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); Index: Src/parse.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/parse.c,v retrieving revision 1.25 diff -u -r1.25 parse.c --- Src/parse.c 2001/06/21 10:54:49 1.25 +++ Src/parse.c 2001/06/21 15:27:31 @@ -878,7 +878,7 @@ par_for(int *complex) { int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT); - int type; + int type, ona = noaliases; p = ecadd(0); @@ -903,19 +903,32 @@ yylex(); type = WC_FOR_COND; } else { - int posix_in; + int np, n, posix_in; infor = 0; if (tok != STRING || !isident(tokstr)) YYERRORV(oecused); - ecstr(tokstr); + np = ecadd(0); + n = 0; incmdpos = 1; - yylex(); + noaliases = 1; + for (;;) { + n++; + ecstr(tokstr); + yylex(); + if (tok != STRING || !strcmp(tokstr, "in") || sel) + break; + if (!isident(tokstr)) + { + noaliases = ona; + YYERRORV(oecused); + } + } + noaliases = ona; + ecbuf[np] = n; posix_in = isnewlin; while (isnewlin) - yylex(); - if (tok == STRING && !strcmp(tokstr, "in")) { - int np, n; - + yylex(); + if (tok == STRING && !strcmp(tokstr, "in")) { incmdpos = 0; yylex(); np = ecadd(0); @@ -925,8 +938,6 @@ ecbuf[np] = n; type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); } else if (!posix_in && tok == INPAR) { - int np, n; - incmdpos = 0; yylex(); np = ecadd(0); Index: Src/text.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/text.c,v retrieving revision 1.5 diff -u -r1.5 text.c --- Src/text.c 2000/12/05 10:34:23 1.5 +++ Src/text.c 2001/06/21 15:27:31 @@ -415,7 +415,7 @@ taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr(")) do"); } else { - taddstr(ecgetstr(state, EC_NODUP, NULL)); + taddlist(state, *state->pc++); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { taddstr(" in "); taddlist(state, *state->pc++); -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH (redux): non-POSIX `for' syntax 2001-06-21 15:31 ` PATCH (redux): non-POSIX " Peter Stephenson @ 2001-06-25 16:05 ` Peter Stephenson 0 siblings, 0 replies; 18+ messages in thread From: Peter Stephenson @ 2001-06-25 16:05 UTC (permalink / raw) To: Zsh hackers list Peter Stephenson wrote: > This is my [for more than one parameter in ...] patch relative to the > foregoing. It improves the documentation, and adds the fix not to expand > aliases in parameter names after the first. Looks like the dust has settled somewhat. I'm going to commit this (on the 4.1 branch, obviously) and we'll see what happens. (P.S. it doesn't expand aliases for the first parameter name either, but it never did that.) -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 18+ messages in thread
* PATCH: POSIX `for' syntax 2001-06-21 7:19 ` Andrej Borsenkow 2001-06-21 9:52 ` Peter Stephenson @ 2001-06-21 9:55 ` Bart Schaefer 2001-06-22 6:29 ` PATCH: test case for " Andrej Borsenkow 1 sibling, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2001-06-21 9:55 UTC (permalink / raw) To: Zsh hackers list On Jun 21, 11:19am, Andrej Borsenkow wrote: } } for_clause : For name linebreak do_group } | For name linebreak in wordlist sequential_sep do_group } name : NAME /* Apply rule 5 */ } ; } in : In /* Apply rule 6 */ } } It means, that the following is valid: } } fot i } in a b c } do } ... } } it is currently does not work in zsh: } } bor@itsrm2% for i } for> in a b c } bor@itsrm2% } ^^^^^^^^^^^^^^^ Oops! The following patch (which almost certainly conflicts with Peter's) makes zsh accept any number of newlines preceding the "in" token. This also applies to `select', which I presumed it ought to. --- zsh-forge/current/Src/parse.c Mon Jun 18 01:05:17 2001 +++ zsh-4.0/Src/parse.c Thu Jun 21 02:45:23 2001 @@ -909,6 +909,8 @@ ecstr(tokstr); incmdpos = 1; yylex(); + while (isnewlin && !csh) + yylex(); if (tok == STRING && !strcmp(tokstr, "in")) { int np, n; -- Bart Schaefer Brass Lantern Enterprises http://www.well.com/user/barts http://www.brasslantern.com Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net ^ permalink raw reply [flat|nested] 18+ messages in thread
* PATCH: test case for POSIX `for' syntax 2001-06-21 9:55 ` PATCH: POSIX " Bart Schaefer @ 2001-06-22 6:29 ` Andrej Borsenkow 0 siblings, 0 replies; 18+ messages in thread From: Andrej Borsenkow @ 2001-06-22 6:29 UTC (permalink / raw) To: Zsh hackers list Index: Test/A01grammar.ztst =================================================================== RCS file: /cvsroot/zsh/zsh/Test/A01grammar.ztst,v retrieving revision 1.1 diff -u -r1.1 A01grammar.ztst --- Test/A01grammar.ztst 2001/04/02 12:29:57 1.1 +++ Test/A01grammar.ztst 2001/06/22 06:28:05 @@ -118,6 +118,15 @@ >to >term + for name + in word to term; do + print $name + done +0:`for' loop with newline before in keyword +>word +>to +>term + for (( name = 0; name < 3; name++ )); do print $name done -andrej ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 18:55 ` Bart Schaefer 2001-06-20 19:12 ` Peter Stephenson @ 2001-06-22 23:49 ` Zefram 2001-06-23 0:04 ` Bart Schaefer 1 sibling, 1 reply; 18+ messages in thread From: Zefram @ 2001-06-22 23:49 UTC (permalink / raw) To: zsh-workers Bart Schaefer wrote: > clearly a parameter named "in" can only appear in the first >position, for out 'in' in a b c d; do ... -zefram ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-22 23:49 ` PATCH: 4.1: multi-parameter for loop Zefram @ 2001-06-23 0:04 ` Bart Schaefer 0 siblings, 0 replies; 18+ messages in thread From: Bart Schaefer @ 2001-06-23 0:04 UTC (permalink / raw) To: Zefram, zsh-workers On Jun 23, 12:49am, Zefram wrote: > Subject: Re: PATCH: 4.1: multi-parameter for loop > Bart Schaefer wrote: > > clearly a parameter named "in" can only appear in the first > >position, > > for out 'in' in a b c d; do ... That requires even more changes to the parser ... bash$ for 'in' in a b c d; do break; done bash: `'in'' is not a valid identifier zsh% for 'in' in a b c d; do break; done zsh: parse error near `'in'' I.e. you can't use a quoted string as the NAME in `for NAME in WORD'. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: PATCH: 4.1: multi-parameter for loop 2001-06-20 14:45 PATCH: 4.1: multi-parameter for loop Peter Stephenson 2001-06-20 16:11 ` Peter Stephenson 2001-06-20 18:01 ` Andrej Borsenkow @ 2001-06-21 8:33 ` Sven Wischnowsky 2 siblings, 0 replies; 18+ messages in thread From: Sven Wischnowsky @ 2001-06-21 8:33 UTC (permalink / raw) To: zsh-workers Peter Stephenson wrote: > ... > > My main worry is that the wordcode stuff is as clear as mud to me. In > particular, I don't know what WC_FOR_SKIP is doing, why it divides the data > size(?) by 4, and whether it needs changing when there's more stuff in > the for structure. >From zsh.h: #define WC_FOR_TYPE(C) (wc_data(C) & 3) #define WC_FOR_PPARAM 0 #define WC_FOR_LIST 1 #define WC_FOR_COND 2 #define WC_FOR_SKIP(C) (wc_data(C) >> 2) #define WCB_FOR(T,O) wc_bld(WC_FOR, ((T) | ((O) << 2))) For for-loops the data field contains 1) the type of the loop (positional params, a list of values or a condition) and 2) the offset to the code after the loop. The type is stored in the lowest two bits, the offset is the rest, hence the `>> 2' to get the offset. And since par_for() calculates the offset at the very end, it already takes into account your parameter list. I'd like to have something like this *a lot*. I've missed it several times already, I just didn't think of enhancing the for loop syntax. I don't have any strong feelings pro or contra one of the suggested syntaxes. Similar like Bart's `foreach' suggestion, one could also use `for (a b) in ...' to make this `save', trying to make it look like one of these tuple assignments that are possible in some languages. Of course, people could then come and think that `(a b)=(1 2)' should work, too. Bye Sven -- Sven Wischnowsky wischnow@informatik.hu-berlin.de ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2001-06-25 16:05 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2001-06-20 14:45 PATCH: 4.1: multi-parameter for loop Peter Stephenson 2001-06-20 16:11 ` Peter Stephenson 2001-06-20 18:01 ` Andrej Borsenkow 2001-06-20 18:20 ` Bart Schaefer 2001-06-20 18:39 ` Peter Stephenson 2001-06-20 18:55 ` Bart Schaefer 2001-06-20 19:12 ` Peter Stephenson 2001-06-20 22:56 ` Danek Duvall 2001-06-21 7:19 ` Andrej Borsenkow 2001-06-21 9:52 ` Peter Stephenson 2001-06-21 10:34 ` PATCH (redux): POSIX `for' syntax Bart Schaefer 2001-06-21 15:31 ` PATCH (redux): non-POSIX " Peter Stephenson 2001-06-25 16:05 ` Peter Stephenson 2001-06-21 9:55 ` PATCH: POSIX " Bart Schaefer 2001-06-22 6:29 ` PATCH: test case for " Andrej Borsenkow 2001-06-22 23:49 ` PATCH: 4.1: multi-parameter for loop Zefram 2001-06-23 0:04 ` Bart Schaefer 2001-06-21 8:33 ` Sven Wischnowsky
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).