Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
206 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,23 @@ | ||
module CFG.Examples (balancedParentheses, sillyGrammar, sillyGrammar2) | ||
where | ||
|
||
import CFG.Helpers.CNF | ||
import CFG.Types | ||
import CFG.Types | ||
|
||
-- | Example grammar: balanced parenthese. | ||
import qualified CFG.Helpers.CNF as CNF | ||
import CFG.Read | ||
|
||
fromRight :: Either String a -> a | ||
fromRight = either error id | ||
|
||
-- | Example grammar: balanced parentheses. | ||
balancedParentheses :: CompiledCNFGrammar | ||
balancedParentheses = | ||
-- S -> SS | LH | LR | ||
-- H -> SR | ||
-- L -> '(' | ||
-- R -> ')' | ||
listToGrammar | ||
[ ruleNonTerminal "S" [ ("S","S"), ("L","H"), ("L","R")] | ||
, ruleNonTerminal "H" [("S","R")] | ||
, ruleTerminal "L" '(' | ||
, ruleTerminal "R" ')' | ||
] | ||
balancedParentheses = CNF.compileGrammar . fromRight . readCNFGrammar $ | ||
"S -> SS, S -> LH, S -> LR, H -> SR, L -> (, R -> )" | ||
|
||
sillyGrammar :: CompiledCNFGrammar | ||
sillyGrammar = | ||
listToGrammar | ||
[ ruleNonTerminal "S" [("S1", "S2")] | ||
, ruleTerminal "S1" 'o' | ||
, ruleTerminal "S2" 'o' ] | ||
sillyGrammar = CNF.compileGrammar . fromRight . readCNFGrammar $ | ||
"S -> S1S2, S1 -> o, S2 -> o" | ||
|
||
sillyGrammar2 :: CompiledCNFGrammar | ||
sillyGrammar2 = | ||
listToGrammar | ||
[ ruleNonTerminal "S" [("S", "S"), ("S1", "S1")] | ||
, ruleTerminal "S1" '1' | ||
, ruleTerminal "S1" '0' ] | ||
sillyGrammar2 = CNF.compileGrammar . fromRight . readCNFGrammar $ | ||
"S -> SS, S -> S1S1, S1 -> 1, S1 -> 0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,69 @@ | ||
-- | Helpers for working with general context-free grammars. | ||
module CFG.Helpers.CFG ( | ||
-- * Helpers for constructing the grammar. | ||
ruleTerminal, ruleNonTerminal | ||
-- * Basic helpers. | ||
ruleName, ruleNumber, isNonTerminalRule, nonTerminalRuleProductions | ||
-- * Monad for fresh names. | ||
,NameMonad, runNameMonad, freshName, rememberName | ||
) | ||
where | ||
|
||
import CFG.Types | ||
|
||
ruleTerminal :: RuleName -> Char -> NamedCFGRule | ||
ruleTerminal name prod = CFGTerminalRule name (charToSymbol prod) | ||
import Control.Monad.State | ||
import qualified Data.Set as S | ||
|
||
ruleNonTerminal :: RuleName -> [[RuleName]] -> NamedCFGRule | ||
ruleNonTerminal name prods = CFGNonTerminalRule name prods | ||
-- Basic helpers | ||
ruleName :: NamedCFGRule -> RuleName | ||
ruleName (CFGTerminalRule name _) = name | ||
ruleName (CFGNonTerminalRule name _) = name | ||
|
||
ruleNumber :: NumberedCFGRule -> RuleNumber | ||
ruleNumber (CFGTerminalRule num _) = num | ||
ruleNumber (CFGNonTerminalRule num _) = num | ||
|
||
isNonTerminalRule :: CFGRule a -> Bool | ||
isNonTerminalRule (CFGNonTerminalRule _ _) = True | ||
isNonTerminalRule _ = False | ||
|
||
nonTerminalRuleProductions :: CFGRule a -> [[a]] | ||
nonTerminalRuleProductions (CFGNonTerminalRule _ prods) = prods | ||
nonTerminalRuleProductions _ = error "Non-terminal rule expected!" | ||
|
||
|
||
-- Monad for generating fresh names. | ||
data NameState = NameState { nameStateCounter :: !Int | ||
, nameStateSet :: !(S.Set RuleName) } | ||
deriving Show | ||
type NameMonad = State NameState | ||
|
||
-- | Initial state, for using in conjunction with 'runState'. | ||
runNameMonad :: S.Set RuleName -> NameMonad a -> a | ||
runNameMonad s act = fst $ runState act (NameState 0 s) | ||
|
||
-- | Generate a fresh name. | ||
freshName :: NameMonad RuleName | ||
freshName = do | ||
c <- getCounter | ||
incCounter | ||
let n = "Z" ++ (show c) | ||
hasSeen <- nameSetContains n | ||
if hasSeen | ||
then freshName | ||
else do rememberName n | ||
return n | ||
where | ||
getCounter :: NameMonad Int | ||
getCounter = gets nameStateCounter | ||
|
||
incCounter :: NameMonad () | ||
incCounter = modify | ||
(\s -> s { nameStateCounter = (+1) . nameStateCounter $ s }) | ||
|
||
nameSetContains :: RuleName -> NameMonad Bool | ||
nameSetContains n = S.member n `fmap` gets nameStateSet | ||
|
||
-- | Remember a given name. A remembered name will never be produced by | ||
-- 'freshName'. | ||
rememberName :: RuleName -> NameMonad () | ||
rememberName n = modify | ||
(\s -> s { nameStateSet = S.insert n . nameStateSet $ s}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters