web-dev-qa-db-ja.com

XMLベースのASTの上にパーサーを書く:私はそれを正しくやっていますか?

ある種のASTをXMLで定義し、解析して評価しようとしています。XMLツリーには、トークンと必要なすべての情報が含まれています。しかし、難しいと感じています。 「適切に」実行してください。これが私が持っているものです。

_    <node type="operation">
        <value name="OP">AND</value>
        <value name="A">
            <node type="comparison">
                <value name="OP">EQ</value>
                <value name="A">1</value>
                <value name="B">1</value>
            </node>
        </value>
        <value name="B">
            <node type="comparison">
                <value name="OP">EQ</value>
                <value name="A">2</value>
                <value name="B">2</value>
            </node>
        </value>
    </node>

    def getNode() {
        switch (xmlNode[type]) {
            case 'operation':
                new OperationNode(xmlNode[value.OP], getNode(xmlNode[value.A]), getNode(xmlNode[value.B]))

            case 'comparison':
                new ComparisonNode(xmlNode[value.OP], xmlNode[value.A], xmlNode[value.B])
        } 
    }

    nodes = getNode(xmlTree)
    nodes.evaluate()
_

これは擬似コードですが、私が何をしているのかがわかります。基本的に、私はXMLのすべてのノード要素に再帰的にアクセスし、switch-caseに基づいてそれが何であるかを発見し、ドメインに適切なオブジェクトを作成して、後ですべてのノードを一緒に評価できるようにします。

しかし、私はいくつかの質問があります:

  1. どうすればスイッチを取り除くことができますか?私には非常に汚いようですが、私はより良い解決策を考えることができません
  2. すべてのノードをエレガントに評価するにはどうすればよいですか?現在、すべてのノードは、eval()メソッドを持つ基本のNodeクラスから継承します。これは、ポリモーフィズムによって、条件と操作の間ですべての異なる動作を行うことになります。
  3. このXMLをトラバースするより効率的な方法はありますか?
2
vinnylinux

実装言語によっては、XMLをオブジェクトグラフにマッピングするための動的マッピングまたはコードジェネレーターが存在する場合があります。

そのルートに行きたくない場合は、XMLドキュメントを作成するのではなく、イベントベースのパーサーを使用してから、再帰下降を使用する代わりに、イベントからASTを作成することをお勧めします。 value要素の開始が表示され、ValueNodeを返す関数を呼び出して、呼び出しスタックにスタックを管理させます(これは、呼び出しスタックが最も深いネストされた式に対して十分な大きさであると想定しています。これはおそらく実際には真実ですが、誰かが厄介なXMLドキュメントを作成したい場合は失敗モードを開きます)。

手作業でコーディングされた解析ルートをたどると、要素タグ名をオンにすることから逃れることはできません。呼び出す関数にタグ名のマップを使用して非表示にすることもできますが、実装言語が文字列のスイッチオンをサポートしている場合、読みやすさが大幅に向上する可能性はほとんどありません。

2
Pete Kirkham