rendered paste bodyimport Data.List
import Data.Char
doSubst :: (String, String) -> String -> (Bool, String, String)
doSubst subst str = doSubst' subst str
doSubst' :: (String, String) -> String -> (Bool, String, String)
doSubst' _ [] = (False, "", [])
doSubst' (from, to) target@(t:ts) = if from `isPrefixOf` target
then if head to == '~'
then (True, tail to, drop (length from) target)
else (True, "", to ++ drop (length from) target)
else let (b, o, s) = doSubst' (from, to) ts in (b, o, t:s)
runThue :: [(String, String)] -> String -> ([String], String)
runThue substs init = runThue' substs init []
runThue' :: [(String, String)] -> String -> [String] -> ([String], String)
runThue' substs init out = case runThue'' substs init [] False of
(False, _, _) -> (out, init)
(True, newout, newinit) -> runThue' substs newinit (out++newout)
runThue'' :: [(String, String)] -> String -> [String] -> Bool -> (Bool, [String], String)
runThue'' [] init out sure = (sure, out, init)
runThue'' (subst:substs) init out sure = case doSubst subst init of
(False, _, _) -> runThue'' substs init out sure
(True, outinc, newinit) -> if outinc == ""
then runThue'' substs newinit out True
else runThue'' substs newinit (out ++ [outinc]) True
dropAllWS :: [String] -> [String]
dropAllWS strs = filter (\str -> str /= "") $ map (\str -> filter (\chr -> and [chr /= ' ', chr /= '\n']) str) strs
pairUp :: [String] -> [(String, String)]
pairUp str = pairUp' str []
pairUp' :: [String] -> [(String, String)] -> [(String, String)]
pairUp' (a:b:str) pairs = pairUp' str ((a, b):pairs)
pairUp' [] pairs = pairs
removeRedundantLfs :: String -> String
removeRedundantLfs str = removeRedundantLfs' str "" True
removeRedundantLfs' :: String -> String -> Bool -> String
removeRedundantLfs' "" acc _ = acc
removeRedundantLfs' (fst:rst) acc lastwaslf =
if and [fst=='\n', lastwaslf]
then removeRedundantLfs' rst acc True
else removeRedundantLfs' rst (acc++[fst]) (fst=='\n')
toTokens :: String -> [String]
toTokens str = toTokens' str [] ""
toTokens' :: String -> [String] -> String -> [String]
toTokens' [] tokens lasttoken = tokens ++ [lasttoken]
toTokens' (fst:rest) tokens lasttoken = if "::=" `isPrefixOf` rest
then toTokens' (drop 3 rest) (tokens ++ [lasttoken ++ [fst]]) ""
else if "\n" `isPrefixOf` rest
then toTokens' (drop 1 rest) (tokens ++ [lasttoken ++ [fst]]) ""
else toTokens' rest tokens (lasttoken ++ [fst])
finalize :: [(String, String)] -> ([(String, String)], String)
finalize strs = let clean = strs in
((tail clean), snd $ head clean) -- first rule should be ("::=", initial string)
main = do
putStr "Input file: "
ifile <- getLine
s <- readFile ifile
let parsed =finalize $ pairUp $ dropAllWS $ toTokens $ removeRedundantLfs s in
let result = runThue (fst parsed) (snd parsed) in
print result