summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/cxx-lexer.cxx164
-rw-r--r--odb/cxx-lexer.hxx45
-rw-r--r--odb/gcc.hxx1
-rw-r--r--odb/makefile1
-rw-r--r--odb/pragma.cxx20
-rw-r--r--odb/type-processor.cxx99
6 files changed, 314 insertions, 16 deletions
diff --git a/odb/cxx-lexer.cxx b/odb/cxx-lexer.cxx
new file mode 100644
index 0000000..525de82
--- /dev/null
+++ b/odb/cxx-lexer.cxx
@@ -0,0 +1,164 @@
+// file : odb/cxx-lexer.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#include <odb/gcc.hxx>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <new> // std::bad_alloc
+#include <cassert>
+#include <iostream>
+
+#include <odb/cxx-lexer.hxx>
+
+using namespace std;
+
+// Token spelling. See cpplib.h for details.
+//
+#define OP(e, s) s ,
+#define TK(e, s) #e ,
+char const* cxx_lexer::token_spelling[N_TTYPES + 1] = { TTYPE_TABLE "KEYWORD"};
+#undef OP
+#undef TK
+
+// Diagnostics callback.
+//
+extern "C" bool
+cpp_error_callback (
+ cpp_reader* reader, int level, location_t, unsigned int,
+ char const* msg, va_list *ap)
+{
+ char const* kind (0);
+ switch (level)
+ {
+ case CPP_DL_NOTE:
+ case CPP_DL_WARNING_SYSHDR:
+ case CPP_DL_WARNING:
+ case CPP_DL_PEDWARN:
+ // Ignore these.
+ break;
+ case CPP_DL_ERROR:
+ case CPP_DL_FATAL:
+ kind = "error";
+ break;
+ case CPP_DL_ICE:
+ kind = "ice";
+ break;
+ default:
+ kind = "unknown";
+ break;
+ }
+
+ if (kind != 0)
+ {
+ fprintf (stderr, "%s: ", kind);
+ vfprintf (stderr, msg, *ap);
+ fprintf (stderr, "\n");
+
+ // By resetting the error callback we indicate to cxx_lexer
+ // that there was an error.
+ //
+ cpp_get_callbacks (reader)->error = 0;
+ return true;
+ }
+
+ return false;
+}
+
+cxx_lexer::
+cxx_lexer ()
+ : reader_ (0)
+{
+ linemap_init (&line_map_);
+ linemap_add (&line_map_, LC_ENTER, 0, "<memory>", 0);
+
+ reader_ = cpp_create_reader (
+ cxx_dialect == cxx0x ? CLK_CXX0X : CLK_CXX98, 0, &line_map_);
+
+ if (reader_ == 0)
+ throw bad_alloc ();
+
+ callbacks_ = cpp_get_callbacks (reader_);
+}
+
+cxx_lexer::
+~cxx_lexer ()
+{
+ if (reader_ != 0)
+ cpp_destroy (reader_);
+
+ linemap_free (&line_map_);
+}
+
+void cxx_lexer::
+start (string const& data)
+{
+ // The previous lexing session should have popped the buffer.
+ //
+ assert (cpp_get_buffer (reader_) == 0);
+ callbacks_->error = &cpp_error_callback;
+
+ data_ = data;
+ buf_ = data;
+ buf_ += '\n';
+
+ cpp_push_buffer (
+ reader_,
+ reinterpret_cast<unsigned char const*> (buf_.c_str ()),
+ buf_.size (),
+ true);
+}
+
+cpp_ttype cxx_lexer::
+next (string& token)
+{
+ token.clear ();
+ cpp_token const* t (cpp_get_token (reader_));
+
+ // If there was an error, the error callback will be reset to 0.
+ // Diagnostics has already been issued.
+ //
+ if (callbacks_->error == 0)
+ throw invalid_input ();
+
+ cpp_ttype tt (t->type);
+
+ // @@ Need to handle literals, at least integer.
+ //
+ switch (tt)
+ {
+ case CPP_NAME:
+ {
+ char const* name (
+ reinterpret_cast<char const*> (NODE_NAME (t->val.node.node)));
+
+ // See if this is a keyword using the C++ parser machinery and
+ // the current C++ dialect.
+ //
+ tree id (get_identifier (name));
+
+ if (C_IS_RESERVED_WORD (id))
+ tt = CPP_KEYWORD;
+
+ token = name;
+ break;
+ }
+ default:
+ {
+ if (tt <= CPP_LAST_PUNCTUATOR)
+ token += token_spelling[tt];
+ else
+ {
+ cerr << "unexpected token '" << token_spelling[tt] << "' in '" <<
+ data_ << "'" << endl;
+ throw invalid_input ();
+ }
+ break;
+ }
+ }
+
+ return tt;
+}
diff --git a/odb/cxx-lexer.hxx b/odb/cxx-lexer.hxx
new file mode 100644
index 0000000..107f92b
--- /dev/null
+++ b/odb/cxx-lexer.hxx
@@ -0,0 +1,45 @@
+// file : odb/cxx-lexer.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_CXX_LEXER_HXX
+#define ODB_CXX_LEXER_HXX
+
+#include <odb/gcc.hxx>
+
+#include <string>
+
+// A C++ keyword. This is an extension to libcpp token types.
+//
+#define CPP_KEYWORD ((cpp_ttype) (N_TTYPES + 1))
+
+// A thin wrapper around cpp_reader for lexing C++ code fragments.
+//
+class cxx_lexer
+{
+public:
+ cxx_lexer ();
+ ~cxx_lexer ();
+
+public:
+ struct invalid_input {};
+
+ void
+ start (std::string const&);
+
+ cpp_ttype
+ next (std::string& token);
+
+public:
+ static char const* token_spelling[N_TTYPES + 1];
+
+private:
+ std::string data_;
+ std::string buf_;
+ line_maps line_map_;
+ cpp_reader* reader_;
+ cpp_callbacks* callbacks_;
+};
+
+#endif // ODB_CXX_LEXER_HXX
diff --git a/odb/gcc.hxx b/odb/gcc.hxx
index 5c5bdde..83161a6 100644
--- a/odb/gcc.hxx
+++ b/odb/gcc.hxx
@@ -29,6 +29,7 @@ extern "C"
#include <tm.h>
+#include <cpplib.h>
#include <diagnostic.h>
#include <c-common.h>
#include <c-pragma.h>
diff --git a/odb/makefile b/odb/makefile
index 0724ec6..00ea4fd 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -8,6 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
# Plugin units.
#
cxx_ptun := \
+cxx-lexer.cxx \
sql-lexer.cxx \
context.cxx \
common.cxx \
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 3a1bc0f..9970376 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -3,18 +3,11 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/cxx-lexer.hxx>
#include <odb/pragma.hxx>
using namespace std;
-// Token spelling. See cpplib.h for details.
-//
-#define OP(e, s) s ,
-#define TK(e, s) #e ,
-static char const* token_spelling[N_TTYPES] = { TTYPE_TABLE };
-#undef OP
-#undef TK
-
// Lists of pragmas.
//
loc_pragmas loc_pragmas_;
@@ -256,11 +249,17 @@ handle_pragma (cpp_reader* reader,
}
size_t pb (0);
+ bool punc (false);
for (tt = pragma_lex (&t);
tt != CPP_EOF && (tt != CPP_CLOSE_PAREN || pb != 0);
tt = pragma_lex (&t))
{
+ if (punc && tt > CPP_LAST_PUNCTUATOR)
+ val += ' ';
+
+ punc = false;
+
if (tt == CPP_OPEN_PAREN)
pb++;
else if (tt == CPP_CLOSE_PAREN)
@@ -288,16 +287,17 @@ handle_pragma (cpp_reader* reader,
case CPP_NAME:
{
val += IDENTIFIER_POINTER (t);
+ punc = true;
break;
}
default:
{
if (tt <= CPP_LAST_PUNCTUATOR)
- val += token_spelling[tt];
+ val += cxx_lexer::token_spelling[tt];
else
{
error ("unexpected token %qs in db pragma %qs",
- token_spelling[tt],
+ cxx_lexer::token_spelling[tt],
pc);
return;
}
diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx
index 2fccbf3..b47c413 100644
--- a/odb/type-processor.cxx
+++ b/odb/type-processor.cxx
@@ -5,6 +5,7 @@
#include <odb/gcc.hxx>
+#include <odb/cxx-lexer.hxx>
#include <odb/type-processor.hxx>
namespace
@@ -609,7 +610,7 @@ namespace
// This is not a template-id. Resolve it and see if it is a
// template or a type.
//
- tree decl (resolve_type (p, c.scope ()));
+ tree decl (resolve_name (p, c.scope (), true));
int tc (TREE_CODE (decl));
if (tc == TYPE_DECL)
@@ -660,6 +661,88 @@ namespace
throw generation_failed ();
}
}
+
+ // Fully-qualify all the unqualified components of the name.
+ //
+ try
+ {
+ lexer.start (ptr);
+ ptr.clear ();
+
+ string t;
+ bool punc (false);
+ bool scoped (false);
+
+ for (cpp_ttype tt = lexer.next (t);
+ tt != CPP_EOF;
+ tt = lexer.next (t))
+ {
+ if (punc && tt > CPP_LAST_PUNCTUATOR)
+ ptr += ' ';
+
+ punc = false;
+
+ switch (static_cast<unsigned> (tt))
+ {
+ case CPP_LESS:
+ {
+ ptr += "< ";
+ break;
+ }
+ case CPP_GREATER:
+ {
+ ptr += " >";
+ break;
+ }
+ case CPP_COMMA:
+ {
+ ptr += ", ";
+ break;
+ }
+ case CPP_NAME:
+ {
+ // If the name was not preceeded with '::', look it
+ // up in the pragmas's scope and add the qualifer.
+ //
+ if (!scoped)
+ {
+ tree decl (resolve_name (t, c.scope (), false));
+ tree scope (CP_DECL_CONTEXT (decl));
+
+ if (scope != global_namespace)
+ {
+ ptr += "::";
+ ptr += decl_as_string (scope, TFF_PLAIN_IDENTIFIER);
+ }
+
+ ptr += "::";
+ }
+
+ ptr += t;
+ punc = true;
+ break;
+ }
+ case CPP_KEYWORD:
+ case CPP_NUMBER:
+ {
+ ptr += t;
+ punc = true;
+ break;
+ }
+ default:
+ {
+ ptr += t;
+ break;
+ }
+ }
+
+ scoped = (tt == CPP_SCOPE);
+ }
+ }
+ catch (cxx_lexer::invalid_input const&)
+ {
+ throw generation_failed ();
+ }
}
else
{
@@ -683,7 +766,7 @@ namespace
catch (invalid_name const& ex)
{
cerr << c.file () << ":" << c.line () << ":" << c.column ()
- << ": error: type name '" << ex.name () << "' specified with "
+ << ": error: name '" << ex.name () << "' specified with "
<< "'#pragma object pointer' is invalid" << endl;
throw generation_failed ();
@@ -691,7 +774,7 @@ namespace
catch (unable_to_resolve const& ex)
{
cerr << c.file () << ":" << c.line () << ":" << c.column ()
- << ": error: unable to resolve type name '" << ex.name ()
+ << ": error: unable to resolve name '" << ex.name ()
<< "' specified with '#pragma object pointer'" << endl;
throw generation_failed ();
@@ -722,10 +805,12 @@ namespace
};
tree
- resolve_type (string const& qn, semantics::scope& ss)
+ resolve_name (string const& qn, semantics::scope& ss, bool type)
{
tree scope (ss.tree_node ());
+ // @@ Could use cxx_lexer to parse the name.
+ //
for (size_t b (0), e (qn.find (':')), size (qn.size ());;
e = qn.find (':', b))
{
@@ -742,7 +827,7 @@ namespace
else
{
tree nid (get_identifier (n.c_str ()));
- scope = lookup_qualified_name (scope, nid, last, false);
+ scope = lookup_qualified_name (scope, nid, last && type, false);
// If this is the first component in the name, then also
// search the outer scopes.
@@ -754,7 +839,7 @@ namespace
{
s = &s->scope_ ();
scope = lookup_qualified_name (
- s->tree_node (), nid, last, false);
+ s->tree_node (), nid, last && type, false);
} while (scope == error_mark_node && !s->global_scope ());
}
@@ -783,6 +868,8 @@ namespace
}
private:
+ cxx_lexer lexer;
+
data_member member_;
traversal::names member_names_;
};