Brainf**k Debugger

Your challenge is to take input like this (a Hello World program):

++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.


And output a prompt (which will be "> "):

>


The user can then enter anything at the prompt. Your simple debugger must have these commands:

• S - step

• Output the current location (see L) after stepping.
• S(a positive integer) - step that many spaces
• L - location

• The term "location" always refers to where you are in the program (i.e., the instruction pointer).
• Formatted like this:

  v
+++++++[>+++++++<-]>.


This means that the current location of the program is at the third +.

• G(an integer) - go to

• This means keep stepping until you get to that location. If you reach the end of the program and you haven't gotten there, simply exit the program.
• A negative integer means that many characters from the end. Yes, this means that -0 is different than 0, and -1 is the second to last character.
• Don't output anything for this command.
• D - dump array

• Formatted like 1, 2, 3, 4, 5
• If the array is 1, 2, 3, 0, 0, 0, 0, 0, ..., only output 1, 2, 3.
• D(a positive integer) (a positive integer) - dump all array items between those two positions (inclusive)
• (a positive integer) - output the item currently at that array position

• P - output the index of the BF pointer (the thing you change with > and <).

When the program requests input, show the prompt "I> ". (You may input one character at a time.)

When it outputs something, show "O> " + (the output). Multiple outputs between commands must be chained together (i.e. you can't do > G-0 O> H O> e O> l O> l O> o ..., it has to be > G-0 O> Hello, World!).

Output "Done" and exit once you reach the end of the program.

Sample run:

++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
> S
1
> S
2
> S2
4
> S0
4
> L
v
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
> D
4
> 0
4
> D10 15
0, 0, 0, 0, 0, 0
> G-0
O> Hello, World!
Done


Sample run showing stepping through loops and the P instruction (calculates 3*2+1)

+++[>++<-]>+
> S3
3
> L
v
+++[>++<-]>+
> S3
6
> L
v
+++[>++<-]>+
> P
1
> S3
9
> L
v
+++[>++<-]>+
> S
3
> L
v
+++[>++<-]>+
> D
2, 2
>


Sample run showing I/O

>+[>,---------------------------------]<[<]>[>.]
> G37
I> H
I> e
I> l
I> l
I> o
I> !
> D
0, 39, 68, 75, 75, 78
> G-0
O> 'DKKN
Done


This is , so the shortest code will win.

PHP - 1008

<?php
$_=trim(fread(STDIN,1e5));$z=$p=0;$t=$l=[];$q='';function s(){global$p,$t,$l,$_,$q,$z;switch($_[$z++]){case'>':$p++;break;case'<':$p--;break;case'+':@$t[$p]++;break;case'-':@$t[$p]--;break;case'.':$q.=chr($t[$p]);break;case',':echo"I>";$t[$p]=ord(trim(fread(STDIN,2)));break;case'[':$l[]=$z;if(!isset($t[$p])||$t[$p]==0){$c=1;while($c>0){$b=$_[$z++];if($b=='[')$c++;elseif($b==']')$c--;}array_pop($l);}break;case']':$z=array_pop($l)-1;break;}if($z==strlen($_)){if($q)echo'O>'.$q."\n";die("Done\n");}}for(;;){echo">";$c=trim(fread(STDIN,1e5));$g=strlen($c);switch($c[0]){case'L':echo str_repeat(' ',$z)."v\n".$_."\n";break;case'D':if($g)$x=$t;else{list($a,$b)=explode(' ',substr($c,1));$x=array_slice($t,$a-1,$b);}echo implode(', ',$x)."\n";break;case'S':if($g)s();for($i=0;$i<substr($c,1);$i++)s();echo$z."\n";break;case'G':if($c[1]=='-')$x=strlen($_)-substr($c,2);else$x=substr($c,1);while($z!=$x)s();break;case'P':echo$p."\n";default:if(is_numeric($c))echo$t[$c]."\n";}if($q)echo'O>'.$q."\n";$q='';}  The output for cells that were never written is slightly different: [timwolla@/data/workspace/php/PCG]php pcg-22585.php + >D15 20 >  Large version: <?php$_=trim(fread(STDIN,1024));
$z=$p=0;
$t=$l=[];
$q=''; function step() { global$p, $t,$l,$_,$q,$z; switch ($_[$z++]){ case '>':$p++;
break;
case '<':
$p--; break; case '+': @$t[$p]++; break; case '-': @$t[$p]--; break; case '.':$q.=chr($t[$p]);
break;
case ',':
echo "I>";
$t[$p] = ord(trim(fread(STDIN, 2)));
break;
case '[':
$l[] =$z;
if (!isset($t[$p]) || $t[$p] == 0) {
$counter = 1; while ($counter > 0) {
$char =$_[$z++]; if ($char == '[') $counter++; else if ($char == ']') $counter--; } array_pop($l);
}
break;
case ']':
$z = array_pop($l)-1;
break;
}
if($z==strlen($_)) {
if ($q) echo 'O>'.$q."\n";
die("Done\n");
}
}

for(;;){
echo ">";
$c=trim(fread(STDIN,100)); switch ($c[0]) {
case 'L':
echo str_repeat(' ', $z)."v\n".$_."\n";
break;
case 'D':
if(strlen($c) == 1)$x=$t; else { list($a,$b)=explode(' ',substr($c,1));
$x=array_slice($t,$a-1,$b);
}
echo implode(', ', $x)."\n"; break; case 'S': if(strlen($c)==1)step();
for($i=0;$i<substr($c,1);$i++)step();
echo $z."\n"; break; case 'G': if($c[1]=='-')$x=strlen($_)-substr($c,2); else$x=substr($c,1); while ($z!=$x)step(); break; case 'P': echo$p."\n";
default:
if(is_numeric($c)) echo$t[$c]."\n"; } if ($q) {
echo 'O>'.$q."\n";$q='';
}
}

• I fixed the third testcase. – Doorknob Mar 5 '14 at 3:01