我目前正在使用 megaparsec 库在 Haskell 中编写我的简单编程语言解析器。
我找到了这个megaparsec 教程,并编写了以下解析器代码:
import Data.Void
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
type Parser = Parsec Void String
lexeme :: Parser a -> Parser a
lexeme = L.lexeme space
rws :: [String] -- list of reserved words
rws = ["if", "then"]
identifier :: Parser String
identifier = (lexeme . try) (p >>= check)
where
p = (:) <$> letterChar <*> many alphaNumChar
check x =
if x `elem` rws
then fail $ "keyword " ++ show x ++ " cannot be an identifier"
else return x
具有保留名称错误处理的简单标识符解析器。它成功解析有效标识符,例如foo
, bar123
。
但是当无效输入(又名保留名称)进入解析器时,它会输出错误:
>> parseTest identifier "if"
1:3:
keyword "if" cannot be an identifier
其中,错误消息还可以,但是错误位置(1:3:
)与我的预期有点不同。我预计错误位置是1:1:
.
在定义的以下部分中identifier
,
identifier = (lexeme . try) (p >>= check)
如果失败并返回源位置,我预计try
会表现得像没有消耗输入。(p >>= check)
1:1:
我的期望错了吗?我怎样才能让这段代码按我的预期工作?