#!/usr/bin/perl

# Copyright 2012-2020, Alexander Shibakov
# This file is part of SPLinT
#
# SPLinT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SPLinT 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SPLinT.  If not, see <http://www.gnu.org/licenses/>.

# a simple script to replace all @G ... @`other' regions with 
# @= ... @>@; lines
# comments are allowed at the end of the lines.
# only one style of comments is accepted: /* ... */. note that these are not
# output

use Getopt::Long;
use Pod::Usage;

my $man = 0;
my $help = 0;
my $elang_start = "\@t}\\lsectionbegin{\%s}\\vb{\@>\n";  
my $elang_finish = "\@t}\\vb{\\yyendgame}\\vb{}\\endparse\\postparse{\@>\n"; 

#Getopt::Long::Configure ("bundling"); # to allow -abc to set a, b, and c

GetOptions ("help|?" => \$help, 
             man => \$man,
            "startol=s" => \$elang_start,    # the string that starts an `other language' region
            "finishol=s"  => \$elang_finish  # the string that ends an `other language' region
    ) or pod2usage(2);

pod2usage(-exitval => 0, -verbose => 1) if $help;
pod2usage(-exitval => 0, -verbose => 2) if $man;

open FILE, "$ARGV[0]" or die "Cannot open input file $ARGV[0]\n";
open FILEOUT, ">$ARGV[1]" or die "Cannot open output file $ARGV[1]\n";

$state = 0;
$paused_state = 0;
while (<FILE>) {

    $inline = $_;


    if ( $inline =~ m/^\@G(.*)$/ ) { # @G detected, this line is part of the `other language' region

	$inline = $1; $state = 1;
        
        if ( $inline =~ m/^\(([^)]*)\).*/ ) { # language specifier present
            $inline = $1;
        } else {
            $inline = "b";
        }
        
        printf FILEOUT "\@q Start generic language section\@>\n" . $elang_start, "$inline"; # a parser switcher

    } elsif ( $inline =~ m/^\@[\scp\*0-9].*$/ ) { # @`other' detected, so `other language' region is over

        if ($state == 1) {
	    printf FILEOUT "\@q%s\@>\n" . $elang_finish, "End of generic language section"; # a parser switcher
        }

	$state = 0;
	printf FILEOUT "%s", "$inline"; 

    } elsif ( $inline =~ m/^\s*\@[=t].*$/ ) { # @= detected, just copy the line

	printf FILEOUT "%s", "$inline"; 

    } elsif ( $inline =~ m/^\@g(.*)$/ ) { # explicit end of other languge region detected

        $inline = $1;

        if ($state == 1) {
	    printf FILEOUT "\@q%s\@>\n" . $elang_finish, "End of generic language section"; # a parser switcher
        }

	$state = 0; 

    } elsif ( $inline =~ m/^\@O(.*)$/ ) { # @O detected, so `other language' region is paused

	$inline = $1; $paused_state = $state; $state = 0; 

	if ( not $inline ) { $inline = "End generic language section"; }
	printf FILEOUT "\@q%s\@>\n", "$inline";

    } elsif ( $inline =~ m/^\@o(.*)$/ ) { # @o detected, so `other language' region is resumed

	$inline = $1; $state = $paused_state; $paused_state = 0;

	if ( not $inline ) { $inline = "End generic language section"; }
	printf FILEOUT "\@q%s\@>\n", "$inline";

    } elsif ( $state != 0 ) {

	if ( $inline =~ m/\/\*.*\*\/\s*$/ ) { # the line contains a comment at the end
	    
	    $inline =~ m/^(.*\S|)\s*(\/\*.*\*\/)\s*$/;
	    $string = $1; $comment = $2;
	    
	} else {
	    
	    $inline =~ m/^(.*)$/;
	    $string = $1; $comment = "";
	    
	}

	if ( $string ) {

	    printf FILEOUT "\@=%s\@>\@t}\\vb{\\n}{\@>\@;", "$string";

	} else {

	    printf FILEOUT "\@=%s\@>\@t}\\vb{\\n}{\@>\@;", " "; # to keep \CWEB\ happy

	}

	if ( $comment ) {

	    printf FILEOUT "%s", "$comment";

	}

	printf FILEOUT "%s", "\n";

    } else {
	
	printf FILEOUT "%s", "$inline";
	
    }
    
}

__END__

=head1 BRACK

brack.pl - Preprocess a CWEB file to allow language extensions

=head1 SYNOPSIS

brack.pl [options] input_file output_file


 Options:
   --help|-h|-?      brief help message
   --man|-m          full documentation
   --startol|-s      string to begin a language region
   --finishol|-f     string to end a language region

=head1 OPTIONS

=over 8

=item B<--help>

Print a brief help message and exit.

=item B<--man>

Print the manual page and exit.

=item B<--startol>=I<CWEB string>

The string to print at the beginning of an other language region

=item B<--finishol>=I<CWEB string>

The string to print at the end of an other language region

=back

=head1 DESCRIPTION

B<brack.pl> will read the given <input_file>, and the format @G(...) sections 
appropriately to be read by CWEAVE and output the result in the <output_file>.

The processing mechanism is very primitive and makes use of some assumptions
on the appearance of the  B<CWEB> file. Unlike the 'standard' B<CWEB> input, the
new 'generic language' section markers (the @G(...) construct) are 
I<case sensitive> and I<must> appear at the beginning of the line. The 
'other language' markers (the @O... sections) follow the same restrictions as
the @G sections above, and I<do not nest>.

A comment at the very end of the line is moved to the B<C> portion of the input.
To put the comment inside the verbatim blocks, one may surround it by [@>@=] and
[@>@= ] (the square brackets are not part of the input and are here to draw attention
to the spacing, see next). Note the space at the end of the closing construct: this
is necessary to pacify B<CWEAVE>.

=cut
