Brainf*** is a crude, turing complete programming language invented by Urban Mueller.
This is a interpreter for it, written in LITTLE.
Surely, it's not as simple as it could be - but that was not it's purpose. :)
;
; A brainf* interpreter in LITTLE.
; It is not THAT short, and not THAT performant, but hey ...!
; It proves LITTLE's Turing completeness, and that IS something,
; isn't it?
;
(package bf)
(using
little.lang.Array
little.lang.Char
little.lang.Exception
little.lang.InstantiableObject
little.lang.Object
little.lang.System
little.lang.container.LinkedList
little.io.File
little.io.TextInputStream
little.io.TextOutputStream)
;
; A BRAINF* instruction. It consists of an action to perform,
; and a specification how to continue the program.
;
(class Instruction (InstantiableObject) :abstract
(attribute
i:static ;last instruction index
i ;instruction index in code stream
next ;next instruction in stream
)
(method i (i) :static
(set self:i i))
(method i () :static
(set self:i (self:i:succ)))
(method init ()
(set self:i (Instruction:i))
self)
(method init (next)
(set self:i (Instruction:i))
(set self:next next)
self)
(method exec () :abstract)
(method next () self:next)
(method next (ins)
(set self:next ins))
(method continuation ()
(self:next))
(method serial ()
self:i)
(method print ()
((TextOutputStream:out):println (self:serial) (self:memnonic)))
)
;
; The pointer increment instruction.
;
(class PInc (Instruction)
(method exec ()
(Engine:pinc))
(method memnonic () ">")
)
;
; The pointer decrement instruction.
;
(class PDec (Instruction)
(method exec ()
(Engine:pdec))
(method memnonic () "<")
)
;
; The value-at-pointer increment instruction.
;
(class Inc (Instruction)
(method exec ()
(Engine:inc))
(method memnonic () "+")
)
;
; The value-at-pointer decrement instruction.
;
(class Dec (Instruction)
(method exec ()
(Engine:dec))
(method memnonic () "-")
)
;
; The input instruction.
;
(class In (Instruction)
(method exec ()
(Engine:in))
(method memnonic () ",")
)
;
; The output instruction.
;
(class Out (Instruction)
(method exec ()
(Engine:out))
(method memnonic () ".")
)
;
; The jump-if-zero instruction.
;
(class JZ (Instruction)
(attribute branch)
(method continuation ()
(if (Engine:v)
(self:next)
(self:branch)))
(method branch ()
self:branch)
(method branch (ins)
(set self:branch ins))
(method exec () nil)
(method memnonic () "[")
(method print ()
((TextOutputStream:out):println (self:serial) (self:memnonic) ((self:branch):serial)))
)
;
; The jump-if-not-zero instruction.
;
(class JNZ (Instruction)
(attribute branch)
(method continuation ()
(if (Engine:v)
(self:branch)
(self:next)))
(method branch ()
self:branch)
(method branch (ins)
(set self:branch ins))
(method exec () nil)
(method memnonic () "]")
(method print ()
((TextOutputStream:out):println (self:serial) (self:memnonic) ((self:branch):serial)))
)
;
; The interpreter execution engine.
;
(class Engine (Object)
(attribute
cs:static ; Code segment
cp:static ; pointer to last instruction - used by method compile()
ds:static ; data array
p:static ; pointer into data array
in:static ; input stream
out:static; output stream
)
(method init ():static
(set self:ds (Array:new 30000))
(self:reset)
(set self:in (TextInputStream:in))
(set self:out (TextOutputStream:out))
self)
;
; Increments the pointer.
;
(method pinc () :static
;(*test.Debug:printsym 'pinc)
(set self:p (self:p:succ)))
;
; Decrements the pointer.
;
(method pdec () :static
;(*test.Debug:printsym 'pdec)
(set self:p (self:p:pred)))
;
; Increments the value at pointer.
;
(method inc () :static
;(*test.Debug:printsym 'inc)
(let ((i (self:ds:get self:p)))
(self:ds:put self:p (i:succ))))
;
; Decrements the value at pointer.
;
(method dec () :static
;(*test.Debug:printsym 'dec)
(let ((i (self:ds:get self:p)))
(self:ds:put self:p (i:pred))))
;
; Inputs a value to the cell below pointer.
;
(method in () :static
;(*test.Debug:printsym 'in)
(let ((c (self:in:readChar)))
(if c
(self:ds:put self:p (c:getcode))
(self:ds:put self:p 0))))
;
; Outputs the value at pointer.
;
(method out () :static
;(*test.Debug:printsym 'out)
(self:out:printChar (Char:from (self:ds:get self:p))))
;
; Returns the value at pointer.
;
(method v () :static
(self:ds:get self:p))
;
; Adds an instruction to the code segment.
;
(method add (ins) :static
(if self:cp
(prog
(self:cp:next ins)
(set self:cp ins))
(set self:cs (set self:cp ins)))
ins)
;
; Compiles a source file into internal representation (a sequence
; of instructions, represented by instances of class Instruction's descendants)
;
(method compile (file label) :static
(let ((c nil))
(while (set c (file:readChar))
(cond
((c:equals ">"c)
(self:add (PInc:new)))
((c:equals "<"c)
(self:add (PDec:new)))
((c:equals "+"c)
(self:add (Inc:new)))
((c:equals "-"c)
(self:add (Dec:new)))
((c:equals "."c)
(self:add (Out:new)))
((c:equals ","c)
(self:add (In:new)))
((c:equals "["c)
(let ((ins (JZ:new)))
(self:add ins)
(self:compile file ins)
(ins:branch self:cp)))
((c:equals "]"c)
(if label
(let ((ins (JNZ:new)))
(ins:branch label)
(self:add ins)
(return nil))
((Exception:new 'MissingLoopStart):throw)))
((c:isspace)
nil)
(true
nil)))))
;((Exception:new 'IllegalBrainfuckOp):throw))))))
;
; Resets the engine, ie. erases the program, and resets the data segment.
;
(method reset () :static
(let ((i 0))
(while (i:lt 30000)
(self:ds:put i 0)
(set i (i:succ))))
(set self:cs nil)
(set self:cp nil)
(set self:p 0)
(Instruction:i 0))
;
; Runs the current code snippet.
;
(method run () :static
(let ((ins self:cs))
(while ins
(ins:exec)
(set ins (ins:continuation)))))
;
; Runs a Brainfuck file.
;
(method run (file) :static
(self:reset)
(self:compile file nil)
(self:run))
;
; The entry point.
;
(method main () :static
(let ((arguments (System:arguments)) (file nil))
(while (arguments:hasMoreElements)
(try
(set file (TextInputStream:new (File:new (arguments:nextElement))))
(self:run file)
catch (e)
(self:out:println "Error:" e)))))
)