bstファイルの output.check, output.nunnull のコード解説

TeX

bstファイルの編集を試みたら、output.check の中で動いている output.nunnull が結構やっかいな動きをしていたので、その覚書です。

コードはTeXに標準搭載されている acm.bst で解説していますが、他のbstファイルでも基礎的な考え方は同じです。

article関数の大まかな構造

まず、文献の情報が大まかにどのように出力されているかを確かめるために、article関数の定義を見てみます。

FUNCTION {article}
{ output.bibitem
  format.authors "author" output.check
  new.block
  format.title "title" output.check
  new.block
  crossref missing$
    { format.journal.vol.num.date output
      format.pages output
    }
    { format.article.crossref output.nonnull
      format.pp.pages output
    }
  if$
  new.block
  note output
  fin.entry
}

output.bibitem はTeXの文献を書く際に用いる「 \bibitem{  }」などの文字列をスタックにプッシュするコマンドです。

format.authors、format.title などはbibファイルから著者やタイトルなどの情報を読み込み、適当なスタイルに変換して、その文字列をプッシュするコマンド。

これらのコマンドは著者やタイトルなどの情報を用意する(スタックにプッシュする)だけです。実際に用意された文字列を、bblファイルに書き込んでいるのが「output.check」というコマンドです。
さらに、output.check は書き込むだけでなく、著者名・タイトル・雑誌名などの間に、状況に応じてカンマやピリオドも付けて出力するようにプログラムされています。

output.check と output.nonnull の仕組み

では、「output.check」の仕組みを説明します。まず acm.bst の場合、コードは次のようになっています。

FUNCTION {output}
{ duplicate$ empty$
    'pop$
    'output.nonnull 
  if$
}

FUNCTION {output.check}
{ 't :=
  duplicate$ empty$
    { pop$ "empty " t * " in " * cite$ * warning$ }
    'output.nonnull
  if$
}
output.check の仕組み
  1. article関数の定義の中でプッシュされた “author” や “title” などの文字列をポップして、変数 t に代入。
  2. bibtexファイルの author や title などのエントリーが、 empty かどうかをチェックして、output.nunmull に引き渡す。emptyならば警告を出力する。

output は単にこれの警告のないバージョンです。

核は次の output.nunnull です。

FUNCTION {output.nonnull}
{ 's :=
  output.state mid.sentence =
    { ", " * write$ }
    { output.state after.block =
        { add.period$ write$
          newline$
          "\newblock " write$
        }
        { output.state before.all =
            'write$
            { add.period$ " " * write$ }
          if$
        }
      if$
      mid.sentence 'output.state :=
    }
  if$
  s
}

 output.nunnull は、ariticle関数の中の各段階で「output.state」に入力された数値から、センテンスの途中(mid.sentence)なのか、センテンスの終わり(after.sentence)なのかなどを判断し、カンマやピリオドを状況に応じて入力するようにプログラムされたコマンドです。
 acm.bst では、これらの状況を判断するために、次の4つの数値がコードの序盤で用意されています。

FUNCTION {init.state.consts}
{ #0 'before.all :=
  #1 'mid.sentence :=
  #2 'after.sentence :=
  #3 'after.block :=
}

output.stateが、この 0~3 のどの数値なのかによって、カンマを出力するのか、ピリオドを出力するのかを決めます、

ちなみに、output.state は一番初めにoutput.bibitem の中で before.all の値に設定されます。

output.nunnull の実際の仕組みは次の通りです。

output.nunnull の仕組み

 1. スタックの中の一番上をポップして、変数 s に代入。
  article関数の定義内で、format.authors や format.titleでプッシュされたものを想定。
  
 2. output.state の値に応じて、以下の条件分岐で処理を実行する。

  • mid.sentence → カンマ “,” を結合して、write する
  • after.block → ピリオドやnewline, new.block などを付けて、writeする。
  • before.all → そのまま write する。
  • after.sentence(どれでもない)→ ピリオド(add.period)とスペース” ” を結合して write する。

 3. 上の条件分岐が、after.block、before.all、after.sentence だった場合は、
  変数 output.state に mid.sentence の値を代入。
 4. 最初に代入した 変数 s の文字列を、スタックにプッシュ。

※1. ここで注意しなければならないのは、初めにformat.authors や format.titleでプッシュされたものを、ポップして変数 s に代入している点です。ポップしたことによって、スタック内にはformat.authorsで入力した情報は一旦なくなっています。
なので article関数の中で書かれている「output.check」はその1行上の情報に、カンマやピリオドを付けて write していることになります。

FUNCTION {article}
{ output.bibitem
  format.authors "author" output.check  %ここのoutput.checkはbibitemを書いている 
  new.block
  format.title "title" output.check. %ここのoutput.checkはauthorの情報を書いている 
  new.block

new.blockの役割

new.block は acm.bst 特有のコードですが、これは output.state を after.block の値に設定しろというコマンドです。

FUNCTION {new.block}
{ output.state before.all =
    'skip$
    { after.block 'output.state := }
  if$
}

これをarticle 関数の定義に入れることで、著者名(format.authors)やタイトル(format.title)の後では、output.check の条件分岐が、output.state=after.block であるときをたどるように設定しているわけです。つまり、著者名やタイトルの後で、ピリオドやnewline, newblock などを付けて、writeするようにしています。

この辺りのピリオドやカンマの設定を変えたければ、new.block をコメントアウトしたり、output.nunnull のコードを変更すればよいのです。

ちなみに author部分の下の new.block をコメントアウトすると著者名の後ろにカンマが入り、title部分の下の new.blockをコメントアウトするとタイトルの後ろにカンマが入ります。
これは、output.checkの仕組みの後半で、変数 output.state に mid.sentence の値が代入されたものが、そのまま維持されるからです。

FUNCTION {article}
{ output.bibitem
  format.authors "author" output.check 
  new.block  %ここをコメントアウトすると、著者名の後ろにカンマが入る。
  format.title "title" output.check. 
  new.block  %ここをコメントアウトすると、タイトルの後ろにカンマが入る。

※2. 上のコードの4行目のnew.block が output.check の後ろにあるのに、authorの後ろにカンマが入るのは、※1で説明したように「format.authors や format.titleでプッシュされたものを、ポップして変数 s に代入している」操作があるためです。
実際には3行目のoutput.checkは2行目の output.bibitem をwrite しているだけです。

他のbstファイルについて

他のbstファイルでは、output.nunnull の条件分岐を複雑化させて、カンマなど入り方を調整してあったりします。例えば ieeetr.bst では、「FUNCTION {init.state.consts}」で6つの値を用意し、クォーテーションマークの後ろでは、カンマもピリオドも出力せず、スペースのみを出力するようにプログラムされていたりします。詳しくは以下の記事の後半をご覧ください。

bstファイルの編集【bibTeX・スタイルファイル】

参考サイト

Bibtexのスタイルファイル:bstファイルの文法
↑bibtexコマンドの文法が非常に分かりやすくまとまっています

Bibtexのスタイルの改変
↑junsrt.bstというbstファイルのコードの解説が分かりやすい

コメント

タイトルとURLをコピーしました