##2010mt2.pl
##
##20100821translate関数追加
##20100820..2009mt2の改良版
##
##....##debug★printの行はデバッグプリント(プログラムのどこを通っているかを確認)。必要に応じて##debug★を削除して使用するとよい。
##
##2009mt2.pl
##形態素解析結果のファイルを読み込み、品詞の並びを見ながら、対訳を出力
##単文のみ対応版
##
##レベル0
##メイン
$infile ="outtaiyaku.txt";
$outfile="MToutput.txt";

##形態素ファイルオープン
open(IN, "$infile")|| die "cannot open $!\n";

##出力ファイルオープン
open(OUT,">>$outfile") || die "cannot open $!\n";

##1行ずつ読み込んで入力文配列にセット
##カウンタ初期化
$i=0;
while(<IN>){
  $line = $_;
  chop($line);  

  if($line ne ""){					#空行は無視
    @dic = split(/#/,$line);

    $sp_w[$i]=$dic[0];
    $sp_p[$i]=$dic[1];
    $jp_w[$i]=$dic[2];
    $jp_p[$i]=$dic[3];
  
##    print $sp_w[$i],$sp_p[$i],$jp_w[$i],$jp_p[$i],"\n";  ##デバッグ用
    print OUT "$sp_w[$i] ";  ##原文を対訳ファイルに出力

    $i++;
  }
}
print OUT "\n";
close(IN);	#形態素ファイルクローズ

##この時点での$iの値が形態素数
$numberofmorph = $i;

##先頭から入力文配列を文末まで見る。(レベル0)
##現在のレベルセット	#レベルは処理中のスタックではなく、埋め込みの深さとする。##未使用
$level = 0;
##カーソル初期化
$cursol = 0;
##スタック１の添え字	#グローバル	
$s1_i = 0;
##スタック２の添え字	#グローバル	
$s2_i = 0;
##スタックの初期化
@stack1 = "";
@stack2 = "";

##20100822自分(カーソル位置)ベースでの分岐に書き換え
while($cursol < $numberofmorph){	##レベル0のwhile

##訳出(スタック1解放)のトリガーになる品詞の判定(VP構成要素および句読点類)
  ##(1)自分がVP構成要素(no-se-に-を-活用動詞)のとき。(he dicho型の助動詞auxは未対応⇒2010★)
  ##(1a)自分がnegのとき、スタック1を解放してから、自分をスタック1に。
  if($sp_p[$cursol] eq "neg"){
    &move_to_stack1;
    $stack1[$s1_i] = $cursol;		##カーソル番号＝形態素列の番号をスタック1に ##20100822pushを使用するとバグ...要検討
    $s1_i++;
  }
  ##(1b)自分がclのとき
  ##1つ前の形態素(=スタック1の先頭)がnegかclなら自分を積んで次へ。
  ##それ以外は、スタック1を解放してから、自分をスタック1に。スタック1が空(自分が0番目の形態素)なら自分を積んで次へ。
  elsif($sp_p[$cursol] eq "cl"){

  ##1つ前の形態素番号
      $mae=$cursol-1;

    if($mae < 0){
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }
    elsif(($sp_p[$mae] eq "neg")||($sp_p[$mae] eq "cl")){
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }
    else{
      &move_to_stack1;
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }      
  }
  ##(1c)自分がvのとき
  ##1つ前の形態素(=スタック1の先頭)がnegかclなら自分を積んで次へ。
  ##それ以外は、スタック1を解放してから、自分をスタック1に。スタック1が空なら自分を積んで次へ。
  elsif($sp_p[$cursol] eq "v"){

      $mae=$cursol-1;

    if($mae < 0){
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }
    elsif(($sp_p[$mae] eq "neg")||($sp_p[$mae] eq "cl")){
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }
    else{
      &move_to_stack1;
      $stack1[$s1_i] = $cursol;		
      $s1_i++;
    }  
  }
  ##(2)自分が句読点類のとき。
  ##スタック1を解放してから、自分を訳出。
  elsif(($sp_p[$cursol] eq "punto")||($sp_p[$cursol] eq "coma")){
    &move_to_stack1;
    &translate($cursol);
##debug★print "1";$tmp = <STDIN>;
  }

  ##(ELSE)自分が区切り品詞でないときは、スタック1に積んで次へ。
  else{
    $stack1[$s1_i] = $cursol;		
    $s1_i++;

  }

  $cursol++;	#原文の形態素列のカーソルを次へ

}	##whileの終わり->このループを抜けてプログラム終了。

##ファイルの行末に改行を出力して、ファイルクローズ
print OUT "\n";
close(OUT);

##
##◆スタック1の解放(このルーチンを抜けるときにs1_iカウンタを0にリセット)
sub move_to_stack1{

##20100822スタック2に積む部分をpushに書き換え⇒それに伴いカウンタ$s2_iの初期化は不要。
##20100823カウンタ初期値を配列の最後の添え字$#stack1とするとエラーに。 for($i=($#stack1);$i>=0;$i--)★⇒素直に$s1_iでループに変更

  ##@stack1を、添え字の大きい要素から0まで見るループ(「後ろから前に訳出」)。途中で保留=stack2に入る場合も(「前から後ろに訳出部分」)⇒別ルーチンを呼び出す)
    
  for($i=($s1_i-1);$i>=0;$i--){

  ##スタックの残りがあるとき(自分が文頭形態素でないとき)
  if($i != 0){
  ##自分がnのとき
    if($sp_p[$stack1[$i]] eq "n"){
    ##1つ前がnum, det, interrog, adjならば自分をスタック2に積んで次へ。
      if(($sp_p[$stack1[$i-1]] eq "num")||($sp_p[$stack1[$i-1]] eq "det")||($sp_p[$stack1[$i-1]] eq "interrog")||($sp_p[$stack1[$i-1]] eq "adj")){
        push(@stack2,$stack1[$i]);

        $stack1[$i]="";	##ここでスタック1からは消す
      }
    ##それ以外は自分を出力してスタック2を解放(★空のはず)
      else{
        &translate($stack1[$i]);
##debug★print "2";$tmp = <STDIN>;  
        &move_to_stack2;
      }
    }
  ##自分がnumのとき
    elsif($sp_p[$stack1[$i]] eq "num"){
    ##1つ前がdetならば自分をスタック2に積んで次へ
      if($sp_p[$stack1[$i-1]] eq "det"){
        push(@stack2,$stack1[$i]);

        $stack1[$i]="";	##ここでスタック1からは消す
      }
    ##それ以外は自分を出力してスタック2を解放
      else{
        &translate($stack1[$i]);
##debug★print "3";$tmp = <STDIN>;
        &move_to_stack2;
      }
    }
  ##自分がdetのとき、自分を出力し、スタック2があれば★解放。さらにその前にdetが続く構造はスペイン語にはない?(★el uno, el otro型未対応!)
    elsif($sp_p[$stack1[$i]] eq "det"){
      &translate($stack1[$i]);
##debug★print "4";$tmp = <STDIN>;
      &move_to_stack2;
    }
   
  ##自分がinterrogのとき、自分を出力し、スタック2があれば★解放。
    elsif($sp_p[$stack1[$i]] eq "interrog"){
      &translate($stack1[$i]);
##debug★print "5";$tmp = <STDIN>;
      &move_to_stack2;
    }
  ##自分がadjのとき
    elsif($sp_p[$stack1[$i]] eq "adj"){
    ##1つ前がnum, det, advならば自分をスタック2に積んで次へ
      if(($sp_p[$stack1[$i-1]] eq "num")||($sp_p[$stack1[$i-1]] eq "det")||($sp_p[$stack1[$i-1]] eq "adv")){
        push(@stack2,$stack1[$i]);

        $stack1[$i]="";	##ここでスタック1からは消す
      }
    ##それ以外は自分を出力してスタック2があれば解放
      else{
        &translate($stack1[$i]);
##debug★print "6";$tmp = <STDIN>;
        &move_to_stack2;
      }
    }
  ##自分がadvのとき(muy guapo, m'as grande型)自分を出力して、スタック2があれば解放
    elsif($sp_p[$stack1[$i]] eq "adv"){
        &translate($stack1[$i]);
##debug★print "7";$tmp = <STDIN>;
        &move_to_stack2;
    }
  ##自分がvのとき
    elsif($sp_p[$stack1[$i]] eq "v"){
    ##1つ前がcl, negなら自分をスタック2に積んで次へ
      if(($sp_p[$stack1[$i-1]] eq "cl")||($sp_p[$stack1[$i-1]] eq "neg")){
##        $stack2[$s2_i] = $stack1[$i];
##        $s2_i++;
        push(@stack2,$stack1[$i]);

        $stack1[$i]="";	##ここでスタック1からは消す
      }
    ##それ以外ならば自分を出力して、スタック2があれば解放(空のはず)
      else{
        &translate($stack1[$i]);
##debug★print "8";$tmp = <STDIN>;
        &move_to_stack2;
      }
    }
  ##自分がclのとき
    elsif($sp_p[$stack1[$i]] eq "cl"){
    ##1つ前がcl, negなら自分をスタック2に積んで次へ
      if(($sp_p[$stack1[$i-1]] eq "cl")||($sp_p[$stack1[$i-1]] eq "neg")){
        push(@stack2,$stack1[$i]);

        $stack1[$i]="";	##ここでスタック1からは消す
      }
    ##それ以外ならば自分を出力して、スタック2があれば解放(空のはず)
      else{
        &translate($stack1[$i]);
##debug★print "9";$tmp = <STDIN>;
        &move_to_stack2;
      }

    }
  ##自分がnegのとき、スタック2を解放してから自分を出力(★ここだけ処理が逆)
    elsif($sp_p[$stack1[$i]] eq "neg"){
      &move_to_stack2;
      &translate($stack1[$i]);
##debug★print "10";$tmp = <STDIN>;
    }
  ##それ以外(スタック2解放のトリガーにならない品詞)のとき、自分を出力して次へ。
    else{
      &translate($stack1[$i]);
##debug★print "11";$tmp = <STDIN>;
    }

  } #スタックの残りがあるときの処理終わり

  ##自分がスタックの底のときは自分を出力し、スタック２があれば解放。自分がnegのときだけ逆。
  else{
    if($sp_p[$stack1[$i]] eq "neg"){
      &move_to_stack2;

      &translate($stack1[$i]);
##debug★print "12";$tmp = <STDIN>;

    }
    else{

      &translate($stack1[$i]);
##debug★print "13";$tmp = <STDIN>;

      &move_to_stack2;
    }
  } #スタックの底のときの処理終わり

##20100826データを空に。正しくは未定義値undef(=0?)とすべき。要調査。
$stack1[$i]="";

  } #スタック1のforの終わり

  ##for文を抜けた時点でスタック1は解放ずみ。スタック1の添え字をリセット
  $s1_i=0;		

}

##
##◆スタック２の解放
sub move_to_stack2{

##20100821pop関数使用

  $y = pop(@stack2);

  while($y != undef){

    ##20100826translate関数使用

    &translate($y);

    $y = pop(@stack2);
  }

  ##while抜けた時点でスタック2の処理は終了。スタックを空に。スタック2の添え字をリセットし、スタック1のルーチンに戻る。
  ##20100822スタック2に積む際pushを用いるよう変更したため下記は不要に。
  ##$s2_i = 0;

}	#スタック2処理のサブルーチンの終わり

##
##◆対訳出力
sub translate{

    print "$jp_w[$_[0]]"," ";		##$_[0]は呼び出し元の第一引数
    print OUT "$jp_w[$_[0]]"," ";


}


##★呼び出し元は &subname;
##sub sayhello {
##  print "hello\n";
##}
