aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-28 13:56:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-28 13:56:07 +0200
commit6c876cf3280ba63d6077656476c2fc692e4bb1ff (patch)
tree446394e681571e5bd59310a5cfc43ea3f69f364e
parent886f5c5511a3b8291fafd7fe1435916a7c993cf0 (diff)
Qualify all unqualified name components in pointer types
This this necessary since they may not resolve in the typedef that we generate in namespace odb.
-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_;
};