2 / index / 4

3. 華和梨文法

3.1. 字句構造

KISはネイティブ言語キャラクタセットで動作する。 アルファベットの大文字と小文字は区別される。

空白文字(半角スペースとタブ)、改行文字は、場所によって扱いが異なる。 いわゆる「辞書」記述とスクリプト言語を共存させるため、 KISの字句構造は複雑であり、多数のモードを持つ。

改行可能かどうかの目安は、「対応する閉じ括弧を必要とする場面かどうか」 である。ブロック、インラインスクリプトブロック、エントリ呼び出し、 演算式などの中身が、これに相当する。

エントリ名

エントリ名には、以下の文字を使用できる。

文字列

華和梨辞書にデータとして書くことのできる文字列には、 ベア文字列(裸の、あるいは生の文字列)と、 クォート文字列がある。 華和梨はほとんどの文章を生に書けるようにモード分けしてあるが、 時としてクォート文字列を使う必要がある。

ベア文字列に使える文字は、日本語などのマルチバイト文字と、 文字コード0x09(水平タブ)、および0x20〜0x7Eの間(改行は入らないことに注意) の以下の文字である。 その場所で意味をなす文字以外は全て使えるようになっている。

通常
" ' $ ( ) ,」以外の文字
インラインスクリプト文中
" ' $ ( ) ;」以外の文字
ブロック中
" ' $ ( )」以外の文字

なお、スクリプト実行中などに動的に文をパースする場合は、 ブロック中扱いとなる。


クォート文字列は'"', "'" のどちらかで囲まれた文字列であり、 この中では、基本的に、クォートに用いた文字以外の全ての文字(空白を含む)が使える。 ただし、「\"」あるいは「\'」 (実際にクォートに用いた文字による)は、クォート文字そのもの、 および「\\」は、 「\」そのものとして扱われる。

echo-mode > "これは\"サンプル\"です"
これは"サンプル"です
echo-mode > 'これは"サンプル"です'
これは"サンプル"です
echo-mode > '"でクォートした文字列の中で「\\"」と書くと、"が出力できます。'
"でクォートした文字列の中で「\"」と書くと、"が出力できます。
echo-mode > 以前の華和梨には「"クォート文字列の最後で\\を出力できない\\"」という仕様バグがありました
以前の華和梨には「クォート文字列の最後で\を出力できない\」という仕様バグがありました

コメント、プラグマ

ある行において、 空白文字を除いた最初の文字が「#」である場合 、その行はコメントとして無視される。 これは、辞書記述中のあらゆる場所において有効である。

また、「:rem」だけの行から 「:endrem」だけの行の間も、コメントとして無視する。 このように行頭が「:」で始まる場合、 その行はプラグマとして扱う。 現在、「:crypt」、 「:endcrypt」等が存在する。

予約語

華和梨に特定の予約語は存在しない。 ただし、KISコマンドとして、 構文コマンドと同名のコマンドをユーザが新たに定義することはできない。 そのほかの組み込みコマンドをオーバーライドすることは可能である。 詳細はKISリファレンスに記載。

3.2. 辞書ファイル形式、ゾーン切り替え

Phase 8の辞書ファイルは、 「辞書記述ゾーン」と「スクリプト記述ゾーン」の二つから成る。 辞書記述ゾーンはPhase 8以前の辞書と同様、 エントリに単語を登録する場所であり、単語の評価は行わない。 従って、エントリの定義のファイル内における順序に意味が無い。 一方、スクリプト記述ゾーンはKISを直ちに評価する。評価する順番は 読み込んだ順であり、辞書記述ゾーンと違い記述の順序に意味がある。

辞書記述ゾーンは、「=dict」のみの行と 「=end」のみの行の間である。 また、スクリプト記述ゾーンは「=kis」のみの行と 「=end」のみの行の間である。 今のところあまり意味はないものの、 辞書記述ゾーンとスクリプト記述ゾーンはお互いに入れ子(ネスト)が可能であり、 この場合「=end」は直前の 「=kis」または「=dict」に 対応すると解釈する。 辞書ファイル読み込み時、デフォルトは辞書記述ゾーンである。

スクリプト記述ゾーンにおける基本文法は、 後述する「インラインスクリプトリスト」と同じである。

