【问题标题】:Parse EBNF with Megaparsec nested sepBy使用 Megaparsec 嵌套 sepBy 解析 EBNF
【发布时间】:2017-05-23 11:39:23
【问题描述】:

作为练习,我尝试使用 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,或者我应该以某种方式使解析变平。但话说回来,我该怎么做呢?

【问题讨论】:

  • 如果您在production 中使用(try alternativeTerm),它会按照您的意愿工作吗?只是猜测,因为您似乎需要回溯。
  • 似乎解析没有逃脱内部sepBy1。它试图解析 |作为term 并失败。改用sepEndBy1 怎么样?
  • @Lazersmoke 尝试不起作用
  • @PhilippKiener 我应该替换哪个 sepBy?
  • alternativeTerm 中的那个。但是,这仅在最后一个术语和 | 之间有保证的空格时才有效。

标签: parsing haskell ebnf megaparsec


【解决方案1】:

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

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

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

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

【讨论】:

  • 谢谢,现在可以了。我很可能会添加一个标记器,所以我不必再处理空格了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 2015-07-28
相关资源
最近更新 更多