使用 Megaparsec 嵌套 sepBy 解析 EBNF

Parse EBNF with Megaparsec nested sepBy

作为练习,我尝试使用 Megaparsec 解析 EBNF/ABNF 语法。我得到了一些琐碎的东西,比如终端和可选的工作,但我正在努力寻找替代品。使用此语法:

S ::= 'hello' ['world'] IDENTIFIER LITERAL | 'test';

还有这段代码:

production :: Parser Production
production = sepBy1 alternativeTerm (char '|') >>= return . Production

alternativeTerm :: Parser AlternativeTerm
alternativeTerm = sepBy1 term space >>= return . AlternativeTerm

term :: Parser Term
term = terminal
    <|> optional
    <|> identifier
    <|> literal

我收到这个错误:

unexpected '|'
expecting "IDENTIFIER", "LITERAL", ''', '[', or white space

我猜 alternativeTerm 解析器在遇到无法解析的序列时并没有返回到生产解析器而是抛出错误。

我该怎么办?更改 EBNF 的 ADT 或者我应该以某种方式展平解析。但是话又说回来,我该怎么做呢?

最好将我之前的评论扩展为完整答案。

您的语法基本上是一个由空格分隔(和结束)的术语列表,而空格又由 | 分隔。您使用 sepBy1 的解决方案不起作用,因为 LITERAL 之后有一个尾随空格 - sepBy1 假设该空格后面还有另一个术语并尝试将 term 应用于 |,失败了。

如果您的 alternativeTerm 保证以空白字符(或多个)结尾,请按如下方式重写您的 alternativeTerm

alternativeTerm = (term `sepEndBy1` space) >>= return . AlternativeTerm