sig ReadLine = peek [] Char | nom sig Abort = aborting [] {} abort [Abort] X abort = aborting ! {} default {[] X} [Abort ? X] [] X default d [x] = x default d [aborting ? k] = d! {[Abort] X} / {[] X} [] {[] X} e / d = {default d ? e!} if Bool then {[] X} else {[] X} [] X if tt then t else f = t! if ff then t else f = f! see Char [ReadLine, Abort] () see c = if (peek! =Char= c) then {()} else {abort!} eat Char [ReadLine, Abort] () eat c = see c >> nom! () >> Y [] Y _ >> y = y X << () [] X x << _ = x data List X = nil | X :: (List X) data SExp = atom (List Char) | SExp & SExp sexp [ReadLine, Abort] SExp sexp = ({see '.' >> abort!} / ({eat '(' >> open!} / ({see ')' >> abort!} / ({eat ' ' >> sexp!} / {atom (name!)} ))))! open [ReadLine, Abort] SExp open = ({see '.' >> abort!} / ({eat ' ' >> open!} / ({eat ')' >> atom nil} / {sexp! & cdr!} )))! cdr [ReadLine, Abort] SExp cdr = ({eat ' ' >> cdr!} / ({eat '.' >> (sexp! << close!)} / {open!} ))! close [ReadLine, Abort] () close = ({eat ' ' >> close!} / ({eat ')'} / {abort!} ))! elem Char (List Char) [] Bool elem c nil = ff elem c (c' :: cs) = if (c =Char= c') then {tt} else {elem c cs} nameChar [ReadLine, Abort] Char nameChar = if (elem (peek!) ('\n' :: (' ' :: ('(' :: (')' :: ('.' :: nil)))))) then {abort!} else {(peek! << nom!)} some {[ReadLine, Abort] X} [ReadLine, Abort] List X some p = (p!) :: many p many {[ReadLine, Abort] X} [ReadLine] List X many p = ({some p} / {nil})! name [ReadLine, Abort] List Char name = some nameChar data Maybe X = no | yes X let X in {X -> [] Y} [] Y let x in f = f x noBS (Maybe Char) [ReadLine ? X] [Console] X noBS _ [x] = x noBS no [peek ? k] = let inch! in {c -> noBS (yes c) ? k c} noBS (yes c) [peek ? k] = noBS (yes c) ? k c noBS _ [nom ? k] = noBS no ? k () data Stk X = (Stk X) -peek {Char -> [ReadLine, Abort] X} | (Stk X) -nom | root {[ReadLine, Abort] X} withBS (Stk X) (Maybe Char) [ReadLine, Abort, {} ? X] [Console] X withBS stk _ [x] = x withBS stk no [peek ? k] = let inch! in { '\b' -> pop stk | c -> withBS (stk -peek k) (yes c) ? k c } withBS stk (yes c) [peek ? k] = withBS stk (yes c) ? k c withBS stk (yes c) [nom ? k] = ouch c >> withBS (stk -nom) no ? k () withBS stk _ [aborting ? l] = pop stk note There's a need for indexing here, to prevent nom! before peek! pop (Stk X) [Console] X pop (stk -peek k) = withBS stk no ? k (peek!) pop (stk -nom) = ouch '\b' >> (ouch ' ' >> (ouch '\b' >> pop stk)) pop (root r) = withBS (root r) no ? r! main [Console] SExp main = withBS (root {sexp!}) no ? sexp! note main [Console, Abort] SExp main = noBS no ? sexp!