From 0ab1d6d28c0b59237ee99a5df3d871e474fa9991 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:20:12 +1200 Subject: [PATCH] Handle quoted arguments in passes Use `std::quoted()` from `` to quote/unquote pass arguments. In order to maintain handling of (unquoted) comments and semicolons this occurs when adding the token to the arg list, rather than in the tokenization itself. Passes no longer receive tokenized-but-raw arguments and are instead pre-unquoted. This will cause problems for some passes (e.g. `setparam`) which rely on arguments having quotation marks for disambiguation. In order to maintain reproducibility with `echo on`, arguments which require quoting will automatically quote (arguments which were quoted but didn't need to be will not be quoted in the echo). --- kernel/io.cc | 18 ++++++++++++++++++ kernel/io.h | 4 ++++ kernel/register.cc | 10 ++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/kernel/io.cc b/kernel/io.cc index 4c593501c..483d303a9 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -2,6 +2,7 @@ #include "kernel/log.h" #include #include +#include #if !defined(WIN32) #include @@ -592,4 +593,21 @@ void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynam format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); } +bool needs_quote(const std::string &s) { + return (s.find(' ') != std::string::npos) || (s.find('\\') != std::string::npos); +} + +std::string quote(const std::string &s) { + std::ostringstream ss; + ss << std::quoted(s); + return ss.str(); +} + +std::string unquote(const std::string &s) { + std::string result; + std::istringstream ss(s); + ss >> std::quoted(result); + return result; +} + YOSYS_NAMESPACE_END diff --git a/kernel/io.h b/kernel/io.h index 2ad0a6466..64caae078 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -470,6 +470,10 @@ void remove_directory(std::string dirname); bool create_directory(const std::string& dirname); std::string escape_filename_spaces(const std::string& filename); +bool needs_quote(const std::string &s); +std::string quote(const std::string &s); +std::string unquote(const std::string &s); + YOSYS_NAMESPACE_END #endif // YOSYS_IO_H diff --git a/kernel/register.cc b/kernel/register.cc index bd12dcc38..a255c4805 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -222,7 +222,7 @@ void Pass::call(RTLIL::Design *design, std::string command) while (!tok.empty() && tok.back() == ';') tok.resize(tok.size()-1), num_semikolon++; if (!tok.empty()) - args.push_back(tok); + args.push_back(unquote(tok)); call(design, args); args.clear(); if (num_semikolon == 2) @@ -230,7 +230,7 @@ void Pass::call(RTLIL::Design *design, std::string command) if (num_semikolon == 3) call(design, "clean -purge"); } else - args.push_back(tok); + args.push_back(unquote(tok)); bool found_nl = false; for (auto c : cmd_buf) { if (c == ' ' || c == '\t') @@ -256,8 +256,10 @@ void Pass::call(RTLIL::Design *design, std::vector args) if (echo_mode) { log("%s", create_prompt(design, 0)); - for (size_t i = 0; i < args.size(); i++) - log("%s%s", i ? " " : "", args[i]); + for (size_t i = 0; i < args.size(); i++) { + auto maybe_quoted = needs_quote(args[i]) ? quote(args[i]) : args[i]; + log("%s%s", i ? " " : "", maybe_quoted); + } log("\n"); }