Perl, 271 chars
@e=qw'die"Hello\x20World!\n" $i-- $i++ $a[$i]-- $a[$i]++ push@s,$p $a[$i]?$p=$s[-1]:pop@s print+chr$a[$i] $a[$i]=ord<>';
say"# $k[$_]: $e[$_]"for 0..8;say;
(The code above has some non-essential line breaks inserted for readability. All line breaks may be removed without affecting the behavior, and should not be counted for scoring purposes.)
perl -M5.010 to enable the
say feature. Reads the input program from standard input (or from a file given as a command line argument), prints an interpreter to standard output. The output is also a Perl script, and should be executed the same way.
The (rudimentary) language spec is included as comments at the beginning of the interpreter, and is formatted as a list of characters and the Perl commands each of them will execute. In the spec,
$p stands for the program counter (which points to the next instruction to execute),
@s for the loop stack,
$i for the tape index and
@a for the tape.
Basically, the language executed by the interpreter is exactly what ugoren suggested in the comments: a simple variant of Brainf*ck, with an extra command that prints
Hello World! and ends the program. This extra command is mapped to the first character of the input program, while the other commands are mapped to subsequent letters. All unrecognized characters are ignored.
For example, using the input
AAAAAA, the output will look like this:
# A: die"Hello\x20World!\n"
# B: $i--
# C: $i++
# D: $a[$i]--
# E: $a[$i]++
# F: push@s,$p
# G: $a[$i]?$p=$s[-1]:pop@s
# H: print+chr$a[$i]
# I: $a[$i]=ord<>
Running the resulting code above with the same input produces the expected output:
whereas running the same code with the input
EEEEEEFDCEEEEBGCFDCECEEEEBBGCEEFDCEHBG (transliterated from this answer) prints:
Ps. To convert normal Brainf*ck code to the variant understood by this interpreter, you can use the transliteration:
B-I should be replaced by the appropriate range of command letters as per the generated spec.
Notes on the BF implementation:
The tape is single-ended, with the read/write head starting at cell 0. Moving the head to a negative position might not cause an error, but will produce weird effects related to Perl's array indexing and should be considered undefined behavior.
Cell values do not wrap around. Technically, each cell is stored as a double, meaning that at some point the value will saturate and further inc/decrements will have no effect. You'll die of boredom before that happens, though.
Character I/O depends on Perl's I/O layers. By default, input values are unsigned bytes, and attempting to output values outside the range 0 – 255 gives a warning message. Passing the
-CS switch to Perl will enable Unicode I/O (encoded as UTF-8), though. Input at EOF yields a zero. To supply both a program and its input on stdin, separate them with a Ctrl+D character (
Edit: I later realized that there's a major difference between the language I implement above and real Brainf*ck: in my language, the loop condition is checked at the end of the loop, rather than at the beginning, which means that every loop executes at least once. In effect, loops in my language behave like
while loops in C-ish languages, whereas those in normal BF behave like plain
As it happens, the difference doesn't matter for the example program above, since all its loops run at least once anyway. What I'm not quite sure about is whether the proof of BF's Turing-completeness can still be made to apply to my variant of the language or not. It might be possible, but it's going to be tricky without any easy way to implement an
I suppose I could fix my program to behave more like normal BF, but it would be a pain in the ass to do without a major redesign of the execution model. :(