summaryrefslogtreecommitdiff
path: root/toke.c
diff options
context:
space:
mode:
authorGurusamy Sarathy <gsar@engin.umich.edu>1997-07-01 10:17:12 +1200
committerTim Bunce <Tim.Bunce@ig.co.uk>1997-08-07 00:00:00 +1200
commitb8a4b1bed690d5e67ab7dfcb2ddfb2aa59ccefd7 (patch)
tree53fece920cb2f78f7e13cc2d8e934b176880f5c0 /toke.c
parentde939608bd9b236d9170fa8c2bcd0a8b397bba0a (diff)
downloadperl-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.c72
1 files changed, 63 insertions, 9 deletions
diff --git a/toke.c b/toke.c
index b443bb2a56..02b54e02a2 100644
--- a/toke.c
+++ b/toke.c
@@ -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;