From 531aa50a582a573ac84e6ed9d60373fb7ea3f547 Mon Sep 17 00:00:00 2001 From: bangerth Date: Sun, 2 Dec 2007 04:04:40 +0000 Subject: [PATCH] Add a program that is able to generate lists of explicit instantiations for arbitrary combinations of token substitutions. git-svn-id: https://svn.dealii.org/trunk@15563 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/common/scripts/Makefile | 9 + .../common/scripts/expand_instantiations.cc | 404 ++++++++++++++++++ 2 files changed, 413 insertions(+) create mode 100644 deal.II/common/scripts/expand_instantiations.cc diff --git a/deal.II/common/scripts/Makefile b/deal.II/common/scripts/Makefile index c799b3d793..13de5d253e 100644 --- a/deal.II/common/scripts/Makefile +++ b/deal.II/common/scripts/Makefile @@ -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 index 0000000000..13542959c5 --- /dev/null +++ b/deal.II/common/scripts/expand_instantiations.cc @@ -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; +// std::complex; +// std::complex } +// VECTORS := { Vector; Vector; Vector } +// -------------------- +// +// 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 +#include +#include +#include + + +// 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 > 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 +split_string_list (const std::string &s, + const char delimiter) +{ + std::string tmp = s; + std::list 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 > &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 > + rest_of_substitutions (++substitutions.begin(), + substitutions.end()); + + for (std::list::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::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 + 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 > + substitutions; + + for (std::list::const_iterator + s = substitutions_list.begin(); + s != substitutions_list.end(); ++s) + { + const std::list + 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 + names = split_string_list (names_and_type.front(), ','); + + for (std::list::const_iterator + x = names.begin(); x != names.end(); ++x) + substitutions.push_back (std::make_pair (*x, + names_and_type.back())); + } + +// for (std::list >::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