二段階ディスパッチによるトークン分類の最適化
はじめに
[編集]YOYUのトークナイザ設計においては、ASCII 128文字それぞれに専用の分類関数を割り当てることを基本方針としている。この設計により、入力文字からトークンの種別判定および処理関数の呼び出しまでを1ステップで完結させることができ、構文記述上の柔軟性と性能の両立を目指していた。
しかしながら、64ビット環境における関数ポインタのサイズは8バイトであり、128文字ぶんの関数ポインタ配列を素直に用意すると、1024バイト(1KB)の静的メモリ領域を占有する。このことが記述の軽量性を志向するYOYUにとって一つの設計的違和感となった。
二段階ディスパッチ方式
[編集]本稿ではこの問題に対処する方法として「二段階ディスパッチ方式」を提案する。この方式では、トークン分類処理を以下の2段階に分けて実装する:
- `tokenid tableA[128]` により、入力文字からトークン種別IDを取得する。
- `funcp tableB[TOKENID_MAX]` により、種別IDに対応する処理関数を取得して実行する。
これにより、関数ポインタの個数は使用される実トークン種別数に比例することとなり、128個の関数ポインタを固定で保持する必要がなくなる。
使用例
[編集]以下はその基本的な構造である:
typedef unsigned char uchar;
typedef unsigned char tokenid;
typedef void (*funcp)();
tokenid tableA[128]; // 1段目:文字 -> 種別
funcp tableB[TOKENID_MAX]; // 2段目:種別 -> 処理関数
void dispatch(uchar c) {
tokenid tid = tableA[c];
funcp f = tableB[tid];
f();
}
既知の技法との関係
[編集]この構造は筆者の独自発明ではなく、歴史的には多くの字句解析器、仮想マシン、命令デコーダ等で類似の最適化が見られる。たとえば、正規表現エンジンにおける文字クラス分解、仮想マシンにおけるオペコード分類、CPythonやLua等における中間コードディスパッチなどが挙げられる。
本論文の意義は、それらの既知の構造をYOYUの設計思想に適合させ、意味処理ではなく記述と分類の明確性に重きを置いた言語処理系においてどう活用できるかを具体的に示した点にある。
設計哲学との一致
[編集]YOYUにおける字句解析の哲学は、関数テーブルの柔軟な分割や、クラス的分類の静的構造を明示することにある。二段階ディスパッチは、この方針と非常に相性がよい:
関数を分類単位に再利用できる
文字→クラス→処理という流れが自然に表現できる
表記上の省略・明示の設計と整合性が取れる
このように、たとえ既知の技法であっても、設計の中でどのような位置づけを与えるかによって新たな価値を持ち得るという一例となった。
結論
[編集]本稿では、関数ポインタテーブルの節約と分類の明示性を両立する「二段階ディスパッチ方式」を紹介した。この構造は古典的技法でありながら、YOYUにおいては設計の中核に据えられる価値を持ち、静的なトークン構成と分類処理の透明性を高めるものである。