#!/usr/bin/perl # Use -*-perl-*- mode in emacs. @files = (); $clssection = "section"; $clssubsection = "subsection"; #for $i (@ARGV) { while ($i = shift) { if ($i eq '-clssection') { $clssection = shift; } elsif ($i eq '-clssubsection') { $clssubsection = shift; } else { @files = (@files, $i); } } @ARGV = @files; $printmember = 0; $printmembercase = 0; $template_param = ''; $class = ''; $classdoc = ''; %item = (); %sectionname = (pri, "Private", pro, "Protected", pub, "Public"); @sectionorder = (pub, pro, pri); while(<>) { while(/^\s*\/\//) { if (/^\s*\/\/\.\s+(.*)/) { do get_doc($1); } elsif (/^\s*\/\/\.\s*$/) { do get_doc(''); } else { last; } } if (/^\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { do new_class($1,'',''); } elsif (/^\s*template <(.*)>\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { do new_class($2,$1,''); } elsif (/^\s*template <(.*)>\s*$/) { $tmp_template_param = $1; while (<>) { last; } if (/^\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { do new_class($1,$tmp_template_param,''); } } elsif (/^\s*private\s*:/) { $interface = 'pri'; } elsif (/^\s*public\s*:/) { $interface = 'pub'; } elsif (/^\s*protected\s*:/) { $interface = 'pro'; } } do write_doc(); sub new_class { # flush out the documentation for the previous class do write_doc(); $class = $_[0]; $template_param = $_[1]; $classdoc = $_[2]; $interface = 'pri'; $private = ''; $protected = ''; $public = ''; } sub write_doc { local($nsection) = keys(%item); if ($classdoc ne '' || $item{'pri'} ne '' || $item{'pro'} ne '' || $item{'pub'} ne '') { $template_param =~ s/_/\\_/g; if (!open(OUTPUT, ">doc/$class.cls.tex")) { die "Can't open doc/$class.cls.tex: $!"; } print "writing $class.cls.tex\n"; if ($template_param eq '') { print OUTPUT "\\$clssection\{The \\clsnm{$class} Class}"; print OUTPUT "\\label{$class}\\index{$class}\n"; #print OUTPUT "\\clssection{$class}\n"; } else { print OUTPUT "\\$clssection\{The \\clsnm{$class"; print OUTPUT "\$<\$$template_param\$>\$} Class Template}"; print OUTPUT "\\label{$class}\\index{$class}\n"; #print OUTPUT "\\tclssection{$class}{$template_param}\n"; } print OUTPUT "\\index{$class}\n"; if ($classdoc ne '') { print OUTPUT "$classdoc\n"; } for (@sectionorder) { if ($item{$_} ne '') { if ($template_param eq '') { print OUTPUT "\\$clssubsection\{The $sectionname{$_} \\clsnm{$class} Interface}\n"; } else { print OUTPUT "\\$clssubsection\{The \\clsnm{$class"; print OUTPUT "\$<\$$template_param\$>\$} Class Template Interface}\n"; } local($memberdoc) = $item{$_}; # two items in a row shouldn't have an mbox $memberdoc =~ s/\\mbox{}\\\\\s*\\item\[/\n\\item\[/g; print OUTPUT "\\begin{classinterface}\n"; print OUTPUT $memberdoc; print OUTPUT "\\end{classinterface}\n"; } } close(OUTPUT); } %item = (); $classdoc = ''; } sub beautify_member { $m = $_[0]; print "MEM=$m\n" if ($printmember); $_ = $m; # remove inline s/inline//; # remove parent/member constructor calls s/::/SAVEDCOLONCOLON/g; s/:.*$//; s/SAVEDCOLONCOLON/::/g; $virtual = 0; $static = 0; $constreturn = 0; # check for a constructor if (/^\s*[A-Za-z_][A-Za-z0-9_]*\s*\(/) { $typename = 'void'; } # check for a destructor elsif (/^\s*(virtual\s)?\s*~\s*[A-Za-z_][A-Za-z0-9_]*\s*\(/) { $typename = 'void'; if (s/^\s*virtual//) { $virtual = 1; } } else { # parse the virtual and static qualifiers if (s/^\s*virtual//) { $virtual = 1; } elsif (s/^\s*static//) { $static = 1; } # parse the const qualifier if (s/^\s*const//) { $constreturn = 1; } # parse the type name /^\s*([A-Za-z_][A-Za-z_0-9<>,]*)(.*)/; $typename = $1; $_ = $2; # parse the reference and pointer and const qualifiers while (/^\s*(&)(.*)/ || /^\s*(\*)(.*)/ || /^\s*(const)(.*)/) { $typename = "$typename $1"; $_ = $2; } $typename =~ s/&/\\&/g; $typename =~ s/_/\\_/g; $typename =~ s//\$>\$/g; $typename = "const $typename" if ($constreturn); } # parse the member name ($destructor, $membername, $rest) = /^\s*(~?)\s*([A-Za-z_][A-Za-z0-9_]*)(.*)/; $_ = $rest; $membername = "$destructor$membername"; if ($typename eq "operator") { # fixup type conversion operators $typename = "$membername"; $membername = "operator $membername"; } elsif ($membername eq 'operator') { # operator () is a special case if (/^\s*\(\s*\)(.*)/) { $membername = "$membername ()"; $_ = $1; } else { /^\s*([^(]*)\s*(\(.*)/; $membername = "$membername $1"; $_ = $2; } } #print "MN = $membername, _ = $_\n"; # look for underscores in membername #@membername = split(/_/,$membername); #$item = ""; #foreach $i (0 .. $#membername) { # $item = join('$item',"{\\bfseries $membername[$i]}"); # if ($i != $#membername) { # $item = "$item\_"; # } #} $item = "{\\bfseries $membername}"; $item =~ s/_/\\_/g; # take care of special characters in item $item =~ s/&/\\&/g; $item =~ s//\$>\$/g; $item =~ s/~/\$\\tilde{}\$/; # parse the arglist /\((.*)\)(.*)/; $arglist = $1; $_ = $2; # take care of special characters in arglist $arglist =~ s/&/\\&/g; $arglist =~ s//\$>\$/g; $arglist =~ s/_/\\_/g; # make sure there is whitespace after commas (for better formatting). $arglist =~ s/,\s*/, /g; # parse the constness of calling object $constobject = 0; if (/^[ \t]*const(.*)/) { $constobject = 1; $_ = $1; } # parse the pure virtual qualifier $pure = 0; if (/[ \t]*=[ \t]*0(.*)/) { $pure = 1; $_ = $1; } # construct the table entry $qualifiers = ''; if ($constobject) { $qualifiers = "$qualifiers const"; } if ($pure) { $qualifiers = "$qualifiers pure"; } elsif ($virtual) { $qualifiers = "$qualifiers virtual"; } elsif ($static) { $qualifiers = "$qualifiers static"; } $_ = $qualifiers; /[ \t]*(.*)[ \t]*/; $qualifiers = $1; #$item = "\@b{$membername}($arglist)"; $item = "$item($arglist)"; if ($qualifiers ne '') { $item = "$item $qualifiers"; } if ($typename ne 'void') { $item = "$item \$\\rightarrow\$ {\\bfseries $typename}"; } return "$item"; } sub get_doc { $doc = $_[0]; $members = ''; $indoc = 1; while (<>) { if ($indoc && /^\s*\/\/(\.)?(\s*.*)/) { $doc = "$doc\n$2"; } elsif (/^\s*template <(.*)>\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { do new_class($2,$1,''); } elsif (/^\s*template <(.*)>\s*$/) { $tmp_template_param = $1; while (<>) { last; } if (/^\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { while(<>) { last; } do new_class($1,$tmp_template_param,''); last; } } elsif (/^\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/) { while(<>) { last; } do new_class($1,'',$doc); last; } elsif (/^\s*((~\s*)?[A-Za-z_].*,)\s*$/) { $indoc = 0; $member = $1; $remainder = &read_member_continuation; $member = "$member$remainder"; print "CASE 1: MEM=$member\n" if ($printmembercase); $member = &beautify_member($member); $members = "$members\\item[$member]\\mbox{}\\\\\n"; } elsif (/^\s*((~\s*)?[A-Za-z_].*)\s*{/) { $indoc = 0; print "CASE 2: MEM=$1\n" if ($printmembercase); $member = &beautify_member($1); $members = "$members\\item[$member]\\mbox{}\\\\\n"; # attempt to skip over simple routines &skip_inlined_routine("{$'"); } elsif (/^\s*((~\s*)?[A-Za-z_].*);\s*/) { $indoc = 0; print "CASE 3: MEM=$1\n" if ($printmembercase); $member = &beautify_member($1); $members = "$members\\item[$member]\\mbox{}\\\\\n"; } elsif (/^\s*((~\s*)?[A-Za-z_].*)\s*/) { $indoc = 0; $member = $1; if (! /\)/) { # the member is not complete--finish it $remainder = &read_member_continuation; $member = "$member$remainder"; } print "CASE 4: MEM=$member\n" if ($printmembercase); $member = &beautify_member($member); $members = "$members\\item[$member]\\mbox{}\\\\\n"; } elsif (/^\s*{/) { $indoc = 0; &skip_inlined_routine("{$'"); } else { $item{$interface} = "$item{$interface}$members$doc\n\n"; last; } } } sub skip_inlined_routine { local($_) = $_[0]; local($nbracket) = &count_brackets($_); return if ($nbracket == 0); while (<>) { $nbracket = $nbracket + &count_brackets($_); return if ($nbracket == 0); } } sub count_brackets { local($_) = $_[0]; local($n) = 0; s/"[^\"]*"//g; local(@chars) = split(//,$_); foreach (@chars) { if ($_ eq "{") { $n++; } elsif ($_ eq "}") { $n--; } } return $n; } sub read_member_continuation { local($member) = ""; while (<>) { if (/^\s*(.*,)\s*$/) { $member = "$member$1"; } elsif (/^\s*(.*){\s*/) { $member = "$member$1"; # attempt to skip over simple routines &skip_inlined_routine("{$'"); last; } elsif (/^\s*(.*);\s*/) { $member = "$member$1"; last; } elsif (/};/) { last; } else { printf "BAD MEMBER CONTINUATION: $_\n"; } } return $member; }