Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

RECODE AST GRAMMAIRE DU PHP


Information sur la source

Catégorie :Divers Classé sous : ast, grammaire, recode, lexeur, parseur Niveau : Initié Date de création : 02/05/2008 Vu / téléchargé: 2 207 / 54

Note :
9,5 / 10 - par 2 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (18)
Ajouter un commentaire et/ou une note


Description

Ces classes servent a faire un systeme de _recode_ d'un code php.

Exemples :
- refaire une indentation correcte
- faire des commentaires doxygen pour les fonctions (les preparer du moins)
- transformer les "foo $a bar $b" en 'foo '.$a.' bar '.$b

(ces trois choses sont implementees dans cet exemple.)

J'aurais aime pouvoir implementer le tail recursif, mais en php5, c'est impossible.
En php6, on devrait avoir des goto, ce qui permetrait de faire ces choses.

exemple :

function sub_f ($a, $b){
if ($a==0) return $b;
else{return sub_f($a-1, $a+$b);}
}

function sumOfNaturals($n){
return sub_f($n, 0);
}

echo sumOfNaturals(5000000);

ce code ne fonctionne pas en php, parce-qu'il contient trop d'appels recursif,
ce qui fait que le code plante. Ca segfault, (erreur de segmentation), en effet,
un appel de fonction necessite un empillement des arguments sur la pile,
au retour de la fonction, on les depile.

En C, avec l'option -O2 (ou 1 ou 3), lorsque le code est _tail_recursif_ (ou recursivite finnie),
des optimisations sont faites, et le code ne conserve pas sa recursivite initiale.

quand un return reutilise la fonction est la derniere operation de la fonction, on peut remplacer le code par :
$argument1= ... ; $argument2= ... ; goto debut_de_la_fonction;

function sub_f ($a, $b){

        label debut:

if ($a==0) return $b;
else{
            $a1=$a-1;
            $b1=$a+$b;

            $a=$a1; $b=$b1;

            goto debut;
        }
}

function sumOfNaturals($n){
return sub_f($n, 0);
}

comme vous pouvez le voir, ici, on ne conserve pas de recursivite, pourtant, la fonction fait la meme chose.
en Ocaml, en C, en Cpp, et dans plein d'autres langages, la recursivite est supprimee (lors de la compilation)
ce qui permet d'eviter ces erreurs de segmentation, et ces empilements inutiles.

en php6, on pourra faire ca (on aura alors les goto). C'etait mon projet initial quand j'ai voulu coder ca.


Ce programme utilise le lexer de php. Il nous renvoie des _Tokens_, que je transforme en Objets Tokens.
Ensuite, un parseur utilise un reducteur pour faire un AST (arbre syntaxique)
exemple :
if -  condition
   -  instructions

Ce qui permet de faire des manipulations sur cet arbre.

Ce code contient donc une grammaire simple sur le php
 

