kuddeldaddeldu
Erfahrenes Mitglied
Hi,
habe gerade keine Zeit zum Kommentieren...
habe gerade keine Zeit zum Kommentieren...
PHP:
#/usr/bin/php5
<?php
class BrainScript {
private $memory; // Speicherzellen
private $m_pointer; // aktuelle Position im Speicher
private $program; // komprimiertes Brainf*ck-Programm
private $pc; // Programmzähler (aktueller Befehl)
private $input; // Eingabearray
public function __construct() {
$this->memory = array(0);
$this->input = array();
$this->m_pointer = 0;
$this->pc = 0;
$this->program = array();
}
public function load($file) {
// Kommentare entfernen
$code = preg_replace('/[^\+^\-^<^>^\.^,^\[^\]]/', '', file_get_contents($file));
// Code aufteilen in zusammenhängende +,-,<,> und einzelne ,,.,[,]
// Für das Klammern-Matching werden die Offsets mit zurückgegeben
$pattern = '/[<]+|[>]+|[\.]?|[,]?|[\+]+|[\-]+|[\[]?|[\]]?/';
$result = preg_match_all($pattern, $code, $matches, PREG_OFFSET_CAPTURE);
if($result) {
$loops = array();
// komprimiertes Programm aus den Matches erstellen
foreach($matches[0] as $match) {
switch(substr($match[0], 0, 1)) {
case '+':
$this->program[] = array('+', strlen($match[0]));
break;
case '-':
$this->program[] = array('-', strlen($match[0]));
break;
case '>':
$this->program[] = array('>', strlen($match[0]));
break;
case '<':
$this->program[] = array('<', strlen($match[0]));
break;
case ',':
$this->program[] = array(',');
break;
case '.':
$this->program[] = array('.');
break;
case '[':
// zunächst Sprungadresse 0 speichern
$this->program[] = array('[', 0);
// aktuelle Position (pc) auf den Loop-Stack schreiben
$loops[] = count($this->program) - 1;
break;
case ']':
if(empty($loops)) {
throw new Exception("Öffnende Klammer fehlt.");
}
// Position der öffnenden Klammer vom Loop-Stack holen
$open_bracket_at = array_pop($loops);
// Rücksprungadresse setzen
$this->program[] = array(']', $open_bracket_at - 1);
// Sprungadresse der öffnenden Klammer auf aktuelle Position setzen
$this->program[$open_bracket_at][1] = count($this->program) - 1;
break;
default:
break;
}
}
if(!empty($loops)) {
throw new Exception("Nicht alle Klammern geschlossen.");
}
} else {
throw new Exception("Kein BrainScript-Code gegeben.");
}
unset($matches);
unset($code);
}
public function execute() {
while($this->pc < count($this->program)) {
switch($this->program[$this->pc][0]) {
case '+':
$this->incrementCell($this->program[$this->pc][1]);
break;
case '-':
$this->decrementCell($this->program[$this->pc][1]);
break;
case '>':
$this->moveRight($this->program[$this->pc][1]);
break;
case '<':
$this->moveLeft($this->program[$this->pc][1]);
break;
case ',':
$this->readChar();
break;
case '.':
echo chr($this->getCellValue());
break;
case '[':
$this->startLoop($this->program[$this->pc][1]);
break;
case ']':
$this->endLoop($this->program[$this->pc][1]);
break;
default:
break;
}
$this->pc++;
}
}
private function readChar() {
if(empty($this->input)) {
$this->input = array_map(create_function('$item', 'return ord($item);'), str_split(fgets(STDIN)));
$this->input[] = 0; // Eingabe terminieren
}
$this->memory[$this->m_pointer] = array_shift($this->input);
}
private function getCellValue() {
return $this->memory[$this->m_pointer];
}
private function moveRight($num) {
// falls erforderlich, den Speicher erweitern
if(!isset($this->memory[$this->m_pointer + $num])) {
$new_cells = $this->m_pointer + $num - count($this->memory) + 1;
$this->memory = array_merge($this->memory, array_fill(0, $new_cells, 0));
}
$this->m_pointer += $num;
}
private function moveLeft($num) {
// falls erforderlich, den Speicher erweitern
if($this->m_pointer - $num < 0) {
$new_cells = $num - $this->m_pointer;
$this->memory = array_merge(array_fill(0, $new_cells, 0), $this->memory);
$this->m_pointer = 0;
} else {
$this->m_pointer -= $num;
}
}
private function incrementCell($num) {
if($this->memory[$this->m_pointer] + $num > 255) {
$this->memory[$this->m_pointer] = $num - 2;
} else {
$this->memory[$this->m_pointer] += $num;
}
}
private function decrementCell($num) {
if($this->memory[$this->m_pointer] - $num < 0) {
$this->memory[$this->m_pointer] = 255 - $num + 2;
} else {
$this->memory[$this->m_pointer] -= $num;
}
}
private function startLoop($jumpTo) {
if($this->getCellValue() == 0) {
$this->pc = $jumpTo;
}
}
private function endLoop($jumpTo) {
$this->pc = $jumpTo;
}
}
// Main
ini_set('memory_limit', '256M');
$program = new BrainScript();
try {
$program->load($argv[1]);
} catch(Exception $e) {
echo $e->getMessage() . "\n";
echo $e->getTraceAsString() . "\n";
}
$program->execute();
echo "\n";
?>