diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-04-02 18:41:18 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-04-02 18:41:18 +0200 |
commit | 15e6fd2b0976f82eb1ef10d2d26912d12e4f0a99 (patch) | |
tree | ebec92c4dd0ef6998c22fbe7e0971463615973db | |
parent | 33e79981967fe82d392c90974031abd444e1f9f8 (diff) |
Implement pragma support
-rw-r--r-- | odb/gcc.hxx | 9 | ||||
-rw-r--r-- | odb/makefile | 1 | ||||
-rw-r--r-- | odb/plugin.cxx | 346 | ||||
-rw-r--r-- | odb/pragma.cxx | 274 | ||||
-rw-r--r-- | odb/pragma.hxx | 89 |
5 files changed, 657 insertions, 62 deletions
diff --git a/odb/gcc.hxx b/odb/gcc.hxx index ab54707..9d1e3bc 100644 --- a/odb/gcc.hxx +++ b/odb/gcc.hxx @@ -29,7 +29,16 @@ extern "C" #include "diagnostic.h" #include "c-common.h" +#include "c-pragma.h" #include "cp/cp-tree.h" } +#ifndef LOCATION_COLUMN +#define LOCATION_COLUMN(LOC) (expand_location (LOC).column) +#endif + +#ifndef DECL_SOURCE_COLUMN +#define DECL_SOURCE_COLUMN(NODE) LOCATION_COLUMN (DECL_SOURCE_LOCATION (NODE)) +#endif + #endif // ODB_GCC_TREE_HXX diff --git a/odb/makefile b/odb/makefile index b66804d..b7c9209 100644 --- a/odb/makefile +++ b/odb/makefile @@ -11,6 +11,7 @@ cxx_ptun := \ context.cxx \ generator.cxx \ plugin.cxx \ +pragma.cxx \ source.cxx cxx_ptun += \ diff --git a/odb/plugin.cxx b/odb/plugin.cxx index 06c7abd..98d12d8 100644 --- a/odb/plugin.cxx +++ b/odb/plugin.cxx @@ -13,18 +13,11 @@ #include <sstream> #include <iostream> +#include <odb/pragma.hxx> #include <odb/options.hxx> #include <odb/semantics.hxx> #include <odb/generator.hxx> -#ifndef LOCATION_COLUMN -#define LOCATION_COLUMN(LOC) (expand_location (LOC).column) -#endif - -#ifndef DECL_SOURCE_COLUMN -#define DECL_SOURCE_COLUMN(NODE) LOCATION_COLUMN (DECL_SOURCE_LOCATION (NODE)) -#endif - using namespace std; using namespace semantics; @@ -33,10 +26,16 @@ int plugin_is_GPL_compatible; class parser { public: - typedef semantics::access access; - - parser (options const& ops) - : ops_ (ops), trace (ops.trace ()), ts (cerr) + class failed {}; + + parser (options const& ops, + loc_pragmas const& lp, + decl_pragmas const& dp) + : ops_ (ops), + loc_pragmas_ (lp), + decl_pragmas_ (dp), + trace (ops.trace ()), + ts (cerr) { } @@ -46,6 +45,7 @@ public: auto_ptr<unit> u (new unit (main_file)); unit_ = u.get (); scope_ = unit_; + error_ = 0; // Define fundamental types. // @@ -72,12 +72,71 @@ public: // code order. // collect (global_scope); + + // Add namespace-level location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (global_namespace)); + + if (i != loc_pragmas_.end ()) + decls_.insert (i->second.begin (), i->second.end ()); + } + + // Construct the semantic graph. + // emit (); + if (error_ > 0) + throw failed (); + return u; } private: + typedef semantics::access access; + + // Extended GGC tree declaration that is either a tree node or a + // pragma. If this declaration is a pragma, then the assoc flag + // indicated whether this pragma has been associated with a + // declaration. + // + struct tree_decl + { + tree decl; + pragma const* prag; + mutable bool assoc; // Allow modification via std::set iterator. + + tree_decl (tree d): decl (d), prag (0) {} + tree_decl (pragma const& p): decl (0), prag (&p), assoc (false) {} + + bool + operator< (tree_decl const& y) const + { + location_t xloc (decl ? DECL_SOURCE_LOCATION (decl) : prag->loc); + location_t yloc (y.decl ? DECL_SOURCE_LOCATION (y.decl) : y.prag->loc); + + if (xloc != yloc) + return xloc < yloc; + + size_t xl (LOCATION_LINE (xloc)); + size_t yl (LOCATION_LINE (yloc)); + + if (xl != yl) + return xl < yl; + + size_t xc (LOCATION_COLUMN (xloc)); + size_t yc (LOCATION_COLUMN (yloc)); + + if (xc != yc) + return xc < yc; + + return false; + } + }; + + typedef std::multiset<tree_decl> decl_set; + +private: void collect (tree ns) { @@ -135,10 +194,15 @@ private: void emit () { - for (decl_set::const_iterator i (decls_.begin ()), e (decls_.end ()); - i != e; ++i) + for (decl_set::const_iterator b (decls_.begin ()), i (b), + e (decls_.end ()); i != e; ++i) { - tree decl (*i); + // Skip pragmas. + // + if (i->prag) + continue; + + tree decl (i->decl); // Get this declaration's namespace and unwind our scope until // we find a common prefix of namespaces. @@ -193,7 +257,14 @@ private: { case TYPE_DECL: { - emit_type_decl (decl); + type* n (emit_type_decl (decl)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + break; } case TEMPLATE_DECL: @@ -203,12 +274,17 @@ private: } } } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls_); } - // Emit a type declaration. This is either a class definition/declaration - // or a typedef. + // Emit a type declaration. This is either a named class-type definition/ + // declaration or a typedef. In the former case the function returns the + // newly created type node. In the latter case it returns 0. // - void + type* emit_type_decl (tree decl) { tree t (TREE_TYPE (decl)); @@ -247,7 +323,7 @@ private: // covered by the typedef handling code below. The second // case will be covere by emit_type(). // - return; + return 0; } } @@ -305,6 +381,8 @@ private: unit_->new_edge<defines> (*scope_, *node, name); else unit_->new_edge<declares> (*scope_, *node, name); + + return node; } else { @@ -316,7 +394,7 @@ private: if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) && TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl) - return; + return 0; path f (DECL_SOURCE_FILE (decl)); size_t l (DECL_SOURCE_LINE (decl)); @@ -333,6 +411,8 @@ private: << DECL_SOURCE_FILE (decl) << ":" << DECL_SOURCE_LINE (decl) << endl; } + + return 0; } } @@ -457,7 +537,12 @@ private: for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); i != e; ++i) { - tree d (*i); + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); switch (TREE_CODE (d)) { @@ -469,6 +554,10 @@ private: } } + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + scope_ = prev_scope; return *ct_node; } @@ -524,7 +613,12 @@ private: for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); i != e; ++i) { - tree d (*i); + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); switch (TREE_CODE (d)) { @@ -536,6 +630,10 @@ private: } } + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + scope_ = prev_scope; return *ut_node; } @@ -660,19 +758,40 @@ private: } } + // Add location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (c)); + + if (i != loc_pragmas_.end ()) + decls.insert (i->second.begin (), i->second.end ()); + } + scope* prev_scope (scope_); scope_ = c_node; - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); i != e; ++i) { - tree d (*i); + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); switch (TREE_CODE (d)) { case TYPE_DECL: { - emit_type_decl (d); + type* n (emit_type_decl (d)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + break; } case TEMPLATE_DECL: @@ -720,11 +839,19 @@ private: << file << ":" << line << endl; } + // Process pragmas that may be associated with this field. + // + process_pragmas (d, member_node, name, b, i, e); + break; } } } + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + scope_ = prev_scope; return *c_node; } @@ -786,19 +913,40 @@ private: } } + // Add location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (u)); + + if (i != loc_pragmas_.end ()) + decls.insert (i->second.begin (), i->second.end ()); + } + scope* prev_scope (scope_); scope_ = u_node; - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); i != e; ++i) { - tree d (*i); + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); switch (TREE_CODE (d)) { case TYPE_DECL: { - emit_type_decl (d); + type* n (emit_type_decl (d)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + break; } case TEMPLATE_DECL: @@ -833,11 +981,19 @@ private: << file << ":" << line << endl; } + // Process pragmas that may be associated with this field. + // + process_pragmas (d, member_node, name, b, i, e); + break; } } } + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + scope_ = prev_scope; return *u_node; } @@ -1149,10 +1305,11 @@ private: } else { - error (G_ ("%s:%d: non-integer array index %s"), - file.string ().c_str (), - line, - tree_code_name[TREE_CODE (max)]); + cerr << file << ':' << line << ':' << clmn << ": error: " + << " non-integer array index " + << tree_code_name[TREE_CODE (max)]; + + throw failed (); } } @@ -1342,8 +1499,9 @@ private: } else { - error (G_ ("non-integer array index %s"), - tree_code_name[TREE_CODE (type)]); + // Non-integer array index which we do not support. The + // error has been/will be issued in emit_type. + // } } @@ -1403,6 +1561,80 @@ private: return r; } + void + process_pragmas (tree t, + node& node, + string const& name, + decl_set::const_iterator begin, + decl_set::const_iterator cur, + decl_set::const_iterator end) + { + // First process the position pragmas by iterating backwards + // until we get to the preceding non-pragma declaration. + // + pragma_set prags; + + if (cur != begin) + { + decl_set::const_iterator i (cur); + for (--i; i != begin && i->prag != 0; --i) ; + + // We may stop at pragma if j == b. + // + if (i->prag == 0) + ++i; + + for (; i != cur; ++i) + { + assert (!i->assoc); + + if (check_decl_type (t, name, i->prag->name, i->prag->loc)) + prags.insert (*i->prag); + else + error_++; + + i->assoc = true; // Mark this pragma as associated. + } + } + + // Now see if there are any identifier pragmas for this decl. + // By doing this after handling the position pragmas we ensure + // correct overriding. + // + { + decl_pragmas::const_iterator i (decl_pragmas_.find (t)); + + if (i != decl_pragmas_.end ()) + prags.insert (i->second.begin (), i->second.end ()); + } + + // Finally, copy the resulting pragma set to context. + // + for (pragma_set::iterator i (prags.begin ()); i != prags.end (); ++i) + { + if (trace) + ts << "\t\t pragma " << i->name << " (" << i->value << ")" + << endl; + + node.set (i->name, i->value); + } + } + + void + diagnose_unassoc_pragmas (decl_set const& decls) + { + for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + i != e; ++i) + { + if (i->prag && !i->assoc) + { + pragma const& p (*i->prag); + error_at (p.loc, "odb pragma %qs is not associated with a declaration", + p.name.c_str ()); + error_++; + } + } + } // Return declaration's fully-qualified scope name (e.g., ::foo::bar). // @@ -1456,6 +1688,8 @@ private: private: options const& ops_; + loc_pragmas const& loc_pragmas_; + decl_pragmas const& decl_pragmas_; bool trace; ostream& ts; @@ -1463,33 +1697,8 @@ private: unit* unit_; scope* scope_; - struct location_comparator - { - bool operator() (tree x, tree y) const - { - location_t xloc (DECL_SOURCE_LOCATION (x)); - location_t yloc (DECL_SOURCE_LOCATION (y)); - - if (xloc != yloc) - return xloc < yloc; - - size_t xl (LOCATION_LINE (xloc)); - size_t yl (LOCATION_LINE (yloc)); - - if (xl != yl) - return xl < yl; - - size_t xc (LOCATION_COLUMN (xloc)); - size_t yc (LOCATION_COLUMN (yloc)); - - if (xc != yc) - return xc < yc; - - return false; - } - }; + size_t error_; - typedef std::multiset<tree, location_comparator> decl_set; decl_set decls_; typedef std::map<string, fund_type*> fund_type_map; @@ -1511,13 +1720,19 @@ gate_callback (void* gcc_data, void*) try { - parser p (*options_); + parser p (*options_, loc_pragmas_, decl_pragmas_); path file (main_input_filename); auto_ptr<unit> u (p.parse (global_namespace, file)); generator g; g.generate (*options_, *u, file); } + catch (parser::failed const&) + { + // Diagnostics has aready been issued. + // + r = 1; + } catch (generator::failed const&) { // Diagnostics has aready been issued. @@ -1576,6 +1791,13 @@ plugin_init (struct plugin_name_args *plugin_info, // asm_file_name = HOST_BIT_BUCKET; + // Register callbacks. + // + register_callback (plugin_info->base_name, + PLUGIN_PRAGMAS, + register_odb_pragmas, + 0); + register_callback (plugin_info->base_name, PLUGIN_OVERRIDE_GATE, &gate_callback, diff --git a/odb/pragma.cxx b/odb/pragma.cxx new file mode 100644 index 0000000..33d69f0 --- /dev/null +++ b/odb/pragma.cxx @@ -0,0 +1,274 @@ +// file : odb/pragma.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/pragma.hxx> + +using namespace std; + +loc_pragmas loc_pragmas_; +decl_pragmas decl_pragmas_; + +static tree +parse_scoped_name (tree& t, + cpp_ttype& tt, + string& name, + bool is_type, + string const& prag) +{ + tree scope, id; + + if (tt == CPP_SCOPE) + { + name += "::"; + scope = global_namespace; + tt = pragma_lex (&t); + } + else + scope = current_scope (); + + while (true) + { + if (tt != CPP_NAME) + { + error ("invalid name in odb pragma %qs", prag.c_str ()); + return 0; + } + + id = t; + name += IDENTIFIER_POINTER (t); + tt = pragma_lex (&t); + + if (tt == CPP_SCOPE) + { + scope = lookup_qualified_name (scope, id, false, false); + + if (scope == error_mark_node) + { + error ("unable to resolve name %qs in odb pragma %qs", + name.c_str (), prag.c_str ()); + return 0; + } + + if (TREE_CODE (scope) == TYPE_DECL) + scope = TREE_TYPE (scope); + + name += "::"; + tt = pragma_lex (&t); + } + else + break; + } + + tree decl (lookup_qualified_name (scope, id, is_type, false)); + + if (decl == error_mark_node) + { + error ("unable to resolve name %qs in odb pragma %qs", + name.c_str (), prag.c_str ()); + return 0; + } + + // Get the actual type if this is a TYPE_DECL. + // + if (is_type && TREE_CODE (decl) == TYPE_DECL) + decl = TREE_TYPE (decl); + + return decl; +} + +bool +check_decl_type (tree d, string const& name, string const& p, location_t l) +{ + int tc (TREE_CODE (d)); + char const* pc (p.c_str ()); + + if (p == "column") + { + if (tc != FIELD_DECL) + { + error_at (l, "name %qs in odb pragma %qs does not refer to " + "a member variable", name.c_str (), pc); + return false; + } + } + else if (p == "table") + { + if (tc != RECORD_TYPE) + { + error_at (l, "name %qs in odb pragma %qs does not refer to a class", + name.c_str (), pc); + return false; + } + } + else + { + error ("unknown odb pragma %qs", pc); + return false; + } + + return true; +} + +static void +handle_pragma (string const& p) +{ + tree t; + cpp_ttype tt; + char const* pc (p.c_str ()); + + string val; + tree decl (0); + location_t loc (input_location); + + if (p == "column") + { + // column ([<identifier>,] "<name>") + // + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error ("%qs expected after odb pragma %qs", "(", pc); + return; + } + + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name; + decl = parse_scoped_name (t, tt, name, false, p); + + if (decl == 0) + return; + + // Make sure we've got the correct declaration type. + // + if (!check_decl_type (decl, name, p, loc)) + return; + + if (tt != CPP_COMMA) + { + error ("column name expected in odb pragma %qs", pc); + return; + } + + tt = pragma_lex (&t); + } + + if (tt != CPP_STRING) + { + error ("column name expected in odb pragma %qs", pc); + return; + } + + val = TREE_STRING_POINTER (t); + + if (pragma_lex (&t) != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of odb pragma %qs", ")", pc); + return; + } + } + else if (p == "table") + { + // table ([<identifier>,] "<name>") + // + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error ("%qs expected after odb pragma %qs", "(", pc); + return; + } + + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name; + decl = parse_scoped_name (t, tt, name, true, p); + + if (decl == 0) + return; + + // Make sure we've got the correct declaration type. + // + if (!check_decl_type (decl, name, p, loc)) + return; + + if (tt != CPP_COMMA) + { + error ("table name expected in odb pragma %qs", pc); + return; + } + + tt = pragma_lex (&t); + } + + if (tt != CPP_STRING) + { + error ("table name expected in odb pragma %qs", pc); + return; + } + + val = TREE_STRING_POINTER (t); + + if (pragma_lex (&t) != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of odb pragma %qs", ")", pc); + return; + } + } + else + { + error ("unknown odb pragma %qs", pc); + return; + } + + // Record this pragma. + // + pragma prag (p, val, loc); + + if (decl) + decl_pragmas_[decl].insert (prag); + else + { + tree scope (current_scope ()); + + if (!CLASS_TYPE_P (scope)) + scope = global_namespace; + + loc_pragmas_[scope].push_back (prag); + } + + // See if there are any more pragmas. + // + tt = pragma_lex (&t); + + if (tt == CPP_NAME) + { + handle_pragma (IDENTIFIER_POINTER (t)); + } + else if (tt != CPP_EOF) + error ("unexpected text after %qs in odb pragma", p.c_str ()); +} + +extern "C" void +handle_pragma_odb_column (cpp_reader*) +{ + handle_pragma ("column"); +} + +extern "C" void +handle_pragma_odb_table (cpp_reader*) +{ + handle_pragma ("table"); +} + +extern "C" void +register_odb_pragmas (void*, void*) +{ + c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column); + c_register_pragma_with_expansion ("odb", "table", handle_pragma_odb_table); +} diff --git a/odb/pragma.hxx b/odb/pragma.hxx new file mode 100644 index 0000000..1a8a98f --- /dev/null +++ b/odb/pragma.hxx @@ -0,0 +1,89 @@ +// file : odb/pragma.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PRAGMA_HXX +#define ODB_PRAGMA_HXX + +#include <odb/gcc.hxx> + +#include <map> +#include <set> +#include <vector> +#include <string> + +struct pragma +{ + pragma (std::string const& n, std::string const& v, location_t l) + : name (n), value (v), loc (l) + { + } + + bool + operator< (pragma const& y) const + { + return name < y.name; + } + + std::string name; + std::string value; + location_t loc; +}; + +typedef std::vector<pragma> pragma_list; + +// A set of pragmas. Insertion of a pragma with the same name +// overrides the old value. +// +struct pragma_set: std::set<pragma> +{ + typedef std::set<pragma> base; + + void + insert (pragma const& p) + { + std::pair<iterator, bool> r (base::insert (p)); + + if (!r.second) + { + pragma& x (const_cast<pragma&> (*r.first)); + x = p; + } + } + + template <typename I> + void + insert (I begin, I end) + { + for (; begin != end; ++begin) + insert (*begin); + } +}; + + +// Position pragmas inside a class or namespace. The key for the +// namespace case is the global_namespace node. +// +typedef std::map<tree, pragma_list> loc_pragmas; + +// Pragmas associated with this declaration. +// +typedef std::map<tree, pragma_set> decl_pragmas; + +extern loc_pragmas loc_pragmas_; +extern decl_pragmas decl_pragmas_; + +extern "C" void +register_odb_pragmas (void*, void*); + +// Check that the pragma is applicable to the declaration. Return true +// on success, complain and return false otherwise. +// +bool +check_decl_type (tree decl, + std::string const& name, + std::string const& prag, + location_t); + +#endif // ODB_PRAGMA_HXX |