Rigi CScripts

Program-Transformation.Org: The Program Transformation Wiki
A sample RCL script that is used to pre-process the RSF generated with cparse for Rigi has been written by JohannesMartin. The RCL script is generic and works for most C programs. He also used the script (with slight modifications) to look at web site structures.

Note that the preprocessing takes away detail and creates a specific structure in the graph. For example, all of the standard library is filtered out. You can use the script as a starting point and modify it to suit your own, specific needs.

# load rsf file and perform some preliminary modifications
proc load_cprog {filename} {
    set_domain cparse 0
    rcl_win_set_drawing 0
    rcl_load_rsf $filename
    puts "Delete standard library nodes..."
    c_delete_std
    puts "Delete disconnected variables..."
    c_delete_disconnected Variable
    puts "Delete disconnected prototypes..."
    c_delete_disconnected Prototype
    puts "Delete disconnected datatypes..."
    c_delete_disconnected Datatype
    puts "Delete disconnected constants..."
    c_delete_disconnected Constant
    puts "Delete disconnected functions..."
    c_delete_disconnected Function
    puts "Delete disconnected unknowns..."
    c_delete_disconnected Unknown

    puts "Redirecting prototypes..."
    c_redirect Prototype prototypes
    puts "Redirecting external variable declarations..."
    c_redirect Variable declares
    c_redirect Constant declares
    puts "Redirecting datatypes..."
    c_redirect Datatype isTheSameAs 
    puts "Collapsing function parameters..."
    c_collapse2 Function isDefinedIn in

    puts "Delete disconnected variables..."
    c_delete_disconnected Variable
    puts "Delete disconnected prototypes..."
    c_delete_disconnected Prototype
    puts "Delete disconnected datatypes..."
    c_delete_disconnected Datatype
    puts "Delete disconnected constants..."
    c_delete_disconnected Constant
    puts "Delete disconnected functions..."
    c_delete_disconnected Function
    puts "Delete disconnected unknowns..."
    c_delete_disconnected Unknown

    rcl_grid_all
    rcl_win_set_drawing 1
    rcl_refresh
}


# Delete every nodes that represent artifacts out of the standard library
# (/usr/include/*) and standard data types.
proc c_delete_std { } {
    rcl_select_none
    rcl_select_grep ".*/usr/include/.*"
    rcl_select_name int 1
    rcl_select_name char 1
    rcl_select_name long 1
    rcl_select_name void 1
    rcl_select_name float 1
    rcl_select_name double 1
    
    set winnodes [rcl_select_get_list]
    rcl_select_none

    foreach node $winnodes {
   rcl_node_delete $node
    }
}


# For all nodes of type ntype (winnodes), find a target node
# (destination) for a first (and only) outgoing arc of type atype (arc1).
# Redirect all incoming arcs of nodes belonging to 'winnodes' to enter
# node 'destination'.
# Delete winnodes and their dependencies out of the graph  
# an example of usage: c_redirect Prototype prototypes
proc c_redirect {ntype atype} {
    rcl_select_none
    rcl_select_type $ntype
    set winnodes [rcl_select_get_list]
    rcl_select_none
    
    foreach node $winnodes {
   set arclist [rcl_node_get_arclist $node $atype out 0 0]
   if { [llength $arclist] >= 1 } {        
       set arc1 [lindex $arclist 0]
       set enterings [rcl_node_get_arclist_in_window $node any in]
       set destination [rcl_get_arc_dst $arc1]
       foreach arc2 $enterings {
      set type [rcl_get_arc_type $arc2]
      if { [rcl_get_arctype level] != $type } {
          set source [rcl_get_arc_src $arc2]
          rcl_arc_create2 $source $destination $type
      }
       }
       rcl_node_delete $node
   }
    }   
    rcl_refresh
}


# For all nodes of type ntype, collapse them and all nodes
# that are connected to them with an arc of type atype 
# (the direction of the connection is dir)
# to a single node (the collapsed node is given the same name as 
# the original ntype type nodes).
# an exampe of usage: c_collapse Function isDefinedIn in
proc c_collapse {ntype atype dir} {
    rcl_select_none
    rcl_select_type $ntype
    set winnodes [rcl_select_get_list]
    rcl_select_none

    foreach node $winnodes {
   rcl_select_id $node
   set name [rcl_get_node_name $node]
   select_neighbors $atype $dir 1
   if {[rcl_collapse Collapse $name] == 0} { return }
    }
}


