我设法结合了 Alex 词法分析器和 Happy 解析器。但是,我对当前解决方案的某些方面不满意:
- 设置初始状态,
- 将状态传递给 Alex 时的样板代码,
Alex
我的ExpParser
单子是分开的实体。
我在下面解释这些方面。
我的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 词法分析器定义一个标准的“初始状态”。
然后我通过以下方式使用词法分析器(使用“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
但是我正在写一些样板文件,并且还重复自己,因为上面的代码中嵌入了 state monad 的行为。如果Alex
为 monad 定义了一个实例,State
我可以避免这种情况,但我认为情况并非如此。
有没有办法在上述方面改进当前的解决方案?