手作業でNFAを作る手順


簡単な例として、C言語のコメントの/**/の内側の文字だけを抽出する方法を説明します。
簡単でない例としてはこれと同じやり方でXMLをフェッチする図面がここにあります。

状態\入力 '/' '*' else
S1 2 1 1
S2 1 3 1
S3 3 4 3
S4 1 3 3


表を見ると、
状態1の時に入力値が/であれば状態2へ
状態2の時に入力値が*であれば状態3へ、それ以外は1へ
状態3の時に入力値が*であれば状態4へ、それ以外は3へ
状態4の時に入力値が/であれば状態1へ、それ以外は3へ

以上の事をgraphvizに入力すると、状態遷移図を自動生成できます。

digraph G {
  graph [rankdir=LR];
  node [shape="circle"];
  S1->S2 [label="/"];
  S2->S1 [label="[^*]"];
  S2->S3 [label="*"];
  S3->S3 [label="[^*]"] ;
  S3->S4 [label="*"];
  S4->S1 [label="/"];
  S4->S3 [label="[^/]"];
}
手製のNFA
んで、上の表と図を見ながら単純にプログラムに置き換えます。

  std::string val; // 結果
  int st = 1;
  for (i = 0; i < MAX; i++) {
    ch = buff[i];
    switch (st) {
    case 1:
      if (ch == '/') st = 2;
      break;
    case 2:
      if (ch == '*') st = 3;
      else st = 1;
      break;
    case 3:
      if (ch == '*') st = 4;
   else val += ch;
      break;
    case 4:
      if (ch == '/') st = 1;
      else {
        val += '*';
        val += ch;
        st = 3;
      }
      break;
    }
  }

これでパターンの照合は可能になりました。
コメント内部の文字列を抽出するタイミングは
状態3と4のelseのブロックです。
3から3への遷移では単純に一文字ずつ追加です。
3から4への遷移で先読みがあるので4から3で一文字戻します。


戻る