From 6c876cf3280ba63d6077656476c2fc692e4bb1ff Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 28 Nov 2010 13:56:07 +0200 Subject: 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. --- odb/cxx-lexer.cxx | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ odb/cxx-lexer.hxx | 45 ++++++++++++++ odb/gcc.hxx | 1 + odb/makefile | 1 + odb/pragma.cxx | 20 +++--- odb/type-processor.cxx | 99 +++++++++++++++++++++++++++-- 6 files changed, 314 insertions(+), 16 deletions(-) create mode 100644 odb/cxx-lexer.cxx create mode 100644 odb/cxx-lexer.hxx 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 +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#include + +#include +#include + +#include // std::bad_alloc +#include +#include + +#include + +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, "", 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 (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 (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 +// 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 + +#include + +// 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 +#include #include #include #include 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 #include 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 +#include #include 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 (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_; }; -- cgit v1.1