【问题标题】:boost wave or spirit for glsl parser增强 glsl 解析器的波浪或精神
【发布时间】:2013-02-17 20:34:53
【问题描述】:

我想在 OpenGL 着色语言 (GLSL) 代码中解析自定义标签,这是一种非常类似于 C 的语言。一般用例如下所示:

#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++ 发送的值的变量。

我想知道的是 - 使用增强波或精神会更好吗?这些是我正在寻找解决这个问题的两个库。

我已经让 boost wave lexer 工作了,因为它会遍历所有标记。所以我必须编写代码来解析返回的令牌并寻找模式。

我不确定我将如何使用 Spirit 来做到这一点,但它似乎是一个更强大的词法分析器/解析器。

大家有什么建议吗?

【问题讨论】:

  • Boost.Wave 是一个 C++ 预处理器。 GLSL 不是 C++。虽然它确实与 C++ 有一些象征性的相似之处,但它很有可能会在它到达 GLSL 的第一行时窒息。由于 GLSL 的第一行是 #version,这不是合法的 C++ 预处理器指令。你的 GLSL 的第一行 #version,对吧?
  • 是的 - 但这不是问题。我只是覆盖 boost.wave 的“未知指令”方法,并接受 glsl 指令。但我并不担心指令方面的预处理,我更关心解析 glsl 代码并挑选某些模式的最佳方法。
  • Jarret,你为什么不告诉我们你想要建立的具体任务是什么。我可以“猜测”你一个我认为适合你写的两行示例的语法,但我不知道你想从解析中得到什么
  • 嘿@sehe,抱歉我不够清楚。我已尝试编辑我的帖子以使其更清晰。

标签: c++ boost glsl boost-spirit


【解决方案1】:

我仍然不确定您希望我们如何了解 glsl 的全部内容。所以我真的只能对实际输入格式做一个广泛的猜测

假设我以我认为合适的最简单的方式解释这一点(而不是荒谬无用):

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

现在,我们需要一种简单的方法来忽略整行,直到找到包含注释的行:

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

如果您想忽略后面没有声明的@bind 行,您可能需要使用!combi 而不是!annot

这对你来说只是一个开始。此外,并不是所有这些 ignorable 行的“隐式”定义都可能导致大量回溯。所以不要指望一流的性能。

#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'

查看详细 (DEBUG) 输出liveworkspace.org

【讨论】:

  • 嘿@sehe,对不起,我不知道你不知道 glsl 是什么。我试图让这个问题更清楚一点。感谢您的回答,我认为它会工作!
猜你喜欢
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多