#! /usr/bin/perl -CSD
use strict;

my ($Prog, $Version) = ("w0pre", "2.0.3");
my ($False, $True) = (0, 1);
my $Macro_start = "<<";
my $Cur_file = "";
my $Last_def = "";
my %Macro = ();
my $N_errors = 0;
my ($Code_mode, $New_line) = ($False, $False);
PARAM:
while (@ARGV && $ARGV[0]=~/^-/) { $_ = shift;
    /^-v$/ and do {
    print STDERR "This is $Prog (version $Version)\n";
    next PARAM; };
    &Message("Unknown option `$_' ignored.");
}
LINE:
while (<>) { chomp;
    unless ($Cur_file) { $Cur_file = $ARGV;  print "file:$Cur_file;\n"; }
$Cur_file = "" if eof;
    while (s/\t+/' 'x(length($&)*8-length($`)%8)/e) {};
    /^@\s*$/ && $Code_mode and do {
    $Code_mode = $New_line = $False;  next LINE; };
    /^$Macro_start(.*?)>>\s*=\s*$/o && !$Code_mode and do {
    $Last_def = &Find_macro_sy($1);  $Code_mode = $True;  
    print "def:$Last_def>>\n";  $New_line = $False;
    next LINE; };
    unless ($Code_mode) { print "text:$_;\n";  next LINE; };
    print "nl\n" if $New_line;
while (s/^(.*?)$Macro_start(.*?)>>//o) {
    print "code:$1;\n" if $1;
    print "use:", &Find_macro_sy($2), ">>\n";
}
print "code:$_;\n" if $_;  $New_line = $True;
}
exit($N_errors ? 1 : 0);

sub Find_macro_sy {
    local $_ = shift;

    unless ($_) {
    &Warning("Illegal use of `$Macro_start>>' notation;",
        "no macro defined yet.") unless $Last_def;
    return $Last_def || "??";
}
    if (/\.{3}$/) {
    my $abbrev = $`;
    my $ab_len = length $abbrev;

    my @match = grep { substr($_,0,$ab_len) eq $abbrev } keys %Macro;
    unless (@match) {
        &Warning("No match for $Macro_start$_>>.");  
        return "??";
    }
    &Warning("Multiple matches for $Macro_start$_>>:",
        join(", ", map("$Macro_start$_>>",@match))) if @match>1;
    return $match[0];
}
    $Macro{$_} = "Defined";  return $_;
}
sub Warning {
    &Message(@_);  ++$N_errors;
}
sub Error {
    &Message(@_);  
    &Tidy_up if defined &Tidy_up;
    exit 1;
}
sub Message {
    print STDERR "$Prog: ", shift, "\n";
    while (@_) {
	print STDERR " "x(2+length $Prog), shift, "\n";
    }
}
