diff --git a/CMakeLists.txt b/CMakeLists.txt index 365d880..c54fa6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ message(STATUS "Configuring Dulcificum version: ${DULCIFICUM_VERSION}") find_package(nlohmann_json REQUIRED) find_package(spdlog REQUIRED) find_package(range-v3 REQUIRED) +find_package(Boost REQUIRED) # --- Setup the shared C++ mgjtp library --- set(DULCIFICUM_SRC @@ -35,6 +36,7 @@ target_link_libraries(dulcificum PUBLIC nlohmann_json::nlohmann_json PRIVATE + boost::boost range-v3::range-v3 spdlog::spdlog) diff --git a/apps/translator_main.cpp b/apps/translator_main.cpp index d6177e6..e8991ee 100644 --- a/apps/translator_main.cpp +++ b/apps/translator_main.cpp @@ -1,21 +1,26 @@ #include "cmdline.h" +#include #include #include +#include +#include +#include #include + int main(int argc, const char** argv) { constexpr bool show_help = true; const std::map args = docopt::docopt(fmt::format(apps::cmdline::USAGE, apps::cmdline::NAME), { argv + 1, argv + argc }, show_help, apps::cmdline::VERSION_ID); - if (args.contains("--quiet")) + if (args.at("--quiet").asBool()) { spdlog::set_level(spdlog::level::err); } - else if (args.contains("--verbose")) + else if (args.at("--verbose").asBool()) { spdlog::set_level(spdlog::level::debug); } @@ -24,4 +29,10 @@ int main(int argc, const char** argv) spdlog::set_level(spdlog::level::info); } spdlog::info("Tasting the menu"); + + auto input{ dulcificum::utils::readFile(args.at("INPUT").asString()).value() }; + std::vector parsedCommand; + bool r = boost::spirit::x3::phrase_parse(input.begin(), input.end(), *dulcificum::gcode::ast::all_rule, boost::spirit::x3::space, parsedCommand); + + return 0; } \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index 0e1b7cf..d959771 100644 --- a/conanfile.py +++ b/conanfile.py @@ -70,6 +70,7 @@ def config_options(self): del self.options.fPIC def configure(self): + self.options["boost"].header_only = True if self.options.shared: self.options.rm_safe("fPIC") @@ -81,6 +82,8 @@ def requirements(self): self.requires("nlohmann_json/3.11.2", transitive_headers = True) self.requires("range-v3/0.12.0") self.requires("spdlog/1.10.0") + self.requires("boost/1.82.0") + self.requires("zlib/1.2.13") if self.options.with_apps: self.requires("docopt.cpp/0.6.3") if self.options.with_python_bindings: diff --git a/include/dulcificum/gcode/ast/ast.h b/include/dulcificum/gcode/ast/ast.h new file mode 100644 index 0000000..1c0efd6 --- /dev/null +++ b/include/dulcificum/gcode/ast/ast.h @@ -0,0 +1,12 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_AST_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_AST_H + +#include "dulcificum/gcode/ast/words/words.h" + +namespace dulcificum::gcode::ast +{ +auto const all_rule = boost::spirit::x3::rule{} = g0_rule | g1_rule; // NOLINT + +} + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_AST_H diff --git a/include/dulcificum/gcode/ast/rules.h b/include/dulcificum/gcode/ast/rules.h new file mode 100644 index 0000000..44db634 --- /dev/null +++ b/include/dulcificum/gcode/ast/rules.h @@ -0,0 +1,28 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_RULES_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_RULES_H + +#include + +namespace dulcificum::gcode::ast +{ + +// TODO: Figure out if the I should maybe use this pattern +//struct rules { +// const boost::spirit::x3::rule x_rule; +// +// rules() : x_rule{ "x" } +// { +// x_rule = 'X' >> boost::spirit::x3::double_; +// } +//}; +// NOLINTBEGIN +auto const x_rule = boost::spirit::x3::rule{ "x" } = 'X' >> boost::spirit::x3::double_; +auto const y_rule = boost::spirit::x3::rule{ "y" } = 'Y' >> boost::spirit::x3::double_; +auto const z_rule = boost::spirit::x3::rule{ "z" } = 'Z' >> boost::spirit::x3::double_; +auto const e_rule = boost::spirit::x3::rule{ "e" } = 'E' >> boost::spirit::x3::double_; +auto const f_rule = boost::spirit::x3::rule{ "f" } = 'F' >> boost::spirit::x3::double_; +// NOLINTEND + +} // namespace dulcificum::gcode::ast + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_RULES_H diff --git a/include/dulcificum/gcode/ast/words/G0.h b/include/dulcificum/gcode/ast/words/G0.h new file mode 100644 index 0000000..542aaf9 --- /dev/null +++ b/include/dulcificum/gcode/ast/words/G0.h @@ -0,0 +1,39 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G0_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G0_H +#include "dulcificum/gcode/ast/rules.h" +#include "dulcificum/gcode/ast/words/command.h" +#include "dulcificum/gcode/ast/words/optional_values.h" +namespace dulcificum::gcode::ast +{ +struct G0 : public Command<"G0"> +{ + std::optional X{}; ///< X coordinate + std::optional Y{}; ///< Y coordinate + std::optional Z{}; ///< Z coordinate + std::optional F{}; ///< Feedrate +}; + + +// Construct the parser rules + +details::OptionalValues G0_VALUES; + +auto G0_ASSIGN_OPTIONAL_VALUES = [](auto& ctx) +{ + _val(ctx).X = G0_VALUES.val_map["x"]; + _val(ctx).Y = G0_VALUES.val_map["y"]; + _val(ctx).Z = G0_VALUES.val_map["z"]; + _val(ctx).F = G0_VALUES.val_map["f"]; +}; + +// clang-format off +auto const g0_rule = boost::spirit::x3::rule{ "g0" } = G0::word.data() + >> *(x_rule[G0_VALUES.assign("x", G0_VALUES.val_map)] + | y_rule[G0_VALUES.assign("y", G0_VALUES.val_map)] + | z_rule[G0_VALUES.assign("z", G0_VALUES.val_map)] + | f_rule[G0_VALUES.assign("f", G0_VALUES.val_map)]) + >> boost::spirit::x3::eps[G0_ASSIGN_OPTIONAL_VALUES]; +// clang-format on + +} // namespace dulcificum::gcode::ast +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G0_H \ No newline at end of file diff --git a/include/dulcificum/gcode/ast/words/G1.h b/include/dulcificum/gcode/ast/words/G1.h new file mode 100644 index 0000000..9b9dcf7 --- /dev/null +++ b/include/dulcificum/gcode/ast/words/G1.h @@ -0,0 +1,44 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G1_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G1_H + +#include "dulcificum/gcode/ast/rules.h" +#include "dulcificum/gcode/ast/words/command.h" + +namespace dulcificum::gcode::ast +{ +struct G1 : public Command<"G1"> +{ + std::optional X{}; ///< X coordinate + std::optional Y{}; ///< Y coordinate + std::optional Z{}; ///< Z coordinate + std::optional E{}; ///< E position + std::optional F{}; ///< Feedrate +}; + + +// Construct the parser rules + +details::OptionalValues G1_VALUES; + +auto G1_ASSIGN_OPTIONAL_VALUES = [](auto& ctx) +{ + _val(ctx).X = G0_VALUES.val_map["x"]; + _val(ctx).Y = G0_VALUES.val_map["y"]; + _val(ctx).Z = G0_VALUES.val_map["z"]; + _val(ctx).E = G0_VALUES.val_map["e"]; + _val(ctx).F = G0_VALUES.val_map["f"]; +}; + +// clang-format off +auto const g1_rule = boost::spirit::x3::rule{ "g1" } = G1::word.data() + >> *(x_rule[G1_VALUES.assign("x", G1_VALUES.val_map)] + | y_rule[G1_VALUES.assign("y", G1_VALUES.val_map)] + | z_rule[G1_VALUES.assign("z", G1_VALUES.val_map)] + | e_rule[G1_VALUES.assign("e", G1_VALUES.val_map)] + | f_rule[G1_VALUES.assign("f", G1_VALUES.val_map)]) + >> boost::spirit::x3::eps[G1_ASSIGN_OPTIONAL_VALUES]; +// clang-format on + +} // namespace dulcificum::gcode::ast + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_G1_H diff --git a/include/dulcificum/gcode/ast/words/command.h b/include/dulcificum/gcode/ast/words/command.h new file mode 100644 index 0000000..6e3fc69 --- /dev/null +++ b/include/dulcificum/gcode/ast/words/command.h @@ -0,0 +1,21 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMAND_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMAND_H + +#include "dulcificum/gcode/ast/words/comment.h" +#include "dulcificum/gcode/ast/words/entry.h" +#include "dulcificum/utils/char_range_literal.h" + +#include + +namespace dulcificum::gcode::ast +{ +template +struct Command : public Entry +{ + static constexpr std::string_view word{ Word.value }; ///< The specific word + std::optional comment; ///< Optional comment related to the command +}; + +} // namespace dulcificum::gcode::details + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMAND_H diff --git a/include/dulcificum/gcode/ast/words/comment.h b/include/dulcificum/gcode/ast/words/comment.h new file mode 100644 index 0000000..21955dd --- /dev/null +++ b/include/dulcificum/gcode/ast/words/comment.h @@ -0,0 +1,15 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMENT_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMENT_H + +#include "dulcificum/gcode/ast/words/entry.h" + +namespace dulcificum::gcode::ast +{ +struct Comment : public Entry +{ + static constexpr std::string_view word{ ";" }; + std::string msg; ///< Message contained in the comment +}; +} // namespace dulcificum::gcode::details + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_COMMENT_H diff --git a/include/dulcificum/gcode/ast/words/entry.h b/include/dulcificum/gcode/ast/words/entry.h new file mode 100644 index 0000000..65e7070 --- /dev/null +++ b/include/dulcificum/gcode/ast/words/entry.h @@ -0,0 +1,17 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_ENTRY_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_ENTRY_H + +#include + +namespace dulcificum::gcode::ast +{ +struct Entry : public boost::spirit::x3::position_tagged +{ + std::size_t index{ 0 }; ///< Represents the index in the source + std::string raw_value; ///< Raw value as represented in the source +}; + +} // namespace dulcificum::gcode::details + + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_ENTRY_H diff --git a/include/dulcificum/gcode/ast/words/optional_values.h b/include/dulcificum/gcode/ast/words/optional_values.h new file mode 100644 index 0000000..e1b63ca --- /dev/null +++ b/include/dulcificum/gcode/ast/words/optional_values.h @@ -0,0 +1,29 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_WORDS_OPTIONAL_VALUES_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_WORDS_OPTIONAL_VALUES_H + +#include +#include + +namespace dulcificum::gcode::ast::details +{ + +struct OptionalValues +{ + std::map val_map; + struct AssignCtxValToVar + { + template + auto operator()(const std::string& key, T& map) const + { + return [&, key](auto& ctx) + { + map[key] = _attr(ctx); + }; + } + } assign; +}; + +} // namespace dulcificum::gcode::ast::details + + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_AST_WORDS_OPTIONAL_VALUES_H diff --git a/include/dulcificum/gcode/ast/words/words.h b/include/dulcificum/gcode/ast/words/words.h new file mode 100644 index 0000000..818622c --- /dev/null +++ b/include/dulcificum/gcode/ast/words/words.h @@ -0,0 +1,15 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_WORDS_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_WORDS_H + +#include "dulcificum/gcode/ast/words/G0.h" +#include "dulcificum/gcode/ast/words/G1.h" + +#include + +namespace dulcificum::gcode::ast +{ +using command_t = std::variant; +} + + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_GCODE_WORDS_WORDS_H diff --git a/include/dulcificum/utils/char_range_literal.h b/include/dulcificum/utils/char_range_literal.h new file mode 100644 index 0000000..55bda48 --- /dev/null +++ b/include/dulcificum/utils/char_range_literal.h @@ -0,0 +1,24 @@ +#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_UTILS_CHAR_RANGE_LITERAL_H +#define DULCIFICUM_INCLUDE_DULCIFICUM_UTILS_CHAR_RANGE_LITERAL_H + +#include +#include + +namespace dulcificum::utils +{ + +// NOLINTBEGIN +template +struct CharRangeLiteral +{ + constexpr CharRangeLiteral(const char (&str)[N]) noexcept + { + std::copy_n(str, N, value); + } + char value[N]; ///< The character array holding the literal +}; +// NOLINTEND + +} // namespace dulcificum::utils + +#endif // DULCIFICUM_INCLUDE_DULCIFICUM_UTILS_CHAR_RANGE_LITERAL_H