CYacc は、構文解析スタック
CYacc::stack を
使って、演算子の優先順位を考慮したり、
一致する構文構造があるかを判定することで、
構文解析を助けます。
CYacc は、トークンスタックの内容がどの式(BNF)と
一致したか調べ、式の優先順位に従って
登録しておいたコールバック関数を呼び出します。
ただし、BNFの優先順位によって、
文章の先頭の式より途中の文章の式が先に
コールバックされることもあります。
(そのため、あとの文章が入力されるまで
コールバックする関数が決定しません。)
字句タイプ(CYacc_TokenType クラス)は、次のようなものがあります。
- 演算子:
{ '-'(単項演算子) }, { '(' }, { '*', '/', '%' }, { '+', '-' }, { ')' }
(左にあるほど優先順位が高い)
- 終端記号:
C 言語の ';', 関数の ')' など
- その他の字句:変数(href属性), 定数, ','
- 字句で無いもの:空白
- テキストファイルを読みこんで、テキストの一部を字句(CYacc_Token クラス)として
区切り、字句タイプ(CYacc_TokenType)に対応付けします。
- 字句をスタックに積んでいく(左右方向に伸びるスタックの右端に追加する)
- 演算子を評価したら(積んだら)演算が必要な式があるか判定する。
演算するなら、スタックから除いて計算結果を入れる
- スタックに追加するのが終わったら右の演算子から順に演算する
- 右から2番目の演算子が、最も右の演算子よりも、優先順位が高いか同じときに、
右から2番目の演算子を評価する
- 単項演算子は、すぐ左が ')' 以外の演算子かどうかで判定する
- '(' を評価しても、スタックから除かない。
- '(' を評価するとき、すぐ左が変数なら関数とする。
- ')' を評価するとき、対応する '(' の左が関数なら関数として評価する
- ')' を評価したら対応する '(' もスタックから除く
- タグはそのまま構文解析スタックに入れ、評価するときに
RXML_Tag_outText 関数で一時ファイルに出力して
VAR 参照を解決し、ローカル変数に代入して評価する。
- プログラムデータは Sym_Ref クラスのメソッドで取得した値を
すぐにローカル変数にして構文解析スタックに入れる。
- 5+2*4 ([ ] 内は、スタックの様子を示す)
- [5+] 演算子が1つなので何もしない。
- [5+2*] '*' より '+' が(優先順位が)低いので何もしない。
- [5+2*4] スタックに追加が終わり、右側の演算子から '*', '+' の順に演算する
- 5*2+4 ([ ] 内は、スタックの様子を示す)
- [5*] 演算子が1つなので何もしない。
- [5*2+] '+' より '*' が(優先順位が)高いので '*' を演算する
- [10+4] スタックに追加が終わり、'+' を演算する
- 5*(2+4) ([ ] 内は、スタックの様子を示す)
- [5*(] '(' より '*' が(優先順位が)低いので何もしない。
- [5*(2+] '+' より '(' が高いので '(' を評価する。すぐ左は変数でないので関数にしない。
- [5*(2+4)] ')' より '+' が高いので '+' を演算する。
- [5*(6)] スタックに追加が終わり、')', '*' の順に演算する
- f(2,5+3) ([ ] 内は、スタックの様子を示す)
- [f(2,5+] '+' より '(' が高いので '(' を評価する。すぐ左は変数なので関数にする。
- [f(2,5+3)] ')' より '+' が高いので '+' を演算する。
- [f(2,8)] スタックに追加が終わり、')' を評価し、'(' の左が関数なので
関数として評価する。
written by Masanori Toda