Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 117 lines (93 sloc) 3.24 KB
#! /usr/bin/env pez
# An interpreter for everybody's favorite minimalist language that you can't
# pronounce the name of in polite company. As it has been proven that BF is
# Turing-complete, and as this is a valid Pez program to simulate the language,
# you can now rest assured of Pez's Turing-completeness.
# Run like this:
# ./bf.pez some-program.bf
# As a sample, here is "Hello, World!", roughly as it appears on the Wikipedia
# page for the language:
# ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++
# ++++++.>.+++.------.--------.>+.>.
# You can paste those two lines as-is; extra characters are ignored.
# For more information on the language, see
# http://esoteric.voxelperfect.net/wiki/BF . http://github.com/pete/lbf should
# also be good for a laugh, and it has a few examples.
# This version of the language uses 20,000 1-byte cells, the cell pointer wraps
# around at the edges, there's no checking for mismatched brackets (in fact, it
# will usually segfault or give a non-obvious error), and EOF on read is zero.
# It works by defining a word, reading the input file a character at a time,
# checking its value in a lookup table, and running the word (if any) from the
# table. The entries in the table are words that compile the code represented
# by the character into the word. When it's done, it finalizes the word and
# runs it. For debugging your BF, there is an extra word defined for dumping
# the state of the world, and you can use the decompiler lib to see the Pez code
# that is generated.
"decompile" load-lib # To see the Pez code generated from the BF code.
# Initialize the state.
20000 constant worldsize
worldsize malloc constant world
variable worldp world worldp !
256 cells malloc constant ctable
: bf-current-val worldp @ c@ ;
: bf+
worldp @ dup c@ 1+ swap c! ;
: bf-
worldp @ dup c@ 1- swap c! ;
: bf>
worldp @ 1+ worldp !
worldp @ world worldsize + >= if world worldp ! then ;
: bf<
worldp @ 1- worldp !
worldp @ world < if world worldsize 1- + worldp ! then ;
: bf.
bf-current-val putc ;
: bf,
getc worldp @ c! ;
: c-bf+ ['] bf+ , ;
: c-bf- ['] bf- , ;
: c-bf< ['] bf< , ;
: c-bf> ['] bf> , ;
: c-bf, ['] bf, , ;
: c-bf. ['] bf. , ;
: c-bf[
['] branch , here 0 , ;
: c-bf]
here over - cell-size / over ! # Back-patch
['] bf-current-val ,
['] 0= ,
['] ?branch ,
here - cell-size / 1+ , ;
: bf-def
swap c@ cells ctable + ! ;
"+" ' c-bf+ bf-def
"-" ' c-bf- bf-def
"<" ' c-bf< bf-def
">" ' c-bf> bf-def
"." ' c-bf. bf-def
"," ' c-bf, bf-def
"[" ' c-bf[ bf-def
"]" ' c-bf] bf-def
# Dumps the state of the world.
: dump-world ( #cells -- )
"BF State:" puts
0 do i . ": " print world i + c@ . cr loop ;
# Bails out if we don't get a filename to run.
: error-bail? ( string -- )
0= if "Please pass a file to run as an argument!" 1 die! then ;
# Reads all of the code from
: compile-bf ( fname -- beginning-of-code )
o_rdonly 0 open >input
begin getc dup while
cells ctable + @
dup if execute else drop then
repeat drop
input> close drop ;
immediate
argv @ dup error-bail?
: run-bf ( -- ) compile-bf ;
# If you want to see the code generated by compile-bf-to
# hex ' pre-here @ here over - dump
run-bf
# And, if you're debugging, you may prefer to dump the first N cells of BF's
# 10 dump-world