#!/usr/bin/env perl
# Copyright 2016 Vincent Danjean <vincent.danjean@inria.fr>
#                Christian Heinrich <franz-christian.heinrich@inria.fr>
#
# Call this script like this:
# C/C++  : ./generate_smpi_defines.pl ../../include/smpi/smpi.h
# FORTRAN: ./generate_smpi_defines.pl -f ../../include/smpi/smpi.h
#
# It will generate macros that are useful for adding file and line numbers to
# traces without obtaining a backtrace (as this would be very slow and make
# the simulation/trace unreliable when compared to a "real" trace as obtained
# with MPI+TAU).
use strict;
use warnings;
use Getopt::Std;

my %options=();
getopts("fc", \%options);

# $incall denotes whether we are currently parsing a macro or not...
my $incall=0;

my $commentChar="//";
if (defined $options{f}) {
  $commentChar="!"
}

print "$commentChar This file has been automatically generated by the script\n";
print "$commentChar in tools/smpi/generate_smpi_defines.pl\n";
print "$commentChar DO NOT EDIT MANUALLY. ALL CHANGES WILL BE OVERWRITTEN!\n";

# Formatting of the output
sub output_macro {
  my $line = shift;
  my @parts = split (/\s*,\s*/, $line);
  my $id = $parts[1];

  # This is a GCC extension. The last statement is the value of the expression
  # in parentheses.
  if (defined $options{f}) {
    print "#define ". lc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__); call ". ucfirst $id ."\n";
    print "#define ". uc($id) ." smpi_trace_set_call_location(__FILE__,__LINE__); call ". ucfirst $id ."\n";
  }
  else {
    if ($id eq "MPI_Init") {
      print "#define MPI_Init(...) ({ smpi_process_init(__VA_ARGS__); smpi_trace_set_call_location(__FILE__,__LINE__); MPI_Init(NULL, NULL); })\n";
    }
    else {
      print "#define $id(...) ({ smpi_trace_set_call_location(__FILE__,__LINE__); $id(__VA_ARGS__); })\n";
    }
  }
}

my $wholemacro;
my $line;
while (defined($line = <>)) {
  chomp($line);
  if ($line =~ /^MPI_CALL/) {
    if ($incall) {
        output_macro($wholemacro);
    }
    $incall=1;
    $wholemacro = $line;
  } elsif ($incall && $line =~ /^\s+\S/) {
    # Did we already start parsing an MPI_CALL macro? If so, just concatenate
    $wholemacro .= ' '.$line;
  } elsif ($incall) {
    output_macro($wholemacro);
    $incall=0;
  }
}