Source

  • <?php
  • error_reporting(E_ALL);
  • if (isset($_SERVER['argv'][1]))
  • $filename=$_SERVER['argv'][1];
  • else if (isset($_GET['argv']))
  • $filename=$_GET['argv'];
  • else
  • $filename='';
  • function makeTab($n){
  • $out='';
  • for ($i=0;$i<$n;$i++){
  • $out.=' ';
  • }
  • return $out;
  • }
  • function parse_error($s){
  • echo $s.'
  • ';
  • exit(1);
  • }
  • class Locator{
  • public function __construct($l){$this->ligne=$l;}
  • public function __toString(){return 'l:'.$this->ligne;}
  • public function Val(){return $this->ligne;}
  • public function isBetween(Locator $v1, Locator $v2){
  • return $v1->Val() <= $this->ligne && $v2->Val() >= $this->ligne;
  • }
  • private $ligne;
  • }
  • class Node{
  • public function is_important(){ return true; }
  • public function isFermant(){ return false; }
  • public function getContent(){ return ''; }
  • public function isVal(){return false;}
  • public function isOperator(){return false;}
  • public function isOperatorAlone(){return false;}
  • public function isInstruction(){ return false; }
  • public function contient(){ return false; }
  • public function getChilds(){ return array();}
  • public function accept($visiteur){
  • $visiteur->visite($this);
  • }
  • }
  • class Token extends Node{
  • public function __construct($t){
  • if (is_array($t)){
  • $this->type=token_name($t[0]);
  • $this->locator=new Locator($t[2]);
  • self::$last=$t[2];
  • if ($this->type=='T_OPEN_TAG'){
  • $this->content='<?php';
  • }else{
  • $this->content=$t[1];
  • }
  • }else{
  • if (!isset(self::$mytoken[$t])){
  • throw new Exception ('Token '.$t.' non defini');
  • }
  • $this->type=self::$mytoken[$t];
  • $this->content=$t;
  • $this->locator=new Locator(self::$last);
  • }
  • }
  • public function getContent(){ return $this->content; }
  • public function __toString(){
  • return $this->content; //.' '.$this->type.' ';
  • }
  • public function contient($a, $b){
  • return $this->type==$a && $this->content==$b;
  • }
  • private static $mytoken = array(
  • ';'=>'MT_PT_VIRGULE',
  • '('=>'MT_PARENTHESE_OPEN',
  • ')'=>'MT_PARENTHESE_CLOSE',
  • ','=>'MT_VIRGULE',
  • '{'=>'MT_ACCOLADE_OPEN',
  • '}'=>'MT_ACCOLADE_CLOSE',
  • '*'=>'MT_FOIS',
  • '-'=>'MT_MOINS',
  • '+'=>'MT_PLUS',
  • '='=>'MT_EGAL',
  • '"'=>'MT_DOUBLE_QUOTE',
  • '.'=>'MT_POINT',
  • '<'=>'MT_INF_A',
  • ':'=>'MT_DEUX_POINTS'
  • );
  • private static $fin = array(
  • 'MT_PARENTHESE_CLOSE'=>'MT_PARENTHESE_OPEN',
  • 'MT_ACCOLADE_CLOSE'=>'MT_ACCOLADE_OPEN',
  • 'T_CLOSE_TAG'=>'T_OPEN_TAG',
  • 'MT_DOUBLE_QUOTE'=>'MT_DOUBLE_QUOTE'
  • );
  • public function is_important(){
  • return !in_array($this->type, self::$no_imp);
  • }
  • public function isFermant(){
  • return isset (self::$fin[$this->type]);
  • }
  • public function getOuvre(){
  • return self::$fin[$this->type];
  • }
  • public function getName(){ return $this->type;}
  • public function isVal(){
  • return in_array($this->type, self::$val);
  • }
  • public function isOperator(){
  • return in_array($this->type, self::$op);
  • }
  • public function isOperatorAlone(){
  • return in_array($this->type, self::$opAlone);
  • }
  • private static $op=array('MT_FOIS', 'MT_PLUS', 'MT_MOINS', 'T_IS_EQUAL','MT_POINT', 'MT_INF_A');
  • private static $opAlone=array('T_INC');
  • private static $val=array(
  • 'Couple_MT_PARENTHESE_OPEN', 'T_VARIABLE', 'T_LNUMBER','EXPR', 'T_CONSTANT_ENCAPSED_STRING'
  • );
  • public function getLine(){
  • return $this->locator;
  • }
  • public function getChilds(){ return array(); }
  • private static $no_imp=array('T_WHITESPACE', 'T_COMMENT', 'T_DOC_COMMENT');
  • private $type;
  • private $content;
  • private $locator;
  • private static $last=0;
  • }
  • class Couple extends Node{
  • public function __construct(){ $this->stack=array(); }
  • public function append($t){ $this->stack[]=$t; }
  • public function end_(){ $this->stack=array_reverse($this->stack);}
  • public function getName(){
  • return 'Couple_'.$this->stack[0]->getName().'';
  • }
  • public function __toString($tab=0){
  • $acc=($this->stack[0]->getName()=='MT_ACCOLADE_OPEN' || $this->stack[0]->getName()=='T_OPEN_TAG');
  • if ($acc)
  • $out=makeTab($tab -1);
  • else
  • $out='';
  • $len=count($this->stack)-1;
  • foreach ($this->stack as $i=>$e){
  • if ($i==$len && $acc){
  • $out.=makeTab($tab -1).$e.'
  • ';
  • }else{
  • $out.=$e->__toString($tab);
  • }
  • if ($i==0 && $acc){
  • $out.='
  • ';
  • }else if ($e->getName()=='MT_VIRGULE'){
  • $out.=' ';
  • }
  • }
  • return $out;
  • }
  • public function getLine(){
  • return $this->stack[0]->getLine();
  • }
  • public function getLastLine(){
  • return $this->stack[ count($this->stack)-1 ]->getLine();
  • }
  • public function contient($a, $b){
  • foreach ($this->stack as $e){
  • if ($e->contient($a, $b)) return true;
  • }
  • return false;
  • }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • foreach ($this->stack as $e){
  • $e->accept($visiteur);
  • }
  • }
  • public function getStack(){return $this->stack;}
  • public function isInstruction(){ return $this->stack[0]->getName()=='MT_ACCOLADE_OPEN'; }
  • public function getChilds(){ return $this->stack; }
  • private $stack;
  • }
  • class PHP_function extends Node {
  • public static $devant_function=array('T_PUBLIC', 'T_STATIC', 'T_PRIVATE', 'T_PROTECTED');
  • public function isInstruction(){ return true; }
  • public function getLine(){return $this->line;}
  • public function __construct($content, $argList, $func){
  • $this->devant=array();
  • $this->line=$func->getLine();
  • $this->name = $func->getContent();
  • $this->argList=$argList;
  • $this->content=$content;
  • }
  • public function ajouter_devant($e){
  • $this->devant[]=$e;
  • }
  • public function getName(){ return 'FUNCTION'; }
  • public function __toString($tab=0){
  • $tab2=$tab+1;
  • $fd='function '.$this->name.$this->argList;
  • foreach ($this->devant as $a){
  • $fd=$a.' '.$fd;
  • }
  • $comments=Tokens__::getComments($this->line, $this->content->getLastLine());
  • $out='
  • '.makeTab($tab).'/**
  • '.makeTab($tab).' * @fn '.$fd.'
  • '.makeTab($tab).' * @brief
  • ';
  • if ($this->isRecursive()){
  • $out.=makeTab($tab).' * recursive function.
  • ';
  • }
  • foreach ($comments as $c){
  • $out.=Tokens__::noComment($c->getContent(), $tab);
  • }
  • foreach ($this->argList->getStack() as $p)
  • if ($p->getName()=='T_VARIABLE')
  • $out.=makeTab($tab).' * @param '.$p.'
  • ';
  • $out.=makeTab($tab).' * @return
  • '.makeTab($tab).' */
  • ';
  • $out.=makeTab($tab).$fd.'
  • '.$this->content->__toString($tab2).'
  • ';
  • return $out;
  • }
  • public function isRecursive(){
  • return $this->content->contient('T_STRING', $this->name);
  • }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • private $line;
  • private $name;
  • private $argList;
  • private $content;
  • private $devant;
  • public function getChilds(){ return $this->content; }
  • }
  • class Expr extends Node{
  • public function getName(){ return 'EXPR';}
  • public function getLine(){return $this->v2->getLine();}
  • public function __toString(){
  • return $this->v2.' '.$this->op.' '.$this->v1;
  • }
  • public function __construct($v1, $op, $v2){
  • $this->op=$op; $this->v1=$v1; $this->v2=$v2;
  • }
  • public function isVal(){ return true; }
  • public function contient($a, $b){
  • if ($this->v1->contient($a, $b)) return true;
  • if ($this->v2->contient($a, $b)) return true;
  • return false;
  • }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->v1->accept($visiteur);
  • $this->v2->accept($visiteur);
  • $this->op->accept($visiteur);
  • }
  • private $op, $v1, $v2;
  • public function getChilds(){ return array($this->v1, $this->v2); }
  • }
  • class ExprAlone extends Node{
  • public function getName(){ return 'EXPRAlone';}
  • public function getLine(){return $this->v2->getLine();}
  • public function __toString(){
  • return $this->v2.' '.$this->op;
  • }
  • public function __construct($op, $v2){
  • $this->op=$op; $this->v2=$v2;
  • }
  • public function isVal(){ return true; }
  • public function contient($a, $b){
  • if ($this->v2->contient($a, $b)) return true;
  • return false;
  • }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->v2->accept($visiteur);
  • $this->op->accept($visiteur);
  • }
  • private $op, $v2;
  • public function getChilds(){ return array($this->v2); }
  • }
  • class CALL extends Node{
  • public function getLine(){return $this->func->getLine();}
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'CALL_FUNC';}
  • public function isVal(){ return true; }
  • public function __toString(){
  • return $this->func.$this->args;
  • }
  • public function __construct($args, $func){
  • $this->func=$func;$this->args=$args;
  • }
  • public function contient($a, $b){
  • if ($this->func->contient($a, $b)) return true;
  • if ($this->args->contient($a, $b)) return true;
  • return false;
  • }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->func->accept($visiteur);
  • $this->args->accept($visiteur);
  • }
  • public function getChilds(){ return $this->args;}
  • private $func;
  • private $args;
  • }
  • class ff_return extends Node{
  • public function getLine(){return $this->expr->getLine();}
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'FF_RETURN';}
  • public function __toString($tab=0){
  • return makeTab($tab).'return '.$this->expr.';
  • ';
  • }
  • public function __construct($expr){
  • $this->expr=$expr;
  • }
  • public function contient($a, $b){
  • if ($this->expr->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->expr); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->expr->accept($visiteur);
  • }
  • private $expr;
  • }
  • class Assign extends Node{
  • public function getLine(){return $this->varName->getLine();}
  • public function isVal(){ return true; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ASSIGN';}
  • public function __toString(){
  • return $this->varName->__toString().' '.$this->op->__toString().' '.$this->value->__toString();
  • }
  • public function __construct($op,$varName, $value){
  • $this->varName=$varName; $this->value=$value; $this->op=$op;
  • }
  • public function contient($a, $b){
  • if ($this->value->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->value); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->varName->accept($visiteur);
  • $this->value->accept($visiteur);
  • $this->op->accept($visiteur);
  • }
  • private $varName;
  • private $value;
  • private $op;
  • }
  • class Instruction extends Node{
  • public function getLine(){return $this->instr->getLine();}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'INSTR';}
  • public function __toString($tab=0){
  • return makeTab($tab).$this->instr->__toString().';
  • ';
  • }
  • public function __construct($instr){
  • $this->instr=$instr;
  • }
  • public function contient($a, $b){
  • if ($this->instr->contient($a, $b)) return true;
  • return false;
  • }
  • public function getContent(){ return $this->instr; }
  • public function getChilds(){ return array($this->instr); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->instr->accept($visiteur);
  • }
  • private $instr;
  • }
  • class _Echo extends Node{
  • public function getLine(){return $this->val->getLine();}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ECHO';}
  • public function __toString(){
  • return 'echo '.$this->val->__toString();
  • }
  • public function __construct($val){
  • $this->val=$val;
  • }
  • public function contient($a, $b){
  • if ($this->val->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->val); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->val->accept($visiteur);
  • }
  • private $val;
  • }
  • class PHP_String extends Node{
  • public function getContent(){ return $this->content; }
  • public function getLine(){return $this->line;}
  • public function isVal(){ return true; }
  • public function getName(){ return 'DOUBLE_STRING';}
  • public function __toString(){
  • return $this->content;
  • }
  • public function __construct($double){
  • $this->content=$double;
  • $this->line=$double->getLine();
  • }
  • public function contient($a, $b){
  • if ($this->content->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return $this->content; }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • public function setElement($e){
  • $this->content=$e;
  • }
  • private $content;
  • private $line;
  • }
  • class php_if extends Node{
  • public function getLine(){return $this->condition->getLine();}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'IF';}
  • public function __construct($content, $condition){
  • $this->condition=$condition;
  • $this->content=$content;
  • }
  • public function __toString($tab=0){
  • return makeTab($tab).'if '.$this->condition.'
  • '.$this->content->__toString($tab+1);
  • }
  • public function contient($a, $b){
  • if ($this->content->contient($a, $b)) return true;
  • if ($this->condition->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->condition, $this->content); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->condition->accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • protected $condition;
  • protected $content;
  • }
  • class php_ifelse extends Node{
  • public function getLine(){return $this->if_->getLine();}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ELSE';}
  • public function __construct($content, $else, $if){
  • $this->if_=$if;
  • $this->content=$content;
  • }
  • public function contient($a, $b){
  • if ($this->if_->contient($a, $b)) return true;
  • if ($this->content->contient($a, $b)) return true;
  • return false;
  • }
  • public function __toString($tab=0){
  • return $this->if_->__toString($tab).makeTab($tab).'else
  • '.$this->content->__toString($tab+1);
  • }
  • public function getChilds(){ return array($this->content, $this->if_); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->if_->accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • private $if_;
  • private $content;
  • }
  • class Tokens__{
  • public static function evalString($s){
  • $s=str_replace('\\n', "\n", $s);
  • $s=str_replace('\\t', "\t", $s);
  • $s=str_replace('\\r', "\r", $s);
  • $s=str_replace('\\"', '"', $s);
  • return $s;
  • }
  • public static function noComment($str, $tab){
  • $c=explode("\n", str_replace(array('/**', '/*', '*/', '//!', '//', '#'), array(''), $str));
  • $out='';
  • foreach ($c as $a){
  • $out.=makeTab($tab).' * '.trim($a).'
  • ';
  • }
  • return $out;
  • }
  • public static function makeString($s){
  • $s=str_replace('\\', '\\\\', $s);
  • $s=str_replace('\'', '\\\'', $s);
  • return new Token(
  • array(
  • T_CONSTANT_ENCAPSED_STRING,
  • '\''.$s.'\'',
  • 0)
  • );
  • }
  • public static function getPoint(){
  • if (self::$Point==NULL)
  • self::$Point=new Token('.');
  • return self::$Point;
  • }
  • public static function AddComment($t){
  • self::$comment[]=$t;
  • }
  • public static function getcomments($v1, $v2){
  • $out=array();
  • if (isset(self::$comment)){
  • foreach (self::$comment as $c){
  • if ($c->getLine()->isBetween($v1, $v2)){
  • $out[]=$c;
  • }
  • }
  • }
  • return $out;
  • }
  • private static $Point;
  • private static $comment;
  • public static $affect=array('T_PLUS_EQUAL', 'MT_EGAL');
  • }
  • class php_while extends Node{
  • public function __construct($content, $condition){
  • $this->content=$content;
  • $this->condition=$condition;
  • }
  • public function getLine(){return $this->condition->getLine();}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'WHILE';}
  • public function contient($a, $b){
  • if ($this->condition->contient($a, $b)) return true;
  • if ($this->content->contient($a, $b)) return true;
  • return false;
  • }
  • public function __toString($tab=0){
  • return makeTab($tab).'while '.$this->condition->__toString($tab+1).'
  • '.$this->content->__toString($tab+1);
  • }
  • public function getChilds(){ return array($this->content, $this->condition); }
  • private $condition;
  • private $content;
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->condition->accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • }
  • class php_for extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'INSTR';}
  • public function __toString($tab=0){
  • $out=makeTab($tab).'for (';
  • foreach ($this->affect as $i=>$e){
  • if ($i!=0) $out.=', ';
  • $out.=$e;
  • }
  • $out.=';';
  • foreach ($this->sortie as $i=>$e){
  • if ($i!=0) $out.=', ';
  • $out.=$e;
  • }
  • $out.=';';
  • foreach ($this->step as $i=>$e){
  • if ($i!=0) $out.=', ';
  • $out.=$e;
  • }
  • $out.=')
  • '.$this->content->__toString($tab+1);
  • return $out;
  • }
  • public function __construct($content, $couple, $for){
  • $this->ligne=$for->getLine();
  • $this->content=$content;
  • $this->affect=array();
  • $this->sortie=array();
  • $this->step=array();
  • $imp=array('MT_PT_VIRGULE', 'MT_VIRGULE', 'MT_PARENTHESE_OPEN','MT_PARENTHESE_CLOSE');
  • $b=false;
  • $s=$couple->getStack();
  • foreach ($s as $i=>$a){
  • if ($a->getName()=='INSTR') { $a=$a->getContent(); $b=true; }
  • if (!in_array($a->getName(), $imp))
  • $this->affect[] = $a;
  • unset($s[$i]);
  • if ( $b ) break;
  • }
  • $b=false;
  • foreach ($s as $i=>$a){
  • if ($a->getName()=='INSTR') { $a=$a->getContent(); $b=true; }
  • if (!in_array($a->getName(), $imp))
  • $this->sortie[] = $a;
  • unset($s[$i]);
  • if ( $b ) break;
  • if ($a->getName()=='MT_PT_VIRGULE') break;
  • }
  • foreach ($s as $i=>$a){
  • if (!in_array($a->getName(), $imp))
  • $this->step[] = $a;
  • }
  • }
  • public function contient($a, $b){
  • if ($this->content->contient($a, $b)) return true;
  • if ($this->affect->contient($a, $b)) return true;
  • if ($this->sortie->contient($a, $b)) return true;
  • if ($this->step->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->content, $this->affect, $this->sortie, $this->step); }
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • foreach ($this->step as $step)
  • $step->accept($visiteur);
  • foreach ($this->sortie as $sortie)
  • $sortie->accept($visiteur);
  • foreach ($this->affect as $affect)
  • $affect->accept($visiteur);
  • $this->content->accept($visiteur);
  • }
  • private $ligne;
  • private $content;
  • private $step;
  • private $affect;
  • private $sortie;
  • }
  • class _Case extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'CASE';}
  • public function __construct($a, $const_, $b){
  • $this->const_=$const_;
  • $this->line=$b->getLine();
  • }
  • public function __toString($tab=0){
  • return makeTab($tab).'case '.$this->const_.':
  • ';
  • }
  • public function contient($a, $b){
  • if ($this->const->contient($a, $b)) return true;
  • return false;
  • }
  • public function getChilds(){ return array($this->const_); }
  • private $const_;
  • public function accept($visiteur){
  • parent::accept($visiteur);
  • $this->const_->accept($visiteur);
  • }
  • private $line;
  • }
  • class _default extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'DEFAULT';}
  • public function __construct($a, $b){ $this->line=$b->getLine(); }
  • public function __toString($tab=0){ return makeTab($tab).'default:
  • '; }
  • public function contient($a, $b){ return false; }
  • public function getChilds(){ return array(); }
  • private $line;
  • }
  • class php_switch extends php_if{
  • public function getName(){ return 'SWITCH';}
  • public function __toString($tab=0){
  • return makeTab($tab).'switch '.$this->condition.'
  • '.$this->content->__toString($tab+1);
  • }
  • }
  • class VarModifier extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ModifieurVar';}
  • public function __construct($a, $b){ $this->line=$a->getLine(); $this->_var=$a; $this->modifier=$b; }
  • public function __toString($tab=0){
  • if (isset($this->className))
  • return $this->className.$this->modifier.$this->_var;
  • else
  • return $this->modifier.' '.$this->_var;
  • }
  • public function contient($a, $b){ return $this->_var->contient($a, $b) || $this->_modifier->contient($a, $b); }
  • public function getChilds(){ return array($this->_var, $this->modifier); }
  • public function setString($a){
  • $this->className=$a;
  • }
  • private $_var, $modifier, $line;
  • }
  • class ClassName extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ClassName';}
  • public function __construct($a, $b){ $this->line=$b->getLine(); $this->name=$a; }
  • public function __toString($tab=0){ return 'class '.$this->name; }
  • public function getChilds(){ return array($this->name); }
  • private $name, $line;
  • }
  • class ClassExtends extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ClassName';}
  • public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
  • public function __toString($tab=0){ return $this->classN.' extends '.$this->name; }
  • public function getChilds(){ return array($this->name); }
  • private $name, $line, $classN;
  • }
  • class ClassImplements extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ClassNameImplements';}
  • public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
  • public function __toString($tab=0){ return $this->classN.' implements '.$this->name; }
  • public function getChilds(){ return array($this->name); }
  • private $name, $line, $classN;
  • }
  • class ClassImplements2 extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'ClassNameImplements';}
  • public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
  • public function __toString($tab=0){ return $this->classN.', '.$this->name; }
  • public function getChilds(){ return array($this->name); }
  • private $name, $line, $classN;
  • }
  • class ClassE extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return false; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'Class';}
  • public function __construct($b, $a){ $this->line=$a->getLine(); $this->name=$a; $this->content=$b; }
  • public function __toString($tab=0){ return $this->name.'
  • '.$this->content->__toString($tab+1); }
  • public function getChilds(){ return array($this->name, $this->content); }
  • private $name, $line, $content;
  • }
  • class objectnew extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return true; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'new'; }
  • public function __construct($b, $a){ $this->line=$a->getLine(); $this->call=$b; }
  • public function __toString($tab=0){ return 'new '.$this->call->__toString($tab); }
  • public function getChilds(){ return array($this->call); }
  • private $line, $call;
  • }
  • class throwException extends Node{
  • public function getLine(){return $this->line;}
  • public function isVal(){ return true; }
  • public function isInstruction(){ return true; }
  • public function getName(){ return 'throw'; }
  • public function __construct($c, $b, $a){ $this->line=$a->getLine(); $this->objnew=$b; }
  • public function __toString($tab=0){ return makeTab($tab).'throw '.$this->objnew->__toString($tab).';
  • '; }
  • public function getChilds(){ return array($this->objnew); }
  • private $line, $objnew;
  • }
  • function reduce($stack){
  • $l=count($stack)-1;
  • if ($l==-1) return false;
  • if ( $l>=1 &&
  • $stack[$l-1]->getName()=='T_NEW' &&
  • $stack[$l]->getName()=='CALL_FUNC'){
  • array_push($stack,new objectnew(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=2 &&
  • $stack[$l-2]->getName()=='T_THROW' &&
  • $stack[$l-1]->getName()=='new' &&
  • $stack[$l]->getName()=='MT_PT_VIRGULE'){
  • array_push($stack,new throwException(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • $modifieurs=array('T_STATIC', 'T_PUBLIC', 'T_PRIVATE', 'T_PROTECTED', 'T_VAR');
  • if ( $l>=1 &&
  • in_array($stack[$l-1]->getName(), $modifieurs) &&
  • $stack[$l]->getName()=='T_VARIABLE' ){
  • array_push($stack, new VarModifier(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=3 &&
  • $stack[$l-2]->getName()=='T_STRING' &&
  • $stack[$l-1]->getName()=='T_DOUBLE_COLON' &&
  • $stack[$l]->getName()=='T_VARIABLE' ){
  • $f=new VarModifier(array_pop($stack), array_pop($stack));
  • $f->setString(array_pop($stack));
  • array_push($stack, $f);
  • return true;
  • }
  • if ( $l>=3 &&
  • $stack[$l-2]->getName()=='T_VARIABLE' &&
  • $stack[$l-1]->getName()=='T_OBJECT_OPERATOR' &&
  • $stack[$l]->getName()=='T_STRING' ){
  • $f=new VarModifier(array_pop($stack), array_pop($stack));
  • $f->setString(array_pop($stack));
  • array_push($stack, $f);
  • return true;
  • }
  • if ( $l>=1 &&
  • in_array($stack[$l-1]->getName(), array('ClassNameImplements', 'ClassName')) &&
  • $stack[$l]->getName()=='Couple_MT_ACCOLADE_OPEN' ) {
  • array_push($stack, new classE(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=1 &&
  • $stack[$l-1]->getName()=='T_CLASS' &&
  • $stack[$l]->getName()=='T_STRING' ){
  • array_push($stack, new ClassName(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=2 &&
  • $stack[$l-2]->getName()=='ClassName' &&
  • $stack[$l-1]->getName()=='T_EXTENDS' &&
  • $stack[$l]->getName()=='T_STRING' ){
  • array_push($stack, new ClassExtends(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=2 &&
  • $stack[$l-2]->getName()=='ClassName' &&
  • $stack[$l-1]->getName()=='T_IMPLEMENTS' &&
  • $stack[$l]->getName()=='T_STRING' ){
  • array_push($stack, new ClassImplements(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • if ( $l>=2 &&
  • $stack[$l-2]->getName()=='ClassNameImplements' &&
  • $stack[$l-1]->getName()=='MT_VIRGULE' &&
  • $stack[$l]->getName()=='T_STRING' ){
  • array_push($stack, new ClassImplements2(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • // les switchs
  • if (
  • $l>=2 &&
  • $stack[$l]->isInstruction() &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_SWITCH'){
  • array_push($stack, new php_switch(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • // les case
  • if ( $l>=2 &&
  • in_array($stack[$l]->getName(), array('MT_PT_VIRGULE', 'MT_DEUX_POINTS')) &&
  • $stack[$l-1]->isVal() &&
  • $stack[$l-2]->getName()=='T_CASE'){
  • array_push($stack, new _Case(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • // les default
  • if ( $l>=2 &&
  • in_array($stack[$l]->getName(), array('MT_PT_VIRGULE', 'MT_DEUX_POINTS')) &&
  • $stack[$l-1]->getName()=='T_DEFAULT'
  • ){
  • array_push($stack, new _default(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • //assign
  • if (
  • $l>=3 &&
  • !$stack[$l]->isOperator() &&
  • $stack[$l-1]->isVal() &&
  • in_array($stack[$l-2]->getName(), Tokens__::$affect) &&
  • in_array($stack[$l-3]->getName(), array('T_VARIABLE', 'ModifieurVar'))){
  • $n=array_pop($stack);
  • $var=array_pop($stack);
  • $op=array_pop($stack);
  • $val=array_pop($stack);
  • array_push($stack, new Assign($op, $val, $var));
  • while (reduce(&$stack)) continue; // IMPORTANT !
  • array_push($stack, $n);
  • return true;
  • }
  • if (
  • $l>=2 &&
  • $stack[$l]->isInstruction() &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_FOR'){
  • array_push($stack, new php_for(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • // les while
  • if (
  • $l>=2 &&
  • $stack[$l]->isInstruction() &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_WHILE'){
  • array_push($stack, new php_while(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • //les chaines
  • if ($stack[$l]->getName()=='Couple_MT_DOUBLE_QUOTE'){
  • $stack[$l]=new PHP_String($stack[$l]);
  • return true;
  • }
  • //les if
  • if (
  • $l>=2 &&
  • $stack[$l]->isInstruction() &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_IF'){
  • array_push($stack, new php_if(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • //les else
  • if (
  • $l>=2 &&
  • $stack[$l]->isInstruction() &&
  • $stack[$l-1]->getName()=='T_ELSE' &&
  • $stack[$l-2]->getName()=='IF'){
  • array_push($stack, new php_ifelse(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • //les couples () {} [] etc...
  • if ($stack[$l]->isFermant()){
  • $e=$stack[$l];
  • $fake=false;
  • if ($e->getName()=='MT_DOUBLE_QUOTE'){
  • $f=0;
  • foreach ($stack as $el){
  • if ($el->getName()=='MT_DOUBLE_QUOTE'){
  • $f++;
  • }
  • }
  • if ($f==1){
  • $fake=true;
  • }
  • }
  • if (!$fake){
  • $couple=new Couple();
  • $couple->append(array_pop($stack));
  • while (true){
  • $l--;
  • $n=array_pop($stack);
  • $couple->append($n);
  • if ($n->getName()==$e->getOuvre()) break;
  • if ($l==0) parse_error('Erreur : element de fin sans element de debut... '.$n->getName().' '.$e->getOuvre());
  • }
  • $couple->end_();
  • array_push($stack, $couple);
  • return true;
  • }
  • }
  • // les declarations de fonctions
  • if (
  • $l>=3 &&
  • $stack[$l]->getName()=='Couple_MT_ACCOLADE_OPEN' &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_STRING' &&
  • $stack[$l-3]->getName()=='T_FUNCTION'){
  • $f=new PHP_function(array_pop($stack), array_pop($stack), array_pop($stack), array_pop($stack));
  • $l-=4;
  • while(in_array($stack[$l]->getName(), PHP_function::$devant_function)){ $f->ajouter_devant(array_pop($stack)); $l--; }
  • array_push($stack, $f);
  • return true;
  • }
  • //les expressions
  • if (
  • $l>=2 &&
  • $stack[$l]->isVal() &&
  • $stack[$l-1]->isOperator() &&
  • $stack[$l-2]->isVal()){
  • array_push($stack, new Expr(array_pop($stack), array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • // expression alone
  • if (
  • $l>=1 &&
  • $stack[$l-1]->isVal() &&
  • $stack[$l]->isOperatorAlone()){
  • array_push($stack, new ExprAlone(array_pop($stack), array_pop($stack)));
  • return true;
  • }
  • //les appels de fonctions
  • if (
  • $l>=2 &&
  • $stack[$l]->getName()!='MT_ACCOLADE_OPEN' &&
  • $stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
  • $stack[$l-2]->getName()=='T_STRING'){
  • $a=array_pop($stack);
  • array_push($stack, new CALL(array_pop($stack), array_pop($stack)));
  • while (reduce(&$stack)) continue; // IMPORTANT !
  • array_push($stack, $a);
  • return true;
  • }
  • //return
  • if (
  • $l>=2 &&
  • $stack[$l]->getName()=='MT_PT_VIRGULE' &&
  • $stack[$l-1]->isVal() &&
  • $stack[$l-2]->getName()=='T_RETURN'){
  • array_pop($stack);
  • $f=new ff_return(array_pop($stack));
  • array_pop($stack);
  • array_push($stack, $f);
  • return true;
  • }
  • //echo
  • if (
  • $l>=1 &&
  • $stack[$l]->isVal() &&
  • $stack[$l-1]->getName()=='T_ECHO'){
  • $val=array_pop($stack);
  • array_pop($stack);
  • array_push($stack, new _Echo($val));
  • return true;
  • }
  • //instructions
  • if (
  • $l>=1 &&
  • $stack[$l]->getName()=='MT_PT_VIRGULE' &&
  • ($stack[$l-1]->isInstruction() || in_array($stack[$l-1]->getName(), array('EXPRAlone', 'T_BREAK', 'T_CONTINUE'))
  • )){
  • array_pop($stack);
  • array_push($stack, new Instruction(array_pop($stack)));
  • return true;
  • }
  • return false;
  • }
  • interface Transformer{ // design : visiteur
  • public function visite(Node $e);
  • public function CanModify($e);
  • public function transforme($e);
  • }
  • class Rewrite_String_double implements Transformer{
  • public function visite(Node $e){
  • if ($this->canModify($e)){
  • $this->transforme($e);
  • }
  • }
  • public function CanModify($e){
  • return $e instanceof PHP_String;
  • }
  • public function transforme($e){
  • $s=$e->getcontent()->getStack();
  • $l=count($s)-1;
  • if ($s[1]->getName()=='T_VARIABLE'){
  • $chaine=$s[1];
  • }else{
  • $chaine=Tokens__::makeString(Tokens__::evalString($s[1]->getContent()));
  • }
  • for ($i=2;$i<$l;$i++){
  • if ($s[$i]->getName()=='T_VARIABLE')
  • $o=$s[$i];
  • else
  • $o=Tokens__::makeString(Tokens__::evalString($s[$i]->getContent()));
  • $chaine=new Expr($o,Tokens__::getPoint(),$chaine);
  • }
  • $e->setElement($chaine);
  • }
  • }
  • if (file_exists($filename)){
  • $lexer=token_get_all(file_get_contents($filename));
  • $stack=array();
  • foreach ($lexer as $token){
  • $t=new Token($token);
  • if ($t->is_important()){
  • array_push($stack, $t);
  • while (reduce(&$stack)) continue;
  • }else if ($t->getName()!='T_WHITESPACE'){
  • Tokens__::AddComment($t);
  • }
  • }
  • // les regles de reecritures
  • $rewrite=array();
  • $rewrite[]=new Rewrite_String_double();
  • // on les applique.
  • foreach ($stack as $i=>$e){
  • foreach ($rewrite as $r){
  • $e->accept($r);
  • }
  • }
  • // on affiche
  • echo '<pre>';
  • foreach ($stack as $e){
  • echo htmlentities($e);
  • }
  • echo '</pre>';
  • }else{
  • echo 'fichier non trouve';
  • }
  • ?>
<?php

error_reporting(E_ALL);

if (isset($_SERVER['argv'][1]))
	$filename=$_SERVER['argv'][1];
else if (isset($_GET['argv']))
	$filename=$_GET['argv'];
else
	$filename='';

function makeTab($n){
	$out='';
	for ($i=0;$i<$n;$i++){
		$out.='	';
	}
	return $out;
}
function parse_error($s){
	echo $s.'

';
	exit(1);
}
class Locator{
	public function __construct($l){$this->ligne=$l;}
	public function __toString(){return 'l:'.$this->ligne;}
	public function Val(){return $this->ligne;}
	public function isBetween(Locator $v1, Locator $v2){
		return $v1->Val() <= $this->ligne && $v2->Val() >= $this->ligne;
	}
	private $ligne;
}
class Node{
	public function is_important(){ return true; }
	public function isFermant(){ return false; }
	public function getContent(){ return ''; }
	public function isVal(){return false;}
	public function isOperator(){return false;}
	public function isOperatorAlone(){return false;}
	public function isInstruction(){ return false; }
	public function contient(){ return false; }
	public function getChilds(){ return array();}
	public function accept($visiteur){
		$visiteur->visite($this);
	}
}
class Token extends Node{
	public function __construct($t){
		if (is_array($t)){
			$this->type=token_name($t[0]);
			$this->locator=new Locator($t[2]);
			self::$last=$t[2];
			if ($this->type=='T_OPEN_TAG'){
				$this->content='<?php';
			}else{
				$this->content=$t[1];
			}
		}else{
			if (!isset(self::$mytoken[$t])){
				throw new Exception ('Token '.$t.' non defini');
			}
			$this->type=self::$mytoken[$t];
			$this->content=$t;
			$this->locator=new Locator(self::$last);
		}
	}
	public function getContent(){ return $this->content; }
	public function __toString(){
		return $this->content; //.' '.$this->type.' ';
	}
	public function contient($a, $b){
		return $this->type==$a && $this->content==$b;
	}
	private static $mytoken = array(
		';'=>'MT_PT_VIRGULE',
		'('=>'MT_PARENTHESE_OPEN',
		')'=>'MT_PARENTHESE_CLOSE',
		','=>'MT_VIRGULE',
		'{'=>'MT_ACCOLADE_OPEN',
		'}'=>'MT_ACCOLADE_CLOSE',
		'*'=>'MT_FOIS',
		'-'=>'MT_MOINS',
		'+'=>'MT_PLUS',
		'='=>'MT_EGAL',
		'"'=>'MT_DOUBLE_QUOTE',
		'.'=>'MT_POINT',
		'<'=>'MT_INF_A',
		':'=>'MT_DEUX_POINTS'
	);
	private static $fin = array(
		'MT_PARENTHESE_CLOSE'=>'MT_PARENTHESE_OPEN',
		'MT_ACCOLADE_CLOSE'=>'MT_ACCOLADE_OPEN',
		'T_CLOSE_TAG'=>'T_OPEN_TAG',
		'MT_DOUBLE_QUOTE'=>'MT_DOUBLE_QUOTE'
	);
	public function is_important(){
		return !in_array($this->type, self::$no_imp);
	}
	public function isFermant(){
		return isset (self::$fin[$this->type]);
	}
	public function getOuvre(){
		return self::$fin[$this->type];
	}
	public function getName(){ return $this->type;}

	public function isVal(){
		return in_array($this->type, self::$val);
	}
	public function isOperator(){
		return in_array($this->type, self::$op);
	}
	public function isOperatorAlone(){
		return in_array($this->type, self::$opAlone);
	}
	private static $op=array('MT_FOIS', 'MT_PLUS', 'MT_MOINS', 'T_IS_EQUAL','MT_POINT', 'MT_INF_A');
	private static $opAlone=array('T_INC');
	private static $val=array(
		'Couple_MT_PARENTHESE_OPEN', 'T_VARIABLE', 'T_LNUMBER','EXPR', 'T_CONSTANT_ENCAPSED_STRING'
	);
	public function getLine(){
		return $this->locator;
	}
	public function getChilds(){ return array(); }
	private static $no_imp=array('T_WHITESPACE', 'T_COMMENT', 'T_DOC_COMMENT');
	private $type;
	private $content;
	private $locator;
	private static $last=0;
}
class Couple extends Node{
	public function __construct(){ $this->stack=array(); }
	public function append($t){ $this->stack[]=$t; }
	public function end_(){ $this->stack=array_reverse($this->stack);}
	public function getName(){
		return 'Couple_'.$this->stack[0]->getName().'';
	}
	public function __toString($tab=0){
		$acc=($this->stack[0]->getName()=='MT_ACCOLADE_OPEN' || $this->stack[0]->getName()=='T_OPEN_TAG');
		if ($acc)
			$out=makeTab($tab -1);
		else
			$out='';
		$len=count($this->stack)-1;
		foreach ($this->stack as $i=>$e){
 			if ($i==$len && $acc){
				$out.=makeTab($tab -1).$e.'
';
			}else{
				$out.=$e->__toString($tab);
			}
			if ($i==0 && $acc){
				$out.='
';
			}else if ($e->getName()=='MT_VIRGULE'){
				$out.=' ';
			}
		}
		return $out;
	}
	public function getLine(){
		return $this->stack[0]->getLine();
	}
	public function getLastLine(){
		return $this->stack[ count($this->stack)-1 ]->getLine();
	}
	public function contient($a, $b){
		foreach ($this->stack as $e){
			if ($e->contient($a, $b)) return true;
		}
		return false;
	}
	public function accept($visiteur){
		parent::accept($visiteur);
		foreach ($this->stack as $e){
			$e->accept($visiteur);
		}
	}
	public function getStack(){return $this->stack;}
	public function isInstruction(){ return $this->stack[0]->getName()=='MT_ACCOLADE_OPEN'; }
	public function getChilds(){ return $this->stack; }
	private $stack;
}
class PHP_function extends Node {
	public static $devant_function=array('T_PUBLIC', 'T_STATIC', 'T_PRIVATE', 'T_PROTECTED');
	public function isInstruction(){ return true; }
	public function getLine(){return $this->line;}
	public function __construct($content, $argList, $func){
		$this->devant=array();
		$this->line=$func->getLine();
		$this->name = $func->getContent();
		$this->argList=$argList;
		$this->content=$content;
	}
	public function ajouter_devant($e){
		$this->devant[]=$e;
	}
	public function getName(){ return 'FUNCTION'; }
	public function __toString($tab=0){
		$tab2=$tab+1;
		$fd='function '.$this->name.$this->argList;
		foreach ($this->devant as $a){
			$fd=$a.' '.$fd;
		}
		$comments=Tokens__::getComments($this->line, $this->content->getLastLine());
		$out='
'.makeTab($tab).'/**
'.makeTab($tab).' * @fn '.$fd.'
'.makeTab($tab).' * @brief
';
		if ($this->isRecursive()){
			$out.=makeTab($tab).' * recursive function.
';
		}
		foreach ($comments as $c){
			$out.=Tokens__::noComment($c->getContent(), $tab);
		}
		foreach ($this->argList->getStack() as $p)
			if ($p->getName()=='T_VARIABLE')
				$out.=makeTab($tab).' * @param '.$p.'
';
		$out.=makeTab($tab).' * @return
'.makeTab($tab).' */
';
	$out.=makeTab($tab).$fd.'
'.$this->content->__toString($tab2).'
';

		return $out;
	}
	public function isRecursive(){
		return $this->content->contient('T_STRING', $this->name);
	}
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->content->accept($visiteur);
	}
	private $line;
	private $name;
	private $argList;
	private $content;
	private $devant;
	public function getChilds(){ return $this->content; }
}
class Expr extends Node{
	public function getName(){ return 'EXPR';}
	public function getLine(){return $this->v2->getLine();}
	public function __toString(){
		return $this->v2.' '.$this->op.' '.$this->v1;
	}
	public function __construct($v1, $op, $v2){
		$this->op=$op; $this->v1=$v1; $this->v2=$v2;
	}
	public function isVal(){ return true; }
	public function contient($a, $b){
		if ($this->v1->contient($a, $b)) return true;
		if ($this->v2->contient($a, $b)) return true;
		return false;
	}
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->v1->accept($visiteur);
		$this->v2->accept($visiteur);
		$this->op->accept($visiteur);
	}
	private $op, $v1, $v2;
	public function getChilds(){ return array($this->v1, $this->v2); }
}
class ExprAlone extends Node{
	public function getName(){ return 'EXPRAlone';}
	public function getLine(){return $this->v2->getLine();}
	public function __toString(){
		return $this->v2.' '.$this->op;
	}
	public function __construct($op, $v2){
		$this->op=$op; $this->v2=$v2;
	}
	public function isVal(){ return true; }
	public function contient($a, $b){
		if ($this->v2->contient($a, $b)) return true;
		return false;
	}
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->v2->accept($visiteur);
		$this->op->accept($visiteur);
	}
	private $op, $v2;
	public function getChilds(){ return array($this->v2); }
}
class CALL extends Node{
	public function getLine(){return $this->func->getLine();}
	public function isInstruction(){ return true; }
	public function getName(){ return 'CALL_FUNC';}
	public function isVal(){ return true; }
	public function __toString(){
		return $this->func.$this->args;
	}
	public function __construct($args, $func){
		$this->func=$func;$this->args=$args;
	}
	public function contient($a, $b){
		if ($this->func->contient($a, $b)) return true;
		if ($this->args->contient($a, $b)) return true;
		return false;
	}
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->func->accept($visiteur);
		$this->args->accept($visiteur);
	}
	public function getChilds(){ return $this->args;}
	private $func;
	private $args;
}
class ff_return extends Node{
	public function getLine(){return $this->expr->getLine();}
	public function isInstruction(){ return true; }
	public function getName(){ return 'FF_RETURN';}
	public function __toString($tab=0){
		return makeTab($tab).'return '.$this->expr.';
';
	}
	public function __construct($expr){
		$this->expr=$expr;
	}
	public function contient($a, $b){
		if ($this->expr->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->expr); }
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->expr->accept($visiteur);
	}
	private $expr;
}
class Assign extends Node{
	public function getLine(){return $this->varName->getLine();}
	public function isVal(){ return true; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ASSIGN';}
	public function __toString(){
		return $this->varName->__toString().' '.$this->op->__toString().' '.$this->value->__toString();
	}
	public function __construct($op,$varName, $value){
		$this->varName=$varName; $this->value=$value; $this->op=$op;
	}

	public function contient($a, $b){
		if ($this->value->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->value); }
	public function accept($visiteur){
		parent::accept($visiteur);
		$this->varName->accept($visiteur);
		$this->value->accept($visiteur);
		$this->op->accept($visiteur);
	}
	private $varName;
	private $value;
	private $op;
}
class Instruction extends Node{
	public function getLine(){return $this->instr->getLine();}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'INSTR';}
	public function __toString($tab=0){
		return makeTab($tab).$this->instr->__toString().';
';
	}
	public function __construct($instr){
		$this->instr=$instr;
	}

	public function contient($a, $b){
		if ($this->instr->contient($a, $b)) return true;
		return false;
	}
	public function getContent(){ return $this->instr; }
	public function getChilds(){ return array($this->instr); }

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->instr->accept($visiteur);
	}

	private $instr;
}
class _Echo extends Node{
	public function getLine(){return $this->val->getLine();}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ECHO';}
	public function __toString(){
		return 'echo '.$this->val->__toString();
	}
	public function __construct($val){
		$this->val=$val;
	}

	public function contient($a, $b){
		if ($this->val->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->val); }

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->val->accept($visiteur);
	}

	private $val;
}
class PHP_String extends Node{
	public function getContent(){ return $this->content; }
	public function getLine(){return $this->line;}
	public function isVal(){ return true; }
	public function getName(){ return 'DOUBLE_STRING';}
	public function __toString(){
		return $this->content;
	}
	public function __construct($double){
		$this->content=$double;
		$this->line=$double->getLine();
	}
	public function contient($a, $b){
		if ($this->content->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return $this->content; }

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->content->accept($visiteur);
	}

	public function setElement($e){
		$this->content=$e;
	}

	private $content;
	private $line;
}
class php_if extends Node{
	public function getLine(){return $this->condition->getLine();}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'IF';}
	public function __construct($content, $condition){
		$this->condition=$condition;
		$this->content=$content;
	}
	public function __toString($tab=0){
		return makeTab($tab).'if '.$this->condition.'
'.$this->content->__toString($tab+1);
	}
	public function contient($a, $b){
		if ($this->content->contient($a, $b)) return true;
		if ($this->condition->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->condition, $this->content); }

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->condition->accept($visiteur);
		$this->content->accept($visiteur);
	}

	protected $condition;
	protected $content;
}
class php_ifelse extends Node{
	public function getLine(){return $this->if_->getLine();}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ELSE';}
	public function __construct($content, $else, $if){
		$this->if_=$if;
		$this->content=$content;
	}
	public function contient($a, $b){
		if ($this->if_->contient($a, $b)) return true;
		if ($this->content->contient($a, $b)) return true;
		return false;
	}
	public function __toString($tab=0){
		return $this->if_->__toString($tab).makeTab($tab).'else
'.$this->content->__toString($tab+1);
	}
	public function getChilds(){ return array($this->content, $this->if_); }

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->if_->accept($visiteur);
		$this->content->accept($visiteur);
	}

	private $if_;
	private $content;

}
class Tokens__{
	public static function evalString($s){
		$s=str_replace('\\n', "\n", $s);
		$s=str_replace('\\t', "\t", $s);
		$s=str_replace('\\r', "\r", $s);
		$s=str_replace('\\"', '"', $s);
		return $s;
	}
	public static function noComment($str, $tab){
		$c=explode("\n", str_replace(array('/**', '/*', '*/', '//!', '//', '#'), array(''), $str));
		$out='';
		foreach ($c as $a){
			$out.=makeTab($tab).' * '.trim($a).'
';
		}
		return $out;
	}
	public static function makeString($s){
		$s=str_replace('\\', '\\\\', $s);
		$s=str_replace('\'', '\\\'', $s);
		return new Token(
			array(
			T_CONSTANT_ENCAPSED_STRING,
			'\''.$s.'\'',
			0)
		);
	}
	public static function getPoint(){
		if (self::$Point==NULL)
			self::$Point=new Token('.');
		return self::$Point;
	}
	public static function AddComment($t){
		self::$comment[]=$t;
	}
	public static function getcomments($v1, $v2){
		$out=array();
		if (isset(self::$comment)){
			foreach (self::$comment as $c){
				if ($c->getLine()->isBetween($v1, $v2)){
					$out[]=$c;
				}
			}
		}
		return $out;
	}
	private static $Point;
	private static $comment;
	public static $affect=array('T_PLUS_EQUAL', 'MT_EGAL');
}
class php_while extends Node{
	public function __construct($content, $condition){
		$this->content=$content;
		$this->condition=$condition;
	}

	public function getLine(){return $this->condition->getLine();}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'WHILE';}
	public function contient($a, $b){
		if ($this->condition->contient($a, $b)) return true;
		if ($this->content->contient($a, $b)) return true;
		return false;
	}
	public function __toString($tab=0){
		return makeTab($tab).'while '.$this->condition->__toString($tab+1).'
'.$this->content->__toString($tab+1);
	}
	public function getChilds(){ return array($this->content, $this->condition); }
	private $condition;
	private $content;

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->condition->accept($visiteur);
		$this->content->accept($visiteur);
	}

}
class php_for extends Node{

	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'INSTR';}
	public function __toString($tab=0){
		$out=makeTab($tab).'for (';
		foreach ($this->affect as $i=>$e){
			if ($i!=0) $out.=', ';
			$out.=$e;
		}
		$out.=';';
		foreach ($this->sortie as $i=>$e){
			if ($i!=0) $out.=', ';
			$out.=$e;
		}
		$out.=';';
		foreach ($this->step as $i=>$e){
			if ($i!=0) $out.=', ';
			$out.=$e;
		}
		$out.=')
'.$this->content->__toString($tab+1);
		return $out;
	}
	public function __construct($content, $couple, $for){
		$this->ligne=$for->getLine();
		$this->content=$content;
		$this->affect=array();
		$this->sortie=array();
		$this->step=array();

		$imp=array('MT_PT_VIRGULE', 'MT_VIRGULE', 'MT_PARENTHESE_OPEN','MT_PARENTHESE_CLOSE');

		$b=false;
		$s=$couple->getStack();
		foreach ($s as $i=>$a){
			if ($a->getName()=='INSTR') { $a=$a->getContent(); $b=true; }
			if (!in_array($a->getName(), $imp))
				$this->affect[] = $a;
			unset($s[$i]);
			if ( $b ) break;
		}
		$b=false;
		foreach ($s as $i=>$a){
			if ($a->getName()=='INSTR') { $a=$a->getContent(); $b=true; }
			if (!in_array($a->getName(), $imp))
				$this->sortie[] = $a;
			unset($s[$i]);
			if ( $b ) break;
			if ($a->getName()=='MT_PT_VIRGULE') break;
		}
		foreach ($s as $i=>$a){
			if (!in_array($a->getName(), $imp))
				$this->step[] = $a;
		}
	}

	public function contient($a, $b){
		if ($this->content->contient($a, $b)) return true;
		if ($this->affect->contient($a, $b)) return true;
		if ($this->sortie->contient($a, $b)) return true;
		if ($this->step->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->content, $this->affect, $this->sortie, $this->step); }

	public function accept($visiteur){
		parent::accept($visiteur);
		foreach ($this->step as $step)
		$step->accept($visiteur);
		foreach ($this->sortie as $sortie)
		$sortie->accept($visiteur);
		foreach ($this->affect as $affect)
		$affect->accept($visiteur);
		$this->content->accept($visiteur);
	}


	private $ligne;
	private $content;
	private $step;
	private $affect;
	private $sortie;
}
class _Case extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'CASE';}
	public function __construct($a, $const_, $b){
		$this->const_=$const_;
		$this->line=$b->getLine();
	}
	public function __toString($tab=0){
		return makeTab($tab).'case '.$this->const_.':
';
	}
	public function contient($a, $b){
		if ($this->const->contient($a, $b)) return true;
		return false;
	}
	public function getChilds(){ return array($this->const_); }
	private $const_;

	public function accept($visiteur){
		parent::accept($visiteur);
		$this->const_->accept($visiteur);
	}

	private $line;
}
class _default extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'DEFAULT';}
	public function __construct($a, $b){ $this->line=$b->getLine(); }
	public function __toString($tab=0){ return makeTab($tab).'default:
'; }
	public function contient($a, $b){ return false; }
	public function getChilds(){ return array(); }
	private $line;
}
class php_switch extends php_if{
	public function getName(){ return 'SWITCH';}
	public function __toString($tab=0){
		return makeTab($tab).'switch '.$this->condition.'
'.$this->content->__toString($tab+1);
	}
}
class VarModifier extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ModifieurVar';}
	public function __construct($a, $b){ $this->line=$a->getLine(); $this->_var=$a; $this->modifier=$b; }
	public function __toString($tab=0){
		if (isset($this->className))
			return $this->className.$this->modifier.$this->_var;
		else
			return $this->modifier.' '.$this->_var;
	}
	public function contient($a, $b){ return  $this->_var->contient($a, $b) || $this->_modifier->contient($a, $b); }
	public function getChilds(){ return array($this->_var, $this->modifier); }
	public function setString($a){
		$this->className=$a;
	}
	private $_var, $modifier, $line;
}
class ClassName extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ClassName';}
	public function __construct($a, $b){ $this->line=$b->getLine(); $this->name=$a; }
	public function __toString($tab=0){ return 'class '.$this->name; }
	public function getChilds(){ return array($this->name); }
	
	private $name, $line;
}
class ClassExtends extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ClassName';}
	public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
	public function __toString($tab=0){ return $this->classN.' extends '.$this->name; }
	public function getChilds(){ return array($this->name); }
	
	private $name, $line, $classN;
}
class ClassImplements extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ClassNameImplements';}
	public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
	public function __toString($tab=0){ return $this->classN.' implements '.$this->name; }
	public function getChilds(){ return array($this->name); }
	
	private $name, $line, $classN;
}
class ClassImplements2 extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'ClassNameImplements';}
	public function __construct($a, $b, $c){ $this->line=$b->getLine(); $this->name=$a; $this->classN=$c; }
	public function __toString($tab=0){ return $this->classN.', '.$this->name; }
	public function getChilds(){ return array($this->name); }
	
	private $name, $line, $classN;
}
class ClassE extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return false; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'Class';}
	public function __construct($b, $a){ $this->line=$a->getLine(); $this->name=$a; $this->content=$b; }
	public function __toString($tab=0){ return $this->name.'
'.$this->content->__toString($tab+1); }
	public function getChilds(){ return array($this->name, $this->content); }
	private $name, $line, $content;

}
class objectnew extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return true; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'new'; }
	public function __construct($b, $a){ $this->line=$a->getLine(); $this->call=$b; }
	public function __toString($tab=0){ return 'new '.$this->call->__toString($tab); }
	public function getChilds(){ return array($this->call); }
	private $line, $call;

}

class throwException extends Node{
	public function getLine(){return $this->line;}
	public function isVal(){ return true; }
	public function isInstruction(){ return true; }
	public function getName(){ return 'throw'; }
	public function __construct($c, $b, $a){ $this->line=$a->getLine(); $this->objnew=$b; }
	public function __toString($tab=0){ return makeTab($tab).'throw '.$this->objnew->__toString($tab).';
'; }
	public function getChilds(){ return array($this->objnew); }
	private $line, $objnew;

}

function reduce($stack){
	$l=count($stack)-1;
	if ($l==-1) return false;

	if ( $l>=1 &&
	$stack[$l-1]->getName()=='T_NEW' &&
	$stack[$l]->getName()=='CALL_FUNC'){
		array_push($stack,new objectnew(array_pop($stack), array_pop($stack)));
		return true;
	}

	if ( $l>=2 &&
	$stack[$l-2]->getName()=='T_THROW' &&
	$stack[$l-1]->getName()=='new' &&
	$stack[$l]->getName()=='MT_PT_VIRGULE'){
		array_push($stack,new throwException(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}


	$modifieurs=array('T_STATIC', 'T_PUBLIC', 'T_PRIVATE', 'T_PROTECTED', 'T_VAR');
	if ( $l>=1 &&
	in_array($stack[$l-1]->getName(), $modifieurs) &&
	$stack[$l]->getName()=='T_VARIABLE' ){
		array_push($stack, new VarModifier(array_pop($stack), array_pop($stack)));
		return true;
	}

	if ( $l>=3 &&
	$stack[$l-2]->getName()=='T_STRING' &&
	$stack[$l-1]->getName()=='T_DOUBLE_COLON' &&
	$stack[$l]->getName()=='T_VARIABLE' ){
		$f=new VarModifier(array_pop($stack), array_pop($stack));
		$f->setString(array_pop($stack));
		array_push($stack, $f);
		return true;
	}

	if ( $l>=3 &&
	$stack[$l-2]->getName()=='T_VARIABLE' &&
	$stack[$l-1]->getName()=='T_OBJECT_OPERATOR' &&
	$stack[$l]->getName()=='T_STRING' ){
		$f=new VarModifier(array_pop($stack), array_pop($stack));
		$f->setString(array_pop($stack));
		array_push($stack, $f);
		return true;
	}

	if ( $l>=1 &&
	in_array($stack[$l-1]->getName(), array('ClassNameImplements', 'ClassName')) &&
	$stack[$l]->getName()=='Couple_MT_ACCOLADE_OPEN' ) {
		array_push($stack, new classE(array_pop($stack), array_pop($stack)));
		return true;
	}


	if ( $l>=1 &&
	$stack[$l-1]->getName()=='T_CLASS' &&
	$stack[$l]->getName()=='T_STRING' ){
		array_push($stack, new ClassName(array_pop($stack), array_pop($stack)));
		return true;
	}

	if ( $l>=2 &&
	$stack[$l-2]->getName()=='ClassName' &&
	$stack[$l-1]->getName()=='T_EXTENDS' &&
	$stack[$l]->getName()=='T_STRING' ){
		array_push($stack, new ClassExtends(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}

	if ( $l>=2 &&
	$stack[$l-2]->getName()=='ClassName' &&
	$stack[$l-1]->getName()=='T_IMPLEMENTS' &&
	$stack[$l]->getName()=='T_STRING' ){
		array_push($stack, new ClassImplements(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}

	if ( $l>=2 &&
	$stack[$l-2]->getName()=='ClassNameImplements' &&
	$stack[$l-1]->getName()=='MT_VIRGULE' &&
	$stack[$l]->getName()=='T_STRING' ){
		array_push($stack, new ClassImplements2(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}

	// les switchs
	if (
	$l>=2 &&
	$stack[$l]->isInstruction() &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_SWITCH'){
		array_push($stack, new php_switch(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	// les case
	if ( $l>=2 &&
	in_array($stack[$l]->getName(), array('MT_PT_VIRGULE', 'MT_DEUX_POINTS')) &&
	$stack[$l-1]->isVal() &&
	$stack[$l-2]->getName()=='T_CASE'){
		array_push($stack, new _Case(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	// les default
	if ( $l>=2 &&
	in_array($stack[$l]->getName(), array('MT_PT_VIRGULE', 'MT_DEUX_POINTS')) &&
	$stack[$l-1]->getName()=='T_DEFAULT'
	){
		array_push($stack, new _default(array_pop($stack), array_pop($stack)));
		return true;
	}
	//assign
	if (
	$l>=3 &&
	!$stack[$l]->isOperator() &&
	$stack[$l-1]->isVal() &&
	in_array($stack[$l-2]->getName(), Tokens__::$affect) &&
	in_array($stack[$l-3]->getName(), array('T_VARIABLE', 'ModifieurVar'))){
		$n=array_pop($stack);
		$var=array_pop($stack);
		$op=array_pop($stack);
		$val=array_pop($stack);
		array_push($stack, new Assign($op, $val, $var));
		while (reduce(&$stack)) continue; // IMPORTANT !
		array_push($stack, $n);
		return true;
	}

	if (
	$l>=2 &&
	$stack[$l]->isInstruction() &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_FOR'){
		array_push($stack, new php_for(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}

	// les while
	if (
	$l>=2 &&
	$stack[$l]->isInstruction() &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_WHILE'){
		array_push($stack, new php_while(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	//les chaines
	if ($stack[$l]->getName()=='Couple_MT_DOUBLE_QUOTE'){
		$stack[$l]=new PHP_String($stack[$l]);
		return true;
	}
	//les if
	if (
	$l>=2 &&
	$stack[$l]->isInstruction() &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_IF'){
		array_push($stack, new php_if(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	//les else
	if (
	$l>=2 &&
	$stack[$l]->isInstruction() &&
	$stack[$l-1]->getName()=='T_ELSE' &&
	$stack[$l-2]->getName()=='IF'){
		array_push($stack, new php_ifelse(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	//les couples () {} [] etc...
	if ($stack[$l]->isFermant()){
		$e=$stack[$l];
		$fake=false;
		if ($e->getName()=='MT_DOUBLE_QUOTE'){
			$f=0;
			foreach ($stack as $el){
				if ($el->getName()=='MT_DOUBLE_QUOTE'){
					$f++;
				}
			}
			if ($f==1){
				$fake=true;
			}
		}
		if (!$fake){
			$couple=new Couple();
			$couple->append(array_pop($stack));
			while (true){
				$l--;
				$n=array_pop($stack);
				$couple->append($n);
				if ($n->getName()==$e->getOuvre()) break;
				if ($l==0) parse_error('Erreur : element de fin sans element de debut... '.$n->getName().' '.$e->getOuvre());
			}
			$couple->end_();
			array_push($stack, $couple);
			return true;
		}
	}
	// les declarations de fonctions
	if (
	$l>=3 &&
	$stack[$l]->getName()=='Couple_MT_ACCOLADE_OPEN' &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_STRING' &&
	$stack[$l-3]->getName()=='T_FUNCTION'){
		$f=new PHP_function(array_pop($stack), array_pop($stack), array_pop($stack), array_pop($stack));
		$l-=4;
		while(in_array($stack[$l]->getName(), PHP_function::$devant_function)){ $f->ajouter_devant(array_pop($stack)); $l--; }
		array_push($stack, $f);
		return true;
	}
	//les expressions
	if (
	$l>=2 &&
	$stack[$l]->isVal() &&
	$stack[$l-1]->isOperator() &&
	$stack[$l-2]->isVal()){
		array_push($stack, new Expr(array_pop($stack), array_pop($stack), array_pop($stack)));
		return true;
	}
	// expression alone
	if (
	$l>=1 &&
	$stack[$l-1]->isVal() &&
	$stack[$l]->isOperatorAlone()){
		array_push($stack, new ExprAlone(array_pop($stack), array_pop($stack)));
		return true;
	}
	//les appels de fonctions
	if (
	$l>=2 &&
	$stack[$l]->getName()!='MT_ACCOLADE_OPEN' &&
	$stack[$l-1]->getName()=='Couple_MT_PARENTHESE_OPEN' &&
	$stack[$l-2]->getName()=='T_STRING'){
		$a=array_pop($stack);
		array_push($stack, new CALL(array_pop($stack), array_pop($stack)));
		while (reduce(&$stack)) continue; // IMPORTANT !
		array_push($stack, $a);
		return true;
	}
	//return
	if (
	$l>=2 &&
	$stack[$l]->getName()=='MT_PT_VIRGULE' &&
	$stack[$l-1]->isVal() &&
	$stack[$l-2]->getName()=='T_RETURN'){
		array_pop($stack);
		$f=new ff_return(array_pop($stack));
		array_pop($stack);
		array_push($stack, $f);
		return true;
	}
	//echo
	if (
	$l>=1 &&
	$stack[$l]->isVal() &&
	$stack[$l-1]->getName()=='T_ECHO'){
		$val=array_pop($stack);
		array_pop($stack);
		array_push($stack, new _Echo($val));
		return true;
	}
	//instructions
	if (
	$l>=1 &&
	$stack[$l]->getName()=='MT_PT_VIRGULE' &&
	($stack[$l-1]->isInstruction() || in_array($stack[$l-1]->getName(), array('EXPRAlone', 'T_BREAK', 'T_CONTINUE'))
	)){
		array_pop($stack);
		array_push($stack, new Instruction(array_pop($stack)));
		return true;
	}
	return false;
}


interface Transformer{ // design : visiteur
	public function visite(Node $e);
	public function CanModify($e);
	public function transforme($e);
}

class Rewrite_String_double implements Transformer{
	public function visite(Node $e){
		if ($this->canModify($e)){
			$this->transforme($e);
		}
	}
	public function CanModify($e){
		return $e instanceof PHP_String;
	}
	public function transforme($e){
		$s=$e->getcontent()->getStack();
		$l=count($s)-1;
		if ($s[1]->getName()=='T_VARIABLE'){
			$chaine=$s[1];
		}else{
			$chaine=Tokens__::makeString(Tokens__::evalString($s[1]->getContent()));
		}
		for ($i=2;$i<$l;$i++){
			if ($s[$i]->getName()=='T_VARIABLE')
				$o=$s[$i];
			else
				$o=Tokens__::makeString(Tokens__::evalString($s[$i]->getContent()));
			$chaine=new Expr($o,Tokens__::getPoint(),$chaine);
		}
		$e->setElement($chaine);
	}
}


if (file_exists($filename)){
	$lexer=token_get_all(file_get_contents($filename));
	$stack=array();
	foreach ($lexer as $token){
		$t=new Token($token);
		if ($t->is_important()){
			array_push($stack, $t);
			while (reduce(&$stack)) continue;
		}else if ($t->getName()!='T_WHITESPACE'){
			Tokens__::AddComment($t);
		}
	}

	// les regles de reecritures
	$rewrite=array();
	$rewrite[]=new Rewrite_String_double();
	// on les applique.
	foreach ($stack as $i=>$e){
		foreach ($rewrite as $r){
			$e->accept($r);
		}
	}

	// on affiche
	echo '<pre>';
	foreach ($stack as $e){
		echo  htmlentities($e);
	}
	echo '</pre>';
}else{
	echo 'fichier non trouve';
}
?>

Conclusion

Je dois avouer que la grammaire que j'emploies n'est pas complete.
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Commentaires et avis

signaler à un administrateur
Commentaire de mfaraday le 02/05/2008 18:18:41

Bonsoir,

Alors la je dois avouer que j'ai rien capté :D Tu m'as bluffé !

Euh... Comment on utilise tout ça dis moi ??

Florian

signaler à un administrateur
Commentaire de coucou747 le 02/05/2008 18:27:30

il suffit d'aller sur la page http://.../recode.php?argv=test.php

signaler à un administrateur
Commentaire de mfaraday le 02/05/2008 18:38:58

Re Bonsoir

Je viens de regarder un peu...

Bon à la barbare, j'ai déclaré un $filename = '';

Donc dans un premier temps, php m'envoies des messages :

[code]
Strict Standards: Declaration of Token::contient() should be compatible with that of Node::contient() in /app/HTTP/recode.php on line 209
[/code]

Toute une liste...

et ensuite :

[code]
Notice: Undefined offset: 2 in /app/HTTP/recode.php on line 130
Notice: Undefined offset: 2 in /app/HTTP/recode.php on line 131
[/code]

et enfin un joli :

[code]
Fatal error: Uncaught exception 'Exception' with message 'Token [ non defini' in /app/HTTP/recode.php:139 Stack trace: #0 /app/HTTP/recode.php(1217): Token->__construct('[') #1 {main} thrown in /app/HTTP/recode.php on line 139
[/code]

Bon j'ai quand même zieuté un peu :
- J'ai capté via php.net que token_get_all renvoie un tableau avec mon code source scindé...
- avec un pauvre echo '<pre>' . print_r( $lexer, true ) . '</pre>'; en ligne 1134 le script me balance bien mon code source scindé.
- étape suivante tu fais un foreach ($lexer as $token) puis un new Token( $token )
- je regarde la class Token et la j'ai un problème : dans ton construct je vois un $t qui visiblement à au moins 3 lignes (0, 1 et 2) mais moi quand je regarde mon $token j'en ai que deux (0 et 1).

Voila mon problème de mes lignes 130 et 131, je n'ai pas d'index 2 dans mon $token... est ce normal ???

Flo

signaler à un administrateur
Commentaire de mfaraday le 02/05/2008 18:44:52

re re Bonsoir

J'apprendrais à lire jusqu'au bout php.net.. l'index 2 est rajouté depuis la version php 5.2.2...

Flo

signaler à un administrateur
Commentaire de coucou747 le 02/05/2008 18:45:42

c'est etrange... quelle est ta version de php ? et sur quel fichier as tu teste ca ?
moi : 5.2.4

http://fr.php.net/manual/en/function.token-get-all.php
5.2.2   Line numbers are returned in element 2

apparement, on a besoin d'un php >= 5.2.2

signaler à un administrateur
Commentaire de mfaraday le 02/05/2008 22:57:21

Hello

Je te remercie pour les renseignements... je viens de me rendre compte que ma version de php était relativement... ancienne.

Ce qui m'a permit de mettre à jour php. Et ok ton code fonctionne parfaitement :)

Florian

signaler à un administrateur
Commentaire de yoman64 le 03/05/2008 02:28:11 9/10

Salut,

Ton code semble excellent, comme à l'habitude, et il m'intéresse beaucoup. Ça va me permettre d'appronfondir mes connaissances sur les tokens en php.
J'ai essayé de l'executer sur le fichier test.php et mis à part quelques warning (Call-time pass-by-reference has been deprecated; If you would like to pass it by reference, modify the declaration of [runtime function name]().) ça fonctionne et me retourne un beau code formaté avec des comms doxygen.

Mais dès que je lui passe un code plus complexe j'ai un fatal error :(. Je te laisse l'erreur:

Fatal error</b>:  Uncaught exception 'Exception' with message 'Token @ non defini' in /home/alextest/html/recode.php:137
Stack trace:
#0 /home/alextest/html/recode.php(1212): Token-&gt;__construct('@')
#1 {main}
  thrown in <b>/home/alextest/html/recode.php

J'ai aussi #0 /home/alextest/html/recode.php(1212): Token-&gt;__construct('[') sur d'autres fichiers (recode.php par exemple)


Ce que j'en comprends c'est que qu'il y a des tokens non gêrés par ton code, si c'est le cas je me demandais pourquoi ? Est-ce qu'ils sont différents ? Juste pas pensé ?

Tien, pour une fois j'vais laisser une note ^^ 9/10 puisque l'idée est excellente, et le code instructif.
@+

signaler à un administrateur
Commentaire de coucou747 le 03/05/2008 03:26:55

en php, t'as des tokens qui n'ont pas de constante (c'est porc de leur part, mais ils ont fait ca...)

regarde la ligne 75 : private static $mytoken = array( c'est ici que j'ai mis les tokens qui n'ont pas de constante (pour pouvoir les traiter de la meme facon que le reste)

Bref, j'ai mis pas beaucoup de tokens, et une grammaire reduite.

signaler à un administrateur
Commentaire de Optitech le 03/05/2008 10:10:03

> goto debut;

J'abore !

signaler à un administrateur
Commentaire de coucou747 le 03/05/2008 14:31:18

pour supprimer la recursiviter de facon automatique, c'est ca ou des Exceptions...

signaler à un administrateur
Commentaire de yoman64 le 03/05/2008 23:54:56

Salut,

L'exemple que tu donnes ça se fait en boucle tout simplement aussi, non ?

function sub_f ($a, $b){
while ($a!=0){
            $a1=$a-1;
            $b1=$a+$b;
            $a=$a1; $b=$b1;
}
return $b
}

function sumOfNaturals($n){
return sub_f($n, 0);
}



Moi je vois mal l'intérêt des Gotos, sauf dans le cas de programmation linéaire ou on doit sauter plus loin dans le code, souvent ça serait vachement pratique.
Je vois pas l'intérêt d'un goto pour faire des boucles comme dans ton exemple, mais peut être y a t'il une subtilité que je n'ai pas comprise ?

PS: Merci pour l'explication sur les tokens, en effet c'est porc de leurs part, je me demande pourquoi...

signaler à un administrateur
Commentaire de coucou747 le 04/05/2008 00:05:28

en effet, ca peut se transformer simplement en une boucle, mais imagine un exemple plus complique, ca serait alors impossible de faire une simple boucle et un break a la place du return...

sinon, ca se fait en O(1) avec une formule genre n(n+1)/2

signaler à un administrateur
Commentaire de LocalStone le 05/05/2008 22:50:26

J'avoue ne pas m'être plongé dans ton code et ma question découle uniquement de la description de ta source ...
Peut-on utiliser ton code dans le but de remplacer quelque chose comme :
/* -------------------- */
$strMyString = 'MyString';
$intCharacterPosition = $strMyString -> indexOf('S');
echo $intCharacterPosition; // 2
/* -------------------- */
par :
/* -------------------- */
$strMyString = 'MyString';
$intCharacterPosition = strpos($strMyString, 'S');
echo $intCharacterPosition; // 2
/* -------------------- */
En gros, l'idée c'est de pouvoir rendre tout les type de base PHP compatible avec l'Orienté Objet.
Merci !
P.S. : Commente ton code ... Parce que je pense pas que la première personne venue puisse comprendre tout ce que tu veux faire, même si c'est bien codé.

signaler à un administrateur
Commentaire de coucou747 le 05/05/2008 22:58:32

non, faudrait faire des calculs d'inference de types pour ca, et dans un langage comme le php, ca ne peut pas se faire aussi facilement...

signaler à un administrateur
Commentaire de coucou747 le 08/05/2008 03:46:39

en fait, suite a une discution sur irc, j'ai vu que continue prennait un paran, je l'ignorais jusqu'a present, le fait que continue prenne un parametre peut permettre de coder un php - tail recursif.

signaler à un administrateur
Commentaire de pserru le 24/05/2009 03:49:39

   Bonjour Coucou747

   C'est du beau code, et je ne regrette pas (-: encore) le temps passé à tenter la mise en ½uvre. J'utilise PHP 5.2.9 en ligne de commamde, sur OpenSuse 10.3. J'ai donc viré les lignes relatives à la sortie en HTML. Et voici la réponse:

> ./recode.php
./recode.php: line 1: ?php: Aucun fichier ou répertoire de ce type
./recode.php: line 3: /bin: is a directory
./recode.php: line 35: syntax error near unexpected token `('
./recode.php: line 35: `En C, avec l'option -O2 (ou 1 ou 3), lorsque le code est _tail_recursif_ (ou recursivite finnie),'

   Visiblement, les messages d'erreur sont inadéquats. En mode console, cela arrive régulièrement (si ce n'est systématiquement) á l'éxécution, tandis que les erreurs issues du "parser" sont toujours justes.

   Pour une construction "de rien", on s'en sort, mais dans le cas présent, il me faudra essayer PHP comme module Apache, sans doute...

   Une idée ?

signaler à un administrateur
Commentaire de coucou747 le 24/05/2009 13:41:03

salut

execute le avec php recode.php

signaler à un administrateur
Commentaire de pserru le 24/05/2009 18:51:40 10/10

   Bonjour Coucou747, bonjour tous,

   Mais bien sûr! La modif concernant le nom du fichier d'entrée dans la source faite, je n'ai pas penser à ajouter
#!/usr/bin/php
en première ligne! Je suis désolé pour le dérangement.

   Maintenant, ça a tout de même une autre et fière allure!

   Merci.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Parseur XML (beaucoup trop gourmant !!!) [ par lcmartin ] Bonjour,Voila j'avais pris un parseur XMl pour cr&#233;er une application Web...(cf: http://engardenet.ilix.net/micv5/parseur_xml.txt pour le code)C'e Au secours : comment parser un fichier xml et inserer a la volé dans une base mysql [ par deblok83 ] Bonjour, &nbsp;&nbsp;&nbsp; c'est mon premier post ici alors je me permet de me presenter je suis le webmaster de deblok83.com . j'ai un petit proble [Parseur Simple] Demande Explication sur le fontionmentt de fread, fgets, fgetc sur fichier balisé [ par Godson ] Bonjour, Voila je dois r&#233;alis&#233; un parseur sur fichier que voici:Liste_TOPO.txt[code]&lt;contributeur class = "contributeur"&gt;&lt;nom&gt;ad Probleme d'enregistrement dans un parseur XML [ par sniktwo ] Salut &#224; tous, alors mon parser XML marche parfaitement et m'affiche bien les donn&#233;es mais, l&#224; o&#249; &#231;a coince, c'est pour les en Parseur de mots clé avec connecteurs logique et parenthèse [ par PerfectSlayer ] Bonjour à vous. Je travaille sur un robot qui joue au trivial poursuit. J'aurais besoin de comparer les réponses entrées par les joueurs à la réponse PHP et les parseur SGML [ par LePueblo ] Bonjour!Je cherche à décomposer un fichier SGML en langage PHP. Mon problème est le suivant:- php ne semble pas reconnaitre les charactères qui corres Parseur Xml StAX [ par anisis ] Bonjour tt le monde,En fait mon prblm c'est que je reçois des fichiers xml de grandes tailles et je dois les parser , Maintenant je suis entrain d'uti


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,780 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.