0

私は中かっこを使用して階層を識別するデータ定義言語に取り組んでいます。

typeA idS
{
    paramX = value
    typeB idT
    {
        paramY = value
    }       
}

特定のタイプのブロックに対してどのパラメーターと子タイプが有効かを検証するためのさまざまなルールが多数あります。

既存のブロックまたは名前と値のペアのセットの周りに特別なブロック タイプを配置できるようにする機能を追加したいと考えています。

BLOCK
{
    typeA idS
    {
        BLOCK
        {
            paramX = value
        }
        BLOCK
        {       
            typeB idT
            {
                paramY = value
            }
        }       
    }
 }

既存のすべての型に BLOCK サポートを具体的に追加する必要がなく、子パラメーター/型が特定の親に対して有効であるというパーサー チェックを失うことなく、ブロック内のすべてを許可するブロックを作成する方法はありますか

私はワイルドカード、貪欲と非貪欲を無駄に使用しようとしました。

block: BLOCK '{' (options {greedy=false;} : .* ) '}'

他の回答は、構文述語で解決できることを示唆していますが、それらの使用方法を理解できません(オンラインソースへのリンクをいただければ幸いです)。

他のすべてのルールに触れずにこれを行う方法はありますか? (親/子のチェックをそのまま維持するために、多くの BLOCK_subtypes を必要としないことを願っています)。可読性とメンテナンスの手間が気になります。

ありがとう

4

1 に答える 1

0

これは、複数のパスが必要なようです。

最初のパスでは、基本的に、検証を行わずにブロックとデータを解析するだけで済みます。

blockType: BLOCK OPEN_BRACE type CLOSE_BRACE -> (BLOCK type);
blockParam: BLOCK OPEN_BRACE param CLOSE_BRACE -> (BLOCK param);
type: blockType | (typeName idName OPEN_BRACE param CLOSE_BRACE ->
                 (TYPE typeName idName param));
param: blockParam | (paramName EQUALS value -> (PARAM paramName value));

これにより、2 番目のパスの入力となる AST が生成されます。そこには、次のようなルールが必要です

paramA: (PARAM paramNameA value) | (BLOCK paramA);
typeB: (TYPE typeNameB idNameB paramB) | (BLOCK typeB);

ブロック構造はすべてのルールに侵入しますが、それは標準的な方法で行われます。おそらく、文法ファイルを変更して追加する何かを書くことさえできます。

プリプロセッサを使用することもできます。BLOCK { とそれに対応する } を特別な、そうでなければ無効な文字列に置き換えるものを書くのは難しくありません。各ルールは BLOCK_START? の形式になります。BLOCK_END? など。アクションを追加して、終了なしに開始しないようにする必要がありますが、プリプロセッサが機能している (そして実際の特別なテキストを拒否している) 場合、それは不可能です。

これらはすべて、おそらくあなたが望んでいたよりも押し付けがましいものですが、構造はかなり押し付けがましいものです。

余分なタグが実際にある種の特別な処理をトリガーすると仮定しています。それらが単なる構文糖衣である場合、どちらのソリューションもローカライズされます。プリプロセッサは BLOCK テキストを削除するだけです。AST ソリューションは、それが BLOCK またはネイキッド ステートメントに一致するかどうかにかかわらず、同じ AST を生成します。

于 2013-01-29T22:56:16.207 に答える