diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for BitcoinAnalysis
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Rick Klomp (c) 2018
+
+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.
+
+    * Neither the name of Rick Klomp nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,80 @@
+# SCRIPT Writer
+![Alt text](.imgs/extendedScriptExample.png?raw=true "Example")
+## ESCRIPT: a human friendly language for programming Bitcoin scripts
+
+SCRIPT Writer defines a human friendly Bitcoin SCRIPT language and provides a set of functions to translate programs written in this extended language (called ESCRIPT, which is an acronym for Extended SCRIPT) to Bitcoin SCRIPT bytecode. See below for the syntax description, or visit https://vm100.cs.stir.ac.uk/~rkl/docu.php.
+
+The extended language is a superset of the bytecode SCRIPT language. This means that it is possible to define a script partially using extended syntax constructions, and partially in direct streams of bytecode. Bytecodes are passed through the parser as-is.
+
+#### Installation
+Dependency: Haskell's Stack (https://docs.haskellstack.org/en/stable/install_and_upgrade/)
+
+In the root directory of this repository run:
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\# On some machines it is required to first manually install happy:<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stack install happy<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\# Install Script Writer and all of its dependencies (other than Happy)<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stack install
+
+
+#### Applying the tool
+
+The executable (SCRIPTWriter-exe) can be executed in any directory of this repository through Stack as follows: stack exec SCRIPTWriter-exe -- _arguments_
+
+Call SCRIPTWriter-exe, with the custom script in stdin, and optionally passing some arguments (call the tool with first argument 'help' for information regarding arguments)
+
+For example, if file scriptA contains a script written in the human friendly language, run the following in Bash: stack exec SCRIPTWriter-exe -- < scriptA
+
+Some example scripts can be found in folder scripts/
+
+#### The custom syntax
+
+The supported syntax is described below.\
+Instructions on how to interpret the description:\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- The "*" symbol specifies a repeated parsing of 0 or more times\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- The "+" symbol specifies a repeated parsing of 1 or more times\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- The "|" specifies an or (either parses following the left hand\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;side or the right hand side)\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- The ".." specifies a range of allowed characters.\
+Any amount of whitespace is allowed between each instruction and between\
+the PUSH keyword and the subsequent bytestring. Parsing starts by applying the\
+Start rule. Anything after "\#" on a line is treated as a comment (similar to how comments work in Bash).\
+
+
+Start := Instruction*
+
+Instruction := Push | Mnemonic | Byte\
+Push := "PUSH" Bytestring  | "PUSH" Integer\
+Integer := "i" Num+ | "i-" Num+\
+Num := "0".."9"\
+Bytestring := Byte+\
+Byte := Hexadecimal Hexadecimal\
+Hexadecimal := "0".."9" | "a".."f" | "A".."F"\
+Mnemonic := "OP_0" | "OP_FALSE" | "OP_PUSHDATA1" | "OP_PUSHDATA2"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_PUSHDATA4" | "OP_1NEGATE" | "OP_RESERVED" | "OP_1"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_2" | "OP_3" | "OP_4" | "OP_5"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_6" | "OP_7" | "OP_8" | "OP_9"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_10" | "OP_11" | "OP_12" | "OP_13"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_14" | "OP_15" | "OP_16" | "OP_NOP"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_VER" | "OP_IF" | "OP_NOTIF" | "OP_VERIF"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_VERNOTIF" | "OP_ELSE" | "OP_ENDIF" | "OP_VERIFY"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_RETURN" | "OP_TOALTSTACK" | "OP_FROMALTSTACK" | "OP_2DROP"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_2DUP" | "OP_3DUP" | "OP_2OVER" | "OP_2ROT"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_2SWAP" | "OP_IFDUP" | "OP_DEPTH" | "OP_DROP"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_DUP" | "OP_NIP" | "OP_OVER" | "OP_PICK"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_ROLL" | "OP_ROT" | "OP_SWAP" | "OP_TUCK"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_CAT" | "OP_SUBSTR" | "OP_LEFT" | "OP_RIGHT"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_SIZE" | "OP_INVERT" | "OP_AND" | "OP_OR"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_XOR" | "OP_EQUAL" | "OP_EQUALVERIFY" | "OP_RESERVED1"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_RESERVED2" | "OP_1ADD" | "OP_1SUB" | "OP_2MUL"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_2DIV" | "OP_NEGATE" | "OP_ABS" | "OP_NOT"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_0NOTEQUAL" | "OP_ADD" | "OP_SUB" | "OP_MUL"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_DIV" | "OP_MOD" | "OP_LSHIFT" | "OP_RSHIFT"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_BOOLAND" | "OP_BOOLOR" | "OP_NUMEQUAL" | "OP_NUMEQUALVERIFY"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_NUMNOTEQUAL" | "OP_LESSTHAN" | "OP_GREATERTHAN" | "OP_LESSTHANOREQUAL"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_GREATERTHANOREQUAL" | "OP_MIN" | "OP_MAX" | "OP_WITHIN"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_RIPEMD160" | "OP_SHA1" | "OP_SHA256" | "OP_HASH160"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_HASH256" | "OP_CODESEPARATOR" | "OP_CHECKSIG" | "OP_CHECKSIGVERIFY"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_CHECKMULTISIG" | "OP_CHECKMULTISIGVERIFY" | "OP_NOP1" | "OP_CHECKLOCKTIMEVERIFY"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_CHECKSEQUENCEVERIFY" | "OP_NOP4" | "OP_NOP5" | "OP_NOP6"\
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| "OP_NOP7" | "OP_NOP8" | "OP_NOP9" | "OP_NOP10"
diff --git a/SCRIPTWriter.cabal b/SCRIPTWriter.cabal
new file mode 100644
--- /dev/null
+++ b/SCRIPTWriter.cabal
@@ -0,0 +1,63 @@
+-- This file has been generated from package.yaml by hpack version 0.27.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 1c6bbe5bc9b52aa84b36d7f60d203b0659e0417aa622f18a395aa7f0818cd7b2
+
+name:           SCRIPTWriter
+version:        1.0
+description:    Please see the README on Github at https://github.com/RKlompUU/SCRIPTWriter
+homepage:       https://github.com/RKlompUU/SCRIPTWriter
+bug-reports:    https://github.com/RKlompUU/SCRIPTWriter/issues
+author:         Rick Klomp
+maintainer:     r.klomp@cs.stir.ac.uk
+copyright:      2018 Rick Klomp
+category:       language, Bitcoin, SCRIPT
+synopsis:       ESCRIPT: a human friendly language for programming Bitcoin scripts
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/RKlompUU/SCRIPTWriter
+
+library
+  exposed-modules:
+      Bitcoin.Script.Parser.API
+  other-modules:
+      Paths_SCRIPTWriter
+      Bitcoin.Script.Parser.AST
+      Bitcoin.Script.Parser.Standard
+      Bitcoin.Script.Parser.SyntaxExtension
+      Bitcoin.Script.Parser.Parser
+  hs-source-dirs:
+      lib
+  build-depends:
+      base >=4.7 && < 5.0,
+      binary,
+      mtl,
+      containers,
+      uu-tc,
+      bytestring >= 0.10.8.1,
+      bitcoin-script,
+      bitcoin-hs,
+      array >= 0.5.2.0
+  default-language: Haskell2010
+
+executable SCRIPTWriter-exe
+  main-is: Main.hs
+  other-modules:
+      Paths_SCRIPTWriter
+  hs-source-dirs:
+      exe
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+    base >=4.7 && < 5.0,
+    SCRIPTWriter
+  default-language: Haskell2010
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/exe/Main.hs b/exe/Main.hs
new file mode 100644
--- /dev/null
+++ b/exe/Main.hs
@@ -0,0 +1,37 @@
+module Main where
+
+import System.IO
+import System.Exit
+import System.Environment
+
+import Data.List
+import Data.Maybe
+
+import Bitcoin.Script.Parser.API
+
+printHelp :: IO ()
+printHelp = do
+  putStrLn $ "Send the script, written in the extended language, through the std_in, and don't pass any arguments.\n" ++ languageDescription
+  exitFailure
+
+readStdin :: IO String
+readStdin = do
+  done <- isEOF
+  if done
+    then return ""
+    else do
+      line <- getLine
+      lines <- readStdin
+      return $ line ++ ('\n' : lines)
+
+main :: IO ()
+main = do
+  args <- getArgs
+  if null args
+    then do
+      res <- eScriptToBytecode <$> readStdin
+      case res of
+        Left err -> putStrLn err
+        Right scrpt -> putStrLn scrpt
+      return ()
+    else printHelp
diff --git a/lib/Bitcoin/Script/Parser/API.hs b/lib/Bitcoin/Script/Parser/API.hs
new file mode 100644
--- /dev/null
+++ b/lib/Bitcoin/Script/Parser/API.hs
@@ -0,0 +1,40 @@
+module Bitcoin.Script.Parser.API (
+  Bitcoin.Script.Parser.SyntaxExtension.languageDescription,
+  Bitcoin.Script.Parser.AST.ScriptAST(..),
+  eScriptToBytecode,
+  eScriptToScriptOps,
+  eScriptToAST
+) where
+
+import Bitcoin.Script.Parser.SyntaxExtension
+import Bitcoin.Script.Parser.AST
+import Bitcoin.Script.Parser.Parser
+
+import qualified Data.ByteString.Lazy.Char8 as B
+import Data.Bitcoin.Script
+
+-- |'eScriptToBytecode' translates a script, written in the extended language, to
+-- Bitcoin script bytecode (in 'String' format). Returns 'Right' 'String' upon successful translation,
+-- and 'Left' 'String' otherwise.
+eScriptToBytecode :: String -> Either String String
+eScriptToBytecode cScrpt =
+  unsugar cScrpt
+
+-- |'eScriptToScriptOps' translates a script, written in the extended language, to
+-- a list of SCRIPT instructions. Returns 'Right' ['ScriptOp'] upon successful translation,
+-- and 'Left' 'String' otherwise.
+eScriptToScriptOps :: String -> Either String [ScriptOp]
+eScriptToScriptOps cScrpt =
+  scriptOps
+  <$> decode
+  <$> B.pack
+  <$> eScriptToBytecode cScrpt
+
+-- |'eScriptToAST' translates a script, written in the extended language, to
+-- an Abstract Syntax Tree (with nested true and false branches of If Then Else).
+-- Returns 'Right' 'ScriptAST' upon successful translation, and 'Left' 'String' otherwise.
+eScriptToAST :: String -> Either String ScriptAST
+eScriptToAST cScrpt =
+  runFillLabels
+  <$> buildAST
+  <$> eScriptToScriptOps cScrpt
diff --git a/lib/Bitcoin/Script/Parser/AST.hs b/lib/Bitcoin/Script/Parser/AST.hs
new file mode 100644
--- /dev/null
+++ b/lib/Bitcoin/Script/Parser/AST.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE GADTs #-}
+module Bitcoin.Script.Parser.AST where
+
+import Data.Bitcoin.Script.Types
+
+import qualified Data.ByteString as BS
+import Bitcoin.Script.Parser.Standard
+
+type Label = Int
+
+data ScriptAST where
+  -- |'ScriptITE':  Location OP_IF -> True branch -> Location OP_ELSE -> False branch -> Location OP_ENDIF -> Continuation
+  ScriptITE  :: Label -> ScriptAST -> Label -> ScriptAST -> Label -> ScriptAST -> ScriptAST
+  -- |'ScriptOp':   Location op -> op -> Continuation
+  ScriptOp   :: Label -> ScriptOp  -> ScriptAST -> ScriptAST
+  ScriptTail :: ScriptAST
+
+instance Show ScriptAST where
+  show (ScriptOp l (OP_PUSHDATA bs _) cont) = show l ++ ":\tBS_" ++ show (BS.length bs) ++ " " ++ printBSInHex bs ++ ";\n" ++ show cont
+  show (ScriptOp l op cont) = show l ++ ":\t" ++ show op ++ ";\n" ++ show cont
+  show (ScriptITE ifLbl b0 elseLbl b1 fiLbl cont) =
+    show ifLbl ++ ":\tIF {\n" ++
+    show b0 ++
+    show elseLbl ++ ":\t} ELSE {\n" ++
+    show b1 ++
+    show fiLbl ++ ":\t}\n" ++
+    show cont
+  show ScriptTail = ""
+
+
+runFillLabels :: ScriptAST -> ScriptAST
+runFillLabels scrpt = evalCounter (fillLabels scrpt)
+
+fillLabels :: ScriptAST -> CounterState ScriptAST
+fillLabels (ScriptITE _ b0 _ b1 _ cont) = do
+  ifLbl <- tickCounter
+  b0' <- fillLabels b0
+  elseLbl <- tickCounter
+  b1' <- fillLabels b1
+  fiLbl <- tickCounter
+  cont' <- fillLabels cont
+  return $ ScriptITE ifLbl b0' elseLbl b1' fiLbl cont'
+fillLabels (ScriptOp _ op cont) = do
+  lblOp <- tickCounter
+  cont' <- fillLabels cont
+  return $ ScriptOp lblOp op cont'
+fillLabels ScriptTail = return ScriptTail
diff --git a/lib/Bitcoin/Script/Parser/Parser.y b/lib/Bitcoin/Script/Parser/Parser.y
new file mode 100644
--- /dev/null
+++ b/lib/Bitcoin/Script/Parser/Parser.y
@@ -0,0 +1,39 @@
+{
+module Bitcoin.Script.Parser.Parser where
+
+import Data.Bitcoin.Script.Types
+import Bitcoin.Script.Parser.AST
+}
+
+%name buildAST
+%tokentype { ScriptOp }
+%error { parseError }
+
+%token
+  if    { OP_IF }
+  ifn   { OP_NOTIF }
+  else  { OP_ELSE }
+  fi    { OP_ENDIF }
+  ifdup { OP_IFDUP }
+  op    { $$ }
+
+%%
+
+scriptAst : stmnts { $1 }
+
+stmnts : if stmnts else stmnts fi stmnts { ScriptITE 0 $2 0 $4 0 $6 }
+       | if stmnts fi stmnts { ScriptITE 0 $2 0 ScriptTail 0 $4 }
+       | ifn stmnts else stmnts fi stmnts { ScriptITE 0 $4 0 $2 0 $6 }
+       | ifn stmnts fi stmnts { ScriptITE 0 ScriptTail 0 $2 0 $4 }
+       | ifdup stmnts { ScriptOp 0 OP_DUP $ ScriptITE 0 (ScriptOp 0 OP_DUP ScriptTail) 0
+                                                        (ScriptOp 0 OP_DROP ScriptTail) 0
+                                                        $2 }
+       | op stmnts { ScriptOp 0 $1 $2 }
+       | { ScriptTail }
+
+
+{
+
+parseError t = error $ "Parse error.. " ++ show t
+
+}
diff --git a/lib/Bitcoin/Script/Parser/Standard.hs b/lib/Bitcoin/Script/Parser/Standard.hs
new file mode 100644
--- /dev/null
+++ b/lib/Bitcoin/Script/Parser/Standard.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Bitcoin.Script.Parser.Standard where
+
+import qualified Data.Typeable as T
+import qualified Data.Data as TD
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Builder as BSB
+import qualified Data.ByteString.Lazy.Char8 as BS8L
+
+import Control.Monad.State.Lazy
+
+import Prelude hiding (catch)
+import System.IO.Error hiding (catch)
+
+import Data.Maybe
+import Data.List
+
+type CounterState a = State Int a
+
+groupList :: [a] -> Int -> [[a]]
+groupList xs n =
+  filter (not . null)
+  $ map (\i -> take n $ drop (i*n) xs) [0..(length xs) `div` n]
+
+replaceX :: Eq a => (a,a) -> [a] -> [a]
+replaceX _ [] = []
+replaceX (f,t) (x:xs)
+  | f == x = t : replaceX (f,t) xs
+  | True   = x : replaceX (f,t) xs
+
+replaceXs :: Eq a => [([a], [a])] -> [a] -> [a]
+replaceXs _ [] = []
+replaceXs xss ys =
+  case find isJust (map (\(xs,xs') -> if xs == ys then Just (xs,xs') else Nothing) xss) of
+    Just (Just (xs,xs')) -> xs' ++ replaceXs xss (drop (length xs) ys)
+    otherwise            -> head ys : replaceXs xss (tail ys)
+
+(!?) :: [a] -> Int -> Maybe a
+[] !? _ = Nothing
+(x:xs) !? i
+  | i < 0  = Nothing
+  | i == 0 = Just x
+  | i > 0  = xs !? (i - 1)
+
+replace :: Eq a => (a, [a]) -> [a] -> [a]
+replace (x,x') xs
+  = concatMap (\y -> if x == y then x' else [y]) xs
+
+replaceIndex :: [a] -> Int -> a -> [a]
+replaceIndex xs i x =
+  take i xs ++ [x] ++ drop (i+1) xs
+
+printBSInHex :: BS.ByteString -> String
+printBSInHex = show . BSB.toLazyByteString . BSB.byteStringHex
+
+hexBS2Str :: BS.ByteString -> String
+hexBS2Str = BS8L.unpack . BSB.toLazyByteString . BSB.byteStringHex
+
+tickCounter :: CounterState Int
+tickCounter = do
+  i <- get
+  put (i+1)
+  return i
+
+evalCounter :: CounterState a -> a
+evalCounter f = evalState f 0
+
+
+ccEq :: (TD.Data a) => a -> TD.Constr -> Bool
+ccEq e c = TD.toConstr e == c
+
+
+{-
+class CC a where
+  cc :: a -> TD.Constr
+
+instance TD.Data a => CC a where
+  cc = TD.toConstr
+
+instance CC a => CC (b -> a) where
+  cc f = cc (f undefined)
+-}
diff --git a/lib/Bitcoin/Script/Parser/SyntaxExtension.hs b/lib/Bitcoin/Script/Parser/SyntaxExtension.hs
new file mode 100644
--- /dev/null
+++ b/lib/Bitcoin/Script/Parser/SyntaxExtension.hs
@@ -0,0 +1,132 @@
+module Bitcoin.Script.Parser.SyntaxExtension (unsugar, languageDescription) where
+
+import Prelude hiding ((<$>), (<*), (*>), (<*>))
+
+import ParseLib.Simple
+import qualified Data.ByteString.Lazy        as BSL
+import Data.Bitcoin.Script hiding (decode)
+import Data.Binary (decode)
+
+import Numeric (showHex)
+
+import Bitcoin.Script.Integer (asByteString)
+import Data.List
+
+import Bitcoin.Script.Parser.Standard
+
+type SParser a = Parser Char a
+
+-- |'languageDescription' generates a 'String' that documents what is supported
+-- in this custom Bitcoin SCRIPT syntax.
+languageDescription :: String
+languageDescription =
+  let mnemonics = map (intercalate " | ")
+                $ groupList (map (\(m,_) -> "\"" ++ m ++ "\"") memnomic2Hex) 4
+  in "The supported syntax is described below.\n\
+     \Instructions on how to interpret the description:\n\
+     \\t - The \"*\" symbol specifies a repeated parsing of 0 or more times\n\
+     \\t - The \"+\" symbol specifies a repeated parsing of 1 or more times\n\
+     \\t - The \"|\" specifies an or (either parses following the left hand\n\
+     \\t\t side or the right hand side)\n\
+     \\t - The \"..\" specifies a range of allowed characters.\n\
+     \Any amount of whitespace is allowed between each instruction and between\n\
+     \the PUSH keyword and the subsequent bytestring. Parsing starts by applying\n\
+     \Start rule. Anything after \"#\" on a line is treated as a comment (similar\n\
+     \to how comments work in Bash).\n\n\n\
+     \Start := (Instruction | Byte)*\n\n\
+     \Instruction := Push | Mnemonic\n\
+     \Push := \"PUSH\" Bytestring | \"PUSH\" Integer\n\
+     \Integer := \"i\" Num+ | \"i-\" Num+\n\
+     \Num := \"0\"..\"9\"\n\
+     \Bytestring := Byte+\n\
+     \Byte := Hexadecimal Hexadecimal\n\
+     \Hexadecimal := \"0\"..\"9\" | \"a\"..\"f\" | \"A\"..\"F\"\n\
+     \Mnemonic := " ++
+     intercalate ("\n" ++ take (length "Mnemonic :") (repeat ' ') ++ "| ") mnemonics
+
+-- |'unsugar' translates a script (of type 'String') written in the custom syntax
+-- supported by this tool to a serialized script format 'String'. It returns 'Left' 'String'
+-- if the given script contains syntax errors, and 'Right' 'String' if translation was
+-- successful.
+unsugar :: String -> Either String String
+unsugar str =
+  let res = parse sugarsParser str
+  in if null res
+      then Left "Failed to parse script"
+      else Right $ fst $ head $ res
+
+sugarsParser :: SParser String
+sugarsParser =
+  concat <$> many (stripwhite *> atom) <* stripwhite <* eof
+
+atom :: SParser String
+atom =
+  (const "" <$> comment)
+  <|> push
+  <|> opKeyword
+  <|> byte
+
+push :: SParser String
+push =
+  pushit <$> (token "PUSH" *> stripwhite *> num)
+  where pushit bytes
+          | numBytes <= 75 = numOp ++ bytes
+          | numBytes > 75 && numBytes < 256 = "4c" ++ numOp ++ bytes
+          | numBytes >= 256 && numBytes < 2^16 = "4d" ++ numOp ++ bytes
+          | numBytes >= 2^16 = "4e" ++ numOp ++ bytes
+          where numBytes = div (length bytes) 2
+                numOp = let str = showHex numBytes ""
+                            str' = if odd (length str)
+                                    then "0" ++ str
+                                    else str
+                        in concat . reverse
+                           $ map (\i -> take 2 $ drop (i*2) str') [0..length str' `div` 2]
+
+num :: SParser String
+num =
+  int
+  <|> concat <$> many byte
+
+comment :: SParser String
+comment =
+  (:) <$> symbol '#' <*> greedy (satisfy (/= '\n'))
+
+opKeyword :: SParser String
+opKeyword =
+  choice (map (\(mem,bs) -> const bs <$> token mem) memnomic2Hex)
+
+byte :: SParser String
+byte =
+  (\a b -> [a,b]) <$> satisfy isHexChar <*> satisfy isHexChar
+
+int :: SParser String
+int =
+  hexInt <$> (symbol 'i' *> integer)
+
+-- |'hexInt' translates an 'Int' to a hexadecimal 'String' (in same endianness as
+-- the integers in SCRIPT).
+hexInt :: Int -> String
+hexInt i =
+  hexBS2Str $ asByteString (fromIntegral i)
+
+isHexChar :: Char -> Bool
+isHexChar c
+  | any (==c) ['0'..'9'] = True
+  | any (==c) ['a'..'f'] = True
+  | any (==c) ['A'..'F'] = True
+  | otherwise = False
+
+memnomic2Hex :: [(String, String)]
+memnomic2Hex =
+  let autoSet = map (\op -> (show $ (decode (BSL.singleton op) :: ScriptOp), hexBS2Str $ BSL.toStrict $ BSL.singleton op))
+              $ [0x4f..0xb9]
+      manualSet = [("OP_0", "00"),
+                   ("OP_FALSE", "00"),
+                   ("OP_PUSHDATA1", "4c"),
+                   ("OP_PUSHDATA2", "4d"),
+                   ("OP_PUSHDATA4", "4e")]
+  in manualSet ++ autoSet
+
+stripwhite :: SParser ()
+stripwhite =
+  const () <$> greedy (choice (map symbol [' ', '\n', '\r', '\t']))
