class parser {
// Исходный код для парсинга
private $sourceCode = '';
// Строки исходника
private $sourceLines = array(), $length = 0;
// индекс текущей строки
private $currentLine = -1;
// Зарезервированные ключевые слова
private $systemFunctions = '/^\\.?addEventListener|\\.?setattribute|\\.?getattribute|while|if|push|new|\\.?match|\\.?replace|function|\\.?test|else|return|settimeout|setinterval|\\.?substr|\\.?substring|cleartimeout|clearinterval|catch|\\.?split|\\.?indexof|\\.?charat|for|do|elseif|parseint|parsefloat|alert$/i';
// Объявления функций
private $defineFunction = array(
'/var\\s+(\\w+)\\s*=\\s*function\\(.*\\)/',
'/function\\s+(\\w+)\\s*\\(.*\\)/',
'/(\\w+)\\s*\:\\s*function\\(.*\\)/'
);
// Вызов функции
private $useFunction = "/(\w+\.?\w*\.?\w*\.?\w*)\\s*\\(.*\\)/";
//
private $map = array(), $mapLength = 0;
private $index = array(), $indexLength = 0;
private $lastOpenned;
// Hello
function __construct($s){
$this->normalize($s);
}
/**
* Базовая проверка на валидность скрипта
* смотрим закрыты ли все скобки
*/
private function isValidSource(&$string){
$ch = array('','{','}','[',']','(',')');
for( $i = 1; $i < 4; $i *= 2 ) {
if( sizeof(explode($ch[$i], $string)) != sizeof(explode($ch[$i+1], $string)) ){
return false;
}
}
return true;
}
/**
* Приводим исходник в порядок
*/
private function normalize($string){
if ( $this->isValidSource($string) )
exit("Bad script");
$this->sourceCode = $string;
$i = 0;
$lines = explode("\n", $string);
foreach( $lines as $line ){
if(($line = trim($lines[$i++]))){
$this->sourceLines[$this->length++] = $line;
#echo $line . "<br>";
}
}
}
/**
* Проверяем, является ли строка объявлением функции
*/
private function isDefineFunction(&$line){
for( $i = 0; $i < 3; $i++ ) {
if(preg_match( $this->defineFunction[$i] , $line, $out )){
return array(++$i, $out[1]);
}
}
return false;
}
/**
* Считаем количество заданных символов в текущей строке
*/
private function sCount($s){
return count(explode($s, $this->sourceLines[$this->currentLine]));
}
/**
* Получаем исходник функции
*/
private function getFunctionSource(){
$start = $this->sCount('{') - $this->sCount('}');
$line = $this->sourceLines[$this->currentLine];
$ret = array($line);
if( $start > 0 ){
while( $start && ($line = $this->sourceLines[++$this->currentLine])){
array_push($ret, $line);
$start += ($this->sCount('{') - $this->sCount('}'));
}
}
return $ret;
}
/**
* Смотрим исходник функции. Ищем зависимости
*/
private function getFunctionDepends(&$lines, $name){
$r = array();
foreach( $lines as $line ){
while(preg_match($this->useFunction, $line, $fns)){
$fn = $fns[1];
$line = implode("", explode($fn, $line));
if( $fn != $name && !preg_match( $this->systemFunctions, $fn) && !in_array($fn, $r)){
$r[] = $fn;
#echo "$fn<br>";
}
}
}
return $r;
}
/**
* Rdy? gO!
*/
public function prepare(){
$stat = 0;
while(++$this->currentLine < $this->length && ($line = $this->sourceLines[$this->currentLine])){
// Если наткнулись на объявление функции
if(($stat = $this->isDefineFunction($line)) ){
// Получаем ее исходник
$fnSource = $this->getFunctionSource();
$this->mapLength++;
#echo implode("<br>", $fnSource);
//if($stat[0] == 3){
;#name of fn
//} else {
if( $this->lastOpenned ){
$this->lastOpenned = 0;
$this->mapLength++;
}
$this->map[$this->mapLength]['source'] = implode("\n", $fnSource);
$this->map[$this->mapLength]['name'] = $stat[1];
$this->map[$this->mapLength]['depends'] = $this->getFunctionDepends($fnSource, $stat[1]);
//}
}
}
}
public function view(){
echo "<ul>";
foreach( $this->map as $m ){
echo "<li>" . $m['name'] . " [ " . implode(', ', $m['depends']) . ' ]</li>';
}
echo "<ul>";
}
}