brainfuck interpreter

by Santiago J

HTML

<textarea id="input">
+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print 'H'
> + .                   print 'e'
+++++ ++ .              print 'l'
.                       print 'l'
+++ .                   print 'o'
> ++ .                  print ' '
<< +++++ +++++ +++++ .  print 'W'
> .                     print 'o'
+++ .                   print 'r'
----- - .               print 'l'
----- --- .             print 'd'
> + .                   print '!'
> .                     print '\n'
>

In compressed form
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
</textarea>
<button id="interpret">Interpret</button>
<input id="asChar" type="checkbox" checked><label for="asChar">Print as char</label>
<textarea id="output"></textarea>
<!--
+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 80/100/30/110/50
    > +++++ +++             add  8 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +++++ +++++ +         add 11 to cell #4
    > +++++                 add  5 to cell #5
    <<<<< -                  decrement counter (cell #0)
]
> .                     print 'P'
> +++++ .               print 'i'
>> .                    print 'n'
<< ++ .                 print 'k'
-- .                    print 'i'
---- .                  print 'e'
> ++ .                  print ' '
< ++++ .                print 'i'
>> +++++ .              print 's'
< .                     print ' '
< ----- -- .            print 'b'
+++ .               ...

CSS

body {
    background-color: #333;
    color: #fff;
    font-family: sans-serif;
    font-size: 76%;
}

#input, #output {
    background-color: #222;
    border: 1px inset #ccc;
    color: #eee;
    display: block;
    font-family: consolas, monospace;
    font-size: 14px;
    width: 640px;
}
#input {
    height: 480px;
}
#output {
    height: 80px;
}

JavaScript

var input, output, asChar, printAsChar;

function log(cc) {
    output.value += printAsChar ? String.fromCharCode(cc) : "[" + cc + "]";
}

function freshMem(len) {
    for (var a = []; len-- > 0; a.push(0));
    return a;
}

var mem,  // memory
    ptr,  // pointer
    prg,  // program code
    len,  // length of code
    pos,  // current position of interpreter
    loopy;

// brainfuck commands
function interpretCmd(cmd) {
    switch (cmd) {
        case "+": ++mem[ptr]; break;
        case "-": --mem[ptr]; break;
        case ">": ++ptr; break;
        case "<": --ptr; break;
        case ".": log(mem[ptr]); break;
        case ",": break; // not sure how to implement
        case "]": break;
        case "[": return loopy();
   }
}

function loopy() {
    var keyPos = pos + 1;
    while (mem[ptr] > 0) {
        for (pos = keyPos; prg[pos] !== "]"; pos++) interpretCmd(prg[pos]);
    }
}

function begin() {
    prg = input.value.replace(/[^\+\-<>\[\]\.,]/g, "");
    len = prg.length;
    ptr = 0;
    mem = freshMem(30000);

    output.value = "";
    printAsChar = asChar.checked;

    for (pos = 0; pos < len; pos++) interpretCmd(prg[pos]);
}

window.onload = function() {
    input = document.getElementById("input");
    output = document.getElementById("output");
    asChar = document.getElementById("asChar");
    document.getElementById("interpret").onclick = begin;
};