diff options
Diffstat (limited to 'cutl')
-rw-r--r-- | cutl/compiler/code-stream.hxx | 153 | ||||
-rw-r--r-- | cutl/compiler/code-stream.txx | 96 | ||||
-rw-r--r-- | cutl/compiler/sloc-counter.hxx | 80 | ||||
-rw-r--r-- | cutl/compiler/sloc-counter.txx | 225 |
4 files changed, 554 insertions, 0 deletions
diff --git a/cutl/compiler/code-stream.hxx b/cutl/compiler/code-stream.hxx new file mode 100644 index 0000000..bb8305a --- /dev/null +++ b/cutl/compiler/code-stream.hxx @@ -0,0 +1,153 @@ +// file : cutl/compiler/code-stream.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_CODE_STREAM_HXX +#define CUTL_COMPILER_CODE_STREAM_HXX + +#include <memory> // std::auto_ptr +#include <ostream> + +namespace cutl +{ + namespace compiler + { + // + // + template <typename C> + class code_stream + { + public: + code_stream () {} + + virtual + ~code_stream (); + + public: + virtual void + put (C) = 0; + + // Unbuffer flushes internal formatting buffers (if any). + // Note that unbuffer is not exactly flushing since it can + // result in formatting errors and in general can not be + // called at arbitrary points. Natural use case would be + // to call unbuffer at the end of the stream when no more + // data is expected. + // + virtual void + unbuffer () = 0; + + private: + code_stream (code_stream const&); + + code_stream& + operator= (code_stream const&); + }; + + // + // + template <typename C> + class from_streambuf_adapter: public code_stream<C> + { + public: + typedef typename std::basic_streambuf<C>::traits_type traits_type; + typedef typename std::basic_streambuf<C>::int_type int_type; + + struct eof {}; + struct sync {}; + + public: + from_streambuf_adapter (std::basic_streambuf<C>& stream) + : stream_ (stream) + { + } + + private: + from_streambuf_adapter (from_streambuf_adapter const&); + + from_streambuf_adapter& + operator= (from_streambuf_adapter const&); + + public: + virtual void + put (C c); + + virtual void + unbuffer (); + + private: + std::basic_streambuf<C>& stream_; + }; + + // + // + template <typename C> + class to_streambuf_adapter: public std::basic_streambuf<C> + { + public: + typedef typename std::basic_streambuf<C>::traits_type traits_type; + typedef typename std::basic_streambuf<C>::int_type int_type; + + public: + to_streambuf_adapter (code_stream<C>& stream) + : stream_ (stream) + { + } + + private: + to_streambuf_adapter (to_streambuf_adapter const&); + + to_streambuf_adapter& + operator= (to_streambuf_adapter const&); + + public: + virtual int_type + overflow (int_type i); + + // Does nothing since calling unbuffer here would be dangerous. + // See the note in code_stream. + // + virtual int + sync (); + + private: + code_stream<C>& stream_; + }; + + // + // + template <template <typename> class S, typename C> + class ostream_filter + { + public: + typedef S<C> stream_type; + + ostream_filter (std::basic_ostream<C>& os); + ~ostream_filter (); + + stream_type& + stream () + { + return stream_; + } + + private: + ostream_filter (ostream_filter const&); + + ostream_filter& + operator= (ostream_filter const&); + + private: + std::basic_ostream<C>& os_; + std::basic_streambuf<C>* prev_; + from_streambuf_adapter<C> from_adapter_; + stream_type stream_; + to_streambuf_adapter<C> to_adapter_; + }; + } +} + +#include <cutl/compiler/code-stream.txx> + +#endif // CUTL_COMPILER_CODE_STREAM_HXX diff --git a/cutl/compiler/code-stream.txx b/cutl/compiler/code-stream.txx new file mode 100644 index 0000000..e834da7 --- /dev/null +++ b/cutl/compiler/code-stream.txx @@ -0,0 +1,96 @@ +// file : cutl/compiler/code-stream.txx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + // code_stream + // + + template <typename C> + code_stream<C>::~code_stream () + { + } + + // from_streambuf_adapter + // + + template <typename C> + void from_streambuf_adapter<C>:: + put (C c) + { + int_type i (stream_.sputc (c)); + + if (i == traits_type::eof ()) + throw eof (); + } + + template <typename C> + void from_streambuf_adapter<C>:: + unbuffer () + { + if (stream_.pubsync () != 0) + throw sync (); + } + + // to_streambuf_adapter + // + + template <typename C> + typename to_streambuf_adapter<C>::int_type to_streambuf_adapter<C>:: + overflow (int_type i) + { + try + { + stream_.put (traits_type::to_char_type (i)); + return i; + } + catch (typename from_streambuf_adapter<C>::eof const&) + { + return traits_type::eof (); + } + } + + template <typename C> + int to_streambuf_adapter<C>:: + sync () + { + return 0; + } + + // ostream_filter + // + + template <template <typename> class S, typename C> + ostream_filter<S, C>:: + ostream_filter (std::basic_ostream<C>& os) + : os_ (os), + prev_ (os_.rdbuf ()), + from_adapter_ (*prev_), + stream_ (from_adapter_), + to_adapter_ (stream_) + { + os_.rdbuf (&to_adapter_); + } + + template <template <typename> class S, typename C> + ostream_filter<S, C>:: + ~ostream_filter () + { + try + { + stream_.unbuffer (); + } + catch (...) + { + os_.rdbuf (prev_); + throw; + } + + os_.rdbuf (prev_); + } + } +} diff --git a/cutl/compiler/sloc-counter.hxx b/cutl/compiler/sloc-counter.hxx new file mode 100644 index 0000000..eb9e259 --- /dev/null +++ b/cutl/compiler/sloc-counter.hxx @@ -0,0 +1,80 @@ +// file : cutl/compiler/sloc-counter.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_SLOC_COUNTER_HXX +#define CUTL_COMPILER_SLOC_COUNTER_HXX + +#include <cctype> // std::isspace +#include <cstddef> // std::size_t + +#include <cutl/compiler/code-stream.hxx> + +namespace cutl +{ + namespace compiler + { + template <typename C> + class sloc_counter: public code_stream<C> + { + public: + sloc_counter (code_stream<C>& out); + + std::size_t + count () const + { + return count_; + } + + private: + sloc_counter (sloc_counter const&); + + sloc_counter& + operator= (sloc_counter const&); + + public: + virtual void + put (C c); + + virtual void + unbuffer (); + + private: + void + code (C c); + + void + c_comment (C c); + + void + cxx_comment (C c); + + void + char_literal (C c); + + void + string_literal (C c); + + private: + code_stream<C>& out_; + std::size_t count_; + + C prev_; // Previous character or '\0'. + bool code_counted_; // This code line has already been counted. + + enum construct + { + con_code, + con_c_com, + con_cxx_com, + con_char_lit, + con_string_lit + } construct_; + }; + } +} + +#include <cutl/compiler/sloc-counter.txx> + +#endif // CUTL_COMPILER_SLOC_COUNTER_HXX diff --git a/cutl/compiler/sloc-counter.txx b/cutl/compiler/sloc-counter.txx new file mode 100644 index 0000000..9befac7 --- /dev/null +++ b/cutl/compiler/sloc-counter.txx @@ -0,0 +1,225 @@ +// file : cutl/compiler/sloc-counter.txx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <cctype> // std::isspace + +namespace cutl +{ + namespace compiler + { + template <typename C> + sloc_counter<C>:: + sloc_counter (code_stream<C>& out) + : out_ (out), + count_ (0), + prev_ ('\0'), + code_counted_ (false), + construct_ (con_code) + { + } + + template <typename C> + void sloc_counter<C>:: + put (C c) + { + construct old (construct_); + + switch (construct_) + { + case con_code: + { + code (c); + break; + } + case con_c_com: + { + c_comment (c); + break; + } + case con_cxx_com: + { + cxx_comment (c); + break; + } + case con_char_lit: + { + char_literal (c); + break; + } + case con_string_lit: + { + string_literal (c); + break; + } + } + + // There are cases when a previous character has been already + // 'used' and therefore can not be used again. Good example + // would be '/* *//'. Here, the second slash doesn't start + // C++ comment since it was already used by C comment. + // + // To account for this we are going to set prev_ to '\0' when + // the mode changes. + // + + prev_ = (old == construct_) ? c : '\0'; + + out_.put (c); + } + + template <typename C> + void sloc_counter<C>:: + unbuffer () + { + } + + template <typename C> + void sloc_counter<C>:: + code (C c) + { + bool count (true); + + switch (c) + { + case '/': + { + if (prev_ == '/') + { + construct_ = con_cxx_com; + count = false; + } + else + { + // This slash can be a beginning of a comment but we + // yet have no way to know. Will have to examine it later + // (see below). + // + count = false; + } + + break; + } + case '*': + { + if (prev_ == '/') + { + construct_ = con_c_com; + count = false; + } + break; + } + case '\'': + { + construct_ = con_char_lit; + break; + } + case '"': + { + construct_ = con_string_lit; + break; + } + case '\n': + { + code_counted_ = false; // Reset for a new line. + count = false; + break; + } + default: + { + if (std::isspace (c)) + count = false; + break; + } + } + + if (!code_counted_) + { + if (count) + { + count_++; + code_counted_ = true; + } + else if (prev_ == '/' && construct_ == con_code) + { + // This condition accounts for the fact that we cannot count + // '/' right away since it can be a beginning of a comment. + // + count_++; + code_counted_ = (c != '\n'); + } + } + } + + template <typename C> + void sloc_counter<C>:: + c_comment (C c) + { + switch (c) + { + case '/': + { + if (prev_ == '*') + construct_ = con_code; + break; + } + case '\n': + { + code_counted_ = false; // Reset for a new line. + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + cxx_comment (C c) + { + switch (c) + { + case '\n': + { + construct_ = con_code; + code_counted_ = false; // Reset for a new line. + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + char_literal (C c) + { + switch (c) + { + case '\'': + { + if (prev_ != '\\') + construct_ = con_code; + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + string_literal (C c) + { + switch (c) + { + case '"': + { + if (prev_ != '\\') + construct_ = con_code; + break; + } + case '\n': + { + count_++; + break; + } + } + } + } +} |