混合解析器字符(词法分析器)与解析器字符串

时间:2018-08-12 22:51:40

标签: haskell monads text-parsing lexer megaparsec

我已经编写了多个编译器,并且熟悉lexer,regexs / NFA / DFA,flex / bison,JavaCC,JavaCup,antlr4等中的解析器和语义规则。

是否存在某种神奇的单子运算符,可以无缝地将令牌与Parser Char(即Text.Megaparsec.Char)和Parser String的混合进行增长/组合?

是否有一种方法/最佳实践来表示词汇化标记和非最终期望的清晰区分?

2 个答案:

答案 0 :(得分:3)

通常,人们使用应用性操作直接组合num_lines = sum(1 for line in f) Parser Char,而不是“升级”前者。例如,对于必须以字母开头的字母数字标识符的解析器可能看起来像:

Parser String

例如,如果您正在做一些更复杂的事情,例如用可选的美分来分析美元金额,则可以这样写:

ident :: Parser String
ident = (:) <$> letterChar <*> alphaNumChar

如果在很多情况下发现自己试图根据复杂的dollars :: Parser String dollars = (:) <$> char '$' <*> some digitChar <**> pure (++) <*> option "" ((:) <$> char '.' <*> replicateM 2 digitChar) Parser String解析器序列构建Parser Char,则可以定义一些辅助运算符。如果您发现烦人的运算符种类繁多,则只需定义Parser String(<++>)的缩写形式,例如charToStr

c :: Parser Char -> Parser String

因此您可以编写如下内容:

(<.+>) :: Parser Char -> Parser String -> Parser String
p <.+> q = (:) <$> p <*> q
infixr 5 <.+>

(<++>) :: Parser String -> Parser String -> Parser String
p <++> q = (++) <$> p <*> q
infixr 5 <++>

(<..>) :: Parser Char -> Parser Char -> Parser String
p <..> q = p <.+> fmap (:[]) q
infixr 5 <..>

就像@leftroundabout所说的那样,dollars' :: Parser String dollars' = char '$' <.+> some digitChar <++> option "" (char '.' <.+> digitChar <..> digitChar) 并没有什么恶意。如果您愿意,可以写fmap (:[]),如果它看起来更清晰。

答案 1 :(得分:2)

fmap (: [])(或fmap purepure <$>)没有任何讨厌或骇人听闻的东西–这是很自然的事情,执行一次简洁,安全,富有表现力和透明的转换同时。

我不会真正推荐的替代方法,但是在某些情况下,它可能最能表达意图:sequence [charParser]。这清楚表明您正在执行字符解析器列表中的“所有”解析器,并将结果“ s”收集为字符“ s”列表。