module Data.Cfg.Reachable (
reachables,
unreachables,
removeUnreachables
) where
import Data.Cfg.Cfg(Cfg(..), V(..), Vs)
import Data.Cfg.FreeCfg(FreeCfg(..))
import qualified Data.Set as S
reachables :: forall cfg t nt . (Cfg cfg t nt, Ord nt)
=> cfg t nt -> S.Set nt
reachables cfg = go [startSymbol cfg] S.empty
where
go :: [nt] -> S.Set nt -> S.Set nt
go [] seen = seen
go (nt : nts) seen
= if nt `S.member` seen
then go nts seen
else do
let seen' = S.insert nt seen
let vs = concat $ S.toList $ productionRules cfg nt
go (nts ++ [nt' | NT nt' <- vs]) seen'
unreachables :: forall cfg t nt . (Cfg cfg t nt, Ord nt)
=> cfg t nt -> S.Set nt
unreachables cfg = nonterminals cfg S.\\ reachables cfg
removeUnreachables :: forall cfg t nt . (Cfg cfg t nt, Ord nt)
=> cfg t nt -> FreeCfg t nt
removeUnreachables cfg = FreeCfg {
nonterminals' = res,
terminals' = terminals cfg,
productionRules' = pr,
startSymbol' = startSymbol cfg
}
where
res :: S.Set nt
res = reachables cfg
pr :: nt -> S.Set (Vs t nt)
pr nt = if nt `S.member` res
then productionRules cfg nt
else S.empty