diff --git a/radiantcore/shaders/ShaderFileLoader.h b/radiantcore/shaders/ShaderFileLoader.h index 546568851a..4c983ec461 100644 --- a/radiantcore/shaders/ShaderFileLoader.h +++ b/radiantcore/shaders/ShaderFileLoader.h @@ -11,7 +11,13 @@ #include "parser/DefBlockTokeniser.h" #include "string/replace.h" +#include "string/trim.h" #include "string/predicate.h" +#include "os/path.h" + +#include "parser/Grammar.h" + +#include namespace shaders { @@ -27,9 +33,61 @@ template class ShaderFileLoader // List of shader definition files to parse std::vector _files; + class BlockParseState + { + public: + BlockParseState(ShaderLibrary_T& library_, const vfs::FileInfo& fileInfo_) : + fileInfo(fileInfo_), + library(library_) + {} + + const vfs::FileInfo& fileInfo; + ShaderLibrary_T& library; + + std::string name; + std::string contents; + }; + + template + struct ParseAction : tao::pegtl::nothing {}; + + template<> + struct ParseAction + { + template + static void apply(const ParseInput& in, BlockParseState& state) + { + state.name = in.string(); + state.contents.clear(); + } + }; + + template<> + struct ParseAction + { + template + static void apply(const ParseInput& in, BlockParseState& state) + { + state.contents = string::trim_right_copy(string::trim_left_copy(in.string(), "{"), "}"); + + string::replace_all(state.name, "\\", "/"); // use forward slashes + + auto shaderTemplate = std::make_shared(state.name, state.contents); + + // Construct the ShaderDefinition wrapper class + ShaderDefinition def(shaderTemplate, state.fileInfo); + + // Insert into the definitions map, if not already present + if (!state.library.addDefinition(state.name, def)) + { + rError() << "[shaders] " << state.fileInfo.name << ": shader " << state.name << " already defined." << std::endl; + } + } + }; + private: - bool parseTable(const parser::BlockTokeniser::Block& block, const vfs::FileInfo& fileInfo) + bool parseTable(const ::parser::BlockTokeniser::Block& block, const vfs::FileInfo& fileInfo) { if (block.name.length() <= 5 || !string::starts_with(block.name, "table")) { @@ -61,14 +119,31 @@ template class ShaderFileLoader // Parse a shader file with the given contents and filename void parseShaderFile(std::istream& inStr, const vfs::FileInfo& fileInfo) { +#if 1 + using namespace tao::pegtl; + + // Wrap the input stream for the pegtl parser + istream_input input(inStr, 1*1024*1024, os::getFilename(fileInfo.name)); + + BlockParseState state(_library, fileInfo); + + try + { + auto parseTree = parse_tree::parse(input, state); + } + catch (const parser::parse_error& ex) + { + rError() << "Error parsing " << fileInfo.name << ": " << ex.what() << std::endl; + } +#else // Parse the file with a blocktokeniser, the actual block contents // will be parsed separately. - parser::BasicDefBlockTokeniser tokeniser(inStr); + ::parser::BasicDefBlockTokeniser tokeniser(inStr); while (tokeniser.hasMoreBlocks()) { // Get the next block - parser::BlockTokeniser::Block block = tokeniser.nextBlock(); + ::parser::BlockTokeniser::Block block = tokeniser.nextBlock(); // Try to parse tables if (parseTable(block, fileInfo)) @@ -99,6 +174,7 @@ template class ShaderFileLoader rError() << "[shaders] " << fileInfo.name << ": shader " << block.name << " already defined." << std::endl; } } +#endif } public: diff --git a/radiantcore/shaders/parser/Grammar.h b/radiantcore/shaders/parser/Grammar.h new file mode 100644 index 0000000000..b0dd0a7ccd --- /dev/null +++ b/radiantcore/shaders/parser/Grammar.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +namespace shaders +{ + +namespace parser +{ + +using namespace tao; +using namespace tao::pegtl; + +struct Nothing : space {}; + +struct TableKeywordPlusSpace : seq, space> {}; + +struct DeclName : plus>>> {}; + +struct LineComment : until {}; +struct BlockComment : until> {}; + +struct Comment : if_must, LineComment> {}; +struct CommentBlock : if_must, BlockComment> {}; + +struct BlockStart : one<'{'> {}; +struct BlockEnd : one<'}'> {}; + +struct BlockContents : not_one<'{', '}'> {}; + +struct BlockDefinition : seq>, BlockEnd> {}; + +struct MaterialBlockDefinition : seq>, BlockEnd> {}; + +struct MaterialDeclaration : if_must>, MaterialBlockDefinition> {}; + +struct TableDeclaration : if_must>, BlockDefinition> {}; + +// Any possible element of a material file (Tables, Materials, Comments and plain whitespace) +struct Anything : sor {}; + +// A Material has no required elements, it can include anything (including nothing) +struct MaterialFile : until {}; + +template struct MaterialFileSelector : std::true_type {}; + +} + +} diff --git a/tools/msvc/DarkRadiantCore.vcxproj b/tools/msvc/DarkRadiantCore.vcxproj index c3a0179bdb..1c273658be 100644 --- a/tools/msvc/DarkRadiantCore.vcxproj +++ b/tools/msvc/DarkRadiantCore.vcxproj @@ -1011,6 +1011,7 @@ + @@ -1090,6 +1091,7 @@ + @@ -1101,6 +1103,7 @@ + @@ -1112,6 +1115,7 @@ + @@ -1123,6 +1127,7 @@ + diff --git a/tools/msvc/DarkRadiantCore.vcxproj.filters b/tools/msvc/DarkRadiantCore.vcxproj.filters index 7c41e18189..9e86326993 100644 --- a/tools/msvc/DarkRadiantCore.vcxproj.filters +++ b/tools/msvc/DarkRadiantCore.vcxproj.filters @@ -197,6 +197,9 @@ {b7afddd6-8c82-4975-a947-00999bd70fec} + + {f8abb79b-fbbd-405b-86a5-2cd729c021bd} + @@ -2091,5 +2094,8 @@ src\shaders + + src\shaders\parser + \ No newline at end of file diff --git a/tools/msvc/properties/pegtl.props b/tools/msvc/properties/pegtl.props new file mode 100644 index 0000000000..2bf3d69c3f --- /dev/null +++ b/tools/msvc/properties/pegtl.props @@ -0,0 +1,12 @@ + + + + + + + + $(DarkRadiantRoot)\w32deps\pegtl\include;%(AdditionalIncludeDirectories) + + + + \ No newline at end of file