summaryrefslogtreecommitdiffstats
path: root/misc/drawtree.pl
blob: 72435952b22b1b3ebcf3ad5263e69a52c7769a76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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";