使用PEG.js简单解析问题

Nic*_*ans 21 javascript parsing peg pegjs

我试图通过在PEG.js操场上输入简单的语法来绕过PEG .

例1:

  • 输入: "abcdef1234567ghijklmn8901opqrs"
  • 期望的输出: ["abcdef", "1234567", "ghijklmn", "8901", "opqrs"]

  • 实际产量: ["abcdef", ["1234567", ["ghijklmn", ["8901", ["opqrs", ""]]]]]

这个例子非常有效,但是我可以让PEG.js不将生成的数组嵌套到百万级别吗?我假设诀窍是使用concat()而不是join()某个地方,但我找不到这个地方.

start
  = Text

Text
  = Numbers Text
  / Characters Text
  / EOF

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Characters
  = text: [a-z]+ {return text.join("")}

EOF
  = !.
Run Code Online (Sandbox Code Playgroud)

例2:

与示例1相同的问题和代码,但将字符规则更改为以下内容,我预期会产生相同的结果.

Characters
  = text: (!Numbers .)+ {return text.join("")}
Run Code Online (Sandbox Code Playgroud)

结果输出是:

[",a,b,c,d,e,f", ["1234567", [",g,h,i,j,k,l,m,n", ["8901", [",o,p,q,r,s", ""]]]]]
Run Code Online (Sandbox Code Playgroud)

为什么我得到所有这些空的比赛?

例3:

最后一个问题.这根本不起作用.我怎样才能使它工作?对于奖励积分,任何关于效率的指针?例如,如果可能,我应该避免递归吗?

我也很欣赏一个很好的PEG教程的链接.我已阅读(http://www.codeproject.com/KB/recipes/grammar_support_1.aspx),但正如您所见,我需要更多帮助......

  • 输入: 'abcdefghijklmnop"qrstuvwxyz"abcdefg'
  • 期望的输出: ["abcdefghijklmnop", "qrstuvwxyz", "abcdefg"]
  • 实际产量: "abcdefghijklmnop\"qrstuvwxyz\"abcdefg"
start
  = Words

Words
  = Quote
  / Text
  / EOF

Quote
  = quote: ('"' .* '"') Words {return quote.join("")}

Text
  = text: (!Quote . Words) {return text.join("")}

EOF
  = !.
Run Code Online (Sandbox Code Playgroud)

小智 21

我收到了PEG.js Google Group的回复,帮助我走上正轨.我正在发布所有三个问题的答案,希望它们可以作为像我这样的其他PEG初学者的基础教程.请注意,不需要递归.

例1:

一旦你理解了基本的PEG习语,这很简单.

start
  = Text+

Text
  = Numbers
  / Characters

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Characters
  = text: [a-z]+ {return text.join("")}
Run Code Online (Sandbox Code Playgroud)

例2:

这里的问题是Peek表达式(&expr和!expr)的PEG.js解析器生成器中的一种特殊设计选择.两者都在不消耗任何字符的情况下向前查看输入流,因此我错误地认为它们没有返回任何内容.但是,它们都返回一个空字符串.我希望PEG.js的作者改变这种行为,因为(据我所知)这只是污染输出流的不必要的瑕疵.如果我错了,请纠正我!

无论如何,这是一个解决方法:

start
  = Text+

Text
  = Numbers
  / Words

Numbers
  = numbers: [0-9]+ {return numbers.join("")}

Words
  = text: Letter+ {return text.join("")}

Letter
  = !Numbers text: . {return text}
Run Code Online (Sandbox Code Playgroud)

例3:

问题是像这样的表达('"' .* '"')永远不会成功.PEG总是贪婪的,所以.*将消耗其余的输入流,永远不会看到第二个引用.这是一个解决方案(顺便说一下,需要与示例2中相同的Peek解决方法).

start
  = Words+

Words
  = QuotedString
  / Text

QuotedString
  = '"' quote: NotQuote* '"' {return quote.join("")}

NotQuote
  = !'"' char: . {return char}

Text
  = text: NotQuote+ {return text.join("")}
Run Code Online (Sandbox Code Playgroud)