如何让我的解析器atom在包含可选空格的规则内终止?

时间:2014-11-23 22:29:33

标签: ruby parslet

我可以单独解析原子,但是当我使用>>链接它们时,解析器似乎不想离开: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 个答案:

答案 0 :(得分: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) }

答案 1 :(得分:1)

就像编写一些代码if (consume_value || consume_expression)一样,它会成功使用该值,并且永远不会尝试使用该表达式。

Parslet会尝试按照定义的顺序匹配您的选项。如果它可以消耗一些输入流而没有任何冲突,那么它被认为是成功的匹配。在成功匹配value后,它没有理由尝试匹配subexpression

因此,您的示例表达式1 == 1以有效的&#34;值&#34;开头。并且你告诉它首先尝试匹配值,((value | bool_operation))它尝试并成功。生成的错误(Extra Input)表示&#34;我成功匹配输入,但似乎还有剩余的东西。&#34;

在简单情况之前,当一个是另一个的子集时,您需要匹配复杂的情况。这样复杂的一个可能会失败,你回到简单的情况。

将规则更改为rule(:subexpression) {(bool_operation | value).repeat(1)}