-- | Analysis of a context-free grammar {-# LANGUAGE ScopedTypeVariables #-} module Data.Cfg.Analysis ( Analysis(..), mkAnalysis, Prediction, Predictions ) where import Data.Cfg.Augment import qualified Data.Cfg.Cfg as Cfg import Data.Cfg.FreeCfg import qualified Data.Cfg.Internal.FirstSet as I import qualified Data.Cfg.Internal.FollowSet as I import qualified Data.Cfg.Internal.Nullable as I import qualified Data.Cfg.Internal.PredictSet as I import Data.Cfg.Internal.PredictSet(Prediction, Predictions) import Data.Cfg.LookaheadSet import qualified Data.Map.Strict as M import qualified Data.Set as S -- | Analysis of a context-free grammar data Analysis t nt = Analysis { baseCfg :: FreeCfg t nt, -- ^ (a 'FreeCfg' equivalent to) the source grammar augmentedCfg :: FreeCfg (AugT t) (AugNT nt), -- ^ the augmented grammar nullables :: S.Set (AugNT nt), -- ^ the nonterminals in the grammar that can produce the -- empty string firstSet :: AugNT nt -> LookaheadSet t, -- ^ the first set of the nonterminal for the grammar firstsOfVs :: AugVs t nt -> LookaheadSet t, -- ^ the first set of a list of symbols followSet :: AugNT nt -> LookaheadSet t, -- ^ the follow set of the nonterminal for the grammar predictSet :: AugProduction t nt -> LookaheadSet t, -- ^ the predict set of the production isLL1 :: Bool, -- ^ 'True' iff the grammar is LL(1) ll1Info :: AugNT nt -> Predictions t nt -- ^ the productions for this nonterminal and the lookaheads -- that predict them } -- | Analyzes a context-free grammar mkAnalysis :: forall cfg t nt . (Cfg.Cfg cfg t nt, Ord nt, Ord t) => cfg t nt -> Analysis t nt mkAnalysis cfg = Analysis { baseCfg = bcfg, augmentedCfg = cfg', nullables = ns, firstSet = fs, firstsOfVs = I.firstsOfVs fs, followSet = fols, predictSet = predict, isLL1 = isLL1', ll1Info = (ll1InfoMap M.!) } where bcfg = toFreeCfg cfg cfg' = augmentCfg bcfg ns = I.nullables cfg' fsm = I.firstSetMap cfg' fs nt = fsm M.! nt folm = I.followSetMap cfg' fs fols nt = folm M.! nt predict = I.predictSet fs fols ll1InfoMap = I.ll1InfoMap cfg' predict isLL1' = I.isLL1 ll1InfoMap