Folks this is a parser for Context Free Grammars, for some reason when I go simplify the grammar trying to remove productions that substitute variables like in the case:
S -> A, A -> B, B -> a, it works perfectly and returns S -> a, the problem is when the root symbol is on the listthat must be replaced as in:
S -> aXa | bXb , X -> a | b | S | £(empty)
instead of returning
S -> aXa | bXb, X -> a | b | £ | aXa | bXb

it ruturns X as
X -> a | b | £ | S <- this S is wrong! it should return X -> a | b | £ | aXa | bXb! Im not sure about where is the mistake. If you can give me hints it would be grat. I will be checking the mail and also hanging over #haskell at freenode ifyou want to contact me directly. Thanks in advance for the help!

Victor
module CFG where
 
import Text.ParserCombinators.Parsec
{--import Data.Map--}
import Control.Monad (liftM)
import Data.Map (Map)
import qualified Data.Map as Map

data CFG t nt = CFG {terminals    :: [Symb t nt],
                     nonterminals :: [Symb t nt],
                     root         ::  Symb t nt ,
                    {-productions :: Map (Symb t nt) [(ProdName,[Symb t nt])]-}
                     productions :: Map (Symb t nt) [[Symb t nt]]}
                deriving (Eq,Ord,Show)

type Prod t nt = (ProdName,[Symb t nt])
 
type ProdName = String
 
data Symb t nt = Root
               | T t
               | NT nt
               | Empty
               deriving (Eq,Ord,Show)


{-Checks if the non-terminals are oki, the restriction that each NT must consist of a single symbol is already checked by the mapping structure here the only check needed id that the terminals and nonterminals sets are disjunct-}
nonterminal :: [Char] -> CharParser st (Symb Char Char)
nonterminal termchars = liftM NT (noneOf (" |\n"++termchars))

{-Now I try to check if a given symbol is a terminal-}
terminal :: [Char] -> CharParser st (Symb Char Char)
terminal termchars = liftM T (oneOf termchars)

{-Checks if it is a $ production, Ive used $ for empty prodution because GHC doesnt supports unicode YET :-) -}
empty :: CharParser st (Symb Char Char)
empty = do {char '$'; return Empty}


{-rhs termchars = production termchars `sepBy` string " | "-}
{- parseTest (rhs "sz") "sN | z" -}
{- rhs stands for right-hand-side -}
production termchars = (do empty; return [])
                       <|> many (terminal termchars <|> nonterminal termchars)

rhs termchars = production termchars `sepBy` string " | "

rule termchars = do x <- nonterminal termchars
                    string " -> "
                    ys <- rhs termchars
                    return (x, ys)


{-parseTest grammar (unlines ["termchars sz","start N","N -> sN | z"])-}
grammar = do string "termchars "; termchars <- many (noneOf " |\n"); newline
             string "start ";     root <- nonterminal termchars;     newline
             productionsList <- rule termchars `sepEndBy` newline
             return (CFG { terminals = map T termchars,
                           nonterminals = map fst productionsList,
                           root = root,
                           productions = Map.fromList productionsList
})

{-let cfg = run grammar "" (unlines ["termchars sz","start N","N -> sN | z"])-}
{-*CFG> let cfg = run grammar "" (unlines ["termchars sz","start N","N -> sN | z"])
Loading package parsec-1.0 ... linking ... done.
*CFG> cfg
CFG {terminals = [T 's',T 'z'], nonterminals = [NT 'N'], root = NT 'N', productions = {NT 'N':=[[T 's',NT 'N'],[T 'z']]}}
*CFG> start

<interactive>:1:0: Not in scope: `start'
*CFG> cfg
CFG {terminals = [T 's',T 'z'], nonterminals = [NT 'N'], root = NT 'N', productions = {NT 'N':=[[T 's',NT 'N'],[T 'z']]}}
*CFG> root cfg
NT 'N'
-}
run p name xs = case parse p name xs of
               	     Left  err -> error (show err)
       		     Right res -> res


{-Finds empty productions-}
{- *CFG> let cfg = run grammar "" (unlines ["termchars ab","start S","S -> aXa | bXb | $","X -> a | b | Y","Y -> $"])
*CFG> empties cfg
 [NT 'S',NT 'Y'] -}
empties cfg = Map.keys (Map.filter (any (==[])) (productions cfg))

{-cleanset cfg = Map.map ((filter (/=[Empty])) (productions cfg))-}
removeEmpties1 cfg = cfg { productions = prods'' }
    where
    prods    = productions cfg
    {-prods'   = Map.map (filter (/=[])) prods-}
    prods'   = Map.mapWithKey (\k -> if k == root cfg 
					then id 
					else filter (/=[])) 
				prods

    prods''  = Map.map (concatMap f) prods'
    f []     = [[]] 
    f (x:xs) | x `elem` empties cfg = map (x:) (f xs) ++ f xs
    	     | otherwise            = map (x:) (f xs)

removeEmpties :: (Ord t, Ord nt) => CFG t nt -> CFG t nt
removeEmpties = doToDeath removeEmpties1

doToDeath f x = findFixedPoint (iterate f x)
    where
    findFixedPoint (x:y:z)
        | x == y    = x
        | otherwise = findFixedPoint (y:z)


--remove useless
{-removeUseless (removeEmpties cfg)-}
useless cfg = Map.keys (Map.delete (root cfg)
                                 (Map.filter null (productions cfg)))

removeUseless cfg = cfg { productions = Map.map (map $ concatMap f)
                                                (productions cfg)
                                        `Map.difference`
                                        (Map.fromList $
                                         zip unwanted (repeat ())),
                          nonterminals = Map.keys (productions cfg) }
    where
    unwanted = useless cfg
    f x | x `elem` unwanted = []
        | otherwise         = [x]



-- remove replacers
{-let cfg = run grammar "" (unlines ["termchars ab","start S","S -> A","A -> B"])-}
{-removeReplacers cfg
CFG {terminals = [T 'a',T 'b'], nonterminals = [NT 'S',NT 'A'], root = NT 'S', productions = {NT 'A':=[[NT 'B']],NT 'S':=[[NT 'B']]}}-}

replacements :: Ord k => Map k k -> Map k k
replacements rmap = result
    where
    result = Map.map (\x -> case Map.lookup x result of
                            Nothing -> x
                            Just y  -> y) rmap

removeReplacers cfg = cfg { productions = prodssimp'',
                            nonterminals = Map.keys prodssimp''}
    where
    prodssimp = productions cfg

    replacers = Map.map (head . head) (Map.filter isReplacer prodssimp)
    isReplacer [[x]] = True
    isReplacer _     = False

    replace :: (Ord k, Ord a) => Map k [[a]] -> Map a a -> Map k [[a]]
    replace prods m = Map.map (map $ map f) prods
        where f x = case Map.lookup x m of
                    Nothing -> x
                    Just y  -> y

    prodssimp'  = replace prodssimp (replacements replacers)
    prodssimp'' = Map.filterWithKey (\k _ -> k == root cfg
                                             || not (Map.member k replacers))
                                    prodssimp' 







_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to