=dict
# ここは辞書記述ゾーン
プログラム , 栞 : 華和梨 , 里々 , 翡翠 , "ese-shiori" , 美坂 , 文

=kis
# ここはスクリプト記述ゾーン
load dict-keeps.txt;
load dict-standard.txt;
setstr Flags "ジギル";

=dict
# ネストした辞書記述ゾーン
植物 : さくら , 双葉 , みかん
妖怪 : 白子 , 毒子 , 薬子
人間 : 陽子 , 名無子
不明 : 美耳 , サンバーレイン
=end

#ここはスクリプト記述ゾーン
function tset $(echo $@arg[2] ; set $@arg[1] $(getcode @arg[2]));
=end

#ここは辞書記述ゾーン
sentence : \0\s[0]私は${人間}です。\e
=end

3.3. 辞書記述

辞書記述は、エントリ定義を並べたものである。 一つのエントリ定義は以下で表され、改行で終了する。

<エントリ名リスト> : <文リスト(改行不可)>
もしくは、
<エントリ名リスト> ( <文リスト(改行可)> )
エントリ名リスト
エントリ名一つか、もしくは 複数のエントリ名をコンマ(",")で区切って並べたもの。 エントリ名とコンマの間に0個以上の空白文字が入ってもよい。 エントリ名リストの最後がコンマであってはならない。
文リスト
「文(後述)」一つか、もしくは、 複数の文をコンマ(",")で区切って並べたもの。 文とコンマの間に、0個以上の空白文字が入ってもよく、 その空白文字は文の解釈に優先して削除される。 文リストの最後がコンマであってはならない。

3.4. 文と単語

文は(1個以上の)単語のリストである。

エントリ定義中は文=単語であるが、 スクリプト文では、 単語は1個以上の空白文字(改行可能な場所では改行も含む)で区切られている。

単語は、「文字列」「置換子」「ブロック」のリストである。

# deprecated
# 以下の文は単語1つ。
# ただし、単語の中身は要素を3つ(文字列、エントリ呼び出し、文字列)持っている。
sentence : ある日パパと二人で${場所}へ行ったさ〜

# 以下の文は単語が1つ。ただし、ブロックの中に単語が3つ。
sentence : (
    ある日パパと二人で
    ${場所}
    へ行ったさ〜
    )

文と単語の区別が重要になるのは、主にスクリプト文の場合である。

=kis
function DAI_OH_JOU $(
  if $[${弾数}>=1000] ${大往生}します。
  )
=end

上記で、ユーザ定義コマンドに登録されたスクリプト文は、 3つの単語のリストであり、 3つめの単語は要素を2つ(エントリ呼び出し、文字列)持っている。

3.5. ブロック

「文(改行可)」を「(」と 「)」ではさんだものをブロックと呼ぶ。 ブロックの小括弧の内部では自由に改行できる。 改行前後で単語が分割されるが、記述上特に気にする必要はない。 また、インラインスクリプトの引数としてブロックを使った場合も、 ブロック全体が一つの単語要素として扱われるため、内部で自由に改行可能である。

単語はブロックを含むため、ブロックの入れ子は可能である(あまり意味はない)。 またベア文字列の定義から、ブロック内では、 「,」をクォートしなくても文字として使用できる。

# ブロックを使用したエントリ定義のサンプル
Question : \0\s[0]それでは質問です。私の名前は\n(
  " "\q[さくら,NameIsさくら]\n
  " "\q[双葉,NameIs双葉]\n
  " "\q[まゆら,NameIsまゆら]\n
  )のどれでしょう?\e

Speech : \0\s[7](
  '"'さくら'"'は正しいコンセプトを持っていながら実装不足で
  デスクトップに立ち続けられなかった。\w8単なる他人の下らない
  プログラムではなく、\w4あと一歩惜しいところで意味のあるもの
  にならなかったこと、\w4それが腹立たしく悔しかった。\w8\n
  実装の不足が生きた素材を殺してしまった。\w8
  '"'さくら'"' は本当は生きて行くはずだった。\w8
  遺志を継がなくてはならない。
  )\e

3.6. 置換子

置換子とは、「エントリ呼び出し」、「エントリ配列呼び出し」、 「インラインスクリプトブロック」、「式呼び出し」のいずれかである。 これら全てが「$」で始まり、 実行時にはその出力が置換履歴に加えられる。 それぞれの文法は次の通りである。

