以下に、 スタート状態の使用に関する注をいくつか示します。
1つのルールにおいては、 単一のスタート状態、 または、 カンマで区切られたスタート状態のリストのみを使用することができます。 また、 こうしたスタート状態の指定はルールの先頭になければなりません。 次に示すものは正当です。
%x state1
%s state2
%%
<state1> "something"
<state2> "another thing"
<state, state2> "something else"
しかし、 次に示すものは不当です。
%x state1
%s state2
%%
wrong<state1>
<state1><state2>"wrong"
<state2>"wrong"<state1>
排他的スタート状態は、 他のすべての状態を「無効」にするので、 強力です。 これは、 スキャナの内部においてもう1つのスキャナを効果的に定義することができることを意味しています。 これにより例えば、 スタート状態次第で、 CとPascalの両方をスキャンするスキャナを定義することが、 理論的には可能になります。 以下のようなコードが持つ効果を想像してみてください。
%x PASCAL
%x C
%%
<PASCAL>begin return(OPEN_BLOCK);
<PASCAL>end return(CLOSE_BLOCK);
<C>{ return(OPEN_BLOCK);
<C>} return(CLOSE_BLOCK);
前述のとおり、
スタート状態はそれ自身の名前空間を持っていません。
その理由は、
スタート状態が#defineとほとんど同じ方法で整数値として定義されているからです。
このことは、
整数値と同様、
スタート状態の「スタック」のようなものを作成することが可能であることを意味しています。
例えば、
%{
int last_state[MAX_STATES]
int state_count = 0;
%}
%x FOO BAR baz
%%
FOO {
last_state[state_count] = FOO;
state_count++;
BEGIN(baz);
}
BAR {
last_state[state_count] = BAR;
state_count++;
BEGIN(baz);
}
<baz>rule 1
...
<baz>rule n
<baz>END {
statecount--;
BEGIN(last_state[statecount]);
}
はFOOとBARの両方によってbaz状態を活性化させ、
<baz>ENDというルールによって1つ前の状態に戻します。
こうした「状態スタック」は将来、
Flexの特徴的な機能になるかもしれません。1