#!/usr/bin/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 bison) to
the ftnchek maintainer listed in README.
END_ERROR_MESSAGE

exit(1);
}
