#!/usr/bin/perl -w # # @(#)$Id: bnf2html.pl,v 3.7 2005/07/13 18:32:35 jleffler Exp $ # # Convert SQL-92, SQL-99 BNF plain text file into hyperlinked HTML. use strict; use POSIX qw(strftime); my(%rules); # Indexed by rule names w/o angle-brackets; each entry is a ref to a hash. my(%keywords); # Index by keywords; each entry is a ref to a hash. use constant debug => 0; sub top { print "
\n\n"; } # Usage: add_entry(\%keywords, $keyword, $rule); # Usage: add_entry(\%rules, $rhs, $rule); sub add_entry { my($reflist, $lhs, $rhs) = @_; ${$reflist}{$lhs} = {} unless defined ${$reflist}{$lhs}; ${$reflist}{$lhs}{$rhs} = 1; } sub add_refs { my($def, $tail) = @_; print "\n\n" if debug; return if $tail =~ m/!!/; while ($tail) { $tail =~ s/^\s*//; if ($tail =~ m%^\<([-:/\w\s]+)\>%) { print "\n" if debug; add_entry(\%rules, $1, $def); $tail =~ s%^\<([-:/\w\s]+)\>%%; } elsif ($tail =~ m%^([-:/\w]+)%) { my($token) = $1; print "\n" if debug; add_entry(\%keywords, $token, $def) if $token =~ m%[[:alpha:]][[:alpha:]]% || $token eq 'C'; $tail =~ s%^[-:/\w]+%%; } else { # Otherwise, it is punctuation (such as the BNF metacharacters). $tail =~ s%^[^-:/\w]%%; } } } # NB: webcode replaces tabs with blanks! open WEBCODE, "webcode @ARGV |" or die "$!"; $_ =\n";
print "Derived from $v1\n";
my $today = iso8601_format(time);
print "
\n";
print "Generated on $today by $v2\n";
print "
\n';
print qq' <$def> ::=';
$tcount = 0;
if ($tail)
{
add_refs($def, $tail);
print " ";
$tcount = print_tail($tail, $tcount);
}
print "\n";
}
elsif (/^\s/)
{
# Expansion line
add_refs($def, $_);
print "
";
$tcount = print_tail($_, $tcount);
}
elsif (m/^--[\/]?(\w+)/)
{
# Pseudo-directive line in lower-case
# Print a 'Top' link before
Start symbol: $start
\n'; } else { # Anything unrecognized passed through unchanged! print "$_\n"; } } # Print index of initial letters for keywords. sub print_index_key { my($prefix, @keys) = @_; my %letters = (); foreach my $keyword (@keys) { my $initial = uc substr $keyword, 0, 1; $letters{$initial} = 1; } foreach my $letter ('A' .. 'Z') { if (defined($letters{$letter})) { print qq' $letter \n'; } else { print qq'$letter\n'; } } print "\n"; } ### Generate cross-reference tables { print "| Rule (non-terminal) | Rules using it |
|---|---|
| $label $rule | \n'; my $pad = ""; foreach my $ref (sort { uc $a cmp uc $b } keys %{$rules{$rule}}) { print qq'$pad <$ref> \n'; $pad = " "; } print " | \n
| Keyword | Rules using it |
|---|---|
| $label $keyword | \n'; my $pad = ""; foreach my $ref (sort { uc $a cmp uc $b } keys %{$keywords{$keyword}}) { print qq'$pad <$ref> \n'; $pad = " "; } print " | \n