リスト文字列を1文字ずつパース

深さを自由に表現できるリストをパースする
まず、どのような動作をすれば良いか書いてみる。

str=%([["A",["B"]],["C","1"]])
希望する結果           リストをスタックに保存       そのための      結果
                       しながら管理する様子         命令
[]                      s0[]                        s[0]=[]          [[]]
[[]]                    s0[] s1[]                   s[1]=[]          [[],[]]
[["A"]]                 s0[] s1["A"]                s[1].push("A")   [[], ["A"]]
[["A",[]]]              s0[] s1["A"] s2[]           s[2]=[]          [[], ["A"],[]]
[["A",["B"]]]           s0[] s1["A"] s2["B"]        s[2].push("B")   [[], ["A"],["B"]]
                        s0[] s1["A",["B"]]          s[1].push(s.pop) [[], ["A", ["B"]]]
                        s0[["A",["B"]]]             s[0].push(s.pop) [[["A", ["B"]]]]
[["A",["B"]],[]]        s0[["A",["B"]]] s1[]        s[1]=[]          [[["A", ["B"]]], []]
[["A",["B"]],["C"]]     s0[["A",["B"]]] s1["C"]     s[1].push("C")   [[["A", ["B"]]], ["C"]]
[["A",["B"]],["C","1"]] s0[["A",["B"]]] s1["C","1"] s[1].push("1")   [[["A", ["B"]]], ["C", "1"]]
                        s0[["A",["B"]],["C","1"]]   s[0].push(s.pop) [["A", ["B"]], ["C", "1"]]
そのための命令
s[1]=[]          : "[" と出会ったとき
s[1].push(s.pop) : "]" と出会ったとき
s[1].push("C")   : 終わりの '"'と出会ったとき 終わりかはじめかはフラグで
class String
  def head; self[0].chr  end
  def tail; self[1...(self.length)] end
end

class Array
  def head; self[0]  end
  def tail; self[1...(self.length)] end
end

# str=%([["A",["B",["0-16-087"]]],["C","1","0-06-074"]])
str=%([["A",["B"]],["C","1"]])

def myEval(inString, out, n,tstr, flag)
  return out if inString.length==1

  head = inString.head
  tail = inString.tail

  if    head == '[' then
      n+=1
    out[n]=[]
    p ["[[[[",n,out]
    myEval(tail, out, n, tstr, flag)
  elsif head == ']' then
    n-=1
    out[n].push(out.pop)
    p ["]]]]",n,out]
    myEval(tail, out, n, tstr, flag)
  elsif head == ',' then myEval(tail, out, n,tstr, flag)
  elsif head == '"' then 
    if flag then 
       out[n].push(tstr)
       p ["push",n,out]
       myEval(tail, out, n, "", false)
    else myEval(tail, out, n, tstr, true) end
  else myEval(tail, out, n, (tstr + head) , true) end
end

p myEval(str, [] , -1,"" ,false).head
["[[[[", 0, [[]]] 
["[[[[", 1, [[], []]]
["push", 1, [[], ["A"]]]
["[[[[", 2, [[], ["A"], []]]
["push", 2, [[], ["A"], ["B"]]]
["]]]]", 1, [[], ["A", ["B"]]]]
["]]]]", 0, [[["A", ["B"]]]]]
["[[[[", 1, [[["A", ["B"]]], []]]
["push", 1, [[["A", ["B"]]], ["C"]]]
["push", 1, [[["A", ["B"]]], ["C", "1"]]]
["]]]]", 0, [[["A", ["B"]], ["C", "1"]]]]
[["A", ["B"]], ["C", "1"]]

位置を示す n は必要なくて末尾の要素に対する操作でよい。

def myEval(inString, out,tstr, flag)
  return out if inString.length==1

  head = inString.head
  tail = inString.tail

  if    head == '[' then
    out.push([])
    myEval(tail, out, tstr, flag)
  elsif head == ']' then
    d = out.pop
    (out.last).push(d)
    myEval(tail, out, tstr, flag)
  elsif head == ',' then myEval(tail, out,tstr, flag)
  elsif head == '"' then 
    if flag then 
       (out.last).push(tstr)
       myEval(tail, out, "", false)
    else myEval(tail, out, tstr, true) end
  else myEval(tail, out, (tstr + head) , true) end
end