{-|
Module : PP.Parsers.Lr
Description : LR parser
Copyright : (c) 2017 Patrick Champion
License : see LICENSE file
Maintainer : chlablak@gmail.com
Stability : provisional
Portability : portable
-}
module PP.Parsers.Lr
( LrConfig(..)
, LrAst(..)
, prettyAst
) where
import PP.Builder (LrAction (..), LrTable (..), action, action')
import PP.Lexer (OToken (..))
import PP.Parser (LrParser (..))
import PP.Rule (Rule (..))
-- |Dynamic AST generated by the parser
data LrAst
= LrAstRoot [LrAst]
| LrAstTerm [OToken]
| LrAstNonTerm String [LrAst]
deriving (Eq, Show)
-- |Configuration for LR parser
data LrConfig = LrConfig
{ lrCount :: Int -- ^Counter
, lrStack :: [Int] -- ^State stack
, lrAction :: LrAction -- ^Action to do
, lrInput :: [OToken] -- ^Input
, lrAst :: LrAst -- ^Parsed AST
} deriving (Eq, Show)
-- Dragon Book (2nd edition, fr), page 230, algorithm 4.44
instance LrParser LrConfig where
config t i = LrConfig 0 [0] (action' t 0 i) i (LrAstRoot [])
next t (LrConfig c ss (LrShift s) (i:is) a) =
LrConfig (c + 1) (s : ss) (action' t s is) is (shift a i)
next t (LrConfig c ss (LrReduce (Rule r xs)) i a) =
LrConfig (c + 1) sr (action t m $ NonTerm r) i (reduce a r $ length xs - 1)
where
sr@(m:_) = drop (length xs - 1) ss
next t (LrConfig c ss (LrGoto s) i a) =
LrConfig (c + 1) (s : ss) (action' t s i) i a
next _ c = c
hasNext _ (LrConfig _ _ LrError _ _) = False
hasNext _ (LrConfig _ _ LrAccept _ _) = False
hasNext _ _ = True
-- |Modify the AST by a Shift action
shift :: LrAst -> OToken -> LrAst
shift (LrAstRoot xs) i = LrAstRoot $ xs ++ [LrAstTerm [i]]
-- |Modify the AST by a Reduce action
reduce :: LrAst -> String -> Int -> LrAst
reduce (LrAstRoot xs) r l = LrAstRoot $ a ++ [LrAstNonTerm r b]
where
(a, b) = splitAt pos xs
pos = length xs - l
-- |Pretty print the LrAst
prettyAst :: LrAst -> String
prettyAst (LrAstRoot a) = concatMap (prettyAst' 0) a
where
prettyAst' d (LrAstTerm t) = tab d ++ show t ++ "\n"
prettyAst' d (LrAstNonTerm r xs) =
tab d ++ r ++ "\n" ++ concatMap (prettyAst' $ d + 2) xs
tab d = replicate d ' ' ++ "|"