File:  [Research Unix] / researchv10no / cmd / sml / lib / twig / runtime.sml
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman


(* April 1989, Jussi Rintanen, Helsinki University of Technology *)

(* This is the signature of a specification generated by ML-Twig *)

signature TWIG_SPECIFICATION =
  sig
    type cost and tree and result
    eqtype rule and symbol

    val get_subtrees : tree -> tree list
    val node_value : tree -> symbol
    val cost_less : cost * cost -> bool

    datatype skeletal = Skeleton of rule * cost * tree * skeletal list

    exception MatchAbort and InternalError of string

    val execute_cost : rule * tree * skeletal list -> cost
    val execute : skeletal -> result
    val getreplacement : result -> tree
    val rewriterule : rule -> bool
    val matches : rule -> int

(* Definitions for unit rule matches and the tree pattern matching automaton *)

    eqtype state

    datatype matchtree = Chain of rule * symbol * matchtree list
    val unitmatches : symbol -> matchtree list

    val childsymbol : int -> symbol
    val initialstate : state
    val go : state * symbol -> state
    val go_f : state * symbol -> (int * rule * symbol) list
end;

(* This functor maps a specification to a structure containing a complete tree
   processor program and associated definitions. *)

functor MAKEtreeprocessor ( Specification : TWIG_SPECIFICATION) =
  struct
    structure Spec : TWIG_SPECIFICATION = Specification

    open Spec

    exception NoCover
    
    fun internal s = raise InternalError ("FATAL:"^s)

(* The structure representation implements a data type for
   maintaining information of the matching tree pattern
   matching process. The actual implementation is left
   unspecified in the signature. However, because of the
   match mode rewrite, an implementation without side effects
   is required. *)

    structure Representation :
      sig
	type 's table
	structure Spec : TWIG_SPECIFICATION

	val empty_table : unit -> 's table
	val new_level : 's table -> 's table
	val contribute0 : 's table * int * Spec.rule * Spec.symbol -> 's table
	val contribute1 : 's table * int * Spec.rule * Spec.symbol * 's -> 's table
	val get_level : 's table -> (Spec.symbol * (Spec.rule * int * 's list) list) list * 's table
      end
    =
    struct

