Skip to content

Commit 4f64bc2

Browse files
committed
Improve output of tokens in Parse Errors
Currently, unexpected tokens in the parser are shown as the text found, plus the internal token name, including the notorious "unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)". This commit replaces that with a more user-friendly format, with two types of token: * Tokens which always represent the same text are shown like "unexpected token '::'" and "expected '::'" * Tokens which have variable text are given a user-friendly name, and show like "unexpected identifier 'foo'", and "expected identifer". As a special-case, quoted strings are not quoted an extra time, so show like "unexpected quoted string 'foo'" rather than ''foo''.
1 parent 7e94082 commit 4f64bc2

File tree

1 file changed

+194
-162
lines changed

1 file changed

+194
-162
lines changed

Zend/zend_language_parser.y

Lines changed: 194 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -86,145 +86,145 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
8686
%precedence T_ELSEIF
8787
%precedence T_ELSE
8888

89-
%token <ast> T_LNUMBER "integer number (T_LNUMBER)"
90-
%token <ast> T_DNUMBER "floating-point number (T_DNUMBER)"
91-
%token <ast> T_STRING "identifier (T_STRING)"
92-
%token <ast> T_VARIABLE "variable (T_VARIABLE)"
89+
%token <ast> T_LNUMBER "integer number"
90+
%token <ast> T_DNUMBER "floating-point number"
91+
%token <ast> T_STRING "identifier"
92+
%token <ast> T_VARIABLE "variable"
9393
%token <ast> T_INLINE_HTML
94-
%token <ast> T_ENCAPSED_AND_WHITESPACE "quoted-string and whitespace (T_ENCAPSED_AND_WHITESPACE)"
95-
%token <ast> T_CONSTANT_ENCAPSED_STRING "quoted-string (T_CONSTANT_ENCAPSED_STRING)"
96-
%token <ast> T_STRING_VARNAME "variable name (T_STRING_VARNAME)"
97-
%token <ast> T_NUM_STRING "number (T_NUM_STRING)"
98-
99-
%token <ident> T_INCLUDE "include (T_INCLUDE)"
100-
%token <ident> T_INCLUDE_ONCE "include_once (T_INCLUDE_ONCE)"
101-
%token <ident> T_EVAL "eval (T_EVAL)"
102-
%token <ident> T_REQUIRE "require (T_REQUIRE)"
103-
%token <ident> T_REQUIRE_ONCE "require_once (T_REQUIRE_ONCE)"
104-
%token <ident> T_LOGICAL_OR "or (T_LOGICAL_OR)"
105-
%token <ident> T_LOGICAL_XOR "xor (T_LOGICAL_XOR)"
106-
%token <ident> T_LOGICAL_AND "and (T_LOGICAL_AND)"
107-
%token <ident> T_PRINT "print (T_PRINT)"
108-
%token <ident> T_YIELD "yield (T_YIELD)"
109-
%token <ident> T_YIELD_FROM "yield from (T_YIELD_FROM)"
110-
%token <ident> T_INSTANCEOF "instanceof (T_INSTANCEOF)"
111-
%token <ident> T_NEW "new (T_NEW)"
112-
%token <ident> T_CLONE "clone (T_CLONE)"
113-
%token <ident> T_EXIT "exit (T_EXIT)"
114-
%token <ident> T_IF "if (T_IF)"
115-
%token <ident> T_ELSEIF "elseif (T_ELSEIF)"
116-
%token <ident> T_ELSE "else (T_ELSE)"
117-
%token <ident> T_ENDIF "endif (T_ENDIF)"
118-
%token <ident> T_ECHO "echo (T_ECHO)"
119-
%token <ident> T_DO "do (T_DO)"
120-
%token <ident> T_WHILE "while (T_WHILE)"
121-
%token <ident> T_ENDWHILE "endwhile (T_ENDWHILE)"
122-
%token <ident> T_FOR "for (T_FOR)"
123-
%token <ident> T_ENDFOR "endfor (T_ENDFOR)"
124-
%token <ident> T_FOREACH "foreach (T_FOREACH)"
125-
%token <ident> T_ENDFOREACH "endforeach (T_ENDFOREACH)"
126-
%token <ident> T_DECLARE "declare (T_DECLARE)"
127-
%token <ident> T_ENDDECLARE "enddeclare (T_ENDDECLARE)"
128-
%token <ident> T_AS "as (T_AS)"
129-
%token <ident> T_SWITCH "switch (T_SWITCH)"
130-
%token <ident> T_ENDSWITCH "endswitch (T_ENDSWITCH)"
131-
%token <ident> T_CASE "case (T_CASE)"
132-
%token <ident> T_DEFAULT "default (T_DEFAULT)"
133-
%token <ident> T_BREAK "break (T_BREAK)"
134-
%token <ident> T_CONTINUE "continue (T_CONTINUE)"
135-
%token <ident> T_GOTO "goto (T_GOTO)"
136-
%token <ident> T_FUNCTION "function (T_FUNCTION)"
137-
%token <ident> T_FN "fn (T_FN)"
138-
%token <ident> T_CONST "const (T_CONST)"
139-
%token <ident> T_RETURN "return (T_RETURN)"
140-
%token <ident> T_TRY "try (T_TRY)"
141-
%token <ident> T_CATCH "catch (T_CATCH)"
142-
%token <ident> T_FINALLY "finally (T_FINALLY)"
143-
%token <ident> T_THROW "throw (T_THROW)"
144-
%token <ident> T_USE "use (T_USE)"
145-
%token <ident> T_INSTEADOF "insteadof (T_INSTEADOF)"
146-
%token <ident> T_GLOBAL "global (T_GLOBAL)"
147-
%token <ident> T_STATIC "static (T_STATIC)"
148-
%token <ident> T_ABSTRACT "abstract (T_ABSTRACT)"
149-
%token <ident> T_FINAL "final (T_FINAL)"
150-
%token <ident> T_PRIVATE "private (T_PRIVATE)"
151-
%token <ident> T_PROTECTED "protected (T_PROTECTED)"
152-
%token <ident> T_PUBLIC "public (T_PUBLIC)"
153-
%token <ident> T_VAR "var (T_VAR)"
154-
%token <ident> T_UNSET "unset (T_UNSET)"
155-
%token <ident> T_ISSET "isset (T_ISSET)"
156-
%token <ident> T_EMPTY "empty (T_EMPTY)"
157-
%token <ident> T_HALT_COMPILER "__halt_compiler (T_HALT_COMPILER)"
158-
%token <ident> T_CLASS "class (T_CLASS)"
159-
%token <ident> T_TRAIT "trait (T_TRAIT)"
160-
%token <ident> T_INTERFACE "interface (T_INTERFACE)"
161-
%token <ident> T_EXTENDS "extends (T_EXTENDS)"
162-
%token <ident> T_IMPLEMENTS "implements (T_IMPLEMENTS)"
163-
%token <ident> T_NAMESPACE "namespace (T_NAMESPACE)"
164-
%token <ident> T_LIST "list (T_LIST)"
165-
%token <ident> T_ARRAY "array (T_ARRAY)"
166-
%token <ident> T_CALLABLE "callable (T_CALLABLE)"
167-
%token <ident> T_LINE "__LINE__ (T_LINE)"
168-
%token <ident> T_FILE "__FILE__ (T_FILE)"
169-
%token <ident> T_DIR "__DIR__ (T_DIR)"
170-
%token <ident> T_CLASS_C "__CLASS__ (T_CLASS_C)"
171-
%token <ident> T_TRAIT_C "__TRAIT__ (T_TRAIT_C)"
172-
%token <ident> T_METHOD_C "__METHOD__ (T_METHOD_C)"
173-
%token <ident> T_FUNC_C "__FUNCTION__ (T_FUNC_C)"
174-
%token <ident> T_NS_C "__NAMESPACE__ (T_NS_C)"
94+
%token <ast> T_ENCAPSED_AND_WHITESPACE "quoted string and whitespace"
95+
%token <ast> T_CONSTANT_ENCAPSED_STRING "quoted string"
96+
%token <ast> T_STRING_VARNAME "variable name"
97+
%token <ast> T_NUM_STRING "number"
98+
99+
%token <ident> T_INCLUDE "'include'"
100+
%token <ident> T_INCLUDE_ONCE "'include_once'"
101+
%token <ident> T_EVAL "'eval'"
102+
%token <ident> T_REQUIRE "'require'"
103+
%token <ident> T_REQUIRE_ONCE "'require_once'"
104+
%token <ident> T_LOGICAL_OR "'or'"
105+
%token <ident> T_LOGICAL_XOR "'xor'"
106+
%token <ident> T_LOGICAL_AND "'and'"
107+
%token <ident> T_PRINT "'print'"
108+
%token <ident> T_YIELD "'yield'"
109+
%token <ident> T_YIELD_FROM "'yield from'"
110+
%token <ident> T_INSTANCEOF "'instanceof'"
111+
%token <ident> T_NEW "'new'"
112+
%token <ident> T_CLONE "'clone'"
113+
%token <ident> T_EXIT "'exit'"
114+
%token <ident> T_IF "'if'"
115+
%token <ident> T_ELSEIF "'elseif'"
116+
%token <ident> T_ELSE "'else'"
117+
%token <ident> T_ENDIF "'endif'"
118+
%token <ident> T_ECHO "'echo'"
119+
%token <ident> T_DO "'do'"
120+
%token <ident> T_WHILE "'while'"
121+
%token <ident> T_ENDWHILE "'endwhile'"
122+
%token <ident> T_FOR "'for'"
123+
%token <ident> T_ENDFOR "'endfor'"
124+
%token <ident> T_FOREACH "'foreach'"
125+
%token <ident> T_ENDFOREACH "'endforeach'"
126+
%token <ident> T_DECLARE "'declare'"
127+
%token <ident> T_ENDDECLARE "'enddeclare'"
128+
%token <ident> T_AS "'as'"
129+
%token <ident> T_SWITCH "'switch'"
130+
%token <ident> T_ENDSWITCH "'endswitch'"
131+
%token <ident> T_CASE "'case'"
132+
%token <ident> T_DEFAULT "'default'"
133+
%token <ident> T_BREAK "'break'"
134+
%token <ident> T_CONTINUE "'continue'"
135+
%token <ident> T_GOTO "'goto'"
136+
%token <ident> T_FUNCTION "'function'"
137+
%token <ident> T_FN "'fn'"
138+
%token <ident> T_CONST "'const'"
139+
%token <ident> T_RETURN "'return'"
140+
%token <ident> T_TRY "'try'"
141+
%token <ident> T_CATCH "'catch'"
142+
%token <ident> T_FINALLY "'finally'"
143+
%token <ident> T_THROW "'throw'"
144+
%token <ident> T_USE "'use'"
145+
%token <ident> T_INSTEADOF "'insteadof'"
146+
%token <ident> T_GLOBAL "'global'"
147+
%token <ident> T_STATIC "'static'"
148+
%token <ident> T_ABSTRACT "'abstract'"
149+
%token <ident> T_FINAL "'final'"
150+
%token <ident> T_PRIVATE "'private'"
151+
%token <ident> T_PROTECTED "'protected'"
152+
%token <ident> T_PUBLIC "'public'"
153+
%token <ident> T_VAR "'var'"
154+
%token <ident> T_UNSET "'unset'"
155+
%token <ident> T_ISSET "'isset'"
156+
%token <ident> T_EMPTY "'empty'"
157+
%token <ident> T_HALT_COMPILER "'__halt_compiler'"
158+
%token <ident> T_CLASS "'class'"
159+
%token <ident> T_TRAIT "'trait'"
160+
%token <ident> T_INTERFACE "'interface'"
161+
%token <ident> T_EXTENDS "'extends'"
162+
%token <ident> T_IMPLEMENTS "'implements'"
163+
%token <ident> T_NAMESPACE "'namespace'"
164+
%token <ident> T_LIST "'list'"
165+
%token <ident> T_ARRAY "'array'"
166+
%token <ident> T_CALLABLE "'callable'"
167+
%token <ident> T_LINE "'__LINE__'"
168+
%token <ident> T_FILE "'__FILE__'"
169+
%token <ident> T_DIR "'__DIR__'"
170+
%token <ident> T_CLASS_C "'__CLASS__'"
171+
%token <ident> T_TRAIT_C "'__TRAIT__'"
172+
%token <ident> T_METHOD_C "'__METHOD__'"
173+
%token <ident> T_FUNC_C "'__FUNCTION__'"
174+
%token <ident> T_NS_C "'__NAMESPACE__'"
175175

