summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-09-19 10:47:42 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-09-19 10:47:42 +0200
commit28b0b90f965f08c6363555b6e672da807f9faf7a (patch)
tree266bb76a474dd87aead1bfba01702b42812c5129 /cli
parentcb65012eb524eb57b00249f1dee0f245e947cda4 (diff)
Open output files and generate boilerplate code
Diffstat (limited to 'cli')
-rw-r--r--cli/cli.cxx6
-rw-r--r--cli/context.cxx164
-rw-r--r--cli/context.hxx23
-rw-r--r--cli/generator.cxx194
-rw-r--r--cli/generator.hxx2
5 files changed, 383 insertions, 6 deletions
diff --git a/cli/cli.cxx b/cli/cli.cxx
index 3d54452..3a38782 100644
--- a/cli/cli.cxx
+++ b/cli/cli.cxx
@@ -56,4 +56,10 @@ int main (int argc, char* argv[])
//
return 1;
}
+ catch (generator::failed const&)
+ {
+ // Diagnostics has already been issued by the generator.
+ //
+ return 1;
+ }
}
diff --git a/cli/context.cxx b/cli/context.cxx
index 3c62e38..d90df99 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -3,18 +3,178 @@
// copyright : Copyright (c) 2009 Code Synthesis Tools CC
// license : MIT; see accompanying LICENSE file
+#include <algorithm> // std::binary_search
+
#include "context.hxx"
+using namespace std;
+
context::
context (std::ostream& os_)
: data_ (new (shared) data),
- os (os_)
+ os (os_),
+ reserved_name_map (data_->reserved_name_map_)
{
}
context::
context (context& c)
: data_ (c.data_),
- os (c.os)
+ os (c.os),
+ reserved_name_map (c.reserved_name_map)
+{
+}
+
+namespace
{
+ char const* keywords[] =
+ {
+ "NULL",
+ "and",
+ "asm",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "class",
+ "compl",
+ "const",
+ "const_cast",
+ "continue",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "end_eq",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "inline",
+ "int",
+ "long",
+ "mutable",
+ "namespace",
+ "new",
+ "not",
+ "not_eq",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_cast",
+ "struct",
+ "switch",
+ "template",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq"
+ };
+}
+
+string context::
+escape (string const& name) const
+{
+ typedef string::size_type size;
+
+ string r;
+ size n (name.size ());
+
+ // In most common cases we will have that many characters.
+ //
+ r.reserve (n);
+
+ for (size i (0); i < n; ++i)
+ {
+ char c (name[i]);
+
+ if (i == 0)
+ {
+ if (!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '_'))
+ r = (c >= '0' && c <= '9') ? "cxx_" : "cxx";
+ }
+
+ if (!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_'))
+ r += '_';
+ else
+ r += c;
+ }
+
+ if (r.empty ())
+ r = "cxx";
+
+ // Custom reserved words.
+ //
+ reserved_name_map_type::const_iterator i (reserved_name_map.find (r));
+
+ if (i != reserved_name_map.end ())
+ {
+ if (!i->second.empty ())
+ return i->second;
+ else
+ r += L'_';
+ }
+
+ // Keywords
+ //
+ size const ks (sizeof (keywords) / sizeof (char*));
+
+ if (std::binary_search (keywords, keywords + ks, r))
+ {
+ r += '_';
+
+ // Re-run custom words.
+ //
+ i = reserved_name_map.find (r);
+
+ if (i != reserved_name_map.end ())
+ {
+ if (!i->second.empty ())
+ return i->second;
+ else
+ r += L'_';
+ }
+ }
+
+ return r;
}
diff --git a/cli/context.hxx b/cli/context.hxx
index 28b74eb..8dc9fff 100644
--- a/cli/context.hxx
+++ b/cli/context.hxx
@@ -6,6 +6,8 @@
#ifndef CLI_CONTEXT_HXX
#define CLI_CONTEXT_HXX
+#include <map>
+#include <string>
#include <ostream>
#include <cutl/shared-ptr.hxx>
@@ -17,15 +19,30 @@ using std::endl;
class context
{
+public:
+ typedef std::string string;
+
+private:
+ struct data;
+ cutl::shared_ptr<data> data_;
+
+public:
+ std::ostream& os;
+
+ typedef std::map<string, string> reserved_name_map_type;
+ reserved_name_map_type& reserved_name_map;
+
private:
struct data
{
+ reserved_name_map_type reserved_name_map_;
};
- cutl::shared_ptr<data> data_;
-
public:
- std::ostream& os;
+ // Escape C++ keywords, reserved names, and illegal characters.
+ //
+ string
+ escape (string const&) const;
public:
context (std::ostream& os_);
diff --git a/cli/generator.cxx b/cli/generator.cxx
index a5c588c..cf9de69 100644
--- a/cli/generator.cxx
+++ b/cli/generator.cxx
@@ -3,13 +3,205 @@
// copyright : Copyright (c) 2009 Code Synthesis Tools CC
// license : MIT; see accompanying LICENSE file
+#include <cctype> // std::toupper, std::is{alpha,upper,lower}
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#include <cutl/fs/auto-remove.hxx>
+
+#include <cutl/compiler/code-stream.hxx>
+#include <cutl/compiler/cxx-indenter.hxx>
+
+#include "context.hxx"
#include "generator.hxx"
+using namespace std;
+using namespace cutl;
+using namespace cutl;
+
+using semantics::path;
+
+namespace
+{
+ static char const header[] =
+ "// This code was generated by CLI, a command line interface\n"
+ "// compiler for C++.\n"
+ "//\n\n";
+
+ string
+ make_guard (string const& file, string const& prefix, context& ctx)
+ {
+ string g (file);
+
+ if (!prefix.empty ())
+ g = prefix + '_' + g;
+
+ // Split words, e.g., "FooBar" to "Foo_Bar" and convert everything
+ // to upper case.
+ //
+ string r;
+ for (string::size_type i (0), n (g.size ()); i < n - 1; ++i)
+ {
+ char c1 (g[i]);
+ char c2 (g[i + 1]);
+
+ r += toupper (c1);
+
+ if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2))
+ r += "_";
+ }
+ r += toupper (g[g.size () - 1]);
+
+ return ctx.escape (r);
+ }
+}
+
generator::
generator ()
{
}
+
void generator::
-generate (semantics::cli_unit& unit, semantics::path const& path)
+generate (semantics::cli_unit& unit, path const& p)
{
+ try
+ {
+ bool inl (false);
+
+ string hxx_suffix (".hxx");
+ string ixx_suffix (".ixx");
+ string cxx_suffix (".cxx");
+
+ string out_dir;
+
+ path file (p.leaf ());
+ string base (file.base ().string ());
+
+ string hxx_name (base + hxx_suffix);
+ string ixx_name (base + ixx_suffix);
+ string cxx_name (base + cxx_suffix);
+
+ path hxx_path (hxx_name);
+ path ixx_path (ixx_name);
+ path cxx_path (cxx_name);
+
+ if (!out_dir.empty ())
+ {
+ path dir (out_dir);
+
+ hxx_path = dir / hxx_path;
+ ixx_path = dir / ixx_path;
+ cxx_path = dir / cxx_path;
+ }
+
+ fs::auto_removes auto_rm;
+
+ //
+ //
+ ofstream hxx (hxx_path.string ().c_str ());
+
+ if (!hxx.is_open ())
+ {
+ cerr << "error: unable to open '" << hxx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (hxx_path);
+
+ //
+ //
+ ofstream ixx;
+
+ if (inl)
+ {
+ ixx.open (ixx_path.string ().c_str (), ios_base::out);
+
+ if (!ixx.is_open ())
+ {
+ cerr << "error: unable to open '" << ixx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (ixx_path);
+ }
+
+ //
+ //
+ ofstream cxx (cxx_path.string ().c_str ());
+
+ if (!cxx.is_open ())
+ {
+ cerr << "error: unable to open '" << cxx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (cxx_path);
+
+ // Print headers.
+ //
+ hxx << header;
+ if (inl)
+ ixx << header;
+ cxx << header;
+
+ typedef compiler::ostream_filter<compiler::cxx_indenter, char> cxx_filter;
+
+ // HXX
+ //
+ {
+ cxx_filter filt (hxx);
+ context ctx (hxx);
+
+ string guard (make_guard (hxx_name, "", ctx));
+
+ hxx << "#ifndef " << guard << endl
+ << "#define " << guard << endl
+ << endl;
+
+
+ if (inl)
+ {
+ hxx << "#include \"" << ixx_name << "\"" << endl
+ << endl;
+ }
+
+ hxx << "#endif // " << guard << endl;
+ }
+
+ // IXX
+ //
+ if (inl)
+ {
+ cxx_filter filt (ixx);
+ context ctx (ixx);
+ }
+
+ // CXX
+ //
+ {
+ cxx_filter filt (cxx);
+ context ctx (cxx);
+
+ cxx << "#include \"" << hxx_name << "\"" << endl
+ << endl;
+ }
+
+ auto_rm.cancel ();
+ }
+ catch (semantics::invalid_path const& e)
+ {
+ cerr << "error: '" << e.path () << "' is not a valid filesystem path"
+ << endl;
+ throw failed ();
+ }
+ catch (fs::error const&)
+ {
+ // Auto-removal of generated files failed. Ignore it.
+ //
+ throw failed ();
+ }
}
diff --git a/cli/generator.hxx b/cli/generator.hxx
index 5db2aa5..40081af 100644
--- a/cli/generator.hxx
+++ b/cli/generator.hxx
@@ -13,6 +13,8 @@ class generator
public:
generator ();
+ class failed {};
+
void
generate (semantics::cli_unit&, semantics::path const&);