(* The table is a list, where the head contains the match information
   for the current node of the user tree. The tail of the list
   contains the match information for the ancestors of the current
   node. The match information for a node is an ordered list of pairs,
   where the first member is the number of the non-terminal, to which
   the matches in the second member contribute.
     The matches for a non-terminal are in an ordered list of triples
   rule * number of matches * children skeletons. *)

      structure Spec = Spec

      open Spec

      type 's table = (symbol * (rule * int * 's list) list) list list
      fun empty_table () = []
      fun new_level l = []::l
      fun insert0' (r:rule,nil) = [(r,1,[])]
	| insert0' (r:rule,(h as (r',m',s'))::hs) =
	  if r' <> r
	    then h :: insert0' (r,hs)
	  else (r,m'+1,s')::hs
      fun insert0 (nil,r,t:symbol) = [(t,[(r,1,[])])]
	| insert0 ((h as (t',a))::hs,r,t) =
	  if t' <> t
	    then h :: insert0 (hs,r,t)
	  else (t,insert0' (r,a))::hs
      fun insert1' (r:rule,s,nil) = [(r,1,[s])]
	| insert1' (r,s,(h as (r',m',s'))::hs) =
	  if r' <> r
	    then h :: insert1' (r,s,hs)
	  else (r,m'+1,s::s')::hs
      fun insert1 (nil,r,t:symbol,s) = [(t,[(r,1,[s])])]
	| insert1 ((h as (t',a))::hs,r,t,s) =
	  if t' <> t
	    then h :: insert1 (hs,r,t,s)
	  else (t,insert1' (r,s,a)):: hs
      fun contribute0 (a::l,1,r,t) = insert0 (a,r,t) :: l
	| contribute0 (a::l,n,r,t) = a::contribute0(l,n-1,r,t)
	| contribute0 _ = internal "run out of levels"
      fun contribute1 (a::l,1,r,t,s) = insert1(a,r,t,s) :: l
        | contribute1 (a::l,n,r,t,s) = a::contribute1(l,n-1,r,t,s)
	| contribute1 _ = internal "run out of levels"
      fun get_level (a::l) = (a,l)
	| get_level _ = internal "run out of levels"
    end

  open Representation

(* Utility functions *)

  val accum = revfold

  fun cost (Skeleton(_,c,_,_)) = c
    
  fun insert (i:symbol, s, nil) = [(i,s)]
    | insert (i, s, (head as (i',s'))::rest) =
	  if i = i'
	    then
	      if cost_less (cost s,cost s')
		then (i,s)::rest
	      else head::rest
	  else head :: (insert (i,s,rest))

  fun build_skeleton (ar as (r,t,cs)) = Skeleton (r,execute_cost ar,t,rev cs)

(* get_closure takes four arguments. The first is a unit rule tree.
The second is the sub-skeleton in the unit rule match. The third
is the ir-tree of the current node, and the fourth is the list
of skeletons generated so far. The skeleton list consists of pairs:
the first element is the number of the non-terminal of the rule,
and the second element is the skeleton. *)

  fun get_closure (ct,ss,t,ac) =
    accum (fn (Chain(r,n,cs),ac') =>
	   let val skel = build_skeleton(r,t,ss)
	   in
	     get_closure (cs,[skel],t,insert (n,skel,ac'))
	   end handle MatchAbort => ac')
	   ct ac

  fun someone (t,still_best, nil) = [still_best]
    | someone (t,still_best, (r,m,cs)::rest) =
      if matches r = m
	then
	  let val skel = build_skeleton (r,t,cs)
	  in someone (t,if cost_less (cost skel,cost still_best)
			then skel
		      else still_best,rest)
	  end handle MatchAbort => someone (t,still_best,rest)
	else someone(t,still_best,rest)

  fun still_no_one (t,nil) = nil
    | still_no_one (t,(r,m,cs)::rest) =
      if matches r = m
	then someone (t,build_skeleton (r,t,cs),rest)
	  handle MatchAbort => still_no_one (t,rest)
      else still_no_one (t,rest)

  fun leave_best_alone (t,nil) = internal "matcher state inconsistent. lba."
    | leave_best_alone (t,l) = still_no_one (t,l)

  fun skeletons_of (state,node,tab) =
    let val (t,s) =
      case get_subtrees node of
	nil =>
	  let val tab' =
	    accum (fn ((h,r,n),t) => contribute0 (t,h-1,r,n))
	      (go_f(state, node_value node)) tab
	  in
	    (tab', get_closure ((unitmatches o node_value) node,[],node,[]))
	  end
      | ls =>
	  let val state' = go (state, node_value node)
	    val (table, _) =
	      accum (fn (l,(t,i)) =>
		     let val state'' = go (state',childsymbol i)
		       val (t', ss) = skeletons_of (state'',l,t)
		     in (accum (fn ((r,s),t'') =>
				let val finals = go_f (state'',r)
				in
				  accum
				  (fn ((h,r,n),t''') =>
				     contribute1 (t''',h-1,r,n,s))
				     finals t''
				end) ss t',i+1)
		     end)
		     ls
		     (new_level tab, 1)
	    val (toplevel, table') = get_level table
	  in
	    (table',
	     let val unclosurized = accum (fn ((_,nil),l) => l | ((n,[e]),l) => (n,e)::l | _ => internal "inconsistency. 01l")
	       (map (fn (n,sl) => (n,leave_best_alone (node,sl))) toplevel)
		  nil
	     in
	       accum (fn ((n,s),al) =>
		      get_closure (unitmatches n,[s],node,al)) unclosurized unclosurized
	     end)
	  end
    in
      case s of
	[] => (t,[])
      | [(_,S as Skeleton(r,_,_,_))] =>
	  if rewriterule r
	    then skeletons_of(state,(getreplacement o execute) S,tab)
	  else (t,s)
      |  (_,sk)::rest =>
	    let val best as Skeleton (r,_,_,_) =
	      accum (fn ((n,s),bs) =>
		     if cost_less (cost s,cost bs) then s else bs) rest sk
	    in
	      if rewriterule r
		then skeletons_of(state,
				  (getreplacement o execute) best,
				   tab)
	      else (t,s)
	    end
    end

  fun translate t = execute
    (case (skeletons_of (initialstate,t,empty_table())) of
       (_,(_,s)::t) =>
	  accum (fn ((n,s),bs) =>
		 if cost_less (cost s,cost bs) then s else bs) t s
    | (_,nil) => raise NoCover)

  end;

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.