176176
%token END 0 "end of file"
177-
%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
178-
%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
179-
%token T_MUL_EQUAL "*= (T_MUL_EQUAL)"
180-
%token T_DIV_EQUAL "/= (T_DIV_EQUAL)"
181-
%token T_CONCAT_EQUAL ".= (T_CONCAT_EQUAL)"
182-
%token T_MOD_EQUAL "%= (T_MOD_EQUAL)"
183-
%token T_AND_EQUAL "&= (T_AND_EQUAL)"
184-
%token T_OR_EQUAL "|= (T_OR_EQUAL)"
185-
%token T_XOR_EQUAL "^= (T_XOR_EQUAL)"
186-
%token T_SL_EQUAL "<<= (T_SL_EQUAL)"
187-
%token T_SR_EQUAL ">>= (T_SR_EQUAL)"
188-
%token T_COALESCE_EQUAL "??= (T_COALESCE_EQUAL)"
189-
%token T_BOOLEAN_OR "|| (T_BOOLEAN_OR)"
190-
%token T_BOOLEAN_AND "&& (T_BOOLEAN_AND)"
191-
%token T_IS_EQUAL "== (T_IS_EQUAL)"
192-
%token T_IS_NOT_EQUAL "!= (T_IS_NOT_EQUAL)"
193-
%token T_IS_IDENTICAL "=== (T_IS_IDENTICAL)"
194-
%token T_IS_NOT_IDENTICAL "!== (T_IS_NOT_IDENTICAL)"
195-
%token T_IS_SMALLER_OR_EQUAL "<= (T_IS_SMALLER_OR_EQUAL)"
196-
%token T_IS_GREATER_OR_EQUAL ">= (T_IS_GREATER_OR_EQUAL)"
197-
%token T_SPACESHIP "<=> (T_SPACESHIP)"
198-
%token T_SL "<< (T_SL)"
199-
%token T_SR ">> (T_SR)"
200-
%token T_INC "++ (T_INC)"
201-
%token T_DEC "-- (T_DEC)"
202-
%token T_INT_CAST "(int) (T_INT_CAST)"
203-
%token T_DOUBLE_CAST "(double) (T_DOUBLE_CAST)"
204-
%token T_STRING_CAST "(string) (T_STRING_CAST)"
205-
%token T_ARRAY_CAST "(array) (T_ARRAY_CAST)"
206-
%token T_OBJECT_CAST "(object) (T_OBJECT_CAST)"
207-
%token T_BOOL_CAST "(bool) (T_BOOL_CAST)"
208-
%token T_UNSET_CAST "(unset) (T_UNSET_CAST)"
209-
%token T_OBJECT_OPERATOR "-> (T_OBJECT_OPERATOR)"
210-
%token T_DOUBLE_ARROW "=> (T_DOUBLE_ARROW)"
211-
%token T_COMMENT "comment (T_COMMENT)"
212-
%token T_DOC_COMMENT "doc comment (T_DOC_COMMENT)"
213-
%token T_OPEN_TAG "open tag (T_OPEN_TAG)"
214-
%token T_OPEN_TAG_WITH_ECHO "open tag with echo (T_OPEN_TAG_WITH_ECHO)"
215-
%token T_CLOSE_TAG "close tag (T_CLOSE_TAG)"
216-
%token T_WHITESPACE "whitespace (T_WHITESPACE)"
217-
%token T_START_HEREDOC "heredoc start (T_START_HEREDOC)"
218-
%token T_END_HEREDOC "heredoc end (T_END_HEREDOC)"
219-
%token T_DOLLAR_OPEN_CURLY_BRACES "${ (T_DOLLAR_OPEN_CURLY_BRACES)"
220-
%token T_CURLY_OPEN "{$ (T_CURLY_OPEN)"
221-
%token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)"
222-
%token T_NS_SEPARATOR "\\ (T_NS_SEPARATOR)"
223-
%token T_ELLIPSIS "... (T_ELLIPSIS)"
224-
%token T_COALESCE "?? (T_COALESCE)"
225-
%token T_POW "** (T_POW)"
226-
%token T_POW_EQUAL "**= (T_POW_EQUAL)"
227-
%token T_BAD_CHARACTER "invalid character (T_BAD_CHARACTER)"
177+
%token T_PLUS_EQUAL "'+='"
178+
%token T_MINUS_EQUAL "'-='"
179+
%token T_MUL_EQUAL "'*='"
180+
%token T_DIV_EQUAL "'/='"
181+
%token T_CONCAT_EQUAL "'.='"
182+
%token T_MOD_EQUAL "'%='"
183+
%token T_AND_EQUAL "'&='"
184+
%token T_OR_EQUAL "'|='"
185+
%token T_XOR_EQUAL "'^='"
186+
%token T_SL_EQUAL "'<<='"
187+
%token T_SR_EQUAL "'>>='"
188+
%token T_COALESCE_EQUAL "'??='"
189+
%token T_BOOLEAN_OR "'||'"
190+
%token T_BOOLEAN_AND "'&&'"
191+
%token T_IS_EQUAL "'=='"
192+
%token T_IS_NOT_EQUAL "'!='"
193+
%token T_IS_IDENTICAL "'==='"
194+
%token T_IS_NOT_IDENTICAL "'!=='"
195+
%token T_IS_SMALLER_OR_EQUAL "'<='"
196+
%token T_IS_GREATER_OR_EQUAL "'>='"
197+
%token T_SPACESHIP "'<=>'"
198+
%token T_SL "'<<'"
199+
%token T_SR "'>>'"
200+
%token T_INC "'++'"
201+
%token T_DEC "'--'"
202+
%token T_INT_CAST "'(int)'"
203+
%token T_DOUBLE_CAST "'(double)'"
204+
%token T_STRING_CAST "'(string)'"
205+
%token T_ARRAY_CAST "'(array)'"
206+
%token T_OBJECT_CAST "'(object)'"
207+
%token T_BOOL_CAST "'(bool)'"
208+
%token T_UNSET_CAST "'(unset)'"
209+
%token T_OBJECT_OPERATOR "'->'"
210+
%token T_DOUBLE_ARROW "'=>'"
211+
%token T_COMMENT "comment"
212+
%token T_DOC_COMMENT "doc comment"
213+
%token T_OPEN_TAG "open tag"
214+
%token T_OPEN_TAG_WITH_ECHO "'<?='"
215+
%token T_CLOSE_TAG "'?>'"
216+
%token T_WHITESPACE "whitespace"
217+
%token T_START_HEREDOC "heredoc start"
218+
%token T_END_HEREDOC "heredoc end"
219+
%token T_DOLLAR_OPEN_CURLY_BRACES "'${'"
220+
%token T_CURLY_OPEN "'{$'"
221+
%token T_PAAMAYIM_NEKUDOTAYIM "'::'"
222+
%token T_NS_SEPARATOR "'\\'"
223+
%token T_ELLIPSIS "'...'"
224+
%token T_COALESCE "'??'"
225+
%token T_POW "'**'"
226+
%token T_POW_EQUAL "'**='"
227+
%token T_BAD_CHARACTER "invalid character"
228228

