error_reporting(E_ALL);
ini_set("display_errors", 1);
class parser {
// Исходный код для парсинга
private $sourceCode = '';
// Строки исходника
private $sourceLines = array(), $length = 0;
// индекс текущей строки
private $currentLine = -1;
// Зарезервированные ключевые слова
private $systemFunctions = array(
'/^Math.round|Math.random|Math.pow|typeof|isNan|int|string|function|if|new|return|settimeout|setInterval|else|elseif|while|do|for|parseint|parsefloat|alert|push|cleartimeout|clearinterval|catch$/i',
'/^(\\w+\\.)?appendChild|(\\w+\\.)?addRule|(\\w+\\.)?insertRule|(\\w+\\.)?touppercase|(\\w+\\.)?toLowerCase|(\\w+\\.)?addEventListener|(\\w+\\.)?setattribute|math\\.ceil|math\\.floor$/i',
'/^(\\w+\\.)?getattribute|(\\w+\\.)?match|(\\w+\\.)?replace|(\\w+\\.)?test|(\\w+\\.)?substr|(\\w+\\.)?substring|(\\w+\\.)?split|(\\w+\\.)?indexof|(\\w+\\.)?charat$/i',
'/^(\\w+\\.)?getElementsByTagName|(\\w+\\.)?getElementsByTagId|(\\w+\\.)?getElementsByClassName|(\\w+\\.)?call|(\\w+\\.)?apply$/i'
);
// Объявления функций
private $defineFunction = array(
'/var\\s+(\\w+)\\s*=\\s*function\\(.*\\)/',
'/function\\s+(\\w+)\\s*\\(.*\\)/',
'/(\\w+)\\s*\:\\s*function\\(.*\\)/',
'/(var\\s*\\w*)?\\(function\\(\\)\\{/'
);
// Вызов функции
private $useFunction = "/(\w+\.?\w*\.?\w*\.?\w*)\\s*\\(.*\\)/";
//
private $map = array(), $mapLength = 0;
private $index = array(), $indexLength = 0;
private $lastOpenned;
private $extend = array(), $extendIndex = 0;
// 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 . "
";
}
}
}
/**
* Проверяем, является ли строка объявлением функции
*/
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 isNotSystemFunction(&$fn){
foreach($this->systemFunctions as $sys){
if ( preg_match( $sys, $fn) ){
return false;
}
}
return true;
}
/**
* Считаем количество заданных символов в текущей строке
*/
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)); # protect regexp error
if( $fn != $name && $this->isNotSystemFunction($fn) && !in_array($fn, $r)){
$r[] = $fn;
#echo "$fn
";
}
}
}
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++;
switch( $stat[0] ) {
// Функция явно указана
// function a(){} или var a = function(){}
case 1: case 2:
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]);
break;
// Функция вложенная в объект
// a: function(){}
case 3:
;
break;
}
}
}
}
public function view(){
echo "