Amplifying wave or spirit for glsl analyzer
I want to parse a custom tag in OpenGL Shading Language (GLSL) code, which is a very C-like language. A general usage example would look like this:
#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;
}
I want to do this to "annotate" the variables with a tag @bind
so that I can hook them up to variables in my actual application (ie, I can pass values from my application to glsl). So I would parse the glsl code, and whenever I find a tag @bind
, I then parse ProjectionMatrix
(or ViewMatrix
) as a variable to go from C ++ to glsl, and then parse projMatrix
(or ViewMatrix
) as a variable that should store the value sent from C ++.
What is interesting to me - would it be better to use a wave or a spirit for this purpose? these are the two libraries i am looking for to solve this problem.
I have a wave activated lexer in which it iterates over all tokens. so I would have to write code to parse the returned tokens and find patterns.
I'm not sure exactly how I would do it with spirit, but it seems to be a more reliable lexer / parser.
Anyone have any suggestions?
source to share
I'm still not sure how you expect us to know what glsl is. Thus, I can really only talk broadly about the actual input format.
Let's say I interpret this in the simplest way I see fit (without being ridiculously useless):
annot = "@bind" >> ident >> eol;
declaration =
omit [ +(ident >> !char_(';')) ] // omit the type, TODO
>> ident >> ';' >> eol;
Now all we need is an easy way to ignore full lines until we find one that contains the annotation:
ignore = !annot >> *(char_ - eol) >> eol;
If you want to ignore lines @bind
that are not followed by a declaration, you can use !combi
instead !annot
.
This is just a starter for you. Also, not all of this "implicit" definition of ignorant strings can cause a lot of indentation. So don't expect high performance.
#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());
}
This will print:
'myVariable2' annotated with name 'Var2Name'
'myVariable' annotated with name 'VarName'
See verbose (DEBUG) output live on liveworkspace.org
source to share