]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Add a program that is able to generate lists of explicit instantiations for arbitrary...
authorbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 2 Dec 2007 04:04:40 +0000 (04:04 +0000)
committerbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 2 Dec 2007 04:04:40 +0000 (04:04 +0000)
git-svn-id: https://svn.dealii.org/trunk@15563 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/common/scripts/Makefile
deal.II/common/scripts/expand_instantiations.cc [new file with mode: 0644]

index c799b3d793423a58d0533158627cac657aa69dd6..13de5d253e3bc1358072b14bef00ad19ea660f3a 100644 (file)
@@ -14,6 +14,9 @@ ifeq ($(GXX-VERSION),compaq_cxx)
   XLDFLAGS = $(LDFLAGS:-shared=)
 endif
 
+default: make_dependencies expand_instantiations
+
+
 # rules to generate the program. let is be dependent on the global flags for
 # the following reason: if you go to a different system, but keep with the
 # same directory, you get into trouble because make_dependencies is not
@@ -24,8 +27,14 @@ make_dependencies : make_dependencies.cc $D/common/Make.global_options
        @echo ============================ Compiling $@
        @$(CXX) $(CXXFLAGS.o) $(LDFLAGS) $< -o $@
 
+expand_instantiations : expand_instantiations.cc $D/common/Make.global_options
+       @echo ============================ Compiling $@
+       @$(CXX) $(CXXFLAGS.g) $(LDFLAGS) $< -o $@
+
 clean:
        -rm -f make_dependencies
        -rm -f make_dependencies.o
+       -rm -f expand_instantiations
+       -rm -f expand_instantiations.o
 
 .PHONY: clean
diff --git a/deal.II/common/scripts/expand_instantiations.cc b/deal.II/common/scripts/expand_instantiations.cc
new file mode 100644 (file)
index 0000000..1354295
--- /dev/null
@@ -0,0 +1,404 @@
+//----------------------------  expand_instantiations.cc  -------------------
+//    $Id: expand_instantiations.cc 8165 2003-10-24 22:34:01Z deal $
+//    Version: $Name$
+//
+//    Copyright (C) 2007 by the deal.II authors
+//
+//    This file is subject to QPL and may not be  distributed
+//    without copyright and license information. Please refer
+//    to the file deal.II/doc/license.html for the  text  and
+//    further information on this license.
+//
+//----------------------------  expand_instantiations.cc  -------------------
+
+// This is the program that we use to generate explicit instantiations for a
+// variety of template arguments. It takes two kinds of input files. The first
+// is given as arguments on the command line and contains entries of the
+// following form:
+// --------------------
+// REAL_SCALARS    := { double; float; long double }
+// COMPLEX_SCALARS := { std::complex<double>;
+//                      std::complex<float>;
+//                      std::complex<long double> }
+// VECTORS := { Vector<double>; Vector<float>; Vector<long double> }
+// --------------------
+//
+// The input file of this form is typically located in the common/ directory
+// and is generated by ./configure to contain the list of vectors etc that
+// make sense for the current configuration. For example, the list of VECTORS
+// is going to contain PETSc vectors if so configured.
+//
+// The second intput is read from the command line and consists of a sequence
+// of statements of the following form:
+// --------------------
+// for (u,v:VECTORS; z:SCALARS) { f(u, z, const v &); }
+// --------------------
+// Here, everything between {...} will be copied as many times as there are
+// combinations of arguments u,v in the list of substitutions given by
+// VECTORS. For each copy, the arguments u,v will be replaced by one of these
+// combinations.
+
+// Author: Wolfgang Bangerth, 2007
+
+
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <list>
+
+
+// a map from the keys in the expansion lists to the list itself. For
+// instance, the example above will lead to the entry
+//      expansion_lists[REAL_SCALARS] = (double, float, long double)
+// in this map, among others
+std::map<std::string, std::list<std::string> >  expansion_lists;
+
+
+
+// extract from the start of #in the part of the string that ends with one of
+// the characters in #delim_list. The extracted part is deleted from #in
+std::string
+get_substring_with_delim (std::string       &in,
+                         const std::string &delim_list)
+{
+  std::string x;
+  while ((in.size() != 0)
+        &&
+        (delim_list.find (in[0]) == std::string::npos))
+    {
+      x += in[0];
+      in.erase (0, 1);
+    }
+
+  return x;
+}
+
+
+void
+skip_space (std::string &in)
+{
+  while ((in.size() != 0)
+        &&
+        ((in[0] == ' ') || (in[0] == '\t') || (in[0] == '\n')))
+    in.erase (0, 1);
+}
+
+
+
+std::string read_whole_file (std::istream &in)
+{
+  std::string whole_file;
+  while (in)
+    {
+      std::string line;
+      getline (in, line);
+
+      if (line.find ("//") != 0)
+       {
+         whole_file += line;
+         whole_file += '\n';
+       }
+    }
+                                  // substitute tabs by spaces, multiple
+                                  // spaces by single ones
+  for (unsigned int i=0; i<whole_file.size(); ++i)
+    if (whole_file[i] == '\t')
+      whole_file[i] = ' ';
+  while (whole_file.find("  ") != std::string::npos)
+    whole_file.replace (whole_file.find("  "), 2, " ");
+
+  return whole_file;
+}
+
+
+
+std::list<std::string>
+split_string_list (const std::string &s,
+                  const char         delimiter)
+{
+  std::string tmp = s;
+  std::list<std::string> split_list;
+
+                                  // split the input list
+  while (tmp.length() != 0)
+    {
+      std::string name;
+      name = tmp;
+
+      if (name.find(delimiter) != std::string::npos)
+       {
+         name.erase (name.find(delimiter), std::string::npos);
+         tmp.erase (0, tmp.find(delimiter)+1);
+       }
+      else
+       tmp = "";
+      
+      while ((name.length() != 0) &&
+            (name[0] == ' '))
+       name.erase (0,1);
+
+      while (name[name.length()-1] == ' ')
+       name.erase (name.length()-1, 1);
+
+      split_list.push_back (name);
+    }
+
+  return split_list;
+}
+
+
+
+void read_expansion_lists (const std::string &filename)
+{
+  std::ifstream in (filename.c_str());
+
+  if (! in)
+    {
+      std::cerr << "Instantiation list file can not be read!"
+               << std::endl;
+      std::exit (1);
+    }
+
+                                  // read the entire file into a string for
+                                  // simpler processing. replace end-of-line
+                                  // characters by spaces
+  std::string whole_file = read_whole_file (in);
+
+                                  // now process entries of the form
+                                  // NAME := { class1; class2; ...}.
+  while (whole_file.size() != 0)
+    {
+      const std::string
+       name = get_substring_with_delim (whole_file, " :");
+
+      skip_space (whole_file);
+      if (whole_file.find (":=") != 0)
+       {
+         std::cerr << "Invalid entry <" << name << '>' << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 2);
+      skip_space (whole_file);
+      if (whole_file.find ("{") != 0)
+       {
+         std::cerr << "Invalid entry <" << name << '>' << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 1);
+      skip_space (whole_file);
+
+      std::string
+       expansion = get_substring_with_delim (whole_file, "}");
+
+      if (whole_file.find ("}") != 0)
+       {
+         std::cerr << "Invalid entry <" << name << '>' << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 1);
+      skip_space (whole_file);
+
+      expansion_lists[name] = split_string_list (expansion, ';');
+    }
+}
+
+
+bool is_real_token (const std::string &text,
+                   const std::string::size_type pos,
+                   const std::string::size_type length)
+{
+  static const std::string token_chars ("abcdefghijklmnopqrstuvwxyz"
+                                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                       "0123456789"
+                                       "_");
+  if ((pos != 0) && (token_chars.find (text[pos-1]) != std::string::npos))
+    return false;
+
+  if ((pos+length < text.size()) &&
+      (token_chars.find (text[pos+length]) != std::string::npos))
+    return false;
+
+  return true;
+}
+
+    
+std::string substitute_tokens (const std::string &text,
+                              const std::string &token,
+                              const std::string &substitute)
+{
+  std::string x_text = text;
+  std::string::size_type pos = 0;
+  while ((pos = x_text.find(token, pos)) != std::string::npos)
+    {
+      if (is_real_token (x_text, pos, token.size()))
+       {  
+         x_text.replace (pos, token.size(), substitute);
+         pos += substitute.size();
+       }
+      else
+       ++pos;
+    }
+  
+  return x_text;
+}
+
+
+
+void substitute (const std::string &text,
+                const std::list<std::pair<std::string, std::string> > &substitutions)
+{
+                                  // do things recursively: if the list of
+                                  // substiutions has a single entry, then
+                                  // process all of them. otherwise, process
+                                  // the first in the list and call the
+                                  // function recursively with the rest of
+                                  // the substitutions
+  if (substitutions.size() > 1)
+    {
+                                      // do the first substitution, then call
+                                      // function recursively
+      const std::string name    = substitutions.front().first,
+                       pattern = substitutions.front().second;
+
+      const std::list<std::pair<std::string, std::string> >
+       rest_of_substitutions (++substitutions.begin(),
+                              substitutions.end());
+
+      for (std::list<std::string>::const_iterator
+            expansion = expansion_lists[pattern].begin();
+          expansion != expansion_lists[pattern].end();
+          ++expansion)
+       {
+         std::string new_text
+           = substitute_tokens (text, name, *expansion);
+
+         substitute (new_text, rest_of_substitutions);
+       }
+    }
+  else if (substitutions.size() == 1)
+    {
+                                      // do the substitutions
+      const std::string name    = substitutions.front().first,
+                       pattern = substitutions.front().second;
+      
+      for (std::list<std::string>::const_iterator
+            expansion = expansion_lists[pattern].begin();
+          expansion != expansion_lists[pattern].end();
+          ++expansion)
+       std::cout << substitute_tokens (text, name, *expansion)
+                 << std::endl;
+    }
+  else
+    {
+      std::cout << text
+               << std::endl;
+    }
+}
+
+
+
+void process_instantiations ()
+{
+  std::string whole_file = read_whole_file (std::cin);
+
+                                  // process entries of the form
+                                  //  for (X:Y; A:B) { INST }
+  while (whole_file.size() != 0)
+    {
+      skip_space (whole_file);
+      if (whole_file.find ("for") != 0)
+       {
+         std::cerr << "Invalid instantiation list" << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 3);
+      skip_space (whole_file);
+      if (whole_file.find ("(") != 0)
+       {
+         std::cerr << "Invalid instantiation list" << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 1);
+      skip_space (whole_file);
+
+      const std::list<std::string>
+       substitutions_list
+       = split_string_list (get_substring_with_delim (whole_file,
+                                                                    ")"),
+                                          ';');
+      if (whole_file.find (")") != 0)
+       {
+         std::cerr << "Invalid instantiation list" << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 1);
+      skip_space (whole_file);
+
+                                      // process the header
+      std::list<std::pair<std::string, std::string> >
+       substitutions;
+      
+      for (std::list<std::string>::const_iterator
+            s = substitutions_list.begin();
+          s != substitutions_list.end(); ++s)
+       {
+         const std::list<std::string>
+           names_and_type = split_string_list (*s, ':');
+         if (names_and_type.size() != 2)
+           {
+             std::cerr << "Invalid instantiation header" << std::endl;
+             std::exit (1);
+           }
+         
+         const std::list<std::string>
+           names = split_string_list (names_and_type.front(), ',');
+
+         for (std::list<std::string>::const_iterator
+                x = names.begin(); x != names.end(); ++x)
+           substitutions.push_back (std::make_pair (*x,
+                                                    names_and_type.back()));
+       }
+
+//       for (std::list<std::pair<std::string, std::string> >::const_iterator
+//          x = substitutions.begin(); x != substitutions.end(); ++x)
+//     std::cout << x->first
+//               << "->"
+//               << x->second
+//               << std::endl;
+
+                                      // now read the part in {...}
+      skip_space (whole_file);
+      if (whole_file.find ("{") != 0)
+       {
+         std::cerr << "Invalid substitution text" << std::endl;
+         std::exit (1);
+       }
+      whole_file.erase (0, 1);
+      skip_space (whole_file);
+      const std::string text_to_substitute
+       = get_substring_with_delim (whole_file, "}");
+      whole_file.erase (0,1);
+      skip_space (whole_file);
+
+                                      // now produce the substitutions
+      substitute (text_to_substitute, substitutions);
+    }
+}
+
+
+
+int main (int argc, char **argv)
+{
+  if (argc < 2)
+    {
+      std::cerr << "Usage: " << std::endl
+               << "  expand_instantiations class_list_file < in_file > out_file"
+               << std::endl;
+      std::exit (1);
+    }
+
+  for (int i=1; i<argc; ++i)
+    read_expansion_lists (argv[i]);
+
+  process_instantiations ();
+}

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.