# This file is part of the Attempto Parsing Engine (APE). # Copyright 2008-2013, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch). # # The Attempto Parsing Engine (APE) is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later version. # # The Attempto Parsing Engine (APE) is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along with the Attempto # Parsing Engine (APE). If not, see http://www.gnu.org/licenses/. # ACE Syntax Report generator # # This Perl script converts APE grammar files into HTML, preserving only the comments, i.e. # it extracts the lines that start with a comment symbol (%) from: # * grammar.fit # * grammar_functionwords.fit # * grammar_contentwords.fit # # For comments which you don't want to have in the output, use "/* ... */" or "%% ...". # # This script also generates a table of contents and saves it into a file 'syntax_report.toc'. # The content of 'syntax_report.toc' is placed right after the title of the resulting HTML. # This however needs two runs in the general case. During the first run the table of contents # is generated (or an existing 'syntax_report.toc' is updated), during the second run the # updated 'syntax_report.toc' is placed into the report. # # @author Tobias Kuhn # @author Kaarel Kaljurand # @version 2013-07-31 # # Usage: # # cat grammar.fit grammar_functionwords.fit grammar_contentwords.fit | perl make_syntax_report.perl --number 6.7 use strict; use Getopt::Long; # Version number (e.g. 6.7) of the grammar, shown in the title. # Specify it on the commandline. my $number = ""; my $getopt_result = GetOptions( "number=s" => \$number, ); my $syntax_report_toc = 'syntax_report.toc'; my $title_numbers = [0, 0, 0, 0, 0]; # This is output only if the input contains \version{...} my $message = "This report was generated automatically from the following APE grammar files: grammar.fit, grammar_functionwords.fit, grammar_contentwords.fit."; my $name_set = {}; my $href_set = {}; my $closetag = ""; # = "

": "p"-tag is open that will be closed implicitly # = " ": "pre"- or "blockquote"-tag is open that has to be closed explicitly # = "": no such tag is open my $str = ""; my $label; my $section; &make_header; &make_toc; open (TOC, '>', $syntax_report_toc) or die "Can't open $syntax_report_toc: $!"; while() { next if !/^%/; next if /^%%/; s{&}{&}g; s{-->}{→}g; s{<}{<}g; s{>}{>}g; s{^%}{}; s{^===.*}{}; if ( m{^ *\\section\{(.*)\}} ) { $str = &generate_number($title_numbers, 0); } elsif ( m{^ *\\subsection\{(.*)\}} ) { $str = &generate_number($title_numbers, 1); } elsif ( m{^ *\\subsubsection\{(.*)\}} ) { $str = &generate_number($title_numbers, 2); } if ( s{^ *\\version\{(.*)\}}{

$message Version: $1

} ) { } elsif ( s{^\s*-([0-9]+[a-z]?)------------.*}{$closetag
$1\n} ) {
		# start of a grammar rule box
		$name_set->{$1} = 1;
		$closetag = " ";
	} elsif ( s{^\s*--------------.*}{
\n} ) { # end of a grammar rule box $closetag = ""; } elsif ( s{>>\|}{$closetag
} ) {
		# start of a code block
		$closetag = " ";
	} elsif ( s{>>}{$closetag

} ) { # start of a quote $closetag = " "; } elsif ( s{^ *\\section\{(.*)\}}{$closetag

$str $1

} ) { $section = $1; $label = $1; $label =~ s/[^a-zA-Z0-9]//g; # labels are not allowed to contain spaces s/--label--/$label/; print TOC "$str $section\n"; $closetag = ""; } elsif ( s{^ *\\subsection\{(.*)\}}{$closetag

$str $1

} ) { $section = $1; $label = $1; $label =~ s/[^a-zA-Z0-9]//g; # labels are not allowed to contain spaces s/--label--/$label/; print TOC "$str $section\n"; $closetag = ""; } elsif ( s{^ *\\subsubsection\{(.*)\}}{$closetag

$str $1

} ) { $section = $1; $label = $1; $label =~ s/[^a-zA-Z0-9]//g; # labels are not allowed to contain spaces s/--label--/$label/; print TOC "$str $section\n"; $closetag = ""; } elsif ( $closetag eq "

" && s{^\s*$}{<\/p>

} ) { # empty line -> new paragraph $closetag = "

"; } elsif ( $closetag eq "" ) { # start new paragraph s{^(.*)$}{

$1}; $closetag = "

