diff options
| author | David A. Madore <david+git@madore.org> | 2018-01-29 15:31:24 +0100 | 
|---|---|---|
| committer | David A. Madore <david+git@madore.org> | 2018-01-29 15:31:24 +0100 | 
| commit | d1a7e0acc7c78ec3d2bf473b4b4739315b8a2f1f (patch) | |
| tree | f119b2f49198d04b462276c87224172d1b38f1b1 | |
| parent | 5ae6d7fbf72a36f7891d14399c0d4fc9cfb370b8 (diff) | |
| download | inf105-d1a7e0acc7c78ec3d2bf473b4b4739315b8a2f1f.tar.gz inf105-d1a7e0acc7c78ec3d2bf473b4b4739315b8a2f1f.tar.bz2 inf105-d1a7e0acc7c78ec3d2bf473b4b4739315b8a2f1f.zip | |
Simple Perl program used to generate TikZ trees.
| -rwxr-xr-x | misc/drawtree.pl | 116 | 
1 files changed, 116 insertions, 0 deletions
| diff --git a/misc/drawtree.pl b/misc/drawtree.pl new file mode 100755 index 0000000..7243595 --- /dev/null +++ b/misc/drawtree.pl @@ -0,0 +1,116 @@ +#! /usr/local/bin/perl -w + +use strict; +use warnings; + +my $str = <>; +chomp $str; + +my $cursor = 0; +sub parse { +    my $nodelabel = ""; +    while (substr($str,$cursor,1) ne "<" && substr($str,$cursor,1) ne ".") { +	die if $cursor >= length($str); +	$nodelabel .= substr($str,$cursor,1); +	$cursor++; +    } +    $cursor++ if substr($str,$cursor,1) eq "<"; +    my %node = (); +    $node{label} = $nodelabel; +    die if $nodelabel eq ""; +    my @children = (); +    $node{t} = \@children; +    while (substr($str,$cursor,1) ne ">" && substr($str,$cursor,1) ne ".") { +	die if $cursor >= length($str); +	my $child = parse(); +	$child->{parent} = \%node; +	push @children, $child; +    } +    $cursor++; +    return \%node; +} + +my $tree = parse; + +my @leafnodes = (); +my @pfxnodes = (); +my @sfxnodes = (); +sub donodes { +    my $node = shift; +    die unless defined($node->{label}); +    die unless defined($node->{t}); +    die unless ref($node->{t}) eq "ARRAY"; +    $node->{depth} = defined($node->{parent}) ? $node->{parent}->{depth} + 1 : 0; +    push @pfxnodes, $node;  $node->{pfx} = $#pfxnodes; +    if ( scalar(@{$node->{t}}) ) { +	foreach my $n (@{$node->{t}}) { +	    donodes($n); +	} +    } else { +	push @leafnodes, $node; +    } +    push @sfxnodes, $node;  $node->{sfx} = $#sfxnodes; +} +donodes $tree; + +for ( my $i=0 ; $i<scalar(@leafnodes) ; $i++ ) { +    $leafnodes[$i]->{x} = $i * 20; +} + +my %nodenames; + +for ( my $i=0 ; $i<scalar(@pfxnodes) ; $i++ ) { +    my $node = $pfxnodes[$i]; +    my $base = $node->{label}; +    $base = "o" if $base eq "\#" || $base eq "\@"; +    $base = "p" if $base eq "\(" || $base eq "\)"; +    my $j; +    for ( $j=0 ; ; $j++ ) { +	last unless defined($nodenames{$base.$j}); +    } +    my $name = $base.$j; +    $node->{name} = $name; +    $nodenames{$name} = $node; +    my $ltxlabel = $node->{label}; +    $ltxlabel = "\\" . $ltxlabel if $ltxlabel eq "\#"; +    $node->{ltxlabel} = $ltxlabel; +} + +for ( my $i=0 ; $i<scalar(@pfxnodes) ; $i++ ) { +    my $node = $pfxnodes[$i]; +    if ( defined($node->{parent}) ) { +	my $p = $node->{parent}; +	die unless defined $p->{y}; +	if ( scalar(@{$p->{t}}) > 1 ) { +	    $node->{y} = $p->{y} + 30; +	} else { +	    $node->{y} = $p->{y} + 20; +	} +    } else { +	$node->{y} = 0; +    } +} + +for ( my $i=0 ; $i<scalar(@sfxnodes) ; $i++ ) { +    my $node = $sfxnodes[$i]; +    if ( scalar(@{$node->{t}}) ) { +	my $sum = 0;  my $cnt = 0; +	foreach my $n (@{$node->{t}}) { +	    die unless defined $n->{x}; +	    $sum += $n->{x};  $cnt++; +	} +	$node->{x} = $sum/$cnt; +    } +} + +printf "\\begin{tikzpicture}\[line join=bevel,baseline=(%s.base)\]\n", $tree->{name}; +for ( my $i=0 ; $i<scalar(@pfxnodes) ; $i++ ) { +    my $node = $pfxnodes[$i]; +    printf "\\node (%s) at (%.3fbp,%.3fbp) \[draw=none\] {\$%s\$};", $node->{name}, $node->{x}, -$node->{y}, $node->{ltxlabel}; +    if ( defined($node->{parent}) ) { +	printf "  \\draw (%s) -- (%s);\n", $node->{parent}->{name}, $node->{name}; +    } else { +	printf "\n"; +    } +} +print "\\end{tikzpicture}\n"; | 
