Add basic interpreter and start of exampl

This commit is contained in:
Ian Adam Naval 2014-09-30 22:26:28 -04:00
commit b3e3ea3427
5 changed files with 379 additions and 0 deletions

16
bf_to_bw.py Normal file
View File

@ -0,0 +1,16 @@
import sys
commands = {
'>': 'ee ee ee',
'<': 'ee ee o',
'+': 'ee o ee',
'-': 'ee o o',
'.': 'o ee ee',
',': 'o ee o',
'[': 'o o ee',
']': 'o o o',
}
for line in sys.stdin:
for char in line:
print commands.get(char, '')

95
bookworm.bw Normal file
View File

@ -0,0 +1,95 @@
ee ee ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
o ee ee
o o ee
ee o o
o o o

161
bookworm.py Normal file
View File

@ -0,0 +1,161 @@
import sys
from collections import defaultdict
def generate_words(input_file):
"""Generator that yields words from a file-like object.
:param input_file: the file-like object
:yield: words from the file-like object until EOF
"""
for line in input_file:
for word in line.split():
yield word
def words_to_bits(words):
"""Converts a lit of words to a string of bits. The '0's correspond
with an even length word, and the '1's correspond with odd-length
words.
>>> words_to_bits(["Hi,", "I'm", "Paul"])
"110"
:param words: List of words to convert into bits
:return: string of ASCII 1s and 0s representing the bits
"""
evenness = ['0' if len(word) % 2 == 0 else '1' for word in words]
return ''.join(evenness)
class BookwormInterpreter(object):
"""A bookworm interpreter executes a program written in the Bookworm
programming language for a particular file."""
code = {}
data = defaultdict(lambda: 0)
address = 0
instruction_pointer = 0
def __init__(self, input_file):
"""Initializer for bookworm interpreters.
:param input_file: the file to interpret
"""
self.word_generator = generate_words(input_file)
self.commands = {
"000": self.move_right,
"001": self.move_left,
"010": self.increment,
"011": self.decrement,
"100": self.output,
"101": self.read,
"110": self.open_bracket,
"111": self.close_bracket,
}
def move_right(self):
"""Moves the address on the data tape right."""
self.address += 1
def move_left(self):
"""Moves the address on the data tape left."""
self.address -= 1
def increment(self):
"""Increments the value of the data tape at the address."""
self.data[self.address] = self.data[self.address] + 1
def decrement(self):
"""Decrements the value of the data tape at the address."""
self.data[self.address] = self.data[self.address] - 1
def output(self):
"""Outputs the current value of the data tape to stdout."""
sys.stdout.write(chr(self.data[self.address]))
def read(self):
"""Writes from stdin one byte into the data tape."""
self.data[self.address] = sys.stdin.read(1)
def open_bracket(self):
"""If the current value of the data tape is 0, jumps to the next
matching close_bracket (denoted by opcode '111')."""
if self.data[self.address] == 0:
curr_byte = self.code[self.instruction_pointer]
num_unresolved_pairs = 1
while num_unresolved_pairs > 0:
self.instruction_pointer += 1
curr_byte = self.get_op_code_at(self.instruction_pointer)
if curr_byte == '110':
num_unresolved_pairs += 1
elif curr_byte == '111':
num_unresolved_pairs -= 1
def close_bracket(self):
"""If the current value of the data tape is 0, jumps back to
the next matching open_bracket (denoted by opcode '110')."""
if self.data[self.address] != 0:
curr_byte = None
num_unresolved_pairs = 1
while num_unresolved_pairs > 0:
self.instruction_pointer -= 1
curr_byte = self.get_op_code_at(self.instruction_pointer)
if curr_byte == '110':
num_unresolved_pairs -= 1
elif curr_byte == '111':
num_unresolved_pairs += 1
def get_op_code_at(self, index):
"""Returns the opcode stored in the code tape at the given
index. Reads it from the file if it's not available. Assumes
that if the given index is not already in the code tape, we have
to read the next opcode from the word generator.
:param index: The index on the code tape
:return: The value of the code tape at the given index
"""
if index not in self.code:
self.code[index] = self.get_op_code()
return self.code[index]
def get_op_code(self):
""""""
words = []
while len(words) < 3:
words.append(next(self.word_generator))
return words_to_bits(words)
def execute_code(self):
"""Executes code by getting the opcodes one at a time and
executing them sequentially."""
op_code = self.get_op_code_at(self.instruction_pointer)
command = self.commands[op_code]
command()
self.instruction_pointer += 1
def main():
"""Main function for this interpreter command line interface."""
# Check num args
if len(sys.argv) < 2:
sys.exit("Usage: {} <input file>")
input_file = open(sys.argv[1])
bookworm = BookwormInterpreter(input_file)
while True:
try:
bookworm.execute_code()
except StopIteration:
break
if __name__ == '__main__':
main()

106
hello.bw Normal file
View File

@ -0,0 +1,106 @@
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
o o ee
ee ee ee
ee o ee
ee o ee
ee o ee
ee o ee
o o ee
ee ee ee
ee o ee
ee o ee
ee ee ee
ee o ee
ee o ee
ee o ee
ee ee ee
ee o ee
ee o ee
ee o ee
ee ee ee
ee o ee
ee ee o
ee ee o
ee ee o
ee ee o
ee o o
o o o
ee ee ee
ee o ee
ee ee ee
ee o ee
ee ee ee
ee o o
ee ee ee
ee ee ee
ee o ee
o o ee
ee ee o
o o o
ee ee o
ee o o
o o o
ee ee ee
ee ee ee
o ee ee
ee ee ee
ee o o
ee o o
ee o o
o ee ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
ee o ee
o ee ee
o ee ee
ee o ee
ee o ee
ee o ee
o ee ee
ee ee ee
ee ee ee
o ee ee
ee ee o
ee o o
o ee ee
ee ee o
o ee ee
ee o ee
ee o ee
ee o ee
o ee ee
ee o o
ee o o
ee o o
ee o o
ee o o
ee o o
o ee ee
ee o o
ee o o
ee o o
ee o o
ee o o
ee o o
ee o o
ee o o
o ee ee
ee ee ee
ee ee ee
ee o ee
o ee ee
ee ee ee
ee o ee
ee o ee
o ee ee

1
idiomatic_hello.bw Normal file
View File

@ -0,0 +1 @@
This program is Bookworm's reference "Hello World" implementation. Please do not take this example as "the one true way" since many possible alternative programs could certainly be used instead. This particular program took over one hour to write as Bookworm's constraints make you carefully consider each individual character. Fortunately, idiomatic Bookworm programs are self-documenting in that source code and comments become combined. In actuality, the source code consists entirely of comments! We strongly believe that code ought to document itself so that other people (read: your colleagues) will very quickly understand what the code is doing by reading the code. There could be no comments at all as well as zero documentation. The only resource that your fellow programmers would need is your source code as it stands. That's exactly why Bookworm programs will typically avoid the use of explicit comment markers. o o o o o ee ee ee ee ee ee o ee ee ee ee ee ee o o ee o o ee o o o ee ee ee o ee ee o ee ee o ee ee o ee ee o ee ee o ee ee o ee o ee ee o ee ee ee o ee ee o ee ee o ee o ee ee ee ee ee ee ee ee o ee ee ee ee o ee o o o ee ee ee ee o o ee ee ee o ee ee o ee ee o ee o ee ee ee o o ee o o ee o o ee o o ee o o ee o o o ee ee ee o o ee o o ee o o ee o o ee o o ee o o ee o o ee o o o ee ee ee ee ee ee ee ee ee o ee o ee ee ee ee ee ee o ee ee o ee o ee ee