#!/usr/bin/perl

$| = 1;

$level = 1;
$size = 500;
$labels = "labelheader.h";

use Getopt::Long;
GetOptions("level=n" => \$level,
	   "size=n" => \$size,
	   "labels=s" => \$labels);

$splittype = $ARGV[0];
shift @ARGV;

if ($splittype eq "c") {
    &split_c();
}
elsif ($splittype eq "m4") {
    &split_m4();
}
else {
    &usage();
    exit 1;
}

sub split_c() {

    mkdir("pieces",0777);
    print "pieces/piece1.o ";

    if ($level == 4) {
	open(LABELS, "<" . $labels) || die "Unable to open label definitions";
	while (<LABELS>) {
	    if (/^\s*extern /) {
		split;
		$name = $_[2];
		$name =~ s/[^_]*_/_/;
		$name =~ s/\(.*//;
		$labels{$name}=$_;
	    } elsif (/^#define __LE_/) {
		split;
		$labels{$_[1]}=$_;
	    }
	}
	close(LABELS);
	%savelabels = %labels;
    }

    open(OUTFILE, ">pieces/piece1.c");
    if ($level == 4) {
	open(OUTHEAD, ">pieces/piece1.h");
    }
    $cnt = 0;
    $filenum = 1;
    $looktoend = 0;

    while (<>) {

	if ($level == 4) {
	    if (/^#include "main\.h"/) {
		print OUTFILE "#include \"pieces/piece1.h\"\n";
		print OUTFILE "#include \"header.h\"\n";
	    }
	}
	if ($looktoend != 0) {
	    if (($level == 2 && /^void _L_/) ||
		($level == 3 && /^void \*_L_/) ||
		($level == 4 && /^void \*__LE_/) ||
		($level == 4 && /^void \*_T_/)) {
		close(OUTFILE);
		$filenum++;
		open(OUTFILE, ">pieces/piece" . $filenum . ".c");
		print OUTFILE "#include <isa.h>\n";
		if ($level == 4) {
		    close(OUTHEAD);
		    open(OUTHEAD, ">pieces/piece" . $filenum . ".h");
		    print OUTFILE "#include \"header.h\"\n";
		    print OUTFILE "#include \"pieces/piece" . $filenum . ".h\"\n";
		}
		print "pieces/piece" . $filenum . ".o ";
		$looktoend = 0;
		$cnt = 0;
		%labels = %savelabels;
	    }
	}

	print OUTFILE $_;
	if (/PR_oper_pre/) { $cnt++; }
	if ($cnt >= $size) {
	    $looktoend = 1;
	    $cnt = 0;
	}
	if ($level == 4) {
	    # @matching = /(_\$[\$\w]*)|(__LE_[\w]*)/g;
	    @matching = /(__LE_[\$\w]*)/g;
	    foreach $s (@matching) {
		if (exists $labels{$s}) {
		    print OUTHEAD $labels{$s};
		    $t = $s;
		    while ((exists $labels{$t}) && $labels{$t} =~ /^#define/) {
			split(/\s+/,$labels{$t});
			delete $labels{$t};
			$t = $_[2];
			if (exists $labels{$t}) {
			  print OUTHEAD $labels{$t};
			}
		    }
		    delete $labels{$t};
		}
	    }
	}
	
    }

    close(OUTFILE);
    if ($level == 4) {
	close(OUTHEAD);
    }
}

sub split_m4() {

    print "Splitting program.m4\n";
    open(LABEL, ">label.m4") || die("Unable to write label.m4");
    open(DATA, ">data.m4") || die("Unable to write data.m4");
    open(CODE, ">code.m4") || die("Unable to write code.m4");
    
    while (<>) {
	if ($_ =~ /^__EM4_label_func\(/ || $_ =~ /^__EM4_label_cb\(/) {
	    print LABEL $_;
	    print CODE $_;
	}
	elsif ($_ =~ /^__EM4_data\(/ || $_=~ /^__EM4_data_init/) {
	    print DATA $_;
	}
	elsif ($_ =~ /^__EM4_comment\(/) { # skip these 
	}
	elsif ($_ =~ /^m4_define/ || $_ =~ /^\'\)/) { # skip these 
	}
	else {
	    print CODE $_;
	}
    }
    close CODE;
    close DATA;
    close LABEL;
    close PROGRAM;

}

sub usage() {
    die "
Usage: le_splitprog (m4|c) [options] filename
         c                      - split up a c program
         m4                     - split up m4 macros
       options:
        -level                  - level used in generating the c program
        -size                   - size of c program pieces (in opers)

Examples: 
   - to split up prog.c:
        le_splitprog c -level 1 -size 200 prog.c
   - to split up program.m4:
        le_splitprog m4 program.m4
";

}
