我设法结合了Alex lexer和Happy parser。但是我的current solution有些方面我不满意:
Alex
和我的ExpParser
monad是分开的实体。我在下面解释这些方面。
我的ExpParser
monad看起来如下:
data ParserEnv = ParserEnv
{ varModifier :: String -> String }
newtype ExpParser a = ExpParser
{ runExpParser :: ReaderT ParserEnv (StateT AlexState (Except String)) a }
deriving ( Functor, Applicative, Monad
, MonadReader ParserEnv
, MonadState AlexState
, MonadError String
)
顶级解析函数定义为:
-- | Parsing function.
parse :: (String -> String) -> String -> Either String Exp
parse f str = runExcept $ (`evalStateT` initState) $ runReaderT (runExpParser calc) initEnv
where initEnv = ParserEnv { varModifier = f}
initState = AlexState -- TODO: isn't it a standard initial state that we can use?
{ alex_pos = AlexPn 0 0 0
, alex_inp = str
, alex_chr = '\n' -- TODO: What to include here?
, alex_bytes = []
, alex_scd = 0
}
第一个问题是我必须设置初始状态,其中包含一些我不确定的字段。此外,我希望定义Alex lexer的标准“初始状态”。
然后我以下列方式使用词法分析器(使用“monad”包装器生成):
mLexer :: (Token -> ExpParser a) -> ExpParser a
mLexer cont = do -- TODO: is there a way to reduce this boilerplate?
alexSt <- get
case unAlex alexMonadScan alexSt of
Left err -> throwError err
Right (nextAlexSt, token) ->
do
put nextAlexSt
cont token
但是我正在编写一些样板文件,并且还重复自己,因为上面的代码中嵌入了状态monad的行为。如果Alex
为State
monad定义了一个实例,我可以避免这种情况,但我不认为是这种情况。
是否有办法改善上述方面的当前解决方案?