"; } # end of a code block if ( s{\|<<}{
} ) { $closetag = ""; } # end of a quote if ( s{<<}{

} ) { $closetag = ""; } # symbol anchor if ( s{^ ([a-zA-Z0-9\-_']+)(.*) →}{$1<\/span>$2 →} ) { $name_set->{$1} = 1; } if (/ Example:/) { s{ Example:}{Example:}; s/([^\\])\[/$1[/g; s/([^\\])\]/$1]<\/span>/g; s/\\\[/[/g; s/\\\]/]/g; } # reference to rule (by rule number) while ( s/\[\[([0-9]+[a-z]?)\]\]/$1<\/a><\/tt>/ ) { $href_set->{$1} = 1; } # reference to symbol if (/^\t/) { while ( s/([\s(])([A-Z][a-zA-Z0-9\-_']*)/$1$2<\/a><\/tt>/ ) { $href_set->{$2} = 1; } } # labels in XHTML are not allowed to contain an apostrophe # (we use apostrophes only at the end of symbols) s{'">}{Bar">}g; # references to features s{-([A-Z]+)}{-$1}g; s{\+([A-Z]+)}{+$1}g; # italics s/([^\\])_([a-zA-Z0-9]+)_/$1$2<\/em>/g; s/_\|//g; s/\|_/<\/em>/g; s/\\_/_/g; # bold s/([^\\])\*([a-zA-Z0-9]+)\*/$1$2<\/strong>/g; s/\*\|//g; s/\|\*/<\/strong>/g; s/\\\*/\*/g; # code s/([^\\])=([a-zA-Z0-9]+)=/$1$2<\/code>/g; s/=\|//g; s/\|=/<\/code>/g; s/\\=/=/g; s{\\lor}{∨}g; s{\\land}{∧}g; s{\\forall}{∀}g; s{\\exists}{∃}g; s{\\rightarrow}{⇒}g; s{---}{—}g; s{--}{–}g; s{BUG}{BUG}; print; } close TOC or die "Can't close $syntax_report_toc: $!"; &make_footer; &show_warnings($name_set, $href_set); exit; sub make_header { print < ACE $number Syntax Report

ACE $number Syntax Report

EOF } sub make_toc { if (-e $syntax_report_toc) { print "
\n";
		open (TOC, $syntax_report_toc) or die "Can't open $syntax_report_toc: $!";
		while () {
			print;
		}
		close TOC or die "Can't close $syntax_report_toc: $!";
		print "
\n"; } } sub make_footer { print < EOF } sub show_warnings { my $name_set = shift; my $href_set = shift; for (keys %{$name_set}) { if (! (defined $href_set->{$_})) { warn "declared but not linked: " . $_, "\n"; } } for (keys %{$href_set}) { if (! (defined $name_set->{$_})) { warn "broken link: " . $_, "\n"; } } } sub increase_title_numbers { my $numbers = shift; my $pos = shift; $numbers->[$pos]++; } sub reset_title_numbers { my $numbers = shift; my $pos = shift; for (my $i = $pos; defined $numbers->[$i]; $i++) { $numbers->[$i] = 0; } } sub title_numbers_tostring { my $title_numbers = shift; my @numbers = @{$title_numbers}; my $str = shift @numbers; foreach (@numbers) { if ($_ eq "0") { last; } else { $str = $str . "." . $_; } } return $str; } sub generate_number { my $numbers = shift; my $level = shift; &increase_title_numbers($numbers, $level); &reset_title_numbers($numbers, $level + 1); return &title_numbers_tostring($numbers); }