#!@PERL@

# $Id: make_blockmatch.pl.in,v 1.3 2001/05/27 14:28:48 moniot Rel $

#  Script to generate block_match.h file from tokdefs.h.  The result is
#  the contents of an array to map from block-closing tokens to the
#  required block-opening tokens.  It is used by fortran.y in pop_block
#  routine to check proper balancing of structured control forms.

%block_opener = (
      'ELSE' => 'IF',
      'ENDIF' => 'IF',
      'ENDDO' => 'DO',
      'CASE' => 'SELECTCASE',
      'ENDSELECT' => 'SELECTCASE',
      'ENDSUBROUTINE' => 'SUBROUTINE',
      'ENDFUNCTION' => 'FUNCTION',
      'ENDPROGRAM' => 'PROGRAM',
      'ENDBLOCKDATA' => 'BLOCKDATA'
);


		# Read the token definitions.  Find the defs corresponding
		# to block oeners and closers, and save them in hashes.

open(TOKDEFS,"tokdefs.h") || die "Can't open tokdefs.h: $!";

$min_block_token = -1;
$max_block_token = -1;
foreach (<TOKDEFS>) {
    if( /^\#\s*define\s+tok_(\S*)\s*(\d+)/ ) {
	$name = $1;
	$number = $2;

	if( grep(/^$name$/,values(%block_opener) ) ) {
	    $opener_number{$name} = $number;
	}
	if( grep(/^$name$/,keys(%block_opener) ) ) {
	    $closer_name{$number} = $name;
	}
				# keep track of min and max block tokens
	if( $opener_number{$name} || $closer_name{$number} ) {
	    if( $min_block_token == -1 ) { $min_block_token = $number; }
	    if( $max_block_token == -1 ) { $max_block_token = $number; }
	    if( $number < $min_block_token ) { $min_block_token = $number; }
	    if( $number > $max_block_token ) { $max_block_token = $number; }
	}
    }
}

close(TOKDEFS);

		# Make sure tokdefs.h was parsed OK.  All the token names
		# in the %block_opener table above must be defined.

foreach ( (keys %block_opener) ) {
    $key = $_;
    if( ! grep(/^$key$/, values(%closer_name) ) ) {
	not_found($key);
    }
}

foreach ( (values %block_opener) ) {
    $val = $_;
    if( ! defined($opener_number{$val}) )  {
	not_found($val);
    }
}

		# Find range of token values used to index array

$min_closer = (sort keys %closer_name)[0];
$max_closer = (reverse sort keys %closer_name)[0];

		# Print initializer for the C lookup table that gives
		# matching opener for any closer.  This initializer is
		# to be included like so:
		#   int block_opener[] = {
		#   #include "blockmatch.h"
		#   };
		# It also defines range and offset of index values.
		# Look up a value as
		#   matching_token = block_opener[closer_token-MIN_CLOSER]

print <<END_OF_TEXT;
/* DO NOT EDIT
     File automatically generated by make_blockmatch.pl from tokdefs.h
*/
#define MIN_CLOSER $min_closer
#define MAX_CLOSER $max_closer
#define MIN_BLOCK_TOKEN $min_block_token
#define MAX_BLOCK_TOKEN $max_block_token
END_OF_TEXT

for($i=$min_closer; $i <= $max_closer; $i++) {
    if( ($i-$min_closer) % 10 == 0) {
	print "\n";		# newline every 10 values
    }
		# Put matching token number in the array at each closing
		# token.  If array position is not for a closer, put a zero.
    if( defined($closer_name{$i}) ) {
	print "$opener_number{$block_opener{$closer_name{$i}}},";
    }
    else {
	print "0,";
    }
}
print "\n";

		# This error should not occur unless the user has touched
		# fortran.y and re-made fortran.h and tokdefs.h with a
		# different parser generator
sub not_found {
print STDERR <<END_ERROR_MESSAGE;

  ===> ERROR: tok_$_[0] not found in tokdefs.h <===

This probably means that the regular expression in the first foreach
of $0 is not correct for the tokdefs.h file produced
using the local parser generator.  Please send a copy of the tokdefs.h
file, along with information identifying the operating system and the
name and version number of the parser generator (probably @YACC@) to
the ftnchek maintainer listed in README.
END_ERROR_MESSAGE

exit(1);
}
