# fpp.pl - quick hack Fortran preprocessor
# Copyright (C) TOYODA Eizi, 1999.  All rights reserved.

@Include = ();
%Macro = ();
%Lines = ();

while ($arg = shift) {
	(unshift(@ARGV, $arg), last) unless ($arg =~ /^[\-\/]/);
	$arg =~ /^-I(.*)/ && ((push @Include, $1), next);
	$arg =~ /^\/include:(.*)/i && ((push @Include, $1), next);
	$arg =~ /^\/define:(\w+)=(.*)/i && (($Macro{$1} = $2), next);
	$arg =~ /^-D(\w+)/i && (($Macro{$1} = 1), next);
	$arg =~ /^\/define:(\w+)/i && (($Macro{$1} = 1), next);
}

$Input = shift || "-";
$Output = shift || "-";

print "! include(", join(",", @Include), ")\n";
print "! defined(", join(",", %Macro), ")\n";
print "! input(", $Input, ")\n";
print "! output(", $Output, ")\n";

open(OUTPUT, ">$Output") || die "cannot open $Output for writing";
&pushInput($Input);

$ifvalue = 1;
@ifvalue = ();
@elsevalue = ();
while ($_ = &readLine) {
	chop;
	/^#ifdef\s+(\w+)/ && (&ifdef($1), next);
	/^#elif\s+(\w+)/ && (&elif($1), next);
	/^#else\b/ && (&else_($1), next);
	/^#endif\b/ && (&endif($1), next);
	next unless $ifvalue;
	/^#include\s+<([^>]+)>/ && (&pushInput(&search($1)), next);
	/^#include\s+"([^"]+)"/ && (&pushInput(&search($1)), next);
	/^#\s*define\s+(\w+)\s+(.*)/ && (&define($1, $2), next);
	# cluge for Makefile
	/^\*=define\s+(\w+)\s+(.*)/ && (&define($1, $2), next);
	s/^#/*/;
	unless (/[\'\"]/) {
		foreach $key (keys %Macro) {
			s/$key/$Macro{$key}/g;
		}
	}
	print OUTPUT "$_\n";
}

exit 0;

sub define {
	local($name, $value) = @_;
	$Macro{$name} = $value;
}

sub ifdef {
	local($expr) = @_;
	push @ifvalue, $ifvalue;
	$ifvalue = defined($Macro{$expr});
	warn "! #ifdef $ifvalue\n";
	push @elsevalue, $ifvalue;
}

sub else_ {
	local($expr) = @_;
	(scalar @elsevalue == 0) && (warn("unexpected #elif"), return);
	$elsevalue[$#elsevalue] && ($ifvalue = 0, return);
	warn "! #else\n";
	$elsevalue[$#elsevalue] = $ifvalue = 1;
}

sub elif {
	local($expr) = @_;
	(scalar @elsevalue == 0) && (warn("unexpected #elif"), return);
	$elsevalue[$#elsevalue] && ($ifvalue = 0, return);
	warn "! #elif $ifvalue\n";
	$elsevalue[$#elsevalue] = $ifvalue = defined($Macro{$expr});
}

sub endif {
	if (scalar @elsevalue == 0) {
		warn "unexpected #endif without #ifdef";
		return;
	}
	warn "! #endif $ifvalue\n";
	pop @elsevalue;
	$ifvalue = pop @ifvalue;
}

sub readLine {
	local($line);
	($line = pop @note) && return $line;
	while (1) {
		$Lines{$INPUT}++;
		($line = <$INPUT>) && return $line;
		warn "! EOF of $INPUT\n";
		$Lines{$INPUT} = undef;
		$INPUT = pop @Lines || return;
		push @note, "# $Lines{$INPUT} $INPUT\n";
		warn "! return to $INPUT\n";
	}
}

sub pushInput {
	local($filename) = @_;
	warn "! #input <$filename>\n";
	warn("$filename already opened\n"), return if $Lines{$filename};
	push @Lines, $INPUT;
	$INPUT = $filename;
	open($INPUT, $filename) || die "cannot open $filename for reading";
	push @note, "# 1 $INPUT\n";
	$Lines{$INPUT} = 1;
}

sub search {
	local($basename) = @_;
	local($try);
	foreach (".", @Include) {
		$try = "$_/$basename";
		return $try if -f $try;
	}
	warn "<$basename> not found";
}
