3 // +----------------------------------------------------------------------+
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2002 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Alan Knowles <alan@akbkhome.com> |
17 // +----------------------------------------------------------------------+
20 * Docbook data container (for pages and sections)
22 * @package PHP_CodeDoc
24 * @author Alan Knowles <alan@akbkhome.com>
27 PEAR::loadExtension('tokenizer');
29 ini_set("memory_limit","128M");
31 error_reporting(E_ALL);
35 require_once("PHP/CodeDoc/Data/Class.php");
36 require_once("PHP/CodeDoc/Data/Var.php");
37 require_once("PHP/CodeDoc/Data/Define.php");
38 require_once("PHP/CodeDoc/Data/Method.php");
39 require_once("PHP/CodeDoc/Data/PhpDoc.php");
40 require_once("PHP/CodeDoc/Data/Directory.php");
41 require_once("PHP/CodeDoc/Data/Package.php");
42 require_once("PHP/CodeDoc/Data/Docbook.php");
44 require_once("PHP/CodeDoc/Parser/Class.php");
45 require_once("PHP/CodeDoc/Parser/Var.php");
46 require_once("PHP/CodeDoc/Parser/Define.php");
47 require_once("PHP/CodeDoc/Parser/Method.php");
48 require_once("PHP/CodeDoc/Parser/Comment.php");
49 require_once("PHP/CodeDoc/Parser/Docbook.php");
53 class PHP_CodeDoc_Parser {
55 var $original_URL_base; // base url.
57 var $_level; // what level is the parser at (0 = base, 1=in class)
58 var $pos=0; // current position.
59 var $total=0; // total number of tokens in current file
60 var $tokens; // the array of tokens
62 var $_active_class =0; // id of active class being created
63 var $active_class; //during output this is the currently dumped class object
64 var $activeFile; // active file being parsed
65 var $active_package; // active used package object
66 var $active_directory; // active used directory object
68 var $start_file = ""; // the file (or directory) that was called at the start..
69 var $packages; // associative array of package name -> package object
70 var $_base_dir; // root of tree !
71 var $_base_dir_len; // root of tree !
74 var $_parser_class; // class parser
75 var $_parser_method;// method parser
76 var $_parser_var;// var parser
77 var $_parser_comment;// comment parser
79 var $classes = array(); // array of classes
80 var $defines = array(); // array of defines
84 function start() { // Main entry - start parsing a file or directory
85 /* initiate global parsers */
86 $options = PHP_CodeDoc::$options;
89 $filename = $options['source'];
91 $this->_initializeParsers();
92 if (is_dir($filename)) {
93 $this->_base_dir = dirname(realpath($filename));
94 $this->_base_dir_len = strlen($this->_base_dir );
95 $this->_build($filename);
97 foreach($this->files as $dir => $files) {
98 foreach($files as $file)
100 $this->_parseFile($dir . "/".$file);
102 if (@$options['maxFiles'] && $n > $options['maxFiles']) {
108 $this->_parseFile($filename);
112 var $_init =0; //initialization flag (has init been run?)
115 function _initializeParsers() {
116 if ($this->_init) return;
121 $this->packages['No Package']= new PHP_CodeDoc_Data_Package;
122 $this->packages['No Package']->name = "No Package";
128 var $_pre_output =0; // pre output flag;
130 function _build( $filename) { // build a list of file to parse
133 $this->files[$filename] = array();
135 $fh = opendir($filename);
138 while (($file =readdir($fh)) !== FALSE) {
139 if ($file{0} == ".") continue;
140 //echo "READ: $filename/$file\n";
141 if (is_file($filename."/".$file)) {
143 if (!ereg("\.(inc|php|class)$",$file)) continue;
144 $this->files[$filename][] = $file;
146 } elseif (is_dir($filename."/".$file)) {
147 if ($file == "CVS") continue;
148 if ($file == "RCS") continue;
150 $this->_build($filename . "/". $file);
155 //echo "\nDO STUFF\n";
159 function _parseFile($filename) { // tockenize a file and start parsing
160 echo "PARSING: $filename\n";
163 $this->activeFile = $filename;
164 if (!filesize ($filename)) return;
167 $this->rdir = substr(dirname(realpath($this->activeFile)),$this->_base_dir_len);
168 $this->rfilename = substr(realpath($this->activeFile),$this->_base_dir_len);
169 $tmpar = explode ('/', $this->rfilename);
171 $base = substr(implode('/',$tmpar),2);
172 $this->file_url = $this->original_URL_base . $base;
174 if (@$this->tokens) unset($this->tokens);
175 $data = implode('',file($filename));
176 $this->tokens = token_get_all($data);
177 /* use this if you have a broken tokenizer
178 $fh = popen(dirname(__FILE__)."/tokenizer_serialize.php $filename","r");
179 $this->tokens= unserialize(fread($fh,filesize($filename) * 16));
183 $pname= 'No Package';
184 $options = PHP_CodeDoc::$options;
185 if (!$options['perDirPackages']) {
186 if (preg_match('/^\s*\*\s*@package\s*(.*)$/im',$data,$args)) {
187 //echo "\nGot package {$this->package}\n";
188 $pname = trim($args[1]);
191 $parts = explode('/',$this->rfilename);
193 if ($this->rfilename{0} == "/") $pname = $parts[2];
194 $pname = preg_replace('/\.php$/','',$pname);
195 if (!$pname) $pname = "No Package";
196 echo "\nUsing package (from dir {$this->rfilename} ) {$pname}\n";
201 if (!@$this->packages[$pname]) {
202 $this->packages[$pname] = new PHP_Codedoc_Data_Package;
203 $this->packages[$pname]->name = $pname;
205 $this->active_package = &$this->packages[$pname];
208 if (!@$this->active_package->directories[$this->rdir]) {
209 $this->active_package->directories[$this->rdir] = new PHP_Codedoc_Data_Directory;
210 $this->active_package->directories[$this->rdir]->name = $this->rdir;
212 $this->active_directory = &$this->active_package->directories[$this->rdir];
214 //print_r($data); exit;
215 // $this->all_tokens[$filename] = token_get_all($contents);
216 // $this->tokens =& $this->all_tokens[$filename];
219 // $this->tokens = &$tokens;
220 $this->total = count($this->tokens);
223 unset($this->tokens);
228 var $last_comment_block = ""; // last comment block found
231 function _parse() { // read the tokens and make the classes
232 $options = PHP_CodeDoc::$options;
238 $this->copyright= " No Copyright specified ";
242 $this->total = count($this->tokens);
243 while ($this->pos < $this->total) {
244 if (@$options['debug']) {
245 echo "{$this->activeFile}:{$this->pos}/{$this->total}\n";
247 $v = $this->tokens[$this->pos];
249 if (!$inbrak && $v[0] == T_WHITESPACE) {
253 //if ($v[0] == T_CURLY_OPEN) {
257 // $this->debug(__METHOD__, "{$this->pos}:" .token_name($v[0]) . ":". $v[1]);
260 PHP_CodeDoc_Parser_Class::read();
265 PHP_CodeDoc_Parser_Method::read($inclass);
268 PHP_CodeDoc_Parser_Var::read($inclass);
271 PHP_CodeDoc_Parser_Define::read($v[1]);
276 // merge forthcomming comments
279 $this->last_comment_block = $v[1];
280 if (substr(trim($v[1]),0,2) == "//") {
287 //echo "Got ". serialize($this->tokens[$this->pos]) ."\n";
288 if (!isset($this->tokens[$this->pos]) || !is_array($this->tokens[$this->pos])) {
291 if ($this->tokens[$this->pos][0] != T_COMMENT) break;
292 if (substr(trim($this->tokens[$this->pos][1]),0,2) != "//") break;
293 $this->last_comment_block .= $this->tokens[$this->pos][1];
302 if (preg_match('/copyright/is', $this->last_comment_block)) {
303 $comment = preg_replace('/^\s*\/(\*)+/m','',$this->last_comment_block);
304 $comment = preg_replace('/(\*)+\/\s*$/m','',$comment);
305 $comment = preg_replace('/^\s*(\*)+/m','',$comment);
306 // tecnically should look back and front and gather all comments
307 $this->copyright = $comment;
308 //echo "-------storing\n";
313 $this->last_comment_block = $v[1];
314 PHP_CodeDoc_Parser_Docbook::read($this->last_comment_block,$inclass);
317 //echo "{$this->pos}:" .
318 // token_name($v[0]) .
319 // ":{$this->level}:". $v[1] .":\n";
320 //if ($v[1] && $v[1]{0} == "(")
326 if (!$inbrak && trim($v) == "}") $this->_level--;
327 if (!$inbrak && trim($v) == "{") $this->_level++;
328 if (trim($v) == "(") $inbrak++;
329 if (trim($v) == ")") $inbrak--;
331 //echo "{$this->pos}:RAW:{$v}\n";
337 var $classes_by_name; // array assoc name=>class
338 var $classes_by_directory; // array assoc directory=>name=>class
339 var $classes_by_package; // array assoc package=>directory=>name=>class
354 function debugToken($pos) { // print out a token for debugging
355 $v = !is_numeric($pos) ? $pos : $this->tokens[$pos];
357 echo ":" .token_name($v[0]) . ":". $v[1] .":\n";
359 echo ":RAW: ". $v .":\n";
364 * find token pos(19,array(T_EXTENDS),"{");
367 * array(T_STRING,'define')
370 * look for T_EXTENDS, stop when it gets to
371 *@ return int Position of token.
374 function find_token_pos($start,$look,$stop) {
376 while ($p < $this->total) {
377 if ($this->compare_token($p,$look))
379 if ($this->compare_token($p,$stop))
386 * @returns false|STRING|constant
389 function look_nws($num, $stop= '')
391 $dir = $num > 0 ? 1 : -1;
393 throw new Exception('invalid direction');
395 $p = $this->pos + $dir;
398 if (!isset($this->tokens[$p] )) {
401 $t = $this->tokens[$p];
402 if (in_array($t[0],array(T_DOC_COMMENT,T_WHITESPACE,T_COMMENT))) {
406 if ($stop != '' && $t == $stop) {
411 if ($c >= abs($num)) {
412 return is_array($t) ? $t[0] : $t;
420 function compare_token($pos,$token) {
421 $t = $this->tokens[$pos];
424 if (!is_array($token)) return FALSE;
425 if ($t[0] != $token[0]) return FALSE;
426 if (count($token) == 1) return TRUE;
427 if (trim($t[1]) != trim($token[1])) return FALSE;
430 if (is_array($token)) return FALSE;
431 if ($token == "") return TRUE; // looking for a strng
432 if (trim($t) != trim($token)) return FALSE;
436 /* not sure if this is the best place for this!*/
437 function output_prune($dir) {
438 // say we get /xxx/yyy/zzz
440 // we need to replate 1
441 $d = explode('/',$dir);
443 for ($i = 1; $i< $c;$i++)
445 return implode('/',$d);
448 function debug($meth, $com) {
451 $t = $this->tokens[$this->pos];
453 echo "{$t[2]}: $meth : $com \n";
455 function debugTok($pos) {
456 if (!isset($this->tokens[$pos]) || empty($this->tokens[$pos])) {
459 $v = $this->tokens[$pos];
461 echo "{$v[2]}: $pos:" .token_name($v[0]) . ":". $v[1] ."\n";