diff options
author | Gurusamy Sarathy <gsar@engin.umich.edu> | 1997-07-01 10:17:12 +1200 |
---|---|---|
committer | Tim Bunce <Tim.Bunce@ig.co.uk> | 1997-08-07 00:00:00 +1200 |
commit | b8a4b1bed690d5e67ab7dfcb2ddfb2aa59ccefd7 (patch) | |
tree | 53fece920cb2f78f7e13cc2d8e934b176880f5c0 /toke.c | |
parent | de939608bd9b236d9170fa8c2bcd0a8b397bba0a (diff) | |
download | perl-b8a4b1bed690d5e67ab7dfcb2ddfb2aa59ccefd7.tar.gz |
Eval fails in certain situations (eval "{'...")
On Sun, 20 Jul 1997 16:02:05 MDT, Dave Carrigan wrote:
>Eval will fail in the following situation:
>
>- eval'ing a string
>- the string represents an anonymous hash
>- the first key of the anon hash is single quoted, and contains an
> embedded single quote escaped with a backslash
>- using the form `` $ref = eval $string ''
>
>The MLDBM module uses this form of eval all the time, so the above
>situation actually has the potential to occur quite often.
>$string2 = "{'a\\'' => 'foo', 'b' => 'bar', 'c' => 'bat'}";
That is one of the cases where the note in perlref (about
disambiguating braces not preceded by anything else) applies.
However, in this particular case, the code that recognizes if
a literal string is the first thing inside the curlies is not
doing a thorough job of it. The attached patch should cure
it.
Note that you'll still need to write C<eval "{ $a => 'foo' }">
as C<eval "+{ $a => 'foo' }"> if you want it to evaluate as a
hashref. Perl only auto-disambiguates if the first thing in
the curlies is a literal string followed by a comma or =>.
I'll change MLDBM to conform, for the next release.
p5p-msgid: 199707211753.NAA14940@aatma.engin.umich.edu
Diffstat (limited to 'toke.c')
-rw-r--r-- | toke.c | 72 |
1 files changed, 63 insertions, 9 deletions
@@ -1990,19 +1990,73 @@ yylex() s = skipspace(s); if (*s == '}') OPERATOR(HASHBRACK); - if (isALPHA(*s)) { - for (t = s; t < bufend && isALNUM(*t); t++) ; + /* This hack serves to disambiguate a pair of curlies + * as being a block or an anon hash. Normally, expectation + * determines that, but in cases where we're not in a + * position to expect anything in particular (like inside + * eval"") we have to resolve the ambiguity. This code + * covers the case where the first term in the curlies is a + * quoted string. Most other cases need to be explicitly + * disambiguated by prepending a `+' before the opening + * curly in order to force resolution as an anon hash. + * + * XXX should probably propagate the outer expectation + * into eval"" to rely less on this hack, but that could + * potentially break current behavior of eval"". + * GSAR 97-07-21 + */ + t = s; + if (*s == '\'' || *s == '"' || *s == '`') { + /* common case: get past first string, handling escapes */ + for (t++; t < bufend && *t != *s;) + if (*t++ == '\\' && (*t == '\\' || *t == *s)) + t++; + t++; + } + else if (*s == 'q') { + if (++t < bufend + && (!isALNUM(*t) + || ((*t == 'q' || *t == 'x') && ++t < bufend + && !isALNUM(*t)))) { + char *tmps; + char open, close, term; + I32 brackets = 1; + + while (t < bufend && isSPACE(*t)) + t++; + term = *t; + open = term; + if (term && (tmps = strchr("([{< )]}> )]}>",term))) + term = tmps[5]; + close = term; + if (open == close) + for (t++; t < bufend; t++) { + if (*t == '\\' && t+1 < bufend && term != '\\') + t++; + else if (*t == term) + break; + } + else + for (t++; t < bufend; t++) { + if (*t == '\\' && t+1 < bufend && term != '\\') + t++; + else if (*t == term && --brackets <= 0) + break; + else if (*t == open) + brackets++; + } + } + t++; } - else if (*s == '\'' || *s == '"') { - t = strchr(s+1,*s); - if (!t++) - t = s; + else if (isALPHA(*s)) { + for (t++; t < bufend && isALNUM(*t); t++) ; } - else - t = s; while (t < bufend && isSPACE(*t)) t++; - if ((*t == ',' && !isLOWER(*s)) || (*t == '=' && t[1] == '>')) + /* if comma follows first term, call it an anon hash */ + /* XXX it could be a comma expression with loop modifiers */ + if (t < bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s))) + || (*t == '=' && t[1] == '>'))) OPERATOR(HASHBRACK); if (expect == XREF) expect = XTERM; |