diff --git a/grammar/php5.y b/grammar/php5.y index d0ba300..9706c5a 100644 --- a/grammar/php5.y +++ b/grammar/php5.y @@ -16,7 +16,8 @@ top_statement_list_ex: top_statement_list: top_statement_list_ex - { makeNop($nop, #1+1); if ($nop !== null) { $1[] = $nop; } $$ = $1; } + { makeNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } ; reserved_non_modifiers: @@ -136,7 +137,8 @@ inner_statement_list_ex: inner_statement_list: inner_statement_list_ex - { makeNop($nop, #1+1); if ($nop !== null) { $1[] = $nop; } $$ = $1; } + { makeNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } ; inner_statement: @@ -187,7 +189,8 @@ non_empty_statement: statement: non_empty_statement { $$ = $1; } | ';' - { makeNop($$, #1); if ($$ === null) $$ = array(); /* means: no statement */ } + { makeNop($$, $this->startAttributeStack[#1]); + if ($$ === null) $$ = array(); /* means: no statement */ } ; catches: diff --git a/grammar/php7.y b/grammar/php7.y index b727041..1cb3cf8 100644 --- a/grammar/php7.y +++ b/grammar/php7.y @@ -16,7 +16,8 @@ top_statement_list_ex: top_statement_list: top_statement_list_ex - { makeNop($nop, #1+1); if ($nop !== null) { $1[] = $nop; } $$ = $1; } + { makeNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } ; reserved_non_modifiers: @@ -136,7 +137,8 @@ inner_statement_list_ex: inner_statement_list: inner_statement_list_ex - { makeNop($nop, #1+1); if ($nop !== null) { $1[] = $nop; } $$ = $1; } + { makeNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } ; inner_statement: @@ -183,7 +185,8 @@ non_empty_statement: statement: non_empty_statement { $$ = $1; } | ';' - { makeNop($$, #1); if ($$ === null) $$ = array(); /* means: no statement */ } + { makeNop($$, $this->startAttributeStack[#1]); + if ($$ === null) $$ = array(); /* means: no statement */ } ; catches: diff --git a/grammar/rebuildParsers.php b/grammar/rebuildParsers.php index 3f39bf3..8f13446 100644 --- a/grammar/rebuildParsers.php +++ b/grammar/rebuildParsers.php @@ -85,7 +85,7 @@ foreach ($grammarFileToName as $grammarFile => $name) { function resolveNodes($code) { return preg_replace_callback( - '~(?[A-Z][a-zA-Z_\\\\]++)\s*' . PARAMS . '~', + '~\b(?[A-Z][a-zA-Z_\\\\]++)\s*' . PARAMS . '~', function($matches) { // recurse $matches['params'] = resolveNodes($matches['params']); @@ -172,7 +172,7 @@ function resolveMacros($code) { if ('makeNop' == $name) { assertArgs(2, $args, $name); - return '$startAttributes = $this->startAttributeStack[' . $args[1] . '];' + return '$startAttributes = ' . $args[1] . ';' . ' if (isset($startAttributes[\'comments\']))' . ' { ' . $args[0] . ' = new Stmt\Nop([\'comments\' => $startAttributes[\'comments\']]); }' . ' else { ' . $args[0] . ' = null; }'; diff --git a/lib/PhpParser/Parser/Php5.php b/lib/PhpParser/Parser/Php5.php index 99e3b91..a40fd80 100644 --- a/lib/PhpParser/Parser/Php5.php +++ b/lib/PhpParser/Parser/Php5.php @@ -924,7 +924,8 @@ class Php5 extends \PhpParser\ParserAbstract } protected function reduceRule4() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)+1]; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; + $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; + if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; } protected function reduceRule5() { @@ -1396,7 +1397,8 @@ class Php5 extends \PhpParser\ParserAbstract } protected function reduceRule122() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)+1]; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; + $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; + if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; } protected function reduceRule123() { @@ -1532,7 +1534,8 @@ class Php5 extends \PhpParser\ParserAbstract } protected function reduceRule156() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; if ($this->semValue === null) $this->semValue = array(); /* means: no statement */ + $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; + if ($this->semValue === null) $this->semValue = array(); /* means: no statement */ } protected function reduceRule157() { diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index aa17ae4..90318d2 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -806,7 +806,8 @@ class Php7 extends \PhpParser\ParserAbstract } protected function reduceRule4() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)+1]; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; + $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; + if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; } protected function reduceRule5() { @@ -1278,7 +1279,8 @@ class Php7 extends \PhpParser\ParserAbstract } protected function reduceRule122() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)+1]; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; + $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $nop = null; }; + if ($nop !== null) { $this->semStack[$this->stackPos-(1-1)][] = $nop; } $this->semValue = $this->semStack[$this->stackPos-(1-1)]; } protected function reduceRule123() { @@ -1398,7 +1400,8 @@ class Php7 extends \PhpParser\ParserAbstract } protected function reduceRule152() { - $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; if ($this->semValue === null) $this->semValue = array(); /* means: no statement */ + $startAttributes = $this->startAttributeStack[$this->stackPos-(1-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; + if ($this->semValue === null) $this->semValue = array(); /* means: no statement */ } protected function reduceRule153() { diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index abae6e1..7326899 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -88,6 +88,8 @@ abstract class ParserAbstract implements Parser protected $startAttributeStack; /** @var array End attributes of last *shifted* token */ protected $endAttributes; + /** @var array Start attributes of last *read* token */ + protected $lookaheadStartAttributes; /** @var bool Whether to throw on first error */ protected $throwOnError; @@ -185,6 +187,7 @@ abstract class ParserAbstract implements Parser // This is necessary to assign some meaningful attributes to /* empty */ productions. They'll get // the attributes of the next token, even though they don't contain it themselves. $this->startAttributeStack[$this->stackPos+1] = $startAttributes; + $this->lookaheadStartAttributes = $startAttributes; //$this->traceRead($symbol); } diff --git a/test/code/parser/comments.test b/test/code/parser/comments.test index 0f8684d..e15b969 100644 --- a/test/code/parser/comments.test +++ b/test/code/parser/comments.test @@ -2,32 +2,32 @@ Comments -----