module NFA where
import AbsSyn
import CharSet ( CharSet, charSetToArray )
import DFS ( t_close, out )
import Map ( Map )
import qualified Map hiding ( Map )
import Util ( str, space )
import Control.Monad ( zipWithM, zipWithM_ )
import Data.Array ( Array, (!), array, listArray, assocs, bounds )
type NFA = Array SNum NState
data NState = NSt {
nst_accs :: [Accept Code],
nst_cl :: [SNum],
nst_outs :: [(CharSet,SNum)]
}
instance Show NState where
showsPrec _ (NSt accs cl outs) =
str "NSt " . shows accs . space . shows cl . space .
shows [ (charSetToArray c, s) | (c,s) <- outs ]
scanner2nfa:: Scanner -> [StartCode] -> NFA
scanner2nfa Scanner{scannerTokens = toks} startcodes
= runNFA $
do
start_states <- sequence (replicate (length startcodes) newState)
tok_states <- zipWithM do_token toks [0..]
zipWithM_ (tok_transitions (zip toks tok_states))
startcodes start_states
where
do_token (RECtx _scs lctx re rctx code) prio = do
b <- newState
e <- newState
rexp2nfa b e re
rctx_e <- case rctx of
NoRightContext ->
return NoRightContext
RightContextCode code' ->
return (RightContextCode code')
RightContextRExp re' -> do
r_b <- newState
r_e <- newState
rexp2nfa r_b r_e re'
accept r_e rctxt_accept
return (RightContextRExp r_b)
accept e (Acc prio code lctx rctx_e)
return b
tok_transitions toks_with_states start_code start_state = do
let states = [ s | (RECtx scs _ _ _ _, s) <- toks_with_states,
null scs || start_code `elem` map snd scs ]
mapM_ (epsilonEdge start_state) states
rexp2nfa :: SNum -> SNum -> RExp -> NFAM ()
rexp2nfa b e Eps = epsilonEdge b e
rexp2nfa b e (Ch p) = charEdge b p e
rexp2nfa b e (re1 :%% re2) = do
s <- newState
rexp2nfa b s re1
rexp2nfa s e re2
rexp2nfa b e (re1 :| re2) = do
rexp2nfa b e re1
rexp2nfa b e re2
rexp2nfa b e (Star re) = do
s <- newState
epsilonEdge b s
rexp2nfa s s re
epsilonEdge s e
rexp2nfa b e (Plus re) = do
s1 <- newState
s2 <- newState
rexp2nfa s1 s2 re
epsilonEdge b s1
epsilonEdge s2 s1
epsilonEdge s2 e
rexp2nfa b e (Ques re) = do
rexp2nfa b e re
epsilonEdge b e
type MapNFA = Map SNum NState
newtype NFAM a = N {unN :: SNum -> MapNFA -> (SNum, MapNFA, a)}
instance Monad NFAM where
return a = N $ \s n -> (s,n,a)
m >>= k = N $ \s n -> case unN m s n of
(s', n', a) -> unN (k a) s' n'
runNFA :: NFAM () -> NFA
runNFA m = case unN m 0 Map.empty of
(s, nfa_map, ()) ->
e_close (array (0,s1) (Map.toAscList nfa_map))
e_close:: Array Int NState -> NFA
e_close ar = listArray bds
[NSt accs (out gr v) outs|(v,NSt accs _ outs)<-assocs ar]
where
gr = t_close (hi+1,\v->nst_cl (ar!v))
bds@(_,hi) = bounds ar
newState :: NFAM SNum
newState = N $ \s n -> (s+1,n,s)
charEdge :: SNum -> CharSet -> SNum -> NFAM ()
charEdge from charset to = N $ \s n -> (s, addEdge n, ())
where
addEdge n =
case Map.lookup from n of
Nothing ->
Map.insert from (NSt [] [] [(charset,to)]) n
Just (NSt acc eps trans) ->
Map.insert from (NSt acc eps ((charset,to):trans)) n
epsilonEdge :: SNum -> SNum -> NFAM ()
epsilonEdge from to
| from == to = return ()
| otherwise = N $ \s n -> (s, addEdge n, ())
where
addEdge n =
case Map.lookup from n of
Nothing -> Map.insert from (NSt [] [to] []) n
Just (NSt acc eps trans) -> Map.insert from (NSt acc (to:eps) trans) n
accept :: SNum -> Accept Code -> NFAM ()
accept state new_acc = N $ \s n -> (s, addAccept n, ())
where
addAccept n =
case Map.lookup state n of
Nothing ->
Map.insert state (NSt [new_acc] [] []) n
Just (NSt acc eps trans) ->
Map.insert state (NSt (new_acc:acc) eps trans) n
rctxt_accept :: Accept Code
rctxt_accept = Acc 0 Nothing Nothing NoRightContext