# For all nodes of type ntype:
# - collapse all nodes that are connected to the node with an arc of 
#   type atype (the direction of the connection is dir) to a single node.
# - redirect all arcs going to or coming from the node to the
#   new collapsed node.
# - give the new collapsed node the name of the original node
#   delete the original node
# an exampe of usage: c_collapse Function isDefinedIn in
proc c_collapse2 {ntype atype dir} {
    rcl_select_none
    rcl_select_type $ntype
    set winnodes [rcl_select_get_list]
    rcl_select_none

    foreach node $winnodes {
   rcl_select_id $node
   select_neighbors $atype $dir 1
   rcl_select_deselect_id $node
   if { [ llength [ rcl_select_get_list ] ] >= 1 } {
       if { [ rcl_collapse $ntype [ rcl_get_node_name $node ] ] == 0} { 
      return 
       }
       set id [rcl_select_get_list]

       set arclist [ rcl_node_get_arclist $node any out 1 1 ]
       foreach arc $arclist {
      set type [rcl_get_arc_type $arc]
      set dst [rcl_get_arc_dst $arc]
      if { $id != $dst } {
          rcl_arc_create2 $id $dst $type
      }
       }
       set arclist [ rcl_node_get_arclist $node any in 1 1 ]
       foreach arc $arclist {
      set type [rcl_get_arc_type $arc]
      set src [rcl_get_arc_src $arc]
      if { $src != $id } {
          rcl_arc_create2 $src $id $type
      }
       }
       rcl_node_delete $node
   }
    }
}


# Delete disconnected nodes of type 'ntype' from the graph
# an example of usage: c_delete_disconnected Variable
proc c_delete_disconnected {ntype} {
    rcl_select_none
    rcl_select_type $ntype
    set winnodes [rcl_select_get_list]
    rcl_select_none
    
    foreach node $winnodes {
   set nnodes [rcl_node_get_neighbors_in_window $node any any]
   if {[llength $nnodes] < 1} {
       rcl_node_delete $node
   }
    }
    rcl_refresh
}


# Find partitions of the graph that are connected with arcs of type atype
# and make them into subsystems.
proc c_partition {atype} {
    rcl_set_current_arctype $atype
    while { 1 } {
   rcl_select_all
   set nodes [rcl_select_get_list]
   foreach id $nodes {
       rcl_select_id $id
       set oldnum 0
       set newnum 1
       while { $newnum > $oldnum } {
      rcl_select_forward_tree
      rcl_select_reverse_tree
      set oldnum $newnum
      set newnum [rcl_select_num_nodes]
       }
       if { $newnum > 1 } {
      puts "Collapsing $newnum nodes..."
      rcl_collapse Collapse "Subsystem ($newnum children)"
      set id 0
      break
       }
   }
   if { $id != 0 } {
       break
   }
    }
}


# Find partitions of the graph by node names and make them into subsystems.
# Name is a regular expression characterizing the names of all nodes to be 
# collapsed.
proc c_partition_by_name {name} {
    rcl_select_none
    rcl_select_grep "$name"
    set num [rcl_select_num_nodes]
    if { $num > 1 } {
   puts "Collapsing $num nodes for library $name..."
   rcl_collapse Collapse "$name Subsystem ($num children)"
    }
}

# Remove mangling from names and move into annotate attribute
proc c_unmangle_names {} {
    rcl_select_all
    set nodes [rcl_select_get_list]
    foreach id $nodes {
   set name [rcl_get_node_name $id]
   if { [regsub {^([^^]*)\^.*} "$name" {\1} newname] > 0 } {
       rcl_set_node_name $id $newname
       regsub {^([^^]*)\^(.*)} "$name" {\2} annotate
       rcl_set_node_attr $id annotate $annotate
   }
    }
    rcl_refresh
}


CategoryRigi