Parslet:排除条款

1 ruby parsing parslet

我目前正在使用Ruby编写Ruby解析器,更准确地说是Parslet,因为我认为它比Treetop或Citrus更容易使用.我使用官方规范创建我的规则,但有一些我不能写的语句,因为它们"排除"了一些语法,我不知道怎么做......嗯,这里有一个例子供你理解. ..

这是一个基本规则:

foo::=
any-character+ BUT NOT (foo* escape_character barbar*)
# Knowing that (foo* escape_character barbar*) is included in any-character
Run Code Online (Sandbox Code Playgroud)

我怎么能用Parslet翻译呢?也许是缺席?/现在?东西 ?

非常感谢,希望有人有个主意....

祝你今天愉快!

编辑:我试过你说的,所以这是我使用parslet翻译成Ruby语言:

  rule(:line_comment){(source_character.repeat >> line_terminator >> source_character.repeat).absent? >> source_character.repeat(1)}
Run Code Online (Sandbox Code Playgroud)

但是,它似乎不起作用(parens中的序列).我做了一些测试,并得出结论,我的parens中写的是错误的.

这是一个非常简单的例子,让我们考虑以下规则:

# Parslet rules
rule(:source_character) {any}
rule(:line_terminator){ str("\n") >> str("\r").maybe }  

rule(:not){source_character.repeat >> line_terminator }
# Which looks like what I try to "detect" up there
Run Code Online (Sandbox Code Playgroud)

我这些规则与这些代码:

# Code to test : 
code = "test
"
Run Code Online (Sandbox Code Playgroud)

但我明白了:

无法匹配第2行char 1处的序列(SOURCE_CHARACTER {0,} LINE_TERMINATOR).- Failed to match sequence (SOURCE_CHARACTER{0, } LINE_TERMINATOR) at line 2 char 1.- 无法匹配第2行char 1处的序列('''?).` - 第2行的输入过早结束char 1. nil

如果这个序列不起作用,那么我的"完整"规则将无法工作......如果有人有想法,那就太好了.

谢谢 !

Bil*_*ber 5

您可以执行以下操作:

rule(:word) { match['^")(\\s'].repeat(1) } # normal word
rule(:op) { str('AND') | str('OR') | str('NOT') }
rule(:keyword) { str('all:') | str('any:') }
rule(:searchterm) { keyword.absent? >> op.absent? >>  word }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,absent?会先行检查以确保下一个标记不是关键字;如果不是,则检查以确保它不是运算符;如果不是,最后看看它是否有效word

一个等效的规则是:

rule(:searchterm) { (keyword | op).absent? >> word }
Run Code Online (Sandbox Code Playgroud)


小智 5

Parslet匹配本质上是贪婪的.这意味着当你重复这样的事情时

foo.repeat
Run Code Online (Sandbox Code Playgroud)

parslet将匹配foo,直到失败.如果foo是

rule(:foo) { any }
Run Code Online (Sandbox Code Playgroud)

你会在失败的道路上,因为any.repeat总是匹配文档的其余部分!

您正在寻找的是类似examples/string_parser.rb(parslet源代码树)中的字符串匹配器:

rule :string do
  str('"') >> 
  (
    (str('\\') >> any) |
    (str('"').absent? >> any)
  ).repeat.as(:string) >> 
  str('"')
end
Run Code Online (Sandbox Code Playgroud)

这说的是:'匹配',然后匹配反斜杠后跟任何字符,或匹配任何其他字符,只要它不是终止"."

所以.absent?实际上是一种从下面的匹配中排除事物的方法:

str('foo').absent? >> (str('foo') | str('bar'))
Run Code Online (Sandbox Code Playgroud)

只会匹配'酒吧'.如果您了解这一点,我认为您将能够解决您的困难.虽然那些不会是你去Ruby解析器的最后一个...