目次
WING 関係
WinGO(GTk WING クライアント)
NNGS プロトコル解析
NNGSライブラリ
Glib 関係
Glib Scanner
Gtk 関係
Widget作成法

GScanner

機能

汎用のスキャナ(字句解析器)生成器です。入力した文字列をトークンに分けてくれます。 入力にはバッファ、ファイルのどちらも利用できます。 スキャナ生成器としては lex(flex) が有名ですが、 lex と違い DFA の生成は実行時に動的に行われます。 そのため、柔軟性や性能は lex に比べると落ちると思いますが、 バグの入りやすい文字列処理を一手に引き受けてくれるので、 うまく使えば非常に便利に利用できます。

Glib Scanner を利用したスキャナのバッファや設定などは構造体にまとめて保持されます。 したがって、新規に構造体を作成することで全く異なるスキャナを複数作成して利用できます。 複数のスキャナを利用するためには、 いろいろな技を使わなければならない lex に比較すると手軽かもしれません。 (最近の GNU flex の場合には -P オプションで複数のスキャナを容易に作成できます)。

Glib Scanner は状態遷移もサポートしています(スコープと呼びます)。 スコープを適切に設定することで、状況に応じた解析が可能です。

用語

1. トークン

入力文字列を意味のある(と思われる)単位に切り分けた際の各パーツをトークンと呼びます。 GScanner からの出力はすべてトークンを単位としておこなわれます。 通常 GScanner がトークンを発見すると、トークンの種類を返します。 トークンの内容については別途取得しなくてはなりません。

2. Symbol

ユーザが定義した文字列です。 Symbol を定義することにより、入力文字列から特定の文字列を探し出すことができます。

3. ID(Identifier)

はじめから定義されているトークンや、ユーザが定義したシンボル以外の複数の文字の並びはすべて ID です。 設定により、ID を使わず一文字単位でトークンに変換することもできます。

4. 例

入力文字列が "1 a foo bar" で、ユーザがシンボル "foo"を定義している場合、 解析結果は G_TOKEN_INT G_TOKEN_CHAR G_TOKEN_SYMBOL G_TOKEN_IDENTIFIER となります。 トークンの内容を取得すると、それぞれ "1"、"a"、"foo"、 "bar" となります。

動作

GScanner は入力をトークンに分割して、 g_scanner_get_next_token() が呼ばれるたびに一つずつ返します。 トークンの境界は空白文字(スペース、タブ、改行など)かコメントです。 トークンの返し方はいくつか選択できますが、 典型的には G_TOKEN_ で始まるトークン番号となります。 トークン番号は見つかったトークンの「種別」を示す整数です。 実際のトークンの内容は g_scanner_cur_value() で取得しなくてはなりません (設定によっては、トークン番号の代わりに内容を直接返すこともできます)。 トークンになりうる文字列を以下に示します。

1. 標準で用意されているもの

以下のトークンが標準で用意されています。 これらのトークンだけでも簡単な字句解析には事足りるかもしれません。

特定の文字に関するトークン

特定の文字に関するトークン
文字 トークン
( G_TOKEN_LEFT_PAREN
) G_TOKEN_RIGHT_PAREN
{ G_TOKEN_LEFT_CURLY
} G_TOKEN_RIGHT_CURLY
[ G_TOKEN_LEFT_BRACE
] G_TOKEN_RIGHT_BRACE
= G_TOKEN_EQUAL_SIGN
, G_TOKEN_COMMA

文字列のクラスに関するトークン

文字列のクラスに関するトークン
クラス トークン
文字 G_TOKEN_CHAR
文字列 G_TOKEN_STRING
2 進数 G_TOKEN_BINARY
8 進数 G_TOKEN_OCTAL
10 進整数 G_TOKEN_INT
10 進小数 G_TOKEN_FLOAT
16進数 G_TOKEN_HEX

文字列は " または ' で括られたものを意味します。 括られていないものは後述の G_TOKEN_IDENTIFIER です。

数値はすべて符号なしです。 符号付きの数値は、 符号を示すトークン(G_TOKEN_CHAR)と数値を示すトークンの二つに分割されます。

コメント文字列

コメント文字列
種類 トークン
一行コメント G_TOKEN_COMMENT_SINGLE
C 言語風コメント G_TOKEN_COMMENT_MULTI

設定によっては、コメントをトークンとして認識せず無視できます。

制御用

制御用
種類 トークン
解析エラー G_TOKEN_ERROR
トークンが無い G_TOKEN_NONE
解析終了 G_TOKEN_EOF

上記にあてはまらないもの

