#!/usr/bin/perl





























($Pgm = $0)    =~ s|.*/||;
$infile        ="";
$tmpfile1      ="/tmp/bspcpp1.$$";
$tmpfile2      ="/tmp/bspcpp2.$$";
$outfile       ="";
$sstep_lineno  = 0;
$next_addr     = 0;
$miller        = 0;
$linenumber    = 0;
$contains_fetch= 0;
$underscore    = 0;
&main();
exit(0);



sub main {
  local($going);
  if ($#ARGV<2) {
    print STDERR"usage: bspcpp [-miller] realname infile outfile\n";
    exit(1);
  } else {
    $going=1;
    while($going) {
      if ($ARGV[0]=~ /-miller/) {
        $miller= 1;
        shift(@ARGV);
      } elsif ($ARGV[0]=~ /-uscore/) {
        $underscore = 1;
        shift(@ARGV);
      } else {
        $going=0;
      }
      $going=0 if $#ARGV==0;
    }
    $filename = $ARGV[0];
    $infile   = $ARGV[1];
    $outfile  = $ARGV[2];
    if (!$miller) {
      &convertStoreFetchs($infile,$outfile);
    } else {
      &catFile($infile,$outfile);
    }
  }
}



sub  catFile {
  local($convin,$convout) = @_;
   
  if (!open(INFILE,$convin)) {
    printf STDERR "$Pgm: unable to open $convin for reading\n";
    exit(1);
  }

  if (!open(OUTFILE,"> ". $convout)) {
    printf STDERR "$Pgm: unable to open $convout for writing\n";
    exit(1);
  }
  print OUTFILE "\#line 1 \"$filename\"\n";
  while (<INFILE>) {
    print OUTFILE $_;
  }
  close(INFILE);
  close(OUTFILE);
}



sub convertStoreFetchs {
  local($convin,$convout) = @_;
  local($superstep_code);
  local($startsuperstep_code);
  local($begin_sstep_code);
  local($in_superstep)=0;
   
  if (!open(INFILE,$convin)) {
    printf STDERR "$Pgm: unable to open $convin for reading\n";
    exit(1);
  }

  if (!open(OUTFILE,"> ". $convout)) {
    printf STDERR "$Pgm: unable to open $convout for writing\n";
    exit(1);
  } 
  print OUTFILE "\#line 1 \"$filename\"\n";
  while($line = <INFILE>) {
    $linenumber++;
    if ($line =~ /\#\s*(\d+)\s*\"[^\"]*\"\s*$/) {
      print OUTFILE $line;
      $linenumber = int($1);
    }
    elsif (&beginSuperStep($line)) {
      $begin_sstep_code = $line; 
      $in_superstep     =1;
    }
    elsif (&endSuperStep($line)) {
      print OUTFILE $startsuperstep_code ,$begin_sstep_code,
                    "\#line ", $sstep_lineno+1, " \"$filename\"\n",
                    $superstep_code;
      print OUTFILE $line; 
      $superstep_code = "";
      $startsuperstep_code = "";
      $in_superstep   =0;
    }
    elsif ($in_superstep) {
      if (&containsLibraryCall($line)) {
        local($i,$j)= &rewriteLibraryCall($line);
        $startsuperstep_code.=$i;
        $superstep_code     .=$j;
      } else {
        $superstep_code .= $line;
      }
    } else {
      print OUTFILE $line;
    }
  }
}




sub containsLibraryCall {
  local($line) = $_[0];
  local($libcall);

  ($line =~/bsp\_store/) && return 1;
  ($line =~/bsp\_fetch/) && return 1;
  return 0;
}

sub rewriteLibraryCall {
   local($line)=$_[0];
   local(@arguments);
   local($pid,$src,$dst,$offset,$nbytes);

   local($i); 
   if ($line =~ /bsp\_store\s*\(/) {
     $line = $`;
     @arguments = &grabArguments($');
     if (($miller  && $#arguments != 4) || 
         (!$miller && $#arguments != 5)) {
        print STDERR "**$Pgm warning**\tThe procedure call bsp_store on ",
                     "line $linenumber of $infile has\n\t\t\t",
                     "the wrong number of arguments\n\n";
     }
     ($pid,$src,$dst,$offset,$nbytes,@rest) = @arguments;
     $line .= "bsp_addr_store($pid,$src,$next_addr,$offset,$nbytes)" . 
              join("",@rest);
     return ("bsp_addr(".$next_addr++.",$dst);\n",$line);
   } elsif ($line =~ /bsp\_fetch\s*\(/) {
     $line = $`;
     @arguments = &grabArguments($');
     if (($miller  && $#arguments != 4) || 
         (!$miller && $#arguments != 5)) {
        print STDERR "**$Pgm warning**\tThe procedure call bsp_fetch on ",
                     "line $linenumber of $infile has\n\t\t\t",
                     "the wrong number of arguments\n\n";
     }
     ($pid,$src,$offset,$dst,$nbytes,@rest) = @arguments;
     $line .= "bsp_addr_fetch($pid,$next_addr,$offset,$dst,$nbytes)" . 
              join("",@rest);
     return ("bsp_addr(".$next_addr++.",$src);\n",$line);
   } else {
      print STDERR "**%Pgm error** internal translation problem\n";
   }
}

sub grabArguments {
   local($line)=$_[0];
   local($after_close);
   local($inside_brackets);
   local($level) = 1;
   local($char);
   
   while ($level != 0) {
     if      ($line =~ /\(|\)/ ) {
       if ($& eq "(") {
         $level++;
       } else {
         $level--;
       }
       $inside_brackets .= $` . $&;
       $line = $';
     } else { 
       $inside_brackets .= $line;
       $line = <INFILE>;
       $linenumber++;
     }
   }
   chop($inside_brackets);
   $after_close = $line;

   $level            =0;
   local(@arguments) =();
   local($word)      ="";
   
   foreach $char (split(//,$inside_brackets)) {
      if ("$char" eq "(") {
         $level++;
         $word .= "$char";
      } elsif ("$char" eq ")") {
         $level--;
         $word .= "$char";
      } elsif (("$char" eq ",") && ($level==0)) {
        push(@arguments,$word);
        $word="";
      } else {
        $word .= "$char";
      }        
   }
   push(@arguments,$word);
   push(@arguments,$after_close);
   return(@arguments);
}

sub beginSuperStep {
  if ($_[0] =~ /bsp\_sstep\(/) {
    $sstep_lineno = $linenumber;
    return 1;
  } else {
    return 0;
  }
}

sub endSuperStep {
  if ($_[0] =~ /bsp\_sstep\_end\(/) {
    if (!$in_superstep) {
           print STDERR "**$Pgm warning** found end of super-step $1 on ",
                        "line $linenumber of $infile before the start\n\n";
    }  
    return(1);
  } else {
     return(0);
  }
}

