sur cette source, je vous presente trois interpreteurs brainfuck.
le premier sans preprocessing
le second, est plus rapide, il evite une boucle.
le troisime est plus un compilateur brainfuck vers php.
Source / Exemple :
<?php
$stdin = fopen('php://stdin', 'r') or die ('erreur etrange');
/**
- @brief fonction d'entree
- renvoie le caractere ascii du caractere suivant de stdin.
- @return int
- /
function prompt(){
global $stdin;
return ord(fread($stdin, 1));
}
/**
- @brief fonction qui interprete un code brainfuck
- solution sans preprocessing
- @param $code le code a interpreter
- /
function brainfuck_verbeux($code){
$code_len = strlen($code);
$mem = array();
$indice_memoire = 0;
for ($i=0;$i<$code_len;$i++){
if (!isset($mem[$indice_memoire])) $mem[$indice_memoire]=0;
else {
// les valeurs sont comprises entre 0 et 256.
$mem[$indice_memoire] = (256 + $mem[$indice_memoire] ) % 256;
}
switch($code[$i]){
case '>': $indice_memoire++; break;
case '<': $indice_memoire--; break;
case '.': echo chr($mem[$indice_memoire]); break; // on affiche la valeur
case ',': $mem[$indice_memoire]=prompt(); break;
case '+': $mem[$indice_memoire]++; break; // on incremente la valeur
case '-': $mem[$indice_memoire]--; break; // on decremente la valeur
case ']':
$n = 1; // on doit remonter $n [ en arriere
while ($n){
$i --; // on cherche en arriere
if ($code[$i]==']') $n++; // si on rencontre un ], alors on attend un [ de plus
else if ($code[$i]=='[') $n--; // si on trouve un [. alors on en attend un de moins
} $i--; // on "jump" devant le [ correspondant.
break;
case '[':
if ( $mem[$indice_memoire] == 0 ){
$n = 1; // on doit monter $n ] en avant
while ($n){
$i ++;
if ($code[$i]=='[') $n++; // si on rencontre un [, alors on attend un ] de plus
else if ($code[$i]==']') $n--; // si on trouve un ]. alors on en attend un de moins
} // ici, on a pas de $i-- parce-qu'on jump apres le ]
} break;
}
}
}
/*
la version ci dessus est une version legerement naive.
On peut faire plus fin : eviter les boucles plus haut.
Celles qui gerent les [ ].
Pour les eviter, il faut resoudre les [] en preprocessing,
pour cela, il nous suffit d'utiliser une pile.
quand on croise un [, on l'empile, quand on croise un ],
on depile et on a le couple.
/**
- @brief fonction qui interprete un code brainfuck
- solution avec preprocessing ( relier les [ aux ] )
- @param $code le code a interpreter
- /
function brainfuck($code){
$code_len = strlen($code);
// on gere les jumps ( [] )
$jmp = array();
$tmp = array();
for ($i=0;$i<$code_len;$i++){
if ($code[$i] == '[') array_push($tmp, $i);
else if ($code[$i] == ']'){
$start = array_pop($tmp);
$jumps[$start] = $i;
$jumps[$i] = $start - 1;
}
}
// on interprete
$mem = array();
$indice_memoire = 0;
for ($i=0;$i<$code_len;$i++){
if (!isset($mem[$indice_memoire])) $mem[$indice_memoire]=0;
else {
// les valeurs sont comprises entre 0 et 256.
$mem[$indice_memoire] = (256 + $mem[$indice_memoire] ) % 256;
}
switch($code[$i]){
case '>': $indice_memoire++; break;
case '<': $indice_memoire--; break;
case '.': echo chr($mem[$indice_memoire]); break;
case ',': $mem[$indice_memoire]=prompt(); break;
case '+': $mem[$indice_memoire]++; break;
case '-': $mem[$indice_memoire]--; break;
case ']': $i = $jumps[$i]; break;
case '[': if ( $mem[$indice_memoire] == 0 ) $i = $jumps[$i]; break;
}
}
}
function brainfuck_compilateur($str){
$checktab='if(!isset($tab[$pos])) $tab[$pos]=0;';
$replace = array(
'+'=>'$tab[$pos] = ($tab[$pos]==255)?0:($tab[$pos]+1);',
'-'=>'$tab[$pos] = ($tab[$pos]==0)?255:($tab[$pos]-1);',
'>'=>'$pos++;'.$checktab,
'<'=>'$pos--;'.$checktab,
'['=>'while($tab[$pos]){',
']'=>'}',
'.'=>'echo chr($tab[$pos]);',
','=>'$tab[$pos]=prompt();',
);
for ($i=0, $code='$tab = array(0); $pos = 0;', $len = strlen($str); $i<$len; $i++)
if (isset($replace[$str[$i]]))
$code.=$replace[$str[$i]]."\n";
eval ($code);
}
brainfuck_verbeux(
'++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.');
brainfuck_verbeux(',>,<+>+<.>.');
?>
Conclusion :
branifuck powaaa