上記以外
種類 トークン
シンボル G_TOKEN_SYMBOL
シンボル以外 G_TOKEN_IDENTIFIER
NULL 文字列 G_TOKEN_IDENTIFIER_NULL

シンボルとは、後述するユーザ定義の文字列のことを示します。

2. ユーザ定義の文字列(シンボル)

GScanner ではユーザが定義した文字列をトークンとして扱えます。 この文字列を GScanner では「シンボル」と呼びます。 シンボルを定義する際には検出して欲しい文字列と、 その文字列に対応するポインタを指定します。 このポインタは GScanner 内部では void * として扱われるため、 どのようなポインタでもかまいません。

設定によりユーザ定義の文字列を発見した場合に、 G_TOKEN_SYMBOL を返すか、シンボルを定義した際に指定したポインタを返すか指定できます。 前者の場合、 G_TOKEN_SYMBOL を検出したあと g_scanner_cur_value() でポインタを取得することになります。

美しいとは言えませんが、 便利な方法としてシンボルに対応するポインタに整数を指定する方法があります。 このポインタを間接参照するとクラッシュすることになりますが、 G_TOKEN_SYMBOL のかわりに、 ポインタを返すように設定することで新しいトークンを定義したのと同様の効果が得られます。 この場合に指定する整数は G_TOKEN_LAST より大きくする必要があります。

使い方

1. 設定構造体の作成

Glib Scanner の設定は、GScannerConfig という構造体を通じておこないます。 glib-1.2.10 では GScannerConfig を作成する関数はありませんので、 手動で確保することになります。構造体のメンバの意味を以下に示します。

gchar *cset_skip_characters

スキップすべき文字の集合です。スペース文字、タブ文字、改行文字などです。 これらの文字はトークンの境界としては利用されますが、 それ自体はトークンにはなりません。 複数連続して並んでいても一つの境界として扱われます。

gchar *cset_identifier_first

トークンの先頭になりうる文字の集合です。 適切に設定すれば、 トークンになりえない文字列を早期に発見できます。

gchar *cset_identifier_nth

トークンの中に現れうる文字の集合です。 適切に設定すれば、 トークンになりえない文字列を早期に発見できます。

gchar *cpair_comment_single

一行コメントの先頭文字および終了文字を設定します。 例えば、 "#\n" を設定すれば # から改行までが一行コメントとして無視されます。 指定できるのは先頭文字、終了文字ともに一文字だけのようです。 ここで指定したコメントの他に C 言語風のコメントが標準で用意されています (skip_comment_multi)。

guint case_sensitive : 1

大文字、小文字を区別するかどうかを指定します。 TRUE を設定すれば区別し、FALSE を設定すれば区別しません。

guint skip_comment_multi : 1

C 言語風のコメントをどう処理するかを指定します。 TRUE なら C 言語風のコメントを空白文字と同様にスキップし、 トークンは返しません。 FALSE なら C 言語風のコメントもトークンの一部として処理し、 対応するトークンを返します。

guint skip_comment_single : 1

cpair_comment_single で指定した一行コメントを処理するかどうかを指定します。 他は skip_comment_multi と同じです。

guint scan_comment_multi : 1

TRUE に設定すれば C 言語風のコメントが存在しうるものとして処理します。 FALSE に設定すれば C 言語風のコメントは存在しないものとして処理するため、 若干処理が高速になります。

guint scan_identifier : 1

ID を認識するかどうかを指定します。 TRUE に設定すれば、スキャナは ID を認識します。 FALSE に設定すれば、スキャナは ID を認識せず処理単位は「一文字」になります。

例えば abcde という文字列を入力した場合、scan_identifier = FALSE なら、 このこの文字列は 5 つの G_TOKEN_CHAR として認識され、 scan_identifier = TRUE なら、1 つの G_TOKEN_IDENTIFIER として認識されます (ユーザ定義シンボルとして abcde が定義されているなら、G_TOKEN_SYMBOL です)。

guint scan_identifier_1char

一文字だけの ID を認めるかどうかを指定します。 TRUE に設定すれば、一文字だけのトークンでも G_TOKEN_IDENTIFIER として認識されます。 FALSE に設定すれば、一文字だけの場合は G_TOKEN_CHAR や G_TOKEN_INT などになります。

guint scan_identifier_null

NULL 文字を ID として扱うかどうかを指定します。 TRUE に設定すれば、NULL 文字は G_TOKEN_IDENTIFIER_NULL として認識されます。 FALSE に設定すれば、NULL 文字は無視されます。

guint scan_symbols

シンボルを認識するかどうかを指定します。 TRUE ならシンボルは G_TOKEN_SYMBOL として認識されます。 FALSE ならシンボルが定義されていても G_TOKEN_IDENTIFIER として認識されます。