############################################################################
#
#	File:     trees.icn
#
#	Subject:  Procedures for manipulating trees and dags
#
#	Author:   Ralph E. Griswold
#
#	Date:     December 27, 1995
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#  
#       depth(t)	compute maximum depth of tree t
#  
#       ldag(s)		construct a dag from the string s
#
#       ltree(s)	construct a tree from the string s
#
#       stree(t)	construct a string from the tree t
#
#       tcopy(t)	copy tree t
#
#       teq(t1,t2)	compare trees t1 and t2
#  
#       visit(t)	visit, in preorder, the nodes of the tree t
#  
############################################################################

procedure depth(ltree)			#: depth of tree
   local count

   count := 0
   every count <:= 1 + depth(ltree[2 to *ltree])
   return count

end

procedure ldag(stree,done)		#: construct dag from string
   local L

   /done := table()
   if L := \done[stree] then return L
   stree ?
      if L := [tab(upto('('))] then {
         move(1)
         while put(L,ldag(tab(bal(',)')),done)) do
            move(1)
         }
      else L := [tab(0)]
   return done[stree] := L

end

procedure ltree(stree)			#: construct tree from string
   local L

   stree ?
      if L := [tab(upto('('))] then {
         move(1)
         while put(L,ltree(tab(bal(',)')))) do
            move(1)
         }
      else L := [tab(0)]
   return L

end

procedure stree(ltree)			#: construct string from tree
   local s

   if *ltree = 1 then return ltree[1]
   s := ltree[1] || "("
   every s ||:= stree(ltree[2 to *ltree]) || ","
   return s[1:-1] || ")"

end

procedure tcopy(ltree)			#: tree copy
   local L

   L := [ltree[1]]
   every put(L,tcopy(ltree[2 to *ltree]))
   return L

end

procedure teq(L1,L2)			#: tree equivalence
   local i

   if *L1 ~= *L2 then fail
   if L1[1] ~== L2[1] then fail
   every i := 2 to *L1 do
      if not teq(L1[i],L2[i]) then fail
   return L2

end

procedure visit(ltree)			#: visit nodes of tree

   suspend ltree | visit(ltree[2 to *ltree])

end
