1

解析引号和转义时(参见为什么 Parslet(在 Ruby 中)在解析空字符串文字时返回一个空数组?)我在 Parslet 中遇到了一个奇怪的问题:(escape_char.absent? >> str('"')).absent? >> any 似乎 Parslet 实际上解决了双重否定并期望转义字符在那里。

require 'parslet'
require 'rspec'
require 'parslet/rig/rspec'
require 'parslet/convenience'

class Parser < Parslet::Parser
  root(:quote)

  rule :quote do
    quote >> text >> quote
  end

  rule :text do
    (quote.absent? >> any).repeat
  end

  rule :quote do
    escape_char.absent? >> str('"')
  end

  rule :escape_char do
    str('\\')
  end
end

describe Parser do
  it 'should parse text in quotes' do
    is_expected.to parse('"hello"')
  end

  it 'should parse text in quotes with escaped quote' do
    is_expected.to parse('"foo\"bar"')
  end

  it 'should parse text in quotes with trailing escaped quote' do
    is_expected.to parse('"text\""')
  end
end

我对如何解决这个问题不太感兴趣,正如上面链接的帖子中已经描述的那样,我只是想了解这种行为。起初这似乎违反直觉,但我相信这背后有充分的理由。

4

1 回答 1

0

Parslet 通过组合更小的解析器来构建解析器。这就是 PEG 的美妙之处。

“缺席”是一个解析器,它需要一个解析器。它尝试将输入流与包装的解析器进行匹配。如果包装的解析器匹配,则 Absent 报告“不匹配”。如果内部解析器匹配失败,则“缺席”解析器通过。

所以,你提到的解析器: (escape_char.absent? >> str('"')).absent? >> any

将匹配单个字符,但仅在(escape_char.absent? >> str('"'))无法匹配相同字符时。

(escape_char.absent? >> str('"'))只有当第一个字符是转义字符或不是引号时才会匹配失败。

对此进行测试,事实证明这是真的。

require 'parslet'
require 'rspec'
require 'parslet/rig/rspec'
require 'parslet/convenience'

class Parser < Parslet::Parser
  root(:x)

  rule :x do 
    (escape_char.absent? >> str('"')).absent? >> any 
  end

  rule :escape_char do
    str('\\')
  end
end

  begin
    Parser.new.parse('a') # passes
    Parser.new.parse('b') # passes
    Parser.new.parse('\\') # passes
    Parser.new.parse('"') # << this one fails
    puts "pass"
  rescue Parslet::ParseFailed => error
    puts error.cause.ascii_tree
  end
于 2015-06-14T02:10:53.317 回答