Как заставить мой атом парсера завершаться внутри правила, включая необязательные пробелы?

Я могу заставить атомы разбираться по отдельности, но когда я их цепью >> парсер не хочет покидать :integer править.

Я получаю эту ошибку:

Extra input after last repetition at line 1 char 2.
`- Expected one of [VALUE, BOOL_OPERATION] at line 1 char 2.
   |- Expected at least 1 of [0-9] at line 1 char 2.
   |  `- Failed to match [0-9] at line 1 char 2.
   `- Failed to match sequence (VALUE BOOL_COMPARISON VALUE) at line 1 char 2.
      `- Expected at least 1 of [0-9] at line 1 char 2.
         `- Failed to match [0-9] at line 1 char 2.

При запуске следующий код:

require 'minitest/autorun'
require 'parslet'
require 'parslet/convenience'

class ExpressionParser < Parslet::Parser
  # Single chars
  rule(:space) { match('\s').repeat(1) }
  rule(:space?) { space.maybe }

  # Values
  rule(:integer) { match('[0-9]').repeat(1).as(:integer) } 
  rule(:value) { integer }

  # Operators
  rule(:equals) { str('=').repeat(1,2).as(:equals) }     
  rule(:bool_comparison) { space? >> equals >> space?}

  # Grammar  
  rule(:bool_operation) { value >> bool_comparison >> value }      
  rule(:subexpression) {(value | bool_operation).repeat(1)}

  root(:subexpression)
end

class TestExpressions < Minitest::Unit::TestCase
  def setup
    @parser = ExpressionParser.new
  end

  def test_equals
    assert @parser.value.parse("1")
    assert @parser.bool_comparison.parse("==")
    assert @parser.parse_with_debug("1 == 1")
  end
end

2 ответа

Решение

Это похоже на написание кода if (consume_value || consume_expression), ему удастся использовать значение и никогда не пытаться использовать выражение.

Parslet постарается сопоставить ваши варианты в том порядке, в котором они определены. Если он может потреблять часть входного потока без каких-либо конфликтов, это считается успешным совпадением. Как это удалось сопоставить value нет смысла пытаться сопоставить subexpression,

Итак, как ваш пример выражения 1 == 1 начинается с действительного значения, и вы сказали ему сначала попробовать сопоставить со значением, ((value | bool_operation)) он пытается и добивается успеха. Произошла ошибка (Extra Input) означает "Я успешно согласовал ввод, но, похоже, что-то осталось".

Вам необходимо сопоставить сложный случай с простым случаем, когда один является подмножеством другого. Таким образом, сложный может потерпеть неудачу, и вы вернетесь к простому случаю.

Изменить правило на rule(:subexpression) {(bool_operation | value).repeat(1)},

subexpression Правило должно сначала попытаться соответствовать bool_operation править, прежде чем перейти к value,

rule(:subexpression) {(bool_operation | value).repeat(1)}

Кроме того, вам нужно пометить valueв bool_operation чтобы они не были неправильно объединены.

rule(:bool_operation) { value.as(:first) >> bool_comparison >> value.as(:second) }
Другие вопросы по тегам