-
I don't know if my title is correct, actually it may be a little confusing. I am trying to build a simple shader format:
it may even evolve into something more like this in a future:
but let's keep it simple for now.
where: The parser needs to detect where the body begins and ends. I've looked through the examples (turing and XML) #include <iostream>
#include <string>
#include <vector>
#include <lexy/action/parse.hpp>
#include <lexy/callback.hpp>
#include <lexy/dsl.hpp>
#include <lexy/input/file.hpp>
#include <lexy_ext/report_error.hpp>
namespace {
namespace ast {
struct Shader
{
std::string name;
std::string body;
};
}
namespace grammar {
namespace dsl = lexy::dsl;
constexpr auto ws = dsl::whitespace(dsl::ascii::space / dsl::ascii::newline);
constexpr auto identifier = dsl::identifier(dsl::ascii::alpha);
constexpr auto kw_shader = LEXY_KEYWORD("Shader", identifier);
struct string_literal
{
static constexpr auto rule = dsl::quoted(dsl::ascii::print);
static constexpr auto value = lexy::as_string<std::string>;
};
struct body
{
static constexpr auto name = "shader-body";
static constexpr auto rule = [] {
// Tokens
auto open = dsl::lit_c<'{'>;
auto close = dsl::lit_c<'}'>;
auto any = dsl::ascii::character; // any single byte
// Counter to track nesting level (0 == inside the outer braces)
struct brace_counter_id {};
auto level = dsl::context_counter<brace_counter_id>;
// Stop when the next char is '}' *and* we are back to level 0.
auto stop = level.is_zero() >> dsl::peek(close) >> dsl::break_;
// Consume a character, adjusting the level if it is a brace.
auto chunk = open >> level.inc() | close >> level.dec() | any;
// Capture/skip everything until `stop` fires.
return level.create() + dsl::loop(stop | chunk);
}();
static constexpr auto value = lexy::construct<std::string>;
};
struct shader
{
static constexpr auto name = "shader";
static constexpr auto whitespace = dsl::ascii::space | dsl::ascii::newline;
static constexpr auto rule = kw_shader + dsl::p<string_literal> + dsl::p<body>;
static constexpr auto value = lexy::construct<ast::Shader>;
};
}
}
#ifndef LEXY_TEST
int main(int argc, char** argv)
{
if (argc < 2)
{
std::fprintf(stderr, "usage: %s <filename>", argv[0]);
return 1;
}
auto file = lexy::read_file<lexy::ascii_encoding>(argv[1]);
if (!file)
{
std::fprintf(stderr, "file '%s' not found", argv[1]);
return 1;
}
auto shader
= lexy::parse<grammar::shader>(file.buffer(), lexy_ext::report_error.path(argv[1]));
if (!shader)
return 2;
std::cout << shader.value().name << "\n" << shader.value().body << '\n';
}
#endif but it does not parse well:
The problem is clearly in the lexy/dsl/capture.hpp(129): error C2338: static_assert failed: 'lexy::is_token_rule<Token>'
lexy/dsl/capture.hpp(129): note: the template instantiation context (the oldest one first) is I read the Walkthrough you created, but I don't know, I don't get it. Could you help me, please? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
I ended up wraping the code into BEGIN_HLSL and END_HLSL keywords |
Beta Was this translation helpful? Give feedback.
-
Sorry for the delay. The problem is that you can't "AND" branch conditions. auto stop = level.is_zero() >> dsl::peek(close) >> dsl::break_; This is equivalent to auto stop = level.is_zero() >> dsl::peek(close) + dsl::break_; because the second // Stop when the next char is '}' *and* we are back to level 0.
auto stop = dsl::if_(level.is_zero() >> dsl::break_);
// Consume a character, adjusting the level if it is a brace.
auto chunk = open >> level.inc() | close >> level.dec() + stop | dsl::else_ >> any;
// Capture/skip everything until `stop` fires.
return level.create() + dsl::loop(chunk); We can parse the closing However, now if you want to capture things, they will include the surrounding // Capture/skip everything until `stop` fires.
return dsl::capture(dsl::token(level.create() + dsl::loop(chunk))); If you try to surround it with an extra set of return dsl::curly_bracketed(dsl::capture(dsl::token(level.create() + dsl::loop(chunk)))); It will stop the first time the counter reaches zero. The way around that, is to parse a list of captures: return dsl::curly_bracketed.list(dsl::capture(dsl::token(level.create() + dsl::loop(chunk)))); Full example: https://lexy.foonathan.net/playground/?id=P17YGMzK6&mode=tree |
Beta Was this translation helpful? Give feedback.
Sorry for the delay.
The problem is that you can't "AND" branch conditions.
This is equivalent to
because the second
>>
isn't used in a branching context. Therefore, you expect}
immediately after the level is zero (and it is initially zero, so that fails). I could special case the context counter somehow, but an easier way is to restructure the code: