我有一个看起来如下的数据类型:
type Parser a = ExceptT ParseError (State [Token]) a
以及状态操作功能:
consumeToken :: Parser Token
consumeToken = do
toks <- lift get
if null toks
then throwE OutOfTokensError
else
do
lift $ put (tail toks)
return $ head toks
peekToken :: Parser Token
peekToken = do
toks <- lift get
if null toks
then throwE OutOfTokensError
else
do
return $ head toks
我正在尝试使用这些功能来帮助验证语法中的生产规则:
charList :: Parser CharList
charList =
(return CharListCharacter <*> isToken (Character "<char>") <*> charList)
<|> (return CharListSpace <*> isToken (Space " ") <*> charList)
<|> (return EmptyCharList)
isToken
似乎需要消耗当前令牌(使用consumeToken
(,以便递归调用charList
然后处理以下令牌。但是,这样做意味着替代情况不会从与第一种情况相同的标记开始。
是否有一种解决此问题的标准方法?
遵循评论的建议,我重塑了解析器,以利用我的语法是ll(1(。这样做意味着我不需要Alternative
。
这是charList
函数的最终版本(使用consumeToken
使用CC_7(:
charList :: Parser CharList
charList = do
tok <- peekToken
case tok of Character _ -> return CharListCharacter <*> isToken (Character "<char>") <*> charList
Space _ -> return CharListSpace <*> isToken (Space " ") <*> charList
_ -> return EmptyCharList