mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-30 04:29:15 +01:00
Slightly optimize the parser and improve the API
This commit is contained in:
parent
aea5e43349
commit
e00b460125
25
README
25
README
@ -5,23 +5,20 @@ This project is work in progress, but it basically works and was tested on a lar
|
||||
Usage:
|
||||
|
||||
$parser = new Parser();
|
||||
$parser->yyparse(
|
||||
$stmts = $parser->yyparse(
|
||||
new Lexer('<?php // some code'),
|
||||
function($stmt) {
|
||||
// this is the accept callback
|
||||
// it is fired in case of a successful parse
|
||||
// $stmts contains an array of nodes
|
||||
// to print them do:
|
||||
foreach ($stmts as $stmt) {
|
||||
echo $stmt, "\n";
|
||||
}
|
||||
},
|
||||
function($msg) {
|
||||
// this is the error callback
|
||||
// it is fired in case of an error (currently
|
||||
// errors abort the parse)
|
||||
// this is the error callback, which is fired in case of
|
||||
// a parse error. It is passed the error message.
|
||||
echo $msg, "\n";
|
||||
}
|
||||
);
|
||||
|
||||
// see example usage in test.php
|
||||
// the return value of Parser->yyparse will either be false (which
|
||||
// signifies that an error occured) or an array of statements (Nodes)
|
||||
if (false !== $stmts) {
|
||||
// dump the AST
|
||||
foreach ($stmts as $stmt) {
|
||||
echo $stmt, "\n";
|
||||
}
|
||||
}
|
@ -114,65 +114,51 @@ class YYParser
|
||||
);
|
||||
}
|
||||
|
||||
protected function accept() {
|
||||
$acceptCallback = $this->acceptCallback;
|
||||
$acceptCallback($this->yyval);
|
||||
}
|
||||
|
||||
protected function yyaccept() {
|
||||
$this->yyaccept = 1;
|
||||
}
|
||||
|
||||
protected function yyabort() {
|
||||
$this->yyaccept = 2;
|
||||
}
|
||||
|
||||
@if -t
|
||||
/* Traditional Debug Mode */
|
||||
private function YYTRACE_NEWSTATE($state, $sym) {
|
||||
if ($this->yydebug) {
|
||||
$this->yyprintln("% State " . $state . ", Lookahead "
|
||||
. ($sym < 0 ? "--none--" : self::$yyterminals[$sym]));
|
||||
$this->yyprintln('% State ' . $state . ', Lookahead '
|
||||
. ($sym < 0 ? '--none--' : self::$yyterminals[$sym]));
|
||||
}
|
||||
}
|
||||
|
||||
private function YYTRACE_READ($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Reading " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Reading ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
|
||||
private function YYTRACE_SHIFT($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Shift " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Shift ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
|
||||
private function YYTRACE_ACCEPT() {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Accepted.");
|
||||
$this->yyprintln('% Accepted.');
|
||||
}
|
||||
|
||||
private function YYTRACE_REDUCE($n) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Reduce by (" . $n . ") " . self::$yyproduction[$n]);
|
||||
$this->yyprintln('% Reduce by (' . $n . ') ' . self::$yyproduction[$n]);
|
||||
}
|
||||
|
||||
private function YYTRACE_POP($state) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Recovering, uncovers state " . $state);
|
||||
$this->yyprintln('% Recovering, uncovers state ' . $state);
|
||||
}
|
||||
|
||||
private function YYTRACE_DISCARD($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Discard " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Discard ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
@endif
|
||||
|
||||
/**
|
||||
* Parser entry point
|
||||
*/
|
||||
public function yyparse($lex, $acceptCallback, $errorCallback) {
|
||||
public function yyparse($lex, $errorCallback) {
|
||||
$this->lex = $lex;
|
||||
$this->acceptCallback = $acceptCallback;
|
||||
$this->errorCallback = $errorCallback;
|
||||
|
||||
$this->yyastk = array();
|
||||
@ -222,14 +208,14 @@ class YYParser
|
||||
@if -t
|
||||
$this->YYTRACE_SHIFT($yychar);
|
||||
@endif
|
||||
$this->yysp++;
|
||||
++$this->yysp;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate = $yyn;
|
||||
$this->yyastk[$this->yysp] = $yylval;
|
||||
$yychar = -1;
|
||||
|
||||
if ($yyerrflag > 0)
|
||||
$yyerrflag--;
|
||||
--$yyerrflag;
|
||||
if ($yyn < self::YYNLSTATES)
|
||||
continue;
|
||||
|
||||
@ -250,36 +236,29 @@ class YYParser
|
||||
@if -t
|
||||
$this->YYTRACE_ACCEPT();
|
||||
@endif
|
||||
$this->accept();
|
||||
return $this->yyaccept - 1;
|
||||
return $this->yyval;
|
||||
} elseif ($yyn != self::YYUNEXPECTED) {
|
||||
/* reduce */
|
||||
$yyl = self::$yylen[$yyn];
|
||||
$n = $this->yysp-$yyl+1;
|
||||
$yyval = isset($this->yyastk[$n]) ? $this->yyastk[$n] : null;
|
||||
@if -t
|
||||
$this->YYTRACE_REDUCE($yyn);
|
||||
@endif
|
||||
$this->{'yyn' . $yyn}();
|
||||
if ($this->yyaccept) {
|
||||
$yyn = self::YYNLSTATES;
|
||||
|
||||
/* Goto - shift nonterminal */
|
||||
$this->yysp -= self::$yylen[$yyn];
|
||||
$yyn = self::$yylhs[$yyn];
|
||||
if (($yyp = self::$yygbase[$yyn] + $yysstk[$this->yysp]) >= 0
|
||||
&& $yyp < self::YYGLAST
|
||||
&& self::$yygcheck[$yyp] == $yyn) {
|
||||
$yystate = self::$yygoto[$yyp];
|
||||
} else {
|
||||
/* Goto - shift nonterminal */
|
||||
$this->yysp -= $yyl;
|
||||
$yyn = self::$yylhs[$yyn];
|
||||
if (($yyp = self::$yygbase[$yyn] + $yysstk[$this->yysp]) >= 0
|
||||
&& $yyp < self::YYGLAST
|
||||
&& self::$yygcheck[$yyp] == $yyn) {
|
||||
$yystate = self::$yygoto[$yyp];
|
||||
} else {
|
||||
$yystate = self::$yygdefault[$yyn];
|
||||
}
|
||||
|
||||
$this->yysp++;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate;
|
||||
$this->yyastk[$this->yysp] = $this->yyval;
|
||||
$yystate = self::$yygdefault[$yyn];
|
||||
}
|
||||
|
||||
++$this->yysp;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate;
|
||||
$this->yyastk[$this->yysp] = $this->yyval;
|
||||
} else {
|
||||
/* error */
|
||||
switch ($yyerrflag) {
|
||||
@ -297,7 +276,7 @@ class YYParser
|
||||
&& $yyn < self::YYLAST
|
||||
&& self::$yycheck[$yyn] == self::YYINTERRTOK))) {
|
||||
if ($this->yysp <= 0) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
$yystate = $yysstk[--$this->yysp];
|
||||
@if -t
|
||||
@ -316,7 +295,7 @@ class YYParser
|
||||
$this->YYTRACE_DISCARD($yychar);
|
||||
@endif
|
||||
if ($yychar == 0) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
$yychar = -1;
|
||||
break;
|
||||
@ -336,7 +315,10 @@ class YYParser
|
||||
%b
|
||||
}
|
||||
@noact
|
||||
private function yyn%n() {}
|
||||
|
||||
private function yyn%n() {
|
||||
$this->yyval = $this->yyastk[$this->yysp];
|
||||
}
|
||||
@endreduce
|
||||
}
|
||||
@tailcode;
|
||||
|
@ -145,7 +145,6 @@ class Parser
|
||||
protected $yyval;
|
||||
protected $yyastk;
|
||||
protected $yysp;
|
||||
protected $yyaccept;
|
||||
|
||||
/** Debug mode flag **/
|
||||
public $yydebug = true;
|
||||
@ -1254,63 +1253,49 @@ class Parser
|
||||
);
|
||||
}
|
||||
|
||||
protected function accept() {
|
||||
$acceptCallback = $this->acceptCallback;
|
||||
$acceptCallback($this->yyval);
|
||||
}
|
||||
|
||||
protected function yyaccept() {
|
||||
$this->yyaccept = 1;
|
||||
}
|
||||
|
||||
protected function yyabort() {
|
||||
$this->yyaccept = 2;
|
||||
}
|
||||
|
||||
/* Traditional Debug Mode */
|
||||
private function YYTRACE_NEWSTATE($state, $sym) {
|
||||
if ($this->yydebug) {
|
||||
$this->yyprintln("% State " . $state . ", Lookahead "
|
||||
. ($sym < 0 ? "--none--" : self::$yyterminals[$sym]));
|
||||
$this->yyprintln('% State ' . $state . ', Lookahead '
|
||||
. ($sym < 0 ? '--none--' : self::$yyterminals[$sym]));
|
||||
}
|
||||
}
|
||||
|
||||
private function YYTRACE_READ($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Reading " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Reading ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
|
||||
private function YYTRACE_SHIFT($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Shift " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Shift ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
|
||||
private function YYTRACE_ACCEPT() {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Accepted.");
|
||||
$this->yyprintln('% Accepted.');
|
||||
}
|
||||
|
||||
private function YYTRACE_REDUCE($n) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Reduce by (" . $n . ") " . self::$yyproduction[$n]);
|
||||
$this->yyprintln('% Reduce by (' . $n . ') ' . self::$yyproduction[$n]);
|
||||
}
|
||||
|
||||
private function YYTRACE_POP($state) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Recovering, uncovers state " . $state);
|
||||
$this->yyprintln('% Recovering, uncovers state ' . $state);
|
||||
}
|
||||
|
||||
private function YYTRACE_DISCARD($sym) {
|
||||
if ($this->yydebug)
|
||||
$this->yyprintln("% Discard " . self::$yyterminals[$sym]);
|
||||
$this->yyprintln('% Discard ' . self::$yyterminals[$sym]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser entry point
|
||||
*/
|
||||
public function yyparse($lex, $acceptCallback, $errorCallback) {
|
||||
public function yyparse($lex, $errorCallback) {
|
||||
$this->lex = $lex;
|
||||
$this->acceptCallback = $acceptCallback;
|
||||
$this->errorCallback = $errorCallback;
|
||||
|
||||
$this->yyastk = array();
|
||||
@ -1354,14 +1339,14 @@ class Parser
|
||||
if ($yyn > 0) {
|
||||
/* shift */
|
||||
$this->YYTRACE_SHIFT($yychar);
|
||||
$this->yysp++;
|
||||
++$this->yysp;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate = $yyn;
|
||||
$this->yyastk[$this->yysp] = $yylval;
|
||||
$yychar = -1;
|
||||
|
||||
if ($yyerrflag > 0)
|
||||
$yyerrflag--;
|
||||
--$yyerrflag;
|
||||
if ($yyn < self::YYNLSTATES)
|
||||
continue;
|
||||
|
||||
@ -1376,38 +1361,30 @@ class Parser
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/* reduce/error */
|
||||
if ($yyn == 0) {
|
||||
/* accept */
|
||||
$this->YYTRACE_ACCEPT();
|
||||
$this->accept();
|
||||
return $this->yyaccept - 1;
|
||||
return $this->yyval;
|
||||
} elseif ($yyn != self::YYUNEXPECTED) {
|
||||
/* reduce */
|
||||
$yyl = self::$yylen[$yyn];
|
||||
$n = $this->yysp-$yyl+1;
|
||||
$yyval = isset($this->yyastk[$n]) ? $this->yyastk[$n] : null;
|
||||
$this->YYTRACE_REDUCE($yyn);
|
||||
$this->{'yyn' . $yyn}();
|
||||
if ($this->yyaccept) {
|
||||
$yyn = self::YYNLSTATES;
|
||||
|
||||
/* Goto - shift nonterminal */
|
||||
$this->yysp -= self::$yylen[$yyn];
|
||||
$yyn = self::$yylhs[$yyn];
|
||||
if (($yyp = self::$yygbase[$yyn] + $yysstk[$this->yysp]) >= 0
|
||||
&& $yyp < self::YYGLAST
|
||||
&& self::$yygcheck[$yyp] == $yyn) {
|
||||
$yystate = self::$yygoto[$yyp];
|
||||
} else {
|
||||
/* Goto - shift nonterminal */
|
||||
$this->yysp -= $yyl;
|
||||
$yyn = self::$yylhs[$yyn];
|
||||
if (($yyp = self::$yygbase[$yyn] + $yysstk[$this->yysp]) >= 0
|
||||
&& $yyp < self::YYGLAST
|
||||
&& self::$yygcheck[$yyp] == $yyn) {
|
||||
$yystate = self::$yygoto[$yyp];
|
||||
} else {
|
||||
$yystate = self::$yygdefault[$yyn];
|
||||
}
|
||||
|
||||
$this->yysp++;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate;
|
||||
$this->yyastk[$this->yysp] = $this->yyval;
|
||||
$yystate = self::$yygdefault[$yyn];
|
||||
}
|
||||
|
||||
++$this->yysp;
|
||||
|
||||
$yysstk[$this->yysp] = $yystate;
|
||||
$this->yyastk[$this->yysp] = $this->yyval;
|
||||
} else {
|
||||
/* error */
|
||||
switch ($yyerrflag) {
|
||||
@ -1425,7 +1402,7 @@ class Parser
|
||||
&& $yyn < self::YYLAST
|
||||
&& self::$yycheck[$yyn] == self::YYINTERRTOK))) {
|
||||
if ($this->yysp <= 0) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
$yystate = $yysstk[--$this->yysp];
|
||||
$this->YYTRACE_POP($yystate);
|
||||
@ -1438,7 +1415,7 @@ class Parser
|
||||
case 3:
|
||||
$this->YYTRACE_DISCARD($yychar);
|
||||
if ($yychar == 0) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
$yychar = -1;
|
||||
break;
|
||||
@ -1452,7 +1429,10 @@ class Parser
|
||||
}
|
||||
}
|
||||
}
|
||||
private function yyn0() {}
|
||||
|
||||
private function yyn0() {
|
||||
$this->yyval = $this->yyastk[$this->yysp];
|
||||
}
|
||||
|
||||
private function yyn1() {
|
||||
$this->yyval = $this->yyastk[$this->yysp-(1-1)];
|
||||
|
21
test.php
21
test.php
@ -10,25 +10,26 @@ $parser = new Parser();
|
||||
$parser->yydebug = false;
|
||||
|
||||
// Output Demo
|
||||
$parser->yyparse(new Lexer(
|
||||
$stmts = $parser->yyparse(new Lexer(
|
||||
'<?php
|
||||
echo HI;
|
||||
hallo();
|
||||
blaBlub();'
|
||||
),
|
||||
function($stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
echo htmlspecialchars($stmt), "\n";
|
||||
}
|
||||
},
|
||||
function($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
);
|
||||
if (false !== $stmts) {
|
||||
foreach ($stmts as $stmt) {
|
||||
echo htmlspecialchars($stmt), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n\n";
|
||||
|
||||
// Correctness Demo
|
||||
$GST = microtime(true);
|
||||
foreach (new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator('.'),
|
||||
RecursiveIteratorIterator::LEAVES_ONLY)
|
||||
@ -40,16 +41,16 @@ foreach (new RecursiveIteratorIterator(
|
||||
set_time_limit(5);
|
||||
|
||||
$startTime = microtime(true);
|
||||
$result = $parser->yyparse(
|
||||
$stmts = $parser->yyparse(
|
||||
new Lexer(file_get_contents($file)),
|
||||
function($stmts) { },
|
||||
function($msg) {
|
||||
echo $msg, "\n";
|
||||
}
|
||||
);
|
||||
$endTime = microtime(true);
|
||||
|
||||
echo str_pad($file . ': ', 120, ' '), ($result == -1 ? 'successful' : 'ERROR'), ' (', $endTime - $startTime, ')', "\n";
|
||||
echo str_pad($file . ': ', 120, ' '), (false !== $stmts ? 'successful' : 'ERROR'), ' (', $endTime - $startTime, ')', "\n";
|
||||
|
||||
flush();
|
||||
}
|
||||
}
|
||||
echo microtime(true) - $GST;
|
Loading…
Reference in New Issue
Block a user