dotter

graphiz helpers
git clone git://deadbeef.fr/dotter.git
Log | Files | Refs | README | LICENSE

uml (4030B)


      1 #!/usr/bin/awk -f
      2 
      3 function is_class( identifier ) {
      4 	return identifier == "struct" || identifier == "class";
      5 }
      6 
      7 function print_ft_name() {
      8 	printf( "\"" );
      9 	for( i = 2; i < NF; ++i )
     10 	{
     11 		printf( "%s ", $i );
     12 	}
     13 	printf( "%s\"", $NF );
     14 }
     15 
     16 function end_class() {
     17 	if( class != "" )
     18 	{
     19 		printf( "}\"\n]\n" );
     20 		prev_class = class;
     21 		class = "";
     22 	}
     23 	class_type = "";
     24 	inside = "";
     25 	fields_max = 0
     26 	fields_cur = 0
     27 }
     28 
     29 function fun( overload ) {
     30 	if( inside != "fun" )
     31 	{
     32 		printf( "|" );
     33 		inside = "fun";
     34 	}
     35 	printf( "%s %s(", scope, $3 )
     36 	for( i = 4; i <= NF; ++i )
     37 	{
     38 		gsub( ":", " ", $i );
     39 		printf( "%s%s", i == 4 ? "" : ", ", $i );
     40 	}
     41 	printf( "): %s %s\l", $2, overload );
     42 }
     43 
     44 function relation( to, tail, head, label, multiplicity ) {
     45 	printf( "%s -> %s [ dir = \"both\", arrowtail = \"%s\", arrowhead = \"%s\"", prev_class, to, tail, head );
     46 	if( label != "" )
     47 	{
     48 		printf( ", label = \"%s\"", label );
     49 	}
     50 	if( multiplicity != "" )
     51 	{
     52 		if( multiplicity ~ /[0-9]*:[0-9n]*/ )
     53 		{
     54 			split( multiplicity, labels, ":" );
     55 			printf( ", taillabel = \"%s\", headlabel = \"%s\"", labels[1], labels[2] );
     56 		}
     57 		else
     58 		{
     59 			printf( ", headlabel = \"%s\"", multiplicity );
     60 		}
     61 	}
     62 }
     63 
     64 function close_relation() {
     65 	printf( " ];\n" );
     66 }
     67 
     68 function depends( type ) {
     69 	end_class();
     70 	relation( $2, "none", "vee", type );
     71 	printf( " style = \"dotted\"" );
     72 	close_relation();
     73 }
     74 
     75 BEGIN {
     76 	printf( "digraph %s\n{\n", FILENAME );
     77 	class = "";
     78 	prev_class = "";
     79 	class_type = "";
     80 	inside = "";
     81 }
     82 
     83 $0 ~ "^[ \t]*private"   { scope = "[-]"; }
     84 $0 ~ "^[ \t]*protected" { scope = "[#]"; }
     85 $0 ~ "^[ \t]*public"    { scope = "[+]"; }
     86 $0 == "package"   { scope = "[~]"; }
     87 
     88 $1 == "splines" {
     89 	end_class();
     90 	printf( "splines = %s;\n", $2 );
     91 }
     92 
     93 $1 == "package_font" {
     94 	end_class();
     95 	printf( "fontname = " );
     96 	print_ft_name();
     97 	printf( ";\n" );
     98 }
     99 
    100 $1 == "class_font" {
    101 	end_class();
    102 	printf( "node [fontname = " );
    103 	print_ft_name();
    104 	printf( "];\n" );
    105 }
    106 
    107 $1 == "link_font" {
    108 	end_class();
    109 	printf( "edge [fontname = " );
    110 	print_ft_name();
    111 	printf( "];\n" );
    112 }
    113 
    114 # TODO: for templates, it would be better to allow providing types as well
    115 $1 == "enum" || $1 == "bitfield" || $1 == "template" || is_class( $1 ) {
    116 	end_class();
    117 
    118 	if( NF == 3 )
    119 	{
    120 		fields_max = $3
    121 		fields_cur = 0
    122 	}
    123 	scope = "[ ] ";
    124 	printf( "\n\n" );
    125 	class = $2;
    126 	class_type = $1;
    127 	special = ""; # for templates, enums, bitfields, structs (why not)...
    128 	if ( class_type != "class" )
    129 	{
    130 		scope = "";
    131 		special = "«" class_type;
    132 		if ( fields_max != 0 )
    133 		{
    134 			special = special "(" fields_max ")";
    135 		}
    136 		special = special "»";
    137 	}
    138 	printf( "%s\n[\n\tshape=\"record\";\n\tlabel=\"{%s %s", class, class, special );
    139 }
    140 
    141 $1 == "fun" {
    142 	fun( "" );
    143 }
    144 
    145 $1 == "virtual" {
    146 	fun( "[[VIRT]]" );
    147 }
    148 
    149 $1 == "abstract" {
    150 	fun( "[[ABST]]" );
    151 }
    152 
    153 $1 == "var" {
    154 	if( inside != "var" )
    155 	{
    156 		printf( "|" );
    157 		inside = "var";
    158 	}
    159 	printf( "%s%s: %s", scope, $3, $2 );
    160 	if( NF == 4 )
    161 	{
    162 		printf( " = %s", $4 );
    163 	}
    164 	printf( "\l" );
    165 }
    166 
    167 $1 == "val" {
    168 	if( inside != "val" )
    169 	{
    170 		printf( "|" );
    171 		inside = "val";
    172 	}
    173 	error = "";
    174 	if ( fields_max != 0 )
    175 	{
    176 		++fields_cur;
    177 		if ( fields_cur > fields_max )
    178 		{
    179 			error = "EE: "
    180 		}
    181 	}
    182 	if ( is_class( class_type ) )
    183 	{
    184 		printf( "%s%s %s", error, scope, $2 );
    185 	}
    186 	else
    187 	{
    188 		if ( fields_max != 0 )
    189 		{
    190 			printf( "%s%d: %s", error, fields_cur, $2 );
    191 		}
    192 		else
    193 		{
    194 			printf( "%s%s", error, $2 );
    195 		}
    196 	}
    197 	printf( "\l" );
    198 }
    199 
    200 $1 == "inherit" {
    201 	end_class();
    202 	relation( $2, "none", "empty" );
    203 	close_relation();
    204 }
    205 
    206 $1 == "associate" {
    207 	end_class();
    208 	relation( $2, "none", "vee", $3, $4 );
    209 	close_relation();
    210 }
    211 
    212 $1 == "aggreg" {
    213 	end_class();
    214 	relation( $2, "odiamond", "vee", $3, $4 );
    215 	close_relation();
    216 }
    217 
    218 $1 == "compose" {
    219 	end_class();
    220 	relation( $2, "diamond", "vee", $3, $4 );
    221 	close_relation();
    222 }
    223 
    224 $1 == "depends" {
    225 	depends( "" );
    226 }
    227 
    228 $1 == "friend" {
    229 	depends( "friend" );
    230 }
    231 
    232 $1 == "package" {
    233 	end_class();
    234 	printf( "\nsubgraph cluster%s\n{\nlabel = \"%s\" ", $2, $2 );
    235 }
    236 
    237 $1 == "endpackage" {
    238 	end_class();
    239 	printf( "}\n" );
    240 }
    241 
    242 END {
    243 	end_class();
    244 	printf( "}\n" );
    245 }