为什么像 `(!"foo" .*)` 这样的表达式会在 PEG.js 中生成 `[undefined, char]` 值的数组

Why does an expression like `(!"foo" .*)` generate arrays of `[undefined, char]`-values in PEG.js

我对PEG.js还是很陌生,我猜这只是初学者的误解。

试图解析这样的东西:

definitions
    some text

if
    some additonal text
    to parse here    

then
    still more text will
    go here

我可以获得正确阅读这三个部分的语法(当然,稍后会进一步解析。)但它会以一种奇怪的格式生成该文本。例如,在上面,“some text”变成了

[
  [undefined, "s"], [undefined, "o"], [undefined, "m"], [undefined, "e"], [undefined, " "], 
  [undefined, "t"], [undefined, "e"], [undefined, "x"], [undefined, "t"]
]

我可以很容易地将其转换为纯字符串,但我想知道我正在做些什么来赋予它这种糟糕的格式。到目前为止,这是我的语法:

{
  const combine = (xs) => xs .map (x => x[1]) .join('')
}

MainObject
  = _ defs:DefSection _ condition:CondSection _ consequent: ConsequentSection
    {return {defs, condition, consequent}}

DefSection = _ "definitions"i _ defs:(!"\nif" .)+
  {return defs}

CondSection = _ "if"i _ cond:(!"\nthen" .)+
  {return combine (cond)}

ConsequentSection = _ "then"i _ cons:.*
  {return cons .join ('')} 

_ "whitespace"
  = [ \t\n\r]*

我可以通过将 {return defs} 替换为 {return combine(defs)} 来修复它,就像在其他部分中一样。

我的主要问题很简单,它为什么会生成该输出?有没有更简单的方法来修复它?


总的来说,因为我对 PEG.js 还是很陌生,我很想知道是否有更好的方法来编写这个语法。 (!"\nif" .*) 之类的表达式似乎很粗略。

  1. 负面展望,例如!Rule,将始终 return 未定义,如果 Rule 匹配,将失败。
  2. . 将始终匹配单个字符。
  3. 一个序列Rule1 Rule2 ...将创建一个包含每个规则
  4. 结果的列表
  5. 重复 Rule+Rule* 将匹配 Rule 尽可能多的次数并创建一个列表。 (如果第一次尝试匹配规则失败,+ 失败)

你的成绩是

[ // Start (!"\nif" .)
  [undefined // First "\nif", 
"s" // First .
] // first ("\nif" .)
, 
[undefined, "o"] // Second (!"\nif" .)
, [undefined, "m"], [undefined, "e"], [undefined, " "], 
  [undefined, "t"], [undefined, "e"], [undefined, "x"], [undefined, "t"]
] // This list is (!"\nif" .)*, all the matches of ("\nif" .)

您似乎想要的是阅读文本,您可以为此使用运算符 $Rule,它将 return 输入而不是生成的输出。

MainObject
  = _ defs:DefSection _ condition:CondSection _ consequent: ConsequentSection
    {return {defs, condition, consequent}}

DefSection = _ "definitions"i _ defs:$(!"\nif" .)+
  {return defs.trim()}

CondSection = _ "if"i _ cond:$(!"\nthen" .)+
  {return cond.trim()}

ConsequentSection = _ "then"i _ cons:$(.*)
  {return cons.trim()} 

_ "whitespace"
  = [ \t\n\r]*

会产生

{
   "defs": "some text",
   "condition": "some additonal text
    to parse here",
   "consequent": "still more text will
    go here"
}