yapb-0.2.2: src/parserlib/LoadAutomaton.hs
module LoadAutomaton where
import AutomatonType
import SaveProdRules(tokenizeLhs)
import System.IO
import Text.Read (readMaybe)
import Data.Char (isSpace)
loadAutomaton :: String -> String -> String
-> IO (ActionTable, GotoTable, ProdRules)
loadAutomaton grammarFileName actionTblFileName gotoTblFileName = do
grammarStr <- readFile grammarFileName
actionTblStr <- readFile actionTblFileName
gotoTblStr <- readFile gotoTblFileName
actionTbl <- loadActionTbl actionTblStr
gotoTbl <- loadGotoTbl gotoTblStr
prodRules <- loadProdRules grammarStr
return (actionTbl, gotoTbl, prodRules)
-- Load action table
loadActionTbl :: String -> IO ActionTable
loadActionTbl str = tokenizeStateNumInAction str
tokenizeStateNumInAction :: String -> IO ActionTable
tokenizeStateNumInAction str =
case lex str of
[] -> return []
[("", therest)] -> return []
[(stateNum, therest)] -> do
(terminal, action, actTbl) <- tokenizeTerminalInAction therest
case readMaybe stateNum :: Maybe Int of
Just stateNum_i -> return $ ((stateNum_i, terminal), action) : actTbl
Nothing -> error $ "[tokenizeStateNumInAction] Unexpected state number\n" ++ stateNum
tokenizeTerminalInAction :: String -> IO (String, Action, ActionTable)
tokenizeTerminalInAction str =
let str' = dropWhile Data.Char.isSpace str
terminal = takeWhile (not . Data.Char.isSpace) str'
str'' = drop (length terminal) str'
lexRes = if length terminal > 0 then [(terminal,str'')] else [("",str'')]
in
case lexRes of
[] -> fail "No terminal found (1)"
[("", therest)] -> fail "No terminal found (2)"
[(terminal, therest)] -> do
(action, actTbl) <- tokenizeActioninAction therest
return (terminal, action, actTbl)
tokenizeActioninAction :: String -> IO (Action, ActionTable)
tokenizeActioninAction str =
case lex str of
[] -> fail "No action found (1)"
[("", therest)] -> fail "No action found (2)"
[(action, therest)] -> do
case action of
"Shift" -> do
tokenizeShiftReduceStateNumInAction therest Shift
"Reduce" -> do
tokenizeShiftReduceStateNumInAction therest Reduce
"Accept" -> do
actTbl <- tokenizeStateNumInAction therest
return (Accept, actTbl)
_ -> fail ("Unexpected action: " ++ action)
tokenizeShiftReduceStateNumInAction :: String -> (Int -> Action)
-> IO (Action, ActionTable)
tokenizeShiftReduceStateNumInAction str fn =
case lex str of
[] -> fail "No shift/reduce state number found (1)"
[("", therest)] -> fail "No shift/reduce state number found (2)"
[(stateNum, therest)] -> do
actTbl <- tokenizeStateNumInAction therest
case readMaybe stateNum :: Maybe Int of
Just stateNum_i -> return (fn stateNum_i, actTbl)
Nothing ->
error $ "[tokenizeShiftReduceStateNumInAction] unexpected state number:"
++ stateNum
-- Load goto table
loadGotoTbl :: String -> IO GotoTable
loadGotoTbl str = tokenizeStateNumInGoto str
tokenizeStateNumInGoto :: String -> IO GotoTable
tokenizeStateNumInGoto str =
case lex str of
[] -> return []
[("", therest)] -> return []
[(stateNum, therest)] -> do
(nonterminal, toStateNum, actTbl) <- tokenizeNonterminalInGoto therest
case (readMaybe stateNum :: Maybe Int, readMaybe toStateNum :: Maybe Int) of
(Just stateNum_i, Just toStateNum_i) -> return $ ((stateNum_i, nonterminal), toStateNum_i) : actTbl
(_,_) -> error $ "[tokenizeStateNumInGoto] Unexpected state numbers: "
++ stateNum ++ " or " ++ toStateNum
tokenizeNonterminalInGoto :: String -> IO (String, String, GotoTable)
tokenizeNonterminalInGoto str =
case lex str of
[] -> fail "No nonterminal found (1)"
[("", therest)] -> fail "No nonterminal found (2)"
[(nonterminal,therest)] -> do
(toStateNum, actTbl) <- tokenizeToStateNumInGoto therest
return (nonterminal, toStateNum, actTbl)
tokenizeToStateNumInGoto :: String -> IO (String, GotoTable)
tokenizeToStateNumInGoto str =
case lex str of
[] -> fail "No to-state found (1)"
[("", therest)] -> fail "No to-state found (2)"
[(toStateNum,therest)] -> do
actTbl <- tokenizeStateNumInGoto therest
return (toStateNum, actTbl)
-- Load production rules
loadProdRules :: String -> IO ProdRules
loadProdRules str = do
numLhsRhsList <- mapM tokenizeNumInProdRules (splitWithCR str)
return [ (lhs, rhs) | (i, lhs, rhs) <- numLhsRhsList ]
tokenizeNumInProdRules :: String -> IO (Int, String, [String])
tokenizeNumInProdRules str =
case lex str of
[] -> fail "No rule number found (1)"
[("", therest)] -> fail "No rule number found (2)"
[(ruleNumStr, therest)] -> do
(lhs, rhs) <- tokenizeColonInProdRules therest
case readMaybe ruleNumStr :: Maybe Int of
Just ruleNumStr_i -> return (ruleNumStr_i, lhs, rhs)
Nothing -> error $ "[tokenizeNumInProdRules] Unexpected rule number: "
++ ruleNumStr
tokenizeColonInProdRules :: String -> IO (String, [String])
tokenizeColonInProdRules str =
case lex str of
[] -> fail "No colon found (1)"
[("", therest)] -> fail "No colon found (2)"
[(colon, therest)] -> do
let lhsRhs = tokenizeLhs therest
return (head lhsRhs, tail lhsRhs)
splitWithCR :: String -> [String]
splitWithCR str =
[ line | line <- splitWithCR' "" str, line /= "" ]
splitWithCR' :: String -> String -> [String]
splitWithCR' app [] = (reverse app) : []
splitWithCR' app ('\n':therest) = (reverse app) : splitWithCR' "" therest
splitWithCR' app (ch:therest) = splitWithCR' (ch : app) therest