229229
/* Token used to force a parse error from the lexer */
230230
%token T_ERROR
@@ -1415,13 +1415,11 @@ isset_variable:
14151415

14161416
%%
14171417

1418-
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
1419-
quotes and backslashes, so that it's suitable for yyerror. The
1420-
heuristic is that double-quoting is unnecessary unless the string
1421-
contains an apostrophe, a comma, or backslash (other than
1422-
backslash-backslash). YYSTR is taken from yytname. If YYRES is
1423-
null, do not copy; instead, return the length of what the result
1424-
would have been. */
1418+
/* Over-ride Bison formatting routine to give better token descriptions.
1419+
Copy to YYRES the contents of YYSTR for use in yyerror.
1420+
YYSTR is taken from yytname, from the %token declaration.
1421+
If YYRES is null, do not copy; instead, return the length of what
1422+
the result would have been. */
14251423
static YYSIZE_T zend_yytnamerr(char *yyres, const char *yystr)
14261424
{
14271425
/* CG(parse_error) states:
@@ -1437,8 +1435,9 @@ static YYSIZE_T zend_yytnamerr(char *yyres, const char *yystr)
14371435
if (CG(parse_error) % 2 == 0) {
14381436
/* The unexpected token */
14391437
char buffer[120];
1440-
const unsigned char *end, *str, *tok1 = NULL, *tok2 = NULL;
1441-
unsigned int len = 0, toklen = 0, yystr_len;
1438+
const char *toktype;
1439+
const unsigned char *tokcontent, *tokcontent_end;
1440+
unsigned int toktype_len, tokcontent_len;
14421441

14431442
CG(parse_error)++;
14441443

@@ -1451,35 +1450,68 @@ static YYSIZE_T zend_yytnamerr(char *yyres, const char *yystr)
14511450
return sizeof("end of file")-1;
14521451
}
14531452

1454-
str = LANG_SCNG(yy_text);
1455-
end = memchr(str, '\n', LANG_SCNG(yy_leng));
1456-
yystr_len = (unsigned int)strlen(yystr);
1453+
/* Prevent the backslash getting doubled in the output (eugh) */
1454+
if (strcmp(yystr, "\"'\\\\'\"") == 0) {
1455+
if (yyres) {
1456+
yystpcpy(yyres, "token '\\'");
1457+
}
1458+
return sizeof("token '\\'")-1;
1459+
}
14571460

1458-
if ((tok1 = memchr(yystr, '(', yystr_len)) != NULL
1459-
&& (tok2 = zend_memrchr(yystr, ')', yystr_len)) != NULL) {
1460-
toklen = (tok2 - tok1) + 1;
1461-
} else {
1462-
tok1 = tok2 = NULL;
1463-
toklen = 0;
1461+
toktype = yystr;
1462+
toktype_len = (unsigned int)strlen(yystr);
1463+
1464+
/* Strip off the outer quote marks */
1465+
if (*toktype == '"') {
1466+
toktype++;
1467+
toktype_len-=2;
1468+
}
1469+
1470+
/* If the token always has one form, the %token line should have a single-quoted name */
1471+
if (*toktype == '\'' ) {
1472+
if (yyres) {
1473+
snprintf(buffer, sizeof(buffer), "token %.*s", toktype_len, toktype);
1474+
yystpcpy(yyres, buffer);
1475+
}
1476+
return toktype_len + sizeof("token ")-1;
14641477
}
14651478

1466-
if (end == NULL) {
1467-
len = LANG_SCNG(yy_leng) > 30 ? 30 : LANG_SCNG(yy_leng);
1479+
/* Fetch the content of the last seen token from global lexer state */
1480+
tokcontent = LANG_SCNG(yy_text);
1481+
tokcontent_end = memchr(tokcontent, '\n', LANG_SCNG(yy_leng));
1482+
1483+
if (tokcontent_end == NULL) {
1484+
tokcontent_len = LANG_SCNG(yy_leng) > 30 ? 30 : LANG_SCNG(yy_leng);
14681485
} else {
1469-
len = (end - str) > 30 ? 30 : (end - str);
1486+
tokcontent_len = (tokcontent_end - tokcontent) > 30 ? 30 : (tokcontent_end - tokcontent);
14701487
}
1488+
14711489
if (yyres) {
1472-
if (toklen) {
1473-
snprintf(buffer, sizeof(buffer), "'%.*s' %.*s", len, str, toklen, tok1);
1474-
} else {
1475-
snprintf(buffer, sizeof(buffer), "'%.*s'", len, str);
1490+
/* If token is a quoted string, don't quote it again, but force the end quote in case we truncated */
1491+
if (*tokcontent=='\'') {
1492+
snprintf(buffer, sizeof(buffer), "%.*s %.*s'", toktype_len, toktype, tokcontent_len-1, tokcontent);
1493+
}
1494+
else if (*tokcontent=='"') {
1495+
snprintf(buffer, sizeof(buffer), "%.*s %.*s\"", toktype_len, toktype, tokcontent_len-1, tokcontent);
1496+
}
1497+
else {
1498+
snprintf(buffer, sizeof(buffer), "%.*s '%.*s'", toktype_len, toktype, tokcontent_len, tokcontent);
14761499
}
14771500
yystpcpy(yyres, buffer);
14781501
}
1479-
return len + (toklen ? toklen + 1 : 0) + 2;
1502+
return toktype_len + tokcontent_len - (*tokcontent=='\'' || *tokcontent=='"' ? 1 : 0) + sizeof(" ''")-1;
14801503
}
14811504

14821505
/* One of the expected tokens */
1506+
1507+
/* Prevent the backslash getting doubled in the output (eugh) */
1508+
if (strcmp(yystr, "\"'\\\\'\"") == 0) {
1509+
if (yyres) {
1510+
yystpcpy(yyres, "'\\'");
1511+
}
1512+
return sizeof("'\\'")-1;
1513+
}
1514+
14831515
if (!yyres) {
14841516
return strlen(yystr) - (*yystr == '"' ? 2 : 0);
14851517
}

0 commit comments

Comments
 (0)