#!/usr/bin/perl
# -*- perl -*-

#  Copyright (C) 2006 Red Hat Inc.
#
#  This file is part of GAS, the GNU Assembler.
#
#  GAS 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 2, or (at your option)
#  any later version.
#
#  GAS 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 GAS; see the file COPYING.  If not, write to
#  the Free Software Foundation, 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.  */

%myfiles = ();

$incdir = ".";

while ($ARGV[0] =~ /^-/) {
    $opt = shift;
    if ($opt eq "-I") {
	$incdir = shift;
    }
}

$infile = shift;
$outfile = shift;

$inbase = $infile;
$inbase =~ s@.*/@@;
$inbase =~ s@[^a-zA-Z0-9].*@@;

$t = 0;
$errors = 0;

if ($outfile) {
    open(OUT, ">$outfile");
} else {
    open(OUT, ">&STDOUT");
}

open(I, "$incdir/macros.inc") || die("$incdir/macros.inc: $!");
&read_file();
close I;
open(I, $infile) || die("$infile: $!");
&read_file();
close I;

sub read_file {
    while (<I>) {
	$line ++;
	next if /^;/;
    s/[\r\n]+$//;
	if (/^macro\s+(\S+)\s+(.*)/) {
	    ($name, $val) = ($1,$2);
	    print "set macro \"$name\" to \"$val\"\n" if $t;
	    $macro{$name} = $val;
	} elsif (/\S/) {
	    &explode($_);
	}
    }
}

exit ($errors);

# There's no way to quote braces so you can output them :-P

sub explode {
    my ($s) = @_;
    my ($a, $b, $p, $e, @params);

    print "explode($s)\n" if $t;

    ($b, $a, @params) = &split_braces($s);
    @params = explode_params (@params);
    if (! $a && ! @params) {
	if ($t) {
	    print "\033[33m$s\033[0m\n";
	} else {
	    print OUT "$s\n";
	}
	return;
    }
    if (@params == 1 && defined $macro{$params[0]}) {
	$p = $macro{$params[0]};
	&explode ("$b$p$a");
    } else {
	for $p (@params) {
	    &explode ("$b$p$a");
	}
    }
}

sub explode_params {
    my (@p) = @_;
    my ($p,@r);

    @r = ();
    while (@p) {
	$p = shift @p;
	($b,$a,@e) = split_braces ($p);
	if (defined $a) {
	    for $e (reverse @e) {
		unshift (@p, "$b$e$a");
	    }
	} else {
	    push (@r, $p);
	}
    }
    return @r;
}

sub getmacro {
    my ($v) = $macro{$_[0]};
    if (! defined $v) {
	print STDERR "$line: Error: macro $_[0] not defined\n";
	$errors ++;
    }
    return $v;
}

sub expand_macros {
    my ($l) = @_;
    0 while $l =~ s/{([^{};]+)}/&getmacro($1)/ge;
    return $l;
}

# returns (before, after, list of variances)
sub split_braces {
    my ($l) = @_;
    my (@l, $i, $a, @parms, $b, $n,$p);

    print "split_braces($l) = (" if $t;

    $l = &expand_macros ($l);

    if ($l !~ /\{.*\}/) {
	print "nothing)\n" if $t;
	return ($l);
    }
    if ($l =~ /^{([^{};]+)}/) {
	print "macro:", $macro{$1}, ")\n" if $t;
	return (&getmacro($1), "");
    }

    $n = 0;
    @parms = ('');
    $p = 0;

    ($a, $l) = $l =~ m@^([^\{]*)\{(.*)@;
    @l = split(//, $l);

    while (defined ($i = shift @l)) {
	if ($n == 0) {
	    print "\033[32m$i" if $t;
	    if ($i eq '}') {
		print "\033[0m$a, ", join('', @l), ", (", join("\033[31m;\033[0m", @parms), ")\n" if $t;
		return ($a, join('',@l), @parms);
	    } elsif ($i eq ';') {
		$p ++;
		$parms[$p] = '';
	    } else {
		$parms[$p] .= $i;
		$n ++ if $i eq '{';
	    }
	} else {
	    print "\033[34m$i" if $t;
	    $n ++ if $i eq '{';
	    $n -- if $i eq '}';
	    $parms[$p] .= $i;
	}
    }
    print "$a, <null>, (", join(';', @parms), ")\n" if $t;
    return ($a, "", @parms);
}

__END__;

macro rest c,d
	foo {a;b},{{rest};e;}

expands to:

        foo a,c
        foo a,d
        foo a,e
        foo a,
        foo b,c
        foo b,d
        foo b,e
        foo b,
