2

興味深い問題があります。次のように行が満たされたファイルがあるとしましょう:

name1[xp,y,z321](a,b,c){text};//comment
#comment
name2(aaaa);

また、(簡略化された)クラスがあります:

class something {
public:
 something(const std::string& name);
 addOptionalParam(const std::string& value);
 addMandatoryParam(const std::string& value);
 setData((const std::string& value);
};

name は、一部のクラス コンストラクターのパラメーター名に対応します。[] 括弧内はオプション、() 内は必須で、{} の間はすべて文字列として渡す必要があります。

最初の行では、名前として「name1」を使用してコンストラクターを呼び出す必要があります。addOptionalParam を 3 回呼び出します。コロンで区切られた項目ごとに 1 回ずつです。また、addMandatoryParam と setData を「テキスト」で 3 回実行します。

私はコメントを行う方法を考え出すことができますが、他のすべては私のために台無しにされています...

今、私はこれがどのように(または)可能であるかについての良いアドバイスが必要です.単純なオブジェクトに対してそれを行う方法を考え出すことができれば、セマンティックの正確さなどの余分な悲惨な詳細をすべて処理する方法を考え出すことができます.

4

3 に答える 3

5

あなたの説明は少し紛らわしいです(例えば、あなたは「コロンで区切られている」と言っていますが、入力にコロンがありません)。角括弧内の項目はオプションのパラメーターであり、括弧内の項目は必須パラメーターであり、中括弧内の項目は「データ」であると想定しています。

その場合、文法は次のようになります。

func: name optionalParams '(' paramList ')' '{' data '}'

paramList: param |
          paramlist ',' param

optionalParams:  // empty
              | '[' paramList ']'

name: WORD
param: WORD
data: WORD

これは、Spiritがおそらく非常にうまく機能するほど単純な文法です。スピリットは、大きな文法の場合、コンパイル時間が非常に長くなる傾向がありますが、この文法は十分に小さいため、コンパイル時間はかなり合理的です。

明らかな代替手段は、代わりに下降パーサーを作成することです(再帰下降パーサーのように、この場合、再帰は必要ありません)。この場合、基本的には、文法のレベルごとに関数を記述し、適切な入力を読み取らせて、読み取ったデータを保持する構造体(ベクトルなど)を返します。たとえば、これoptionalParamsはおそらく解析が最も困難です(単にオプションであるため)。

typedef std::string param;

std::vector<param> read_optional_params(std::istream &in) { 
    std::vector<param> ret;

    char ch = in.peek();
    if (ch == '[' ) {
        in >> ch;
        param temp;
        while (in >> temp && temp != "]") 
            ret.push_back(temp);
            if ((ch=in.peek) == ',')
                in >> ch;
    }
    return ret;    
}

トップレベルでは、次のようなものがあります。

function read_func(std::istream &in) { 
    std::string name = read_name(in);
    std::vector<param> optional_params = read_optional_params(in);
    std::vector<param> mandatory_params = read_mandatory_params(in);
    std::string data = read_data(in);

    if (in.fail()) {
        // malformed input
    }

    function func = function(name);
    for (int i=0; i<optional_params.size(); i++)
        func.addOptionalParam(optional_params[i]);
    for (int i=0; i<mandatory_params.size(); i++)
        func.addMandatoryParam(mandatoryParams[i]);
    func.setData(data);
    return func;
}
于 2010-02-03T16:37:36.350 に答える
5

Boost Spiritなどのパーサーを検討しましたか?

于 2010-02-03T16:14:02.713 に答える
-1

うわー、単にうわー...

これがファイルからの読み取り以外の方法で行われるとは知りませんでした。また、Boost に関するわずかな知識から直接出てきたので、boost::spirit のようなものがあることも知りませんでした。しかし、ドキュメンテーションを読み進めると、従うのが非常に難しいことがわかりました。ほとんどの場合、「real_p を使用する」ようなものであり、名前空間に関する情報がないため、特定のアイテムを見つける場所が非常にわかりにくくなります...しかし、何ができるかを見てください。本当に驚いています。

文法に関する情報を拡張したいと思います(ただし、コード用語でそれを正確に行う方法を解読することはできません):

name: 数字で始まらず、小文字、数字、'_' 以外の文字を含まない任意の文字列を指定
できます param: integer、double、または 'az' 文字のみを含む文字列を指定でき
ます data: 何でもかまいません中括弧 (可能であれば改行) の間にあるため、{{{{{} は '{{{{' を生成し、{}{}{}{} は失敗する必要があります (文法的に言えば)
';': として動作する必要がありますセパレーター、そして明確な終わりなので、必須です

他のものはコメントです。例では実装方法がわかりません。

助けてくれてありがとう、私はそれがどこに向かっているのか見てみたい.

于 2010-02-03T23:55:19.947 に答える