0

我设法结合了 Alex 词法分析器和 Happy 解析器。但是,我对当前解决方案的某些方面不满意:

  1. 设置初始状态,
  2. 将状态传递给 Alex 时的样板代码,
  3. Alex我的ExpParser单子是分开的实体。

我在下面解释这些方面。

我的ExpParsermonad 如下所示:

 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我可以避免这种情况,但我认为情况并非如此。

有没有办法在上述方面改进当前的解决方案?

4

0 回答 0