#!/usr/bin/perl -w
#
# Copyright (C) 2005-2009 FAUmachine Team <info@faumachine.org>.
# This program is free software. You can redistribute it and/or modify it
# under the terms of the GNU General Public License, either version 2 of
# the License, or (at your option) any later version. See COPYING.
#

sub check_section_spec
{
	my ($section);
	my ($line);

	($line) = @_;
	# ".section" keyword
	if ($line =~ /^\s*\.section\b\s*([\.\w]*)/) {
		$section = $1;
	# ".text" keyword
	} elsif ($line =~ /^\s*\.text\s*/) {
		$section = ".text";
	# ".data" keyword
	} elsif ($line =~ /^\s*\.data\s*/) {;
		$section = ".data";
	# No section specifier
	} else {
		$section = undef;
	}
	return $section;
}

sub ext_sym_name
{
	my ($in_file);
	my ($label);
	($in_file, $label) = @_;
	my ($return);

	$module = $in_file;
	$module =~ s/\..*$/\_o/;	
	$module =~ s/\//_/g;	
	$module =~ s/\-/_/g;	
	$return = "${LOC_FUNC_PREFIX}${module}_${label}";
}

$PROGRAM = "preasm_proc.pl";
$GEN_HEAD = "\t/* Generated by $PROGRAM */	\n";
$GEN_TAIL = "\t/* End of $PROGRAM */		\n";
$LOC_FUNC_PREFIX = "__LOCAL_";
$DEBUG = 0;

$in_file = $ARGV[0];
$out_file = $ARGV[1];

my %local_labels = ();

open(IN, $in_file) 
	|| die "$PROGRAM: unable to open input file \"$in_file\" ($!)";

my ($cur_sect);
$cur_sect = ".text";

# First pass: collect necessary data 
while (defined($line = <IN>)) {

	if ($line =~ /\s*(.*):.*/) {
		$local_labels{$1} = "defined";
	}
}

# Second pass: process it
seek(IN, 0, 0);

open(OUT, ">$out_file") 
	|| die "$PROGRAM: unable to open output file \"$out_file\" ($!)";

$code_size = 32;
while (defined($line = <IN>)) {

	# Detect 32-bit code
	if ($line =~ /\s*\.code32\b\s*/) {
		print OUT "/* $PROGRAM: 32-bit code */\n";
		$code_size = 32;
	} elsif ($line =~ /\s*\.code16(|gcc)\b\s*/) {
		if ($code_size eq 32) {
		$code_size = 16;
		print OUT "/* $PROGRAM: End of 32-bit code */\n";
		}
	}

	if ($line =~ /\s*ex_lcall\b\s*\b([\w\.]*)(;|\s)*.*/) {
		$tar_label = $1;
		$tar_type = undef;
		if (grep($tar_label eq $_, keys %local_labels)) {
			$tar_ref = ext_sym_name($in_file, $tar_label);
			$tar_type= "local";
		} else {
			$tar_ref = $tar_label;
			$tar_type = "external";
		}
		if ($DEBUG) {
			print OUT $GEN_HEAD;
			print OUT "\t/* call to $tar_type label $tar_label ($tar_ref) */	\n";
		}
		print OUT "\t.byte 0x9a				\n";
		print OUT "\t.word OFF_$tar_ref, SEG_$tar_ref\n";
		if ($DEBUG) {
			print OUT $GEN_TAIL;
		}

	}elsif ($line =~ /\s*ex_ljmp\b\s*\b([\w\.]*)(;|\s)*.*/) {
		$tar_label = $1;
		$tar_type = undef;
		$tar_ref = undef;
		if (grep($tar_label eq $_, keys %local_labels)) {
			$tar_type = "local (diff. section)";
			$tar_ref = ext_sym_name($in_file, $tar_label);
		} else {
			$tar_ref = $tar_label;
			$tar_type = "external";
		}
		if ($DEBUG) {
			print OUT $GEN_HEAD;
			print OUT "\t/* jump to ${tar_type} label ${tar_label} ref: $tar_label */	\n";
		}
		print OUT "\t.byte 0xea				\n";
		print OUT "\t.word OFF_$tar_ref, SEG_$tar_ref	\n";
		if ($DEBUG) {
			print OUT $GEN_TAIL;
		}

	} elsif ($line =~ /^\s*([a-zA-Z_\.][\.\w]*):.*$/) {
		print OUT $line;
		if ($DEBUG) {
			print OUT $GEN_HEAD, "\t/* export all labels */	\n";
		}
		$label = $1;
		$new_sym_name = ext_sym_name($in_file, $label);
		print OUT "\t.globl $new_sym_name			\n";
		print OUT "$new_sym_name:				\n";
	} else {
		print OUT "$line\n";
	}
}

close(IN) 
	|| die "$PROGRAM: unable to close input file \"$in_file\" ($!)";

close(OUT) 
	|| die "$PROGRAM: unable to close output file \"$out_file\" ($!)";
