From 3d6962f92d6f00f88935abb4105e5c49630960a9 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 7 Jun 2017 02:33:02 -0700 Subject: [PATCH] start implementing generate.cpp --- src/generate_spirv_parser/CMakeLists.txt | 1 + src/generate_spirv_parser/generate.cpp | 106 +++++++++++++ src/generate_spirv_parser/generate.h | 150 ++++++++++++++++++ .../generate_spirv_parser.cpp | 25 ++- src/spirv/CMakeLists.txt | 13 +- 5 files changed, 275 insertions(+), 20 deletions(-) create mode 100644 src/generate_spirv_parser/generate.cpp create mode 100644 src/generate_spirv_parser/generate.h diff --git a/src/generate_spirv_parser/CMakeLists.txt b/src/generate_spirv_parser/CMakeLists.txt index f55fd72..6ac1316 100644 --- a/src/generate_spirv_parser/CMakeLists.txt +++ b/src/generate_spirv_parser/CMakeLists.txt @@ -20,6 +20,7 @@ # cmake_minimum_required(VERSION 3.1 FATAL_ERROR) set(sources ast.cpp + generate.cpp generate_spirv_parser.cpp parser.cpp) add_executable(generate_spirv_parser ${sources}) diff --git a/src/generate_spirv_parser/generate.cpp b/src/generate_spirv_parser/generate.cpp new file mode 100644 index 0000000..4b3f53d --- /dev/null +++ b/src/generate_spirv_parser/generate.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include "generate.h" + +namespace vulkan_cpu +{ +namespace generate_spirv_parser +{ +namespace generate +{ +Generator::Generator_state::Generator_state(const Generator *generator, + Generator_args &generator_args) + : generator_args(generator_args), + indent_level(0), + full_output_file_name(generator_args.output_directory + "/" + + generator->output_base_file_name), + os() +{ + os.exceptions(std::ios::badbit | std::ios::failbit); +} + +void Generator::Generator_state::open_output_file() +{ + os.open(full_output_file_name); +} + +constexpr Generator::Indent_t Generator::indent; + +void Generator::write_indent(Generator_state &state) +{ + static constexpr auto indent_string = " "; + for(std::size_t i = state.indent_level; i > 0; i--) + state << indent_string; +} + +void Generator::write_automatically_generated_file_warning(Generator_state &state) +{ + state << "/* This file is automatically generated by " + "generate_spirv_parser. DO NOT MODIFY. */\n"; +} + +void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright ©right) +{ + state << "/*\n"; + for(auto &line : copyright.lines) + { + if(line.empty()) + { + state << " *\n"; + continue; + } + state << " * "; + bool was_last_star = false; + for(char ch : line) + { + if(was_last_star && ch == '/') + state << ' '; + was_last_star = (ch == '*'); + state << ch; + } + state << "\n"; + } + state << " */\n"; +} + +struct Spirv_header_generator final : public Generator +{ + Spirv_header_generator() : Generator("spirv.h") + { + } + virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override + { + Generator_state state(this, generator_args); + state.open_output_file(); + write_file_comments(state, top_level.copyright); +#warning finish + } +}; + +std::unique_ptr Generators::make_spirv_header_generator() +{ + return std::unique_ptr(new Spirv_header_generator); +} +} +} +} \ No newline at end of file diff --git a/src/generate_spirv_parser/generate.h b/src/generate_spirv_parser/generate.h new file mode 100644 index 0000000..1663bd2 --- /dev/null +++ b/src/generate_spirv_parser/generate.h @@ -0,0 +1,150 @@ +/* + * Copyright 2017 Jacob Lifshay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef GENERATE_SPIRV_PARSER_GENERATE_H_ +#define GENERATE_SPIRV_PARSER_GENERATE_H_ + +#include "ast.h" +#include +#include +#include +#include +#include + +namespace vulkan_cpu +{ +namespace generate_spirv_parser +{ +namespace generate +{ +class Generator +{ +public: + struct Generator_args + { + std::string output_directory; + explicit Generator_args(std::string output_directory) noexcept + : output_directory(std::move(output_directory)) + { + } + Generator_args(Generator_args &&) = default; + Generator_args &operator=(Generator_args &&) = default; + Generator_args(const Generator_args &) = delete; + Generator_args &operator=(const Generator_args &) = delete; + }; + +protected: + struct Generator_state + { + Generator_args &generator_args; + std::size_t indent_level; + std::string full_output_file_name; + std::ofstream os; + explicit Generator_state(const Generator *generator, Generator_args &generator_args); + void open_output_file(); + template ())> + Generator_state &operator<<(T &&v) + { + os << std::forward(v); + return *this; + } + }; + class Push_indent final + { + Push_indent(const Push_indent &) = delete; + Push_indent &operator=(const Push_indent &) = delete; + + private: + Generator_state *state; + + public: + explicit Push_indent(Generator_state &state) noexcept : state(&state) + { + state.indent_level++; + } + Push_indent(Push_indent &&rt) noexcept : state(rt.state) + { + rt.state = nullptr; + } + void finish() noexcept + { + assert(state); + state->indent_level--; + state = nullptr; + } + ~Push_indent() + { + if(state) + state->indent_level--; + } + }; + struct Indent_t + { + explicit Indent_t() = default; + friend Generator_state &operator<<(Generator_state &state, Indent_t) + { + write_indent(state); + return state; + } + }; + static constexpr Indent_t indent{}; + +protected: + const char *const output_base_file_name; + +protected: + static void write_indent(Generator_state &state); + static void write_automatically_generated_file_warning(Generator_state &state); + static void write_copyright_comment(Generator_state &state, const ast::Copyright ©right); + static void write_file_comments(Generator_state &state, const ast::Copyright ©right) + { + write_automatically_generated_file_warning(state); + write_copyright_comment(state, copyright); + } + +public: + explicit Generator(const char *output_base_file_name) noexcept + : output_base_file_name(output_base_file_name) + { + } + virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const = 0; + void run(Generator_args &&generator_args, const ast::Top_level &top_level) const + { + run(generator_args, top_level); + } + +public: + virtual ~Generator() = default; +}; + +struct Spirv_header_generator; + +struct Generators +{ + static std::unique_ptr make_spirv_header_generator(); +}; +} +} +} + +#endif /* GENERATE_SPIRV_PARSER_GENERATE_H_ */ \ No newline at end of file diff --git a/src/generate_spirv_parser/generate_spirv_parser.cpp b/src/generate_spirv_parser/generate_spirv_parser.cpp index 01d014a..07d371e 100644 --- a/src/generate_spirv_parser/generate_spirv_parser.cpp +++ b/src/generate_spirv_parser/generate_spirv_parser.cpp @@ -25,7 +25,7 @@ #include "../json/parser.h" #include "parser.h" #include "../util/optional.h" -#include +#include "generate.h" namespace vulkan_cpu { @@ -34,11 +34,15 @@ namespace generate_spirv_parser int generate_spirv_parser_main(int argc, char **argv) { std::string file_name; + std::string output_directory; if(argc >= 2) file_name = argv[1]; - if(argc != 2 || (file_name.size() > 1 && file_name[0] == '-')) + if(argc >= 3) + output_directory = argv[2]; + if(argc != 3 || (file_name.size() > 1 && file_name[0] == '-') + || (output_directory.size() > 1 && output_directory[0] == '-')) { - std::cerr << "usage: " << argv[0] << " " << std::endl; + std::cerr << "usage: " << argv[0] << " " << std::endl; return 1; } try @@ -49,18 +53,11 @@ int generate_spirv_parser_main(int argc, char **argv) { auto json_in = json::parse(&source); auto ast = parser::parse(json_in.duplicate()); - std::ofstream os("out.json"); - auto json_out = ast.to_json(); - json::write(os, json_out, json::Write_options::pretty()); - os.close(); - auto difference = json::Difference::find_difference(json_in, json_out); - if(difference) + for(auto &generator : { + generate::Generators::make_spirv_header_generator(), + }) { - std::cerr << "differs at " << difference->append_to_string("root") << std::endl; - } - else - { - std::cerr << "no difference" << std::endl; + generator->run(generate::Generator::Generator_args(output_directory), ast); } #warning finish std::cerr << "generate_spirv_parser is not finished being implemented" << std::endl; diff --git a/src/spirv/CMakeLists.txt b/src/spirv/CMakeLists.txt index 95efade..4ea7ac2 100644 --- a/src/spirv/CMakeLists.txt +++ b/src/spirv/CMakeLists.txt @@ -25,20 +25,21 @@ set(do_generate_spirv_parser YES) set(sources spirv.cpp) if(${do_generate_spirv_parser}) - set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/src) + set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/generated) set(spirv_parser_generated_dir ${spirv_parser_generated_include_dir}/spirv) - set(spirv_parser_source ${spirv_parser_generated_dir}/parser.cpp) - set(spirv_parser_header ${spirv_parser_generated_dir}/parser.h) + set(spirv_parser_sources ${spirv_parser_generated_dir}/parser.cpp) + set(spirv_parser_headers ${spirv_parser_generated_dir}/parser.h ${spirv_parser_generated_dir}/spirv.h) set(spirv_core_grammar_json ${CMAKE_CURRENT_SOURCE_DIR}/../khronos-spirv/spirv.core.grammar.json) + message(STATUS "spirv_parser_generated_dir: " ${spirv_parser_generated_dir}) - add_custom_command(OUTPUT ${spirv_parser_source} ${spirv_parser_header} + add_custom_command(OUTPUT ${spirv_parser_sources} ${spirv_parser_headers} COMMAND ${CMAKE_COMMAND} -E make_directory ${spirv_parser_generated_dir} - COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_dir} $ ${spirv_core_grammar_json} + COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_dir} $ ${spirv_core_grammar_json} ${spirv_parser_generated_dir} MAIN_DEPENDENCY ${spirv_core_grammar_json} DEPENDS $ VERBATIM COMMENT "Generating SPIR-V Parser") - set(sources ${sources} ${spirv_parser_source}) + set(sources ${sources} ${spirv_parser_sources}) endif() add_library(spirv STATIC ${sources}) target_link_libraries(spirv util) -- 2.30.2