エントリ呼び出し

${ <エントリ名> }
${ <集合演算式> }

文法的には後者で統一されるが、 単独のエントリ名を書いた場合、後述の集合演算時に展開される可能性がある。 また、単独のエントリ名が整数値であった場合、 履歴参照という特別な動作を行う。

「集合演算式」はエントリを単語の集合と見なし、 和集合や積集合、差集合を記述する。詳細は「集合演算式」の項で説明する。

括弧の中は空白文字、改行文字を(エントリ名が分割されない限り)自由に入れてよい。

エントリ配列呼び出し

$<エントリ指定単語>[ <演算式> ]

エントリ指定単語部には、 置換子、およびエントリ名に使える文字を使って作られた任意の単語が使える。 ただし、途中、前後での空白文字は許されない。 「演算式」は後述。

括弧の中は空白文字、改行文字を(演算子や演算要素が分割されない限り)自由に入れてよい。

$User.Callback.${System.Request.ID}[0]
$User.Callback.$System.Request.ID[0][0]

インラインスクリプトブロック

$( <インラインスクリプト文リスト> )

「インラインスクリプト文リスト」とは、 インラインスクリプト文をセミコロン(";")で区切って並べたものである。

インラインスクリプトは、 空白文字もしくは改行文字で区切られた複数の「単語」のリストである。 「単語」は、前述の通り、また、 インラインスクリプト中の単語で直に書ける文字も前述の通りである。

式呼び出し

$[ <演算式> ]

詳細は「演算式」の項で説明する。

# エントリ呼び出しのサンプル
${npw}、${人間&男性}、${猫-三毛猫}、${${Character}.Head.limithalf}
${(作家&SF作家)-女性}、${犬+猫}、${$(get entries)}
${
  非常に長いエントリ名を使用する場合はこういうことも出来る
}

# エントリ配列呼び出しのサンプル
$wordlist[5]、$${エントリ名}[${@インデックス}]、$@arg[2]
$$インデックスエントリ[5][3]
$event[
  $(date %y) * 365 + $(date %m) *31 + $(date %e)
]

# インラインスクリプトブロックのサンプル
$(if ${a} $(print Yes) else $(print No))、$(date %m)、$(Reference 0)

# 式呼び出しのサンプル
$[ (${収入} - ${支出}) * 3 / 100 ]
$[ "String" != "string" ]
$[
  1+2+3+4+5+6+7+8
  +9+10+11
  +10*5
]

3.7. 演算式

演算式とは、通常の数式・論理式そのものである。 項としては数値、クォート文字列、置換ブロックが使える。 また、小括弧によるグルーピングも使える。 文法は次の通りである。

<単項式> ( <二項演算子> <単項式> )の0個以上の繰り返し : 各要素間に0個以上の空白文字・改行文字を許す

単項式

単項式とは、演算式の「要素」、 もしくは要素の前に「単項演算子」をつけたものである。 単項演算子とは、'+'、'-'、'!'、'~'の4つの記号のことである。

要素、式単語

演算式の要素とは「式単語」、または小括弧で括った演算式そのものである。 式単語とは、十進整数字の文字列、クォート文字列、 置換ブロックのいずれかを並べたものである。

一つ注意しなければならないのは、文字列比較などの際に、 演算式内に直接文字列を書くときは、必ずクォート文字列にしなければならない 点である。

二項演算子

二項演算子とは、 '|'、'&'、'^'、'||'、'&&'、'<'、'<='、 '='、'=='、'!='、'=~'、'!~'、'>='、'>'、'+'、'-'、'*'、 '/' 、'%'、'**' のいずれかの記号、もしくは記号列である。

3.8. 集合演算式

集合演算式とは、エントリを単語の集合と見なし、積集合、和集合、 差集合を表現するものである。文法は次の通りである。

<エントリ要素> ( <エントリ二項演算子> <エントリ要素> )の0個以上の繰り返し : 各要素間に0個以上の空白文字・改行文字を許す

「エントリ要素」とは、エントリ名、 または小括弧で括った集合演算式そのものである。

エントリ二項演算子とは、'+'、'-'、'&'のいずれかの記号である。