用treetop解析ruby中的tcl数组

用treetop解析ruby中的tcl数组,ruby,parsing,grammar,treetop,Ruby,Parsing,Grammar,Treetop,我在(我认为是)tcl阵列中有一堆数据。基本上它是以{a{b c}d{e f}g}的形式出现的。它只嵌套了一层,但并不总是嵌套的,也就是说,a可能只是a,或者它可能是{aabb},或者可能是{},但绝不是{aa{bb cc}。我想提取这个数组,以便在ruby中使用它 我的第一个想法是,“没问题,我会写一点语法来解析它。”我安装了treetop gem,并编写了一个解析器,它似乎工作得很好。当我试图从解析的树中提取数组时,我开始遇到问题。我想更好地了解问题的原因以及我做错了什么 以下是我到目前为止

我在(我认为是)tcl阵列中有一堆数据。基本上它是以
{a{b c}d{e f}g}
的形式出现的。它只嵌套了一层,但并不总是嵌套的,也就是说,
a
可能只是
a
,或者它可能是
{aabb}
,或者可能是
{}
,但绝不是
{aa{bb cc}
。我想提取这个数组,以便在ruby中使用它

我的第一个想法是,“没问题,我会写一点语法来解析它。”我安装了treetop gem,并编写了一个解析器,它似乎工作得很好。当我试图从解析的树中提取数组时,我开始遇到问题。我想更好地了解问题的原因以及我做错了什么

以下是我到目前为止的解析器代码:(tcl_array.treetop)

调用
p.parse(“{a}”).content
生成
tcl\u数组。rb:99:in'content':未定义的局部变量或方法'array\u element'

array_element_列表中的第一个术语(array_element)表示array_element是一个未定义的局部变量,但是应该根据treetop文档自动定义访问器方法

早些时候,我尝试了一种基于语法的解决方案,其规则较少但略为复杂:

grammar TCLArray
  rule array
    "{" ([\s]* array_element ([\s]+ array_element)* )? [\s]* "}"
  end

  rule array_element
    [^{}\s]+ / array
  end
end

但是使用这种语法时,我遇到了一些问题,解析器似乎在为数组规则创建几个不同的表达式,尽管它没有使用任何替代表达式(/)。结果是,我无法理解如何访问数组规则的各个位以将它们作为ruby数组返回。

在这种情况下,可能语法分析器生成器的功能过火了。下面是一个简单的手动递归下降解析器,它基于:

#/usr/bin/env ruby
#基于James Edward Gray II解析JSON的解决方案
#Ruby测验#155:
需要“strscan”
类TcArrayParserarray注意这一点以供参考,但我刚刚发布了一个用于解析简单TCL的gem


您为当前的问题提供了一个令人钦佩的解决方案,非常感谢。:)也就是说,最简单的解决方案可能是学习一点TCL,并编写一些ruby可以理解的东西来输出数组,但我认为这是一个对解析器进行一点复习的机会。因此,我仍然很好奇It’我想知道我做错了什么。我不知道这是树梢上的缺陷还是我对它的理解上的缺陷。无论如何,非常感谢你的辛勤工作!
grammar TCLArray
  rule array
    "{" ([\s]* array_element ([\s]+ array_element)* )? [\s]* "}"
  end

  rule array_element
    [^{}\s]+ / array
  end
end
#!/usr/bin/env ruby
# based on James Edward Gray II's solution to the Parsing JSON
#   Ruby Quiz #155: <http://RubyQuiz.Com/quiz155.html>

require 'strscan'

class TclArrayParser < StringScanner
  def parse
    parse_value
  ensure
    eos? or error "Unexpected data: '#{rest}'"
  end

  private

  def parse_value
    trim_space
    parse_string or parse_array
  ensure
    trim_space
  end

  def parse_array
    return nil unless scan(/\{\s*/)
    array = []
    while contents = parse_value
      array << contents
    end
    scan(/\}/) or error('Unclosed array')
    array
  end

  def parse_string
    scan(/[^{}[:space:]]+/)
  end

  def trim_space
    skip(/\s*/)
  end

  def error(message)
    pos = if eos? then 'end of input' else "position #{self.pos}" end
    raise ParseError, "#{message} at #{pos}"
  end

  class ParseError < StandardError; end
end
require 'test/unit'
class TestTclArrayParser < Test::Unit::TestCase
  def test_that_an_empty_string_parses_to_nil
    assert_nil TclArrayParser.new('').parse
  end
  def test_that_a_whitespace_string_parses_to_nil
    assert_nil TclArrayParser.new("  \t  \n  ").parse
  end
  def test_that_an_empty_array_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{}').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_front_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' {}').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_end_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{} ').parse
  end
  def test_that_an_empty_array_with_whitespace_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{ }').parse
  end
  def test_that_an_empty_array_surrounded_by_whitespace_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' {} ').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_front_and_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' { }').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_end_and_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{ } ').parse
  end
  def test_that_an_empty_array_surrounded_by_whitespace_with_whitespace_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' { } ').parse
  end
  def test_that_a_sole_element_parses
    assert_equal 'a', TclArrayParser.new('a').parse
  end
  def test_that_an_array_with_one_element_parses
    assert_equal ['a'], TclArrayParser.new('{a}').parse
  end
  def test_that_a_nested_array_parses
    assert_equal [[]], TclArrayParser.new('{{}}').parse
  end
  def test_that_a_nested_array_with_one_element_parses
    assert_equal [['a']], TclArrayParser.new('{{a}}').parse
  end
  def test_that_whitespace_is_ignored
    assert_equal [], TclArrayParser.new('     {     }     ').parse
  end
  def test_that_complex_arrays_parse_correctly
    assert_equal ['a', %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{a {b c} d {e f} g}').parse
    assert_equal [%w[aa bb], %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{{aa bb} {b c} d {e f} g}').parse
    assert_equal [[], %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{{} {b c} d {e f} g}').parse
    assert_equal [[], ['b', 'c'], 'd', ['e', 'f'], 'g'], TclArrayParser.new("\n{\n{\n}\n{\nb\nc\n}\nd\n{\ne\nf\n}\ng\n}\n").parse
  end
end