Parslet: исключение - PullRequest
       20

Parslet: исключение

1 голос
/ 22 ноября 2011

В настоящее время я пишу синтаксический анализатор 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

Как я могу перевести это, используя Parslet? Может отсутствовать? / Присутствует? вещи?

Большое спасибо, надеюсь, у кого-то есть идея ...

Хорошего дня!

EDIT: Я попробовал то, что вы сказали, поэтому вот мой перевод на язык Ruby с использованием parslet:

  rule(:line_comment){(source_character.repeat >> line_terminator >> source_character.repeat).absent? >> source_character.repeat(1)}

Однако, похоже, это не работает (последовательность в скобках). Я провел несколько тестов и пришел к выводу, что то, что написано в моих словах, неверно.

Вот очень простой пример, давайте рассмотрим эти правила:

# 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

Я эти правила с этим кодом:

# Code to test : 
code = "test
"

Но я понимаю:

Не удалось сопоставить последовательность (SOURCE_CHARACTER {0,} LINE_TERMINATOR) в строка 2, символ 1. - Failed to match sequence (SOURCE_CHARACTER{0, } LINE_TERMINATOR) at line 2 char 1. - не соответствует последовательности ('' ''?) в строке 2 char 1. `- преждевременный конец ввода в строке 2, символ 1. ноль

Если эта последовательность не сработает, моё «полное» правило там никогда не сработает ... Если у кого-то есть идея, было бы здорово.

Спасибо!

Ответы [ 2 ]

5 голосов
/ 23 ноября 2011

Соответствие Петрушки является жадным по своей природе. Это означает, что когда вы повторяете что-то вроде

foo.repeat

parslet будет соответствовать foo, пока не потерпит неудачу. Если foo

rule(:foo) { any }

вы будете на пути к сбою, поскольку any.repeat всегда соответствует всему остальному документу!

То, что вы ищете, это что-то вроде соответствия строк в examples / string_parser.rb (исходное дерево parslet):

rule :string do
  str('"') >> 
  (
    (str('\\') >> any) |
    (str('"').absent? >> any)
  ).repeat.as(:string) >> 
  str('"')
end

То, что это говорит: «сопоставить», затем сопоставить либо обратную косую черту, за которой следует любой символ, либо сопоставить любой другой символ, если только он не является завершающим ».

Так. Нет? действительно способ исключить вещи из следующего матча:

str('foo').absent? >> (str('foo') | str('bar'))

будет соответствовать только 'bar'. Если вы понимаете это, я предполагаю, что вы сможете решить свои трудности. Хотя они не будут последними на вашем пути к анализатору Ruby ...

4 голосов
/ 22 ноября 2011

Вы можете сделать что-то вроде этого:

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 }

В этом случае absent? заглядывает в будущее, чтобы убедиться, что следующий токен не является ключевым словом; если нет, то он проверяет, не является ли он оператором; в противном случае, наконец, посмотрите, действительно ли это word.

Эквивалентное правило:

rule(:searchterm) { (keyword | op).absent? >> word }
...