私はスクリプトインタープリターに取り組んでおり、なんとか動作状態になりました。スクリプトを解析してバイトコードを生成するコンパイラと、バイトコードを実行する VM を備えています。
case
インタプリタの中心にあるのは、次のような巨大なステートメントを含むループです。
case CurrentOpcode.Operation of
OP_1: DoOp1(CurrentOpcode);
OP_2: DoOp2(CurrentOpcode);
...
OP_N: DoOpN(CurrentOpcode);
end;
プロファイリングによると、何らかの理由で、スクリプトの実行がそのステートメント内でかなりの時間を費やしていることがわかりましたcase
。これは奇妙に思えるので、それを最適化する方法を探しています。すべての操作関数は基本的に同じシグネチャを持っているため、明白な解決策は、オペコードのOperation
値によってインデックス付けされたメソッド ポインターの配列を作成することです。しかしOperation
、列挙型として宣言されており、これを const 配列として宣言できると便利です。これにより、将来さらにオペコードを追加した場合に、コンパイラが配列を更新するように通知することができます。
メソッド ポインターは実行時の状態 (実行Self
中のオブジェクトへの参照) を格納するため、メソッド ポインターの const 配列を作成することはできません。(とにかく、これは良い考えではありません。同時に複数のスクリプトを実行することになる可能性が非常に高いためです。) しかし、とにかくメソッドは単なる構文糖衣です。何かのようなもの:
procedure TMyObject.DoSomething(x, y: integer);
本当に意味:
procedure TMyObject_DoSomething(Self: TMyObject; x, y: integer);
したがって、後者の形式で関数ポインター型を宣言し、そのように割り当てることができるはずです。その後、Self
呼び出すときに最初のパラメーターとして明示的に渡す必要があります。しかし、コンパイラはそれを好まない。
type TOpcodeProc = procedure (Self: TScriptVM; Opcode: TOpcode);
const OPCODE: TOpcodeProc = TScriptVM.DoOp1;
[DCC Error]: E2009 Incompatible types: 'regular procedure and method pointer'
これをコンパイルするためにさまざまなバリエーションを試しましたが、すべてエラーが発生します。これをコンパイルする方法はありますか?