1 /*! 2 * \file MFrontUtilities.cxx 3 * \brief 4 * \author Thomas Helfer 5 * \date 15 août 2015 6 * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights 7 * reserved. 8 * This project is publicly released under either the GNU GPL Licence 9 * or the CECILL-A licence. A copy of thoses licences are delivered 10 * with the sources of TFEL. CEA or EDF may also distribute this 11 * project under specific licensing conditions. 12 */ 13 14 #include <cctype> 15 #include <sstream> 16 #include <ostream> 17 #include <cstring> 18 #include <stdexcept> 19 #include <algorithm> 20 #include "TFEL/Raise.hxx" 21 #include "TFEL/UnicodeSupport/UnicodeSupport.hxx" 22 #include "TFEL/Utilities/StringAlgorithms.hxx" 23 #include "MFront/VariableBoundsDescription.hxx" 24 #include "MFront/MFrontUtilities.hxx" 25 26 namespace mfront{ 27 insert_if(std::vector<std::string> & d,const std::string & v)28 void insert_if(std::vector<std::string>& d, const std::string& v) { 29 if(v.empty()){ 30 return; 31 } 32 if(std::find(d.begin(),d.end(),v)==d.end()){ 33 d.push_back(v); 34 } 35 } 36 insert_if(std::vector<std::string> & d,const char * const v)37 void insert_if(std::vector<std::string>& d, const char* const v) { 38 if(v==nullptr){ 39 return; 40 } 41 if(strlen(v)==0){ 42 return; 43 } 44 if(std::find(d.begin(),d.end(),v)==d.end()){ 45 d.emplace_back(v); 46 } 47 } 48 write(std::ostream & os,const std::vector<std::string> & v,const std::string & id)49 void write(std::ostream& os, 50 const std::vector<std::string>& v, 51 const std::string& id){ 52 using tfel::utilities::replace_all; 53 if(v.empty()){ 54 return; 55 } 56 os << id << " : {\n"; 57 for(auto p = v.begin();p!=v.end();){ 58 os << "\"" << replace_all(*p,"\"","\\\"") 59 << "\""; 60 if(++p!=v.end()){ 61 os << ",\n"; 62 } else { 63 os << "\n"; 64 } 65 } 66 os << "};\n"; 67 } // end of write 68 69 template<> read(tfel::utilities::CxxTokenizer::const_iterator & p,const tfel::utilities::CxxTokenizer::const_iterator pe)70 double read(tfel::utilities::CxxTokenizer::const_iterator& p, 71 const tfel::utilities::CxxTokenizer::const_iterator pe) 72 { 73 auto c = p; 74 auto r = tfel::utilities::CxxTokenizer::readDouble(c,pe); 75 p=c; 76 return r; 77 } // end of read 78 79 template<> 80 std::string read(tfel::utilities::CxxTokenizer::const_iterator & p,const tfel::utilities::CxxTokenizer::const_iterator pe)81 read(tfel::utilities::CxxTokenizer::const_iterator& p, 82 const tfel::utilities::CxxTokenizer::const_iterator pe) 83 { 84 auto c = p; 85 const auto r = tfel::utilities::CxxTokenizer::readString(c,pe); 86 p=c; 87 const auto v = tfel::utilities::replace_all(r,"\\\"","\""); 88 return v; 89 } // end of read 90 91 template<> 92 std::vector<std::string> read(tfel::utilities::CxxTokenizer::const_iterator & p,const tfel::utilities::CxxTokenizer::const_iterator pe)93 read(tfel::utilities::CxxTokenizer::const_iterator& p, 94 const tfel::utilities::CxxTokenizer::const_iterator pe) 95 { 96 auto c = p; 97 auto r = tfel::utilities::CxxTokenizer::readStringArray(c,pe); 98 for(auto&s : r){ 99 s = tfel::utilities::replace_all(s,"\\\"","\""); 100 } 101 p=c; 102 return r; 103 } // end of read 104 readVariableBounds(tfel::utilities::CxxTokenizer::const_iterator & p,const tfel::utilities::CxxTokenizer::const_iterator pe)105 std::pair<std::string, VariableBoundsDescription> readVariableBounds( 106 tfel::utilities::CxxTokenizer::const_iterator& p, 107 const tfel::utilities::CxxTokenizer::const_iterator pe) { 108 using tfel::utilities::CxxTokenizer; 109 const std::string m = "mfront::readVariableBounds"; 110 auto throw_if = [&m](const bool b, const std::string& msg) { 111 tfel::raise_if(b, m + ": " + msg); 112 }; 113 VariableBoundsDescription b; 114 CxxTokenizer::checkNotEndOfLine(m, p, pe); 115 auto n = tfel::unicode::getMangledString(p->value); 116 ++p; 117 CxxTokenizer::checkNotEndOfLine(m, "Expected '[' or '(' or 'in'.", p, pe); 118 if (p->value == "[") { 119 CxxTokenizer::readSpecifiedToken(m, "[", p, pe); 120 CxxTokenizer::checkNotEndOfLine(m, p, pe); 121 std::string position(p->value); 122 std::istringstream converter(position); 123 unsigned int pos; 124 converter >> pos; 125 throw_if(!converter || (!converter.eof()), 126 "could not read position number for variable '" + n + "'"); 127 ++p; 128 CxxTokenizer::checkNotEndOfLine(m, p, pe); 129 CxxTokenizer::readSpecifiedToken(m, "]", p, pe); 130 n += '[' + position + ']'; 131 } 132 CxxTokenizer::checkNotEndOfLine(m, "Expected '(' or 'in'.", p, pe); 133 if (p->value == "(") { 134 CxxTokenizer::readSpecifiedToken(m, "(", p, pe); 135 CxxTokenizer::checkNotEndOfLine(m, p, pe); 136 if (p->value != "*") { 137 unsigned int component; 138 std::istringstream converter(p->value); 139 converter >> component; 140 throw_if(!converter || (!converter.eof()), 141 "could not read component number for variable '" + n + "'"); 142 b.component = component; 143 } 144 ++(p); 145 CxxTokenizer::checkNotEndOfLine(m, p, pe); 146 CxxTokenizer::readSpecifiedToken(m, ")", p, pe); 147 } 148 CxxTokenizer::readSpecifiedToken(m, "in", p, pe); 149 CxxTokenizer::checkNotEndOfLine( 150 m, "Expected '\u211D\u208A', '\u211D\u208B', ']' or '['.", p, pe); 151 if (p->value == "\u211D\u208A") { 152 b.lowerBound = 0.; 153 b.boundsType = VariableBoundsDescription::LOWER; 154 } else if (p->value == "\u211D\u208B") { 155 b.upperBound = 0.; 156 b.boundsType = VariableBoundsDescription::UPPER; 157 } else { 158 if (p->value == "]") { 159 ++p; 160 CxxTokenizer::checkNotEndOfLine(m, "Expected '*'.", p, pe); 161 throw_if(p->value != "*", "Expected '*' (read '" + p->value + "')"); 162 b.boundsType = VariableBoundsDescription::UPPER; 163 ++p; 164 } else if (p->value == "[") { 165 ++p; 166 CxxTokenizer::checkNotEndOfLine( 167 m, "Expected lower bound value for variable '" + n + "'", p, pe); 168 b.lowerBound = mfront::read<double>(p, pe); 169 b.boundsType = VariableBoundsDescription::LOWERANDUPPER; 170 } else { 171 throw_if(true, "Expected ']' or '[' (read '" + p->value + "')"); 172 } 173 CxxTokenizer::readSpecifiedToken(m, ":", p, pe); 174 CxxTokenizer::checkNotEndOfLine( 175 m, "expected upper bound value for variable '" + n + "'", p, pe); 176 if (p->value == "*") { 177 throw_if(b.boundsType == VariableBoundsDescription::UPPER, 178 "Upper and lower values bounds are both infinity. " 179 "This is inconsistent."); 180 b.boundsType = VariableBoundsDescription::LOWER; 181 ++p; 182 CxxTokenizer::readSpecifiedToken(m, "[", p, pe); 183 } else { 184 b.upperBound = mfront::read<double>(p, pe); 185 if (b.boundsType == VariableBoundsDescription::LOWERANDUPPER) { 186 throw_if(b.lowerBound > b.upperBound, 187 "Lower bound value is greater than upper " 188 "bound value for variable '" + 189 n + "'"); 190 } 191 CxxTokenizer::readSpecifiedToken(m, "]", p, pe); 192 } 193 } 194 return std::make_pair(n, b); 195 } // end of readVariableBounds 196 197 std::tuple<std::string, bool, unsigned short> extractVariableNameAndArrayPosition(const std::string & n)198 extractVariableNameAndArrayPosition(const std::string& n) { 199 auto throw_if = [](const bool c, const std::string& m) { 200 tfel::raise_if(c, "mfront::extractVariableNameAndArrayPosition: " + m); 201 }; 202 unsigned short i = 0; 203 auto p = n.cbegin(); 204 auto pe = n.cend(); 205 while ((p != pe) && (*p != '[')) { 206 ++p; 207 } 208 if (p == pe) { 209 return std::make_tuple(n, false, i); 210 } 211 auto r = std::string{n.cbegin(), p}; 212 ++p; 213 throw_if(p == pe, "unexpected end of string 'n'"); 214 throw_if(!std::isdigit(*p), "unexpected a digit 'n'"); 215 while ((p != pe) && (std::isdigit(*p))) { 216 i *= 10; 217 i += *p - '0'; 218 ++p; 219 } 220 throw_if(p == pe, "unexpected end of string '" + n + "'"); 221 throw_if(*p != ']', "invalid variable name '" + n + "'"); 222 ++p; 223 throw_if(p != pe, "invalid variable name '" + n + "'"); 224 return std::make_tuple(r, true, i); 225 } // end of extractVariableNameAndArrayPosition 226 227 } // end of namespace mfront 228