3

非常に C に似た言語である OpenGL シェーディング言語 (GLSL) コードでカスタム タグを解析したいと考えています。一般的な使用例は次のようになります。

#version 150

@bind ProjectionMatrix
uniform mat4 projMatrix;
@bind ViewMatrix
uniform mat4 viewMatrix;

in vec4 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = projMatrix * viewMatrix * position;
}

タグで変数に「注釈」を付け@bindて、実際のアプリケーションの変数に接続できるようにしたいです(つまり、アプリからglslに値を渡すことができます)。したがって、glsl コードを解析し、@bindタグを見つけるたびに、ProjectionMatrix(またはViewMatrix) を c++ から glsl に渡す変数として解析し、projMatrix(またはviewMatrix) を c++ から送信された値を格納する変数として解析します。 .

私が疑問に思っているのは、これにはブーストウェーブまたはスピリットを使用する方が良いでしょうか? これらは、これを解決するために私が検討している 2 つのライブラリです。

すべてのトークンを反復処理するという点で、boost wave lexer が機能しています。そのため、返されたトークンを解析してパターンを探すコードを作成する必要があります。

これを精神でどのように行うか正確にはわかりませんが、より堅牢なレクサー/パーサーのようです。

誰にも提案はありますか?

4

1 に答える 1

3

glslが何であるかを私たちがどのように知っているかはまだわかりません。したがって、実際の入力形式については、大まかな推測しかできません。

私がこれを私が適切だと思う最も簡単な方法で解釈するとしましょう(ばかばかしいほど役に立たないことはありません):

annot       = "@bind" >> ident >> eol;
declaration = 
   omit [ +(ident >> !char_(';')) ] // omit the type, TODO
    >> ident >> ';' >> eol;

これで、必要なのは、注釈を含む行が見つかるまで完全な行を無視する簡単な方法です。

ignore = !annot >> *(char_ - eol) >> eol;

@bind宣言が続かない行を無視したい場合は、!combiの代わりに使用することをお勧めします!annot

これはあなたにとって単なるスターターです。また、無視できる線のこのすべての「暗黙の」定義が多くのバックトラックを引き起こす可能性があるというわけではありません。したがって、一流のパフォーマンスを期待しないでください。

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <map>

namespace qi = boost::spirit::qi;

typedef std::map<std::string, std::string> Map;

template <typename It>
  struct grammar : qi::grammar<It, Map(), qi::blank_type>
  {
    grammar() : grammar::base_type(start)
    {
        using namespace qi;
        ident = lexeme [ alpha >> *alnum ];
        annot = "@bind" >> ident >> eol;
        declaration = 
            omit [ +(ident >> !char_(';')) ] // omit the type, TODO
            >> ident >> ';' >> eol;

        ignore = !annot >> *(char_ - eol) >> eol;

        combi = annot >> declaration;
        start = *ignore >> combi % *ignore;

        BOOST_SPIRIT_DEBUG_NODE(start);
        BOOST_SPIRIT_DEBUG_NODE(combi);
        BOOST_SPIRIT_DEBUG_NODE(ignore);
        BOOST_SPIRIT_DEBUG_NODE(declaration);
        BOOST_SPIRIT_DEBUG_NODE(annot);
        BOOST_SPIRIT_DEBUG_NODE(ident);
    }
  private:
    qi::rule<It, qi::blank_type> ignore;
    qi::rule<It, std::string(), qi::blank_type> ident, declaration, annot;
    qi::rule<It, std::pair<std::string, std::string>(), qi::blank_type> combi;
    qi::rule<It, Map(), qi::blank_type> start;
  };

template <typename It>
void test(It f, It l)
{
    grammar<It> p;

    Map mappings;
    bool ok = qi::phrase_parse(f, l, p, qi::blank, mappings);

    if (ok)
    {
        for (auto it = mappings.begin(); it!=mappings.end(); ++it)
            std::cout << "'" << it->second << "' annotated with name '" << it->first << "'\n";
    }

    if (f!=l)
        std::cerr << "warning: remaing unparsed: '" << std::string(f,l) << "'\n";
}

int main()
{
    const std::string input(
        "#include <reality>\n"
        "@bind VarName\n"
        "uniform int myVariable;\n"
        "// other stuff\n"
        "@bind Var2Name\n"
        "uniform int myVariable2;\n");

    test(input.begin(), input.end());
}

これは印刷されます:

'myVariable2' annotated with name 'Var2Name'
'myVariable' annotated with name 'VarName'

liveworkspace.orgでライブのverbose(DEBUG)出力を参照してください

于 2013-02-18T17:40:37.520 に答える