Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Bug in case stmt with '('



On Jul 17,  5:01pm, Morris M. Siegel wrote:
> Subject: Bug in case stmt with '('
> It seems that when a pattern in a case statement is preceded by the optional
> '(', the parser is in the wrong state when parsing the statement following
> the pattern.

Yup.  Here's the problem:

To parse the case pattern, zsh attempts to lex a STRING token.  In old
case syntax, this stops before either the next "|" or the ")".  With the
fully-parenthesized syntax, it lexes the entire (...) expression.

Zsh then reads another token, and looks to see whether it's a "|" (in
which case it loops) or a ")" (in which case the parse is finished).
With the new syntax, neither of these is true, which means zsh has
lexed the next word (in this case, "gigo=...") instead of the OUTPAR.
Problem is, it needs to lex that word with incmdpos=1 to get an
ENVSTRING token, but instead it's lexing with incmdpos=0,incasepat=1
and getting a STRING token.

In the old syntax, where the token was OUTPAR, zsh sets incmdpos=1 and
then lexes again, getting ENVSTRING as it should.  When zsh notices that
the token is not OUTPAR, it attempts to fix the situation by skipping
that lex; but the damage has already been done.  Zsh needs to look for
the matched parens sooner.

There's one additional complication: zsh glob syntax uses parens, so zsh
has previously accepted this sort of thing:

    case $foo in
    (v|w)|x)	echo 'case (v|w)|x';;
    (y|z))	echo 'case (y|z)';;
    *)		echo 'default';;
    esac

That means it can't look only for matching parens, but also has to look
for matching parens followed by a closing paren or vertical bar.

I'm unsure of this patch, so the pre3 stuff is still there #ifdef OLD.
There may be a better way to deal with it.

*** Src/parse.c.orig	Mon Jul 15 00:07:21 1996
--- Src/parse.c	Thu Jul 18 11:12:14 1996
***************
*** 502,508 ****
--- 502,527 ----
  	    break;
  	}
  	str = tokstr;
+ #ifdef OLD
  	yylex();
+ #else
+ 	/* POSIX allows (foo*) patterns */
+ 	if (skipparens(Inpar, Outpar, &str) || *str) {
+ 	    /* Not fully parenthesized, look for a token */
+ 	    str = tokstr;
+ 	    yylex();
+ 	} else {
+ 	    /* Fully parenthesized, but zsh glob syntax permits
+ 	     * parens in (x|y) patterns, so check for that too. */
+ 	    int c;
+ 	    str = tokstr;
+ 	    c = hgetc();
+ 	    if (c == /*(*/ ')' || c == '|') {
+ 		hungetc(c);
+ 		yylex();
+ 	    }
+ 	}
+ #endif
  	while (tok == BAR) {
  	    char *str2;
  	    int sl = strlen(str);
***************
*** 527,532 ****
--- 546,552 ----
  	}
  	incasepat = 0;
  	incmdpos = 1;
+ #ifdef OLD
  	if (tok != OUTPAR) {
  	    /* POSIX allows (foo*) patterns */
  	    char *s = str;
***************
*** 534,539 ****
--- 554,560 ----
  	    if (skipparens(Inpar, Outpar, &s) || *s)
  		YYERRORV;
  	} else
+ #endif
  	    yylex();
  	addlinknode(pats, str);
  	addlinknode(lists, par_list());
***************




Messages sorted by: Reverse Date, Date, Thread, Author