如何最好地解析 PEG 语法中的逗号分隔列表

How best to parse a comma separate list in PEG grammar

我正在尝试解析逗号分隔列表。为简化起见,我只使用数字。这些表达式是有效的:

(1, 4, 3)

()

(4)

我可以想到两种方法来做到这一点,我想知道为什么失败的例子不起作用。我相信它是一个正确的 BNF,但我无法让它作为 PEG 工作。任何人都可以解释为什么吗?我试图更好地理解 PEG 解析逻辑。

我在这里使用在线浏览器解析器生成器进行测试: https://pegjs.org/online

这不起作用:

list = '(' some_digits? ')'
some_digits = digit / ', ' some_digits
digit = [0-9]

(实际上,它解析正常,喜欢 () 或 (1) 但不识别 (1, 2)

但这确实有效:

list = '(' some_digits? ')'
some_digits = digit another_digit*
another_digit = ', ' digit
digit = [0-9]

这是为什么? (这里是语法新手)

很酷的问题,在他们的文档中仔细研究了一秒钟后,我发现 / 字符的意思是:

Try to match the first expression, if it does not succeed, try the second one, etc. Return the match result of the first successfully matched expression. If no expression matches, consider the match failed.

所以这引导我找到解决方案:

list = '(' some_digits? ')'
some_digits = digit ', ' some_digits / digit
digit = [0-9]

这样做的原因:

输入:(1, 4)

  • 吃'('
  • 检查是否有一些数字?
  • 检查some_digits - 第一个条件:
    • 吃“1”
    • 吃', '
    • 检查some_digits - 第一个条件:
      • 吃了“4”
      • 吃不下','
    • 检查some_digits - 第二个条件:
      • 吃了“4”
      • 成功
    • 成功
  • 吃')'
  • 成功

如果您颠倒 some_digits 条件的顺序,第一个数字会被 digit 吃掉,并且不会发生递归。然后它会抛出一个错误,因为 ')' 不存在。

一行:

some_digits = '(' digit (', ' digit)* ')'

这取决于您想要的值和 PEG 实现,但以这种方式提取它们可能更容易。