diff --git a/BF.hs b/BF.hs
new file mode 100644
--- /dev/null
+++ b/BF.hs
@@ -0,0 +1,111 @@
+module Main where
+
+import Char (ord,chr)
+import System (getArgs,system)
+import List (nub,isPrefixOf)
+import System.IO.Unsafe (unsafePerformIO)
+import System.IO (isEOF,getChar,putChar,hSetBuffering,BufferMode(..)
+                 ,stdin,stdout,stderr,hPutStrLn,hFlush)
+
+type Tokens = (String,String,String,String,String,String,String,String)
+
+data Token = MRight | MLeft | Inc | Dec | In | Out | JINZ | JMatch
+             deriving Show
+
+data Stmt = TMRight | TMLeft | TInc | TDec | TIn | TOut | TLoop [Stmt]
+            deriving Show
+
+type Machine = ([Int],[Int])
+
+{- | 
+  A brainFuck and derived languages interpreter.  Currently supports Brainfuck
+  and Ook. 
+  
+  Usage:
+    BF [-m mode] prog
+    
+  Options:
+    -m  Sets the programming languages interpreted.  Valid options are:
+        bf  -- Brainfuck
+        ook -- Ook!
+-}
+main = do args <- System.getArgs
+          hSetBuffering stdin NoBuffering
+          let (tokens,prog) = parseArgs args
+          interpret (\x -> putStrLn "") 
+                    (fst $ parse $ tokenise prog tokens)
+                    emptyMachine
+
+emptyMachine :: Machine
+emptyMachine = (repeat 0,repeat 0)
+
+{- | Parse the arguments given to the BF program -}
+parseArgs :: [String] -> (Tokens,String)
+parseArgs []  = (("","","","","","","",""),"")
+parseArgs [p] = ((">","<","+","-",",",".","[","]")
+                ,unsafePerformIO $ readFile p)
+parseArgs ("-m":"bf":xs) =
+  let (_,f) = parseArgs xs
+  in ((">","<","+","-",",",".","[","]"),f)
+parseArgs ("-m":"ook":xs) =
+  let (_,f) = parseArgs xs
+  in (("Ook.Ook?","Ook?Ook.","Ook.Ook.","Ook!Ook!"
+      ,"Ook.Ook!","Ook!Ook.","Ook!Ook?","Ook?Ook!"),f)
+
+{- | Tokenise the program -}
+tokenise :: String -> Tokens -> [Token]
+tokenise p ts@(r,l,i,d,inp,out,j,jm) =
+  tokenise'
+    (filter ((flip elem) (nub (concat [r, l, i, d, inp, out, j, jm]))) p) ts
+  where
+    tokenise' :: String -> Tokens -> [Token]
+    tokenise' p ts@(r,l,i,d,inp,out,j,jm) =
+      if r        `isPrefixOf` p then MRight : tokeniseAfter r   p ts
+      else if l   `isPrefixOf` p then MLeft  : tokeniseAfter l   p ts
+      else if i   `isPrefixOf` p then Inc    : tokeniseAfter i   p ts
+      else if d   `isPrefixOf` p then Dec    : tokeniseAfter d   p ts
+      else if inp `isPrefixOf` p then In     : tokeniseAfter inp p ts
+      else if out `isPrefixOf` p then Out    : tokeniseAfter out p ts
+      else if j   `isPrefixOf` p then JINZ   : tokeniseAfter j   p ts
+      else if jm  `isPrefixOf` p then JMatch : tokeniseAfter jm  p ts
+      else case p of
+             []     -> []
+             (_:np) -> tokenise' np ts
+    dropToken :: String -> String -> String
+    dropToken t p = drop (length t) p
+    tokeniseAfter :: String -> String -> Tokens -> [Token]
+    tokeniseAfter t p ts = tokenise' (dropToken t p) ts
+
+{- | Parse the program -}
+parse :: [Token] -> ([Stmt],[Token])
+parse [] = ([],[])
+parse (MRight:xs) = ((TMRight:st),r) where (st,r) = parse xs
+parse (MLeft:xs)  = ((TMLeft:st),r) where (st,r) = parse xs
+parse (Inc:xs)    = ((TInc:st),r) where (st,r) = parse xs
+parse (Dec:xs)    = ((TDec:st),r) where (st,r) = parse xs
+parse (In:xs)     = ((TIn:st),r) where (st,r) = parse xs
+parse (Out:xs)    = ((TOut:st),r) where (st,r) = parse xs
+parse (JINZ:xs)   = (TLoop lst:st,rr)
+                    where
+                      (lst,r) = parse xs
+                      (st,rr) = parse r
+parse (JMatch:xs) = ([],xs)
+
+{- | Interpret some brain fuck -}
+interpret :: (Machine -> IO ()) -> [Stmt] -> Machine -> IO ()
+interpret c [] x = c x
+interpret c (TMRight:xs)    (l,(h:r)) = interpret c xs ((h:l),r)
+interpret c (TMLeft:xs)     ((h:l),r) = interpret c xs (l,(h:r))
+interpret c (TInc:xs)       (l,(h:r)) = interpret c xs (l,(h+1:r))
+interpret c (TDec:xs)       (l,(h:r)) = interpret c xs (l,(h-1:r))
+interpret c (TIn:xs)        (l,(_:r)) =
+  do y <- isEOF
+     if y
+       then interpret c xs (l,(-1:r))
+       else do x <- getChar
+               interpret c xs (l,(ord x:r))
+interpret c (TOut:xs)       (l,(x:r)) = do putChar (chr x)
+                                           interpret c xs (l,x:r)
+interpret c (TLoop loop:xs) (l,(h:r)) =
+  if h == 0 then interpret c xs (l,(h:r))
+            else interpret (interpret c (TLoop loop:xs)) loop (l,(h:r))
diff --git a/CPBrainfuck.cabal b/CPBrainfuck.cabal
new file mode 100644
--- /dev/null
+++ b/CPBrainfuck.cabal
@@ -0,0 +1,17 @@
+Name:                CPBrainfuck
+Cabal-Version:       >= 1.2
+Version:             1.0
+Synopsis:            A simple Brainfuck interpretter.
+Description:         This is a very simple brainfuck interpretter, that's easy
+                     to understand.
+License:             BSD3
+License-file:        LICENSE
+Author:              Thomas Davie
+Maintainer:          Thomas Davie (tom.davie@gmail.com)
+category:            Compilers/Interpreters
+Data-Files:          README
+build-type:          Simple
+
+Executable bf
+  Build-Depends:        base >= 3.0,haskell98 >= 1.0
+  Main-is:              BF.hs
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+* Copyright (c) 2008, Thomas Davie
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * The names of the contributors may not be used to endorse or promote
+*       products derived from this software without specific prior written
+*       permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THOMAS DAVIE ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THOMAS DAVIE BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+                                  CPBrainfuck
+                                  ===========
+
+Runs brainfuck (and related languages) programs
+
+Install:
+========
+> runhaskell Setup.lhs configure
+> runhaskell Setup.lhs build
+> runhaskell Setup.lhs install (as root)
+
+Copyright (c) 2008 Thomas Davie
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
