The open source CFD toolbox
ifeqEntry.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2018 OpenFOAM Foundation
9 Copyright (C) 2019-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "ifeqEntry.H"
30#include "ifEntry.H"
31#include "stringOps.H"
33
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35
36namespace Foam
37{
38namespace functionEntries
39{
41
43 (
46 execute,
47 dictionaryIstream,
48 ifeq
49 );
50} // End namespace functionEntries
51} // End namespace Foam
52
53
54// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55
57{
58 // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
59 do
60 {
62 {
63 return;
64 }
65 }
66 while (t == token::END_STATEMENT);
67}
68
69
70Foam::token Foam::functionEntries::ifeqEntry::expandToken
71(
72 const dictionary& dict,
73 const string& keyword,
74 const token& t
75)
76{
77 if (keyword[0] == '$') 78 { 79 const word varName(keyword.substr(1)); 80 81 // Lookup the variable name in the given dictionary 82 const entry* ePtr = dict.findScoped(varName, keyType::REGEX_RECURSIVE); 83 if (ePtr) 84 { 85 return token(ePtr->stream()); 86 } 87 else 88 { 89 // String expansion. Allow unset variables 90 string expanded(keyword); 91 stringOps::inplaceExpand(expanded, dict, true, true); 92 93 // Re-form as a string token so we can compare to string 94 return token(expanded, t.lineNumber()); 95 } 96 } 97 else if (!t.isString()) 98 { 99 // Re-form as a string token so we can compare to string 100 return token(keyword, t.lineNumber()); 101 } 102 103 return t; 104} 105 106 107Foam::token Foam::functionEntries::ifeqEntry::expandToken 108( 109 const dictionary& dict, 110 const token& t 111) 112{ 113 if (t.isWord()) 114 { 115 return expandToken(dict, t.wordToken(), t); 116 } 117 else if (t.isVariable()) 118 { 119 return expandToken(dict, t.stringToken(), t); 120 } 121 else if (t.isString()) 122 { 123 return expandToken(dict, t.stringToken(), t); 124 } 125 126 return t; 127} 128 129 130bool Foam::functionEntries::ifeqEntry::equalToken 131( 132 const token& t1, 133 const token& t2 134) 135{ 136 const bool eqType = (t1.type() == t2.type()); 137 138 switch (t1.type()) 139 { 140 case token::UNDEFINED: 141 return eqType; 142 143 case token::BOOL: 144 return (eqType && t1.boolToken() == t2.boolToken()); 145 146 case token::FLAG: 147 return (eqType && t1.flagToken() == t2.flagToken()); 148 150 return (eqType && t1.pToken() == t2.pToken()); 151 152 case token::WORD: 153 case token::DIRECTIVE: 154 if (t2.isWord()) 155 { 156 return t1.wordToken() == t2.wordToken(); 157 } 158 else if (t2.isString()) 159 { 160 const wordRe w2(t2.stringToken(), wordRe::DETECT); 161 return w2.match(t1.wordToken()); 162 } 163 return false; 164 165 case token::STRING: 166 if (eqType) 167 { 168 const wordRe w1(t1.stringToken(), wordRe::DETECT); 169 const wordRe w2(t2.stringToken(), wordRe::DETECT); 170 return w1.match(w2) || w2.match(w1); 171 } 172 else if (t2.isWord()) 173 { 174 const wordRe w1(t1.stringToken(), wordRe::DETECT); 175 return w1.match(t2.wordToken()); 176 } 177 return false; 178 179 case token::VARIABLE: 180 case token::VERBATIM: 181 if (t2.isStringType()) 182 { 183 return t1.stringToken() == t2.stringToken(); 184 } 185 return false; 186 187 case token::LABEL: 188 if (eqType) 189 { 190 return t1.labelToken() == t2.labelToken(); 191 } 192 else if (t2.isScalar()) 193 { 194 return t1.labelToken() == t2.scalarToken(); 195 } 196 return false; 197 198 case token::FLOAT: 199 if (eqType) 200 { 201 return equal(t1.floatToken(), t2.floatToken()); 202 } 203 else if (t2.isLabel()) 204 { 205 return t1.floatToken() == t2.labelToken(); 206 } 207 else if (t2.isScalar()) 208 { 209 return t1.scalarToken() == t2.scalarToken(); 210 } 211 return false; 212 213 case token::DOUBLE: 214 if (eqType) 215 { 216 return equal(t1.doubleToken(), t2.doubleToken()); 217 } 218 else if (t2.isLabel()) 219 { 220 return t1.doubleToken() == t2.labelToken(); 221 } 222 else if (t2.isScalar()) 223 { 224 return t1.scalarToken() == t2.scalarToken(); 225 } 226 return false; 227 229 return false; 230 231 case token::COMPOUND: 232 return false; 233 234 case token::ERROR: 235 return eqType; 236 } 237 238 return false; 239} 240 241 242void Foam::functionEntries::ifeqEntry::skipUntil 243( 244 DynamicList<filePos>& stack, 245 const dictionary& parentDict, 246 const word& endDirective, 247 Istream& is 248) 249{ 250 while (!is.eof()) 251 { 252 token t; 253 readToken(t, is); 254 255 if (!t.isDirective()) 256 { 257 continue; 258 } 259 else if (t.wordToken() == "#if" || t.wordToken() == "#ifeq") 260 { 261 stack.append(filePos(is.name(), is.lineNumber())); 262 skipUntil(stack, parentDict, "#endif", is); 263 stack.remove(); 264 } 265 else if (t.wordToken() == endDirective) 266 { 267 return; 268 } 269 } 270 271 FatalIOErrorInFunction(parentDict) 272 << "Did not find matching " << endDirective << nl 273 << exit(FatalIOError); 274} 275 276 277// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // 278 280( 281 const bool doIf, 283 dictionary& parentDict, 284 Istream& is 285) 286{ 287 while (!is.eof()) 288 { 289 token t; 290 readToken(t, is); 291 bool pending = false; 292 293 if (t.isDirective()) 294 { 295 if (t.wordToken() == "#ifeq") 296 { 297 // Recurse to evaluate 298 execute(stack, parentDict, is); 299 } 300 else if (t.wordToken() == "#if") 301 { 302 // Recurse to evaluate 303 ifEntry::execute(stack, parentDict, is); 304 } 305 else if 306 ( 307 doIf 308 && (t.wordToken() == "#else" || t.wordToken() == "#elif") 309 ) 310 { 311 // Now skip until #endif 312 skipUntil(stack, parentDict, "#endif", is); 313 stack.remove(); 314 break; 315 } 316 else if (t.wordToken() == "#endif") 317 { 318 stack.remove(); 319 break; 320 } 321 else 322 { 323 pending = true; 324 } 325 } 326 else 327 { 328 pending = true; 329 } 330 331 if (pending) 332 { 333 is.putBack(t); 334 bool ok = entry::New(parentDict, is); 335 if (!ok) 336 { 337 return false; 338 } 339 } 340 } 341 return true; 342} 343 344 346( 347 const bool doIf, 349 dictionary& parentDict, 350 Istream& is 351) 352{ 353 if (doIf) 354 { 355 evaluate(true, stack, parentDict, is); 356 } 357 else 358 { 359 // Fast-forward to #else 360 token t; 361 while (!is.eof()) 362 { 363 readToken(t, is); 364 365 // Only consider directives 366 if (!t.isDirective()) 367 { 368 continue; 369 } 370 371 if (t.wordToken() == "#if" || t.wordToken() == "#ifeq") 372 { 373 stack.append(filePos(is.name(), is.lineNumber())); 374 skipUntil(stack, parentDict, "#endif", is); 375 stack.remove(); 376 } 377 else if (t.wordToken() == "#else") 378 { 379 break; 380 } 381 else if (t.wordToken() == "#elif") 382 { 383 // const label lineNo = is.lineNumber(); 384 385 // Read line 386 string line; 387 dynamic_cast<ISstream&>(is).getLine(line); 388 line += ';'; 389 IStringStream lineStream(line); 390 const primitiveEntry e("ifEntry", parentDict, lineStream); 391 392 if (ifEntry::isTrue(e.stream())) 393 { 394 // Info<< "Using #elif " << doIf << " - line " << lineNo 395 // << " in file " << is.relativeName() << endl; 396 break; 397 } 398 } 399 else if (t.wordToken() == "#endif") 400 { 401 stack.remove(); 402 break; 403 } 404 } 405 406 if (t.wordToken() == "#else") 407 { 408 // Evaluate until we hit #endif 409 evaluate(false, stack, parentDict, is); 410 } 411 else if (t.wordToken() == "#elif") 412 { 413 // Evaluate until we hit #else or #endif 414 evaluate(true, stack, parentDict, is); 415 } 416 } 417 return true; 418} 419 420 422( 424 dictionary& parentDict, 425 Istream& is 426) 427{ 428 const label nNested = stack.size(); 429 430 stack.append(filePos(is.name(), is.lineNumber())); 431 432 // Read first token and expand any string 433 token cond1(is); 434 cond1 = expandToken(parentDict, cond1); 435 436 // Read second token and expand any string 437 token cond2(is); 438 cond2 = expandToken(parentDict, cond2); 439 440 const bool equal = equalToken(cond1, cond2); 441 442 // Info<< "Using #" << typeName << " " << cond1 443 // << " == " << cond2 444 // << " at line " << stack.last().second() 445 // << " in file " << stack.last().first() << endl; 446 447 bool ok = ifeqEntry::execute(equal, stack, parentDict, is); 448 449 if (stack.size() != nNested) 450 { 451 FatalIOErrorInFunction(parentDict) 452 << "Did not find matching #endif for condition starting" 453 << " at line " << stack.last().second() 454 << " in file " << stack.last().first() << exit(FatalIOError); 455 } 456 457 return ok; 458} 459 460 461// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // 462 464( 465 dictionary& parentDict, 466 Istream& is 467) 468{ 469 DynamicList<filePos> stack(10); 470 return execute(stack, parentDict, is); 471} 472 473 474// ************************************************************************* // Macros for easy insertion into member function selection tables. #define addNamedToMemberFunctionSelectionTable(baseType, thisType, funcName, argNames, lookupName) Add to hash-table of functions with 'lookupName' as the key. #define w2 Definition: blockCreate.C:35 #define w1 Definition: blockCreate.C:34 A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects. Definition: DynamicList.H:72 T remove() Remove and return the last element. Fatal on an empty list. Definition: DynamicListI.H:655 void append(const T &val) Copy append an element to the end of this list. Definition: DynamicListI.H:503 void evaluate() Evaluate boundary conditions. label lineNumber() const noexcept Const access to the current stream line number. Definition: IOstream.H:318 virtual const fileName & name() const Return the name of the stream. Definition: IOstream.C:40 bool eof() const noexcept True if end of input seen. Definition: IOstream.H:239 Generic input stream using a standard (STL) stream. Definition: ISstream.H:58 Input from string buffer, using a ISstream. Always UNCOMPRESSED. Definition: StringStream.H:112 An Istream is an abstract base class for all input systems (streams, files, token lists etc).... Definition: Istream.H:64 void putBack(const token &tok) Put back a token. Only a single put back is permitted. Definition: Istream.C:70 static autoPtr< Time > New() Construct (dummy) Time - no functionObjects or libraries. Definition: Time.C:717 A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa... Definition: Tuple2.H:58 void size(const label n) Older name for setAddressableSize. Definition: UList.H:114 T & last() Return the last element of the list. Definition: UListI.H:216 A list of keyword definitions, which are a keyword followed by a number of values (eg,... Definition: dictionary.H:126 Conditional parsing of dictionary entries. Definition: ifeqEntry.H:92 A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str... Definition: functionEntry.H:69 virtual bool execute() Calculate the output fields. @ REGEX_RECURSIVE Definition: keyType.H:87 A line primitive. Definition: line.H:68 A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,... A token holds an item read from Istream. Definition: token.H:69 @ LABEL label (integer) type Definition: token.H:85 @ ERROR Token error encountered. Definition: token.H:79 @ DOUBLE double (double-precision) type Definition: token.H:87 @ VARIABLE Definition: token.H:98 @ FLAG stream flag (1-byte bitmask) Definition: token.H:82 @ WORD Foam::word. Definition: token.H:90 @ EXPRESSION Definition: token.H:96 @ UNDEFINED An undefined token-type. Definition: token.H:78 @ COMPOUND Compound type such as List<label> etc. Definition: token.H:92 @ FLOAT float (single-precision) type Definition: token.H:86 @ VERBATIM Definition: token.H:100 @ DIRECTIVE Definition: token.H:94 @ BOOL boolean type Definition: token.H:84 @ STRING Foam::string (usually double-quoted) Definition: token.H:91 @ PUNCTUATION single character punctuation Definition: token.H:83 @ END_STATEMENT End entry [isseparator]. Definition: token.H:154 bool isDirective() const noexcept Token is DIRECTIVE (word variant) Definition: tokenI.H:625 const word & wordToken() const Return const reference to the word contents. Definition: tokenI.H:631 @ DETECT Detect if the string contains meta-characters. Definition: wordRe.H:108 #define defineTypeNameAndDebug(Type, DebugSwitch) Define the typeName and debug information. Definition: className.H:121 #define FatalIOErrorInFunction(ios) Report an error message using Foam::FatalIOError. Definition: error.H:473 void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
Namespace for OpenFOAM.
bool equal(const T &s1, const T &s2)
Compare two values for equality.
Definition: doubleFloat.H:46
IOerror FatalIOError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict
volScalarField & e
Definition: createFields.H:11