diff options
author | 2019-10-18 17:57:55 +0200 | |
---|---|---|
committer | 2019-10-18 17:57:55 +0200 | |
commit | b09fa00cca1a9baa0327a33d865fc970f77d4db0 (patch) | |
tree | 47dd943368aa43a0c0cf4256f88e590960c1e99f /src/lib/netlist/plib | |
parent | ad27643c07d54fc2cc3e56327fe07335e7763d52 (diff) |
Netlist: code maintenance and improvements. [Couriersud]
- Added support for line markers to the preprocessor and parser.
- Added support for include processing to the preprocessor.
- Moved sources base type to plib to be used for preprocessor includes.
This enables to include e.g. from rom memory regions.
- Renamed some defines
Diffstat (limited to 'src/lib/netlist/plib')
-rw-r--r-- | src/lib/netlist/plib/palloc.h | 8 | ||||
-rw-r--r-- | src/lib/netlist/plib/pconfig.h | 30 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfmtlog.cpp | 4 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfmtlog.h | 14 | ||||
-rw-r--r-- | src/lib/netlist/plib/pomp.h | 10 | ||||
-rw-r--r-- | src/lib/netlist/plib/pparser.cpp | 99 | ||||
-rw-r--r-- | src/lib/netlist/plib/pparser.h | 67 | ||||
-rw-r--r-- | src/lib/netlist/plib/pstrutil.h | 22 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.cpp | 32 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.h | 112 |
10 files changed, 336 insertions, 62 deletions
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index 5b7d2f59c2d..aa1aac5544d 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -276,7 +276,7 @@ namespace plib { static inline void *allocate( size_t alignment, size_t size ) { - #if (USE_ALIGNED_ALLOCATION) + #if (PUSE_ALIGNED_ALLOCATION) #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) return _aligned_malloc(size, alignment); #elif defined(__APPLE__) @@ -296,7 +296,7 @@ namespace plib { static inline void deallocate( void *ptr ) { - #if (USE_ALIGNED_ALLOCATION) + #if (PUSE_ALIGNED_ALLOCATION) // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) free(ptr); #else @@ -352,7 +352,7 @@ namespace plib { //auto t = reinterpret_cast<std::uintptr_t>(p); //if (t & (ALIGN-1)) // printf("alignment error!"); -#if (USE_ALIGNED_HINTS) +#if (PUSE_ALIGNED_HINTS) return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN)); #else return p; @@ -364,7 +364,7 @@ namespace plib { { static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)"); static_assert(is_pow2(ALIGN), "Alignment must be a power of 2"); -#if (USE_ALIGNED_HINTS) +#if (PUSE_ALIGNED_HINTS) return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN)); #else return p; diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h index 3e20170a752..102a991e613 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -38,20 +38,20 @@ * netlists like kidniki. */ -#ifndef USE_OPENMP -#define USE_OPENMP (0) +#ifndef PUSE_OPENMP +#define PUSE_OPENMP (0) #endif /* * Set this to one if you want to use aligned storage optimizations. */ -#ifndef USE_ALIGNED_OPTIMIZATIONS -#define USE_ALIGNED_OPTIMIZATIONS (0) +#ifndef PUSE_ALIGNED_OPTIMIZATIONS +#define PUSE_ALIGNED_OPTIMIZATIONS (0) #endif -#define USE_ALIGNED_ALLOCATION (USE_ALIGNED_OPTIMIZATIONS) -#define USE_ALIGNED_HINTS (USE_ALIGNED_OPTIMIZATIONS) +#define PUSE_ALIGNED_ALLOCATION (PUSE_ALIGNED_OPTIMIZATIONS) +#define PUSE_ALIGNED_HINTS (PUSE_ALIGNED_OPTIMIZATIONS) /* * Standard alignment macros */ @@ -114,11 +114,19 @@ typedef __int128_t INT128; //============================================================ #if defined(OPENMP) -#define HAS_OPENMP ( OPENMP >= 200805 ) +#if ( OPENMP >= 200805 ) +#define PHAS_OPENMP (1) +#else +#define PHAS_OPENMP (0) +#endif #elif defined(_OPENMP) -#define HAS_OPENMP ( _OPENMP >= 200805 ) +#if ( _OPENMP >= 200805 ) +#define PHAS_OPENMP (1) +#else +#define PHAS_OPENMP (0) +#endif #else -#define HAS_OPENMP (0) +#define PHAS_OPENMP (0) #endif @@ -126,8 +134,8 @@ typedef __int128_t INT128; // WARNINGS //============================================================ -#if (USE_OPENMP) -#if (!(HAS_OPENMP)) +#if (PUSE_OPENMP) +#if (!(PHAS_OPENMP)) #error To use openmp compile and link with "-fopenmp" #endif #endif diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index ca7ec88e2e3..250ead34cb3 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -112,10 +112,10 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec) else if (pdot != pstring::npos) { strm << std::setprecision(pstonum<int>(fmt.substr(pdot + 1))); - r.width = pstonum<pstring::size_type>(left(fmt,pdot)); + r.width = pstonum<int>(left(fmt,pdot)); } else if (fmt != "") - r.width = pstonum<pstring::size_type>(fmt); + r.width = pstonum<int>(fmt); switch (r.pend) { diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 531b76fafe7..7bf10173857 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -227,7 +227,7 @@ protected: pstring::size_type p; pstring::size_type sl; char32_t pend; - pstring::size_type width; + int width; }; rtype setfmt(std::stringstream &strm, char32_t cfmt_spec); @@ -248,10 +248,14 @@ protected: strm << std::forward<T>(val); const pstring ps(strm.str()); pstring pad(""); - if (ret.width > ps.length()) - pad = pstring(ret.width - ps.length(), ' '); - - m_str = m_str.substr(0, ret.p) + pad + ps + m_str.substr(ret.p + ret.sl); + std::size_t aw(std::abs(ret.width)); + if (aw > ps.length()) + pad = pstring(aw - ps.length(), ' '); + + if (ret.width > 0) + m_str = m_str.substr(0, ret.p) + pad + ps + m_str.substr(ret.p + ret.sl); + else + m_str = m_str.substr(0, ret.p) + ps + pad + m_str.substr(ret.p + ret.sl); } } while (ret.ret == 1); diff --git a/src/lib/netlist/plib/pomp.h b/src/lib/netlist/plib/pomp.h index 400fbee9e64..79fa0f4bf9b 100644 --- a/src/lib/netlist/plib/pomp.h +++ b/src/lib/netlist/plib/pomp.h @@ -14,7 +14,7 @@ #include <cstdint> -#if HAS_OPENMP +#if PHAS_OPENMP #include "omp.h" #endif @@ -26,7 +26,7 @@ void for_static(std::size_t numops, const I start, const I end, const T &what) { if (numops>1000) { - #if HAS_OPENMP && USE_OPENMP + #if PHAS_OPENMP && PUSE_OPENMP #pragma omp parallel for schedule(static) #endif for (I i = start; i < end; i++) @@ -40,7 +40,7 @@ void for_static(std::size_t numops, const I start, const I end, const T &what) template <typename I, class T> void for_static(const I start, const I end, const T &what) { -#if HAS_OPENMP && USE_OPENMP +#if PHAS_OPENMP && PUSE_OPENMP #pragma omp parallel for schedule(static) #endif for (I i = start; i < end; i++) @@ -57,7 +57,7 @@ void for_static_np(const I start, const I end, const T &what) inline void set_num_threads(const std::size_t threads) { -#if HAS_OPENMP && USE_OPENMP +#if PHAS_OPENMP && PUSE_OPENMP omp_set_num_threads(threads); #else plib::unused_var(threads); @@ -66,7 +66,7 @@ inline void set_num_threads(const std::size_t threads) inline std::size_t get_max_threads() { -#if HAS_OPENMP && USE_OPENMP +#if PHAS_OPENMP && PUSE_OPENMP return omp_get_max_threads(); #else return 1; diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp index 74d0b137829..11da93486a4 100644 --- a/src/lib/netlist/plib/pparser.cpp +++ b/src/lib/netlist/plib/pparser.cpp @@ -149,6 +149,23 @@ ptokenizer::token_t ptokenizer::get_token() if (ret.is_type(ENDOFFILE)) return ret; + if (m_support_line_markers && ret.is_type(LINEMARKER)) + { + // FIXME: do something with information gathered + ret = get_token_internal(); + if (!ret.is_type(NUMBER)) + error(pfmt("Expected line number after line marker but got <{1}>")(ret.str()) ); + ret = get_token_internal(); + if (!ret.is_type(STRING)) + error(pfmt("Expected file name after line marker but got <{1}>")(ret.str()) ); + ret = get_token_internal(); + while (ret.is_type(NUMBER)) + { + // FIXME: process flags; actually only 1 (file enter) and 2 (after file exit) + ret = get_token_internal(); + } + } + if (ret.is(m_tok_comment_start)) { do { @@ -184,7 +201,9 @@ ptokenizer::token_t ptokenizer::get_token_internal() return token_t(ENDOFFILE); } } - if (m_number_chars_start.find(c) != pstring::npos) + if (m_support_line_markers && c == '#') + return token_t(LINEMARKER); + else if (m_number_chars_start.find(c) != pstring::npos) { /* read number while we receive number or identifier chars * treat it as an identifier when there are identifier chars in it @@ -259,11 +278,11 @@ ptokenizer::token_t ptokenizer::get_token_internal() // A simple preprocessor // ---------------------------------------------------------------------------------------- -ppreprocessor::ppreprocessor(defines_map_type *defines) +ppreprocessor::ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines) : std::istream(new readbuffer(this)) +, m_sources(sources) , m_if_flag(0) , m_if_level(0) -, m_lineno(0) , m_pos(0) , m_state(PROCESS) , m_comment(false) @@ -289,7 +308,20 @@ ppreprocessor::ppreprocessor(defines_map_type *defines) void ppreprocessor::error(const pstring &err) { - throw pexception("PREPRO ERROR: " + err); + pstring s(""); + pstring trail (" from "); + pstring trail_first("In file included from "); + pstring e = plib::pfmt("PREPRO ERROR: {1}:{2}:0: error: {3}\n") + (m_stack.top().m_name, m_stack.top().m_lineno, err); + m_stack.pop(); + while (m_stack.size() > 0) + { + if (m_stack.size() == 1) + trail = trail_first; + s = trail + plib::pfmt("{1}:{2}:0\n")(m_stack.top().m_name, m_stack.top().m_lineno) + s; + m_stack.pop(); + } + throw pexception("\n" + s + e); } #define CHECKTOK2(p_op, p_prio) \ @@ -504,7 +536,38 @@ pstring ppreprocessor::process_line(pstring line) } else if (lti[0] == "#include") { - // ignore + if (m_if_flag == 0) + { + pstring arg(""); + for (std::size_t i=1; i<lti.size(); i++) + arg += (lti[i] + " "); + + arg = plib::trim(arg); + + if (startsWith(arg, "\"") && endsWith(arg, "\"")) + { + arg = arg.substr(1, arg.length() - 2); + /* first try local context */ + auto l(plib::util::buildpath({m_stack.top().m_local_path, arg})); + auto lstrm(m_sources.get_stream<>(l)); + if (lstrm) + { + m_stack.emplace(input_context(std::move(lstrm), plib::util::path(l), l)); + } + else + { + auto strm(m_sources.get_stream<>(arg)); + if (strm) + { + m_stack.emplace(input_context(std::move(strm), plib::util::path(arg), arg)); + } + else + error("include not found:" + arg); + } + } + else + error("include misspelled:" + arg); + } } else if (lti[0] == "#pragma") { @@ -519,7 +582,7 @@ pstring ppreprocessor::process_line(pstring line) if (m_if_flag == 0) { if (lti.size() < 2) - error("PREPRO: define needs at least one argument: " + line); + error("define needs at least one argument: " + line); else if (lti.size() == 2) m_defines.insert({lti[1], define_t(lti[1], "")}); else @@ -535,7 +598,7 @@ pstring ppreprocessor::process_line(pstring line) else { if (m_if_flag == 0) - error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line))); + error(pfmt("unknown directive on line {1}: {2}")(m_stack.top().m_lineno)(replace_macros(line))); } } else @@ -547,6 +610,28 @@ pstring ppreprocessor::process_line(pstring line) return ret; } +void ppreprocessor::process_stack() +{ + while (m_stack.size() > 0) + { + pstring line; + pstring linemarker = pfmt("# {1} \"{2}\" 1\n")(m_stack.top().m_lineno, m_stack.top().m_name); + m_outbuf += decltype(m_outbuf)(linemarker.c_str()); + while (m_stack.top().m_reader.readline(line)) + { + m_stack.top().m_lineno++; + line = process_line(line); + m_outbuf += decltype(m_outbuf)(line.c_str()) + static_cast<char>(10); + } + m_stack.pop(); + if (m_stack.size() > 0) + { + linemarker = pfmt("# {1} \"{2}\" 2\n")(m_stack.top().m_lineno, m_stack.top().m_name); + m_outbuf += decltype(m_outbuf)(linemarker.c_str()); + } + } +} + } // namespace plib diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h index 5332ee2518c..ced7e500cad 100644 --- a/src/lib/netlist/plib/pparser.h +++ b/src/lib/netlist/plib/pparser.h @@ -12,9 +12,11 @@ #include "pstream.h" #include "pstring.h" +#include "putil.h" // psource_t + //#include <cstdint> #include <unordered_map> - +#include <stack> namespace plib { class ptokenizer @@ -28,6 +30,7 @@ public: , m_px(m_cur_line.begin()) , m_unget(0) , m_string('"') + , m_support_line_markers(true) // FIXME { } @@ -42,6 +45,7 @@ public: TOKEN, STRING, COMMENT, + LINEMARKER, UNKNOWN, ENDOFFILE }; @@ -156,6 +160,7 @@ private: token_id_t m_tok_comment_start; token_id_t m_tok_comment_end; token_id_t m_tok_line_comment; + bool m_support_line_markers; }; @@ -174,26 +179,7 @@ public: using defines_map_type = std::unordered_map<pstring, define_t>; - explicit ppreprocessor(defines_map_type *defines = nullptr); - - ~ppreprocessor() override - { - delete rdbuf(); - } - - template <typename T> - ppreprocessor & process(T &&istrm) - { - putf8_reader reader(std::forward<T>(istrm)); - pstring line; - while (reader.readline(line)) - { - m_lineno++; - line = process_line(line); - m_outbuf += decltype(m_outbuf)(line.c_str()) + static_cast<char>(10); - } - return *this; - } + explicit ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines = nullptr); COPYASSIGN(ppreprocessor, delete) ppreprocessor &operator=(ppreprocessor &&src) = delete; @@ -201,10 +187,10 @@ public: ppreprocessor(ppreprocessor &&s) noexcept : std::istream(new readbuffer(this)) , m_defines(std::move(s.m_defines)) + , m_sources(s.m_sources) , m_expr_sep(std::move(s.m_expr_sep)) , m_if_flag(s.m_if_flag) , m_if_level(s.m_if_level) - , m_lineno(s.m_lineno) , m_outbuf(std::move(s.m_outbuf)) , m_pos(s.m_pos) , m_state(s.m_state) @@ -212,6 +198,19 @@ public: { } + ~ppreprocessor() override + { + delete rdbuf(); + } + + template <typename T> + ppreprocessor & process(T &&istrm) + { + m_stack.emplace(input_context(std::forward<T>(istrm),"","<stream>")); + process_stack(); + return *this; + } + protected: class readbuffer : public std::streambuf @@ -242,6 +241,7 @@ protected: ? std::char_traits<char>::eof() : std::char_traits<char>::to_int_type(*this->gptr()); } + private: ppreprocessor *m_strm; std::array<char_type, 1024> m_buf; @@ -261,20 +261,41 @@ private: LINE_CONTINUATION }; + void process_stack(); + pstring process_line(pstring line); pstring process_comments(pstring line); defines_map_type m_defines; + psource_collection_t<> &m_sources; std::vector<pstring> m_expr_sep; std::uint_least64_t m_if_flag; // 31 if levels int m_if_level; - int m_lineno; + + struct input_context + { + template <typename T> + input_context(T &&istrm, const pstring &local_path, const pstring &name) + : m_reader(std::forward<T>(istrm)) + , m_lineno(0) + , m_local_path(local_path) + , m_name(name) + {} + + putf8_reader m_reader; + int m_lineno; + pstring m_local_path; + pstring m_name; + }; + + std::stack<input_context> m_stack; pstring_t<pu8_traits> m_outbuf; std::istream::pos_type m_pos; state_e m_state; pstring m_line; bool m_comment; + }; } // namespace plib diff --git a/src/lib/netlist/plib/pstrutil.h b/src/lib/netlist/plib/pstrutil.h index 94ecccca09e..d3e62d06af7 100644 --- a/src/lib/netlist/plib/pstrutil.h +++ b/src/lib/netlist/plib/pstrutil.h @@ -88,6 +88,28 @@ namespace plib } template<typename T> + typename T::size_type find_last_of(const T &str, const T &no) + { + typename T::size_type last_found = T::npos; + typename T::size_type pos = 0; + for (auto it = str.begin(); it != str.end(); ++it, ++pos) + { + bool f = false; + for (typename T::value_type const jt : no) + { + if (*it == jt) + { + f = true; + break; + } + } + if (f) + last_found = pos; + } + return last_found; + } + + template<typename T> T ltrim(const T &str, const T &ws = T(" \t\n\r")) { auto f = find_first_not_of(str, ws); diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index b4824d62738..f6eed734a3e 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -13,6 +13,32 @@ namespace plib { namespace util { + #ifdef _WIN32 + static constexpr const char PATH_SEP = '\\'; + #else + static constexpr const char PATH_SEP = '/'; + #endif + + pstring basename(pstring filename) + { + auto p=find_last_of(filename, pstring(1, PATH_SEP)); + if (p == pstring::npos) + return filename; + else + return filename.substr(p+1); + } + + pstring path(pstring filename) + { + auto p=find_last_of(filename, pstring(1, PATH_SEP)); + if (p == pstring::npos) + return ""; + else if (p == 0) // root case + return filename.substr(0, 1); + else + return filename.substr(0, p); + } + pstring buildpath(std::initializer_list<pstring> list ) { pstring ret = ""; @@ -21,11 +47,7 @@ namespace plib if (ret == "") ret = elem; else - #ifdef _WIN32 - ret = ret + '\\' + elem; - #else - ret += ('/' + elem); - #endif + ret += (PATH_SEP + elem); } return ret; } diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 5ff70d941a2..227648b172b 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -10,6 +10,8 @@ #include "pexception.h" #include "pstring.h" +#include "palloc.h" + #include <algorithm> #include <initializer_list> #include <iostream> @@ -24,8 +26,118 @@ namespace plib { + // ---------------------------------------------------------------------------------------- + // A Generic netlist sources implementation + // ---------------------------------------------------------------------------------------- + + class psource_t + { + public: + + using stream_ptr = plib::unique_ptr<std::istream>; + + psource_t() + {} + + COPYASSIGNMOVE(psource_t, delete) + + virtual ~psource_t() noexcept = default; + + virtual stream_ptr stream(const pstring &name) = 0; + private: + }; + + /**! Generic string source + * + * Will return the given string when name matches. + * Is used in preprocessor code to eliminate inclusion of certain files. + * + * @tparam TS base stream class. Default is psource_t + */ + template <typename TS = psource_t> + class psource_str_t : public TS + { + public: + psource_str_t(pstring name, pstring str) + : m_name(name), m_str(str) + {} + + COPYASSIGNMOVE(psource_str_t, delete) + virtual ~psource_str_t() noexcept = default; + + typename TS::stream_ptr stream(const pstring &name) override + { + if (name == m_name) + return plib::make_unique<std::stringstream>(m_str); + else + return typename TS::stream_ptr(nullptr); + } + private: + pstring m_name; + pstring m_str; + }; + + /**! Generic sources collection + * + * @tparam TS base stream class. Default is psource_t + */ + template <typename TS = psource_t> + class psource_collection_t + { + public: + using source_type = plib::unique_ptr<TS>; + using list_t = std::vector<source_type>; + + psource_collection_t() + {} + + COPYASSIGNMOVE(psource_collection_t, delete) + virtual ~psource_collection_t() noexcept = default; + + void add_source(source_type &&src) + { + m_collection.push_back(std::move(src)); + } + + template <typename S = TS> + typename S::stream_ptr get_stream(pstring name) + { + for (auto &s : m_collection) + { + auto source(dynamic_cast<S *>(s.get())); + if (source) + { + auto strm = source->stream(name); + if (strm) + return strm; + } + } + return typename S::stream_ptr(nullptr); + } + + template <typename S, typename F> + bool for_all(pstring name, F lambda) + { + for (auto &s : m_collection) + { + auto source(dynamic_cast<S *>(s.get())); + if (source) + { + if (lambda(source)) + return true; + } + } + return false; + } + + private: + list_t m_collection; + }; + namespace util { + pstring basename(pstring filename); + pstring path(pstring filename); pstring buildpath(std::initializer_list<pstring> list ); pstring environment(const pstring &var, const pstring &default_val); } // namespace util |