ENH: add stringOps::toScalar and dictionary #eval directive

- the #eval directive is similar to the #calc directive, but for evaluating
  string expressions into scalar values. It uses an internal parser for
  the evaluation instead of dynamic code compilation. This can make it
  more suitable for 'quick' evaluations.

  The evaluation supports the following:
    - operations:  - + * /
    - functions:  exp, log, log10, pow, sqrt, cbrt, sqr, mag, magSqr
    - trigonometric:  sin, cos, tan, asin, acos, atan, atan2, hypot
    - hyperbolic:  sinh, cosh, tanh
    - conversions:  degToRad, radToDeg
    - constants:  pi()
    - misc: rand(), rand(seed)
This commit is contained in:
Mark Olesen
2019-09-30 16:40:32 +02:00
committed by Andrew Heather
parent bd9992d0d5
commit 836d3a849f
19 changed files with 3143 additions and 2 deletions

View File

@ -130,9 +130,13 @@ $(strings)/wordRe/wordRe.C
$(strings)/wordRes/wordRes.C
$(strings)/lists/CStringList.C
$(strings)/lists/hashedWordList.C
$(strings)/parsing/parsing.C
$(strings)/parsing/genericRagelLemonDriver.C
$(strings)/stringOps/stringOps.C
$(strings)/stringOps/stringOpsSort.C
$(strings)/parsing/parsing.C
$(strings)/stringOps/toScalar/evalStringToScalarDriver.C
$(strings)/stringOps/toScalar/evalStringToScalarLemonParser.lyy
$(strings)/stringOps/toScalar/evalStringToScalarScanner.cc
ops = primitives/ops
$(ops)/flipOp.C
@ -248,6 +252,7 @@ $(dictionaryListEntry)/dictionaryListEntryIO.C
functionEntries = $(dictionary)/functionEntries
$(functionEntries)/calcEntry/calcEntry.C
$(functionEntries)/codeStream/codeStream.C
$(functionEntries)/evalEntry/evalEntry.C
$(functionEntries)/functionEntry/functionEntry.C
$(functionEntries)/includeEntry/includeEntry.C
$(functionEntries)/includeEtcEntry/includeEtcEntry.C

View File

@ -0,0 +1,163 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "evalEntry.H"
#include "dictionary.H"
#include "stringOps.H"
#include "addToMemberFunctionSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
addNamedToMemberFunctionSelectionTable
(
functionEntry,
evalEntry,
execute,
dictionaryIstream,
eval
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
evalEntry,
execute,
primitiveEntryIstream,
eval
);
} // End namespace functionEntry
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::scalar Foam::functionEntries::evalEntry::evaluate
(
const dictionary& parentDict,
Istream& is
)
{
DetailInfo
<< "Using #eval at line " << is.lineNumber()
<< " in file " << parentDict.name() << nl;
// String to evaluate
string s;
token tok(is);
if (!tok.good())
{
FatalIOErrorInFunction(is)
<< "Bad token - could not get string to evaluate"
<< exit(FatalIOError);
return 0;
}
if (tok.isString())
{
s = tok.stringToken();
}
else if (tok == token::BEGIN_BLOCK)
{
dynamic_cast<ISstream&>(is).getLine(s, token::END_BLOCK);
}
else
{
is.putBack(tok);
FatalIOErrorInFunction(is)
<< "Invalid input for #eval" << nl
<< exit(FatalIOError);
}
#ifdef FULLDEBUG
DetailInfo
<< "input: " << s << endl;
#endif
stringOps::inplaceRemoveComments(s);
stringOps::inplaceExpand(s, parentDict);
#ifdef FULLDEBUG
DetailInfo
<< "expanded: " << s << endl;
#endif
return stringOps::toScalar(s);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionEntries::evalEntry::execute
(
const dictionary& parentDict,
primitiveEntry& entry,
Istream& is
)
{
const scalar value = evaluate(parentDict, is);
// The result as terminated token entry
ITstream result
(
"eval",
tokenList({token(value), token(token::END_STATEMENT)})
);
entry.read(parentDict, result);
return true;
}
bool Foam::functionEntries::evalEntry::execute
(
dictionary& parentDict,
Istream& is
)
{
const scalar value = evaluate(parentDict, is);
// The result as terminated token entry
ITstream result
(
"eval",
tokenList({token(value), token(token::END_STATEMENT)})
);
parentDict.read(result);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionEntries::evalEntry
Description
Uses stringOps::toScalar to evaluate mathematical expressions.
The input can any form of string or, for convenience,
a '{}' delimited string literal. In all cases, C/C++ comment stripping
is also performed.
For example,
\verbatim
a 1;
b 3;
c #eval "sin(pi()*$a/$b)";
d #eval{
// ignore: sin(pi()*$a/$b)
sin(degToRad(45))
};
\endverbatim
SourceFiles
evalEntry.C
\*---------------------------------------------------------------------------*/
#ifndef evalEntry_H
#define evalEntry_H
#include "functionEntry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
/*---------------------------------------------------------------------------*\
Class evalEntry Declaration
\*---------------------------------------------------------------------------*/
class evalEntry
:
public functionEntry
{
//- Evaluate and return a scalar
static scalar evaluate(const dictionary& parentDict, Istream& is);
public:
//- Execute in a primitiveEntry context
static bool execute
(
const dictionary& parentDict,
primitiveEntry& thisEntry,
Istream& is
);
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,192 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "genericRagelLemonDriver.H"
#include "evalStringToScalarDriver.H"
#include "error.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::parsing::genericRagelLemonDriver::genericRagelLemonDriver()
:
content_(std::cref<std::string>(string::null)),
position_(0)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Ostream& Foam::parsing::genericRagelLemonDriver::printBuffer
(
Ostream& os
) const
{
const std::string& s = content_.get();
for (char c : s)
{
// if (!c) break;
if (c == '\t')
{
// Flatten tab to single space for better alignment
os << ' ';
}
else
{
os << c;
}
}
return os;
}
void Foam::parsing::genericRagelLemonDriver::reportFatal
(
const std::string& msg
) const
{
if (position_)
{
reportFatal(msg, position_);
}
else
{
auto& os = FatalIOError
(
FUNCTION_NAME,
__FILE__,
__LINE__,
""
);
os << nl << msg.c_str() << " in expression\n"
<< "<<<<\n";
printBuffer(os)
<< "\n>>>>\n"
<< exit(Foam::FatalIOError);
}
}
void Foam::parsing::genericRagelLemonDriver::reportFatal
(
const std::string& msg,
size_t pos
) const
{
auto& os = Foam::FatalIOError
(
FUNCTION_NAME,
__FILE__,
__LINE__,
""
);
os << nl << msg.c_str()
<< " in expression at position:" << long(pos) << nl
<< "<<<<\n";
const auto begIter = content().cbegin();
const auto endIter = content().cend();
size_t newline0 = 0, newline1 = 0;
auto iter = begIter;
for (/*nil*/; iter != endIter; ++iter)
{
char c(*iter);
if ('\t' == c)
{
// Flatten tab to single space for better alignment
os << ' ';
}
else if ('\n' == c)
{
os << c;
newline1 = (iter-begIter);
if (newline1 < pos)
{
newline0 = newline1;
}
else
{
++iter;
break;
}
}
else
{
os << c;
}
}
if (newline0 == newline1 || newline1 == pos)
{
os << '\n';
}
size_t col = std::min(newline0, newline1);
if (col < pos)
{
col = pos - col;
if (col) --col;
for (/*nil*/; col; --col)
{
os << ' ';
}
}
os << "^^^^ near here\n";
// Finish output
for (/*nil*/; iter != endIter; ++iter)
{
char c(*iter);
if ('\t' == c)
{
// Flatten tab to single space for better alignment
os << ' ';
}
else
{
os << c;
}
}
os << "\n>>>>\n"
<< exit(Foam::FatalIOError);
}
// ************************************************************************* //

View File

@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::parsing::genericRagelLemonDriver
Description
Generic interface code for Ragel/Lemon combination
Subclasses should implement the process() method.
The scanner will often be implemented as localized lexer class.
The parser may be embedded into the scanner as file-scope, or
use a separate interface class.
SourceFiles
genericRagelLemonDriver.C
\*---------------------------------------------------------------------------*/
#ifndef genericRagelLemonDriver_H
#define genericRagelLemonDriver_H
#include "error.H"
#include "className.H"
#include <functional>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace parsing
{
/*---------------------------------------------------------------------------*\
Class genericRagelLemonDriver Declaration
\*---------------------------------------------------------------------------*/
class genericRagelLemonDriver
{
protected:
// Protected Data
//- Reference to the input string
std::reference_wrapper<const std::string> content_;
//- The last known parser position
size_t position_;
public:
// Public Typedefs
//- Type for linear addressing within parse content
// Naming as per bison
typedef size_t location_type;
// Constructors
//- Construct null
genericRagelLemonDriver();
//- Copy construct
genericRagelLemonDriver(const genericRagelLemonDriver& rhs) = default;
//- Move construct
genericRagelLemonDriver(genericRagelLemonDriver&& rhs) = default;
//- Destructor
virtual ~genericRagelLemonDriver() = default;
// Member Functions
//- Reset references
void clear()
{
content_ = std::cref<std::string>(string::null);
position_ = 0;
}
//- Get reference to the input buffer content
const std::string& content() const
{
return content_.get();
}
//- Set reference to the input buffer content
void content(const std::string& s)
{
content_ = std::cref<std::string>(s);
position_ = 0;
}
//- The last parse position
size_t parsePosition() const
{
return position_;
}
//- The last parse position
size_t& parsePosition()
{
return position_;
}
//- Output the input buffer string content
Ostream& printBuffer(Ostream& os) const;
//- Report FatalError
void reportFatal(const std::string& msg) const;
//- Report FatalError at parser position
void reportFatal(const std::string& msg, size_t pos) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace parsing
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -26,6 +26,7 @@ Namespace
Description
Collection of static functions and data related to parsing
and an isolated namespace for lexers, parsers, scanners.
SourceFiles
parsing.C

View File

@ -38,6 +38,7 @@ SourceFiles
#ifndef stringOps_H
#define stringOps_H
#include "scalar.H"
#include "string.H"
#include "SubStrings.H"
#include "word.H"
@ -46,6 +47,8 @@ SourceFiles
#include "stringOpsSort.H"
#include "wordRes.H"
#include "evalStringToScalar.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam

View File

@ -0,0 +1,11 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Manually create ragel scanner and the lemon parser header
"$WM_PROJECT_DIR/wmake/scripts/makeParser" \
-scanner=evalStringToScalarScanner.rl \
-parser=evalStringToScalarLemonParser.lyy \
;
#------------------------------------------------------------------------------

View File

@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::parsing::evalStringToScalar
Description
Parsing encapsulation for stringOps::toScalar
\*---------------------------------------------------------------------------*/
#ifndef evalStringToScalar_H
#define evalStringToScalar_H
#include "scalar.H"
#include "string.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace stringOps
{
//- A simple string to scalar evaluation that handles various basic
//- expressions. For trivial input, use readScalar instead (faster).
//
// The evaluation supports the following:
// - operations: - + * /
// - functions: exp, log, log10, pow, sqrt, cbrt, sqr, mag, magSqr
// - trigonometric: sin, cos, tan, asin, acos, atan, atan2, hypot
// - hyperbolic: sinh, cosh, tanh
// - conversions: degToRad, radToDeg
// - constants: pi()
// - misc: rand(), rand(seed)
//
// \note The rand() function returns a uniform scalar on [0-1] interval
scalar toScalar(const std::string& s);
} // End namespace stringOps
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,72 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Ragel lexer interface for lemon grammar of a simple string to
scalar evaluation
\*---------------------------------------------------------------------------*/
#include "evalStringToScalar.H"
#include "evalStringToScalarDriver.H"
#include "evalStringToScalarScanner.H"
#include "error.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::parsing::evalStringToScalar::parseDriver::parseDriver()
:
genericRagelLemonDriver(),
value_(0)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::scalar Foam::parsing::evalStringToScalar::parseDriver::execute
(
const std::string& s
)
{
// scanner::debug = 1;
scanner().process(s, *this);
return value_;
}
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
Foam::scalar Foam::stringOps::toScalar(const std::string& s)
{
Foam::parsing::evalStringToScalar::parseDriver driver;
scalar val = driver.execute(s);
// val = driver.value();
return val;
}
// ************************************************************************* //

View File

@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::parsing::evalStringToScalar::parseDriver
Description
Driver for stringOps::toScalar parsing
SourceFiles
evalStringToScalarDriver.C
\*---------------------------------------------------------------------------*/
#ifndef evalStringToScalarDriver_H
#define evalStringToScalarDriver_H
#include "scalar.H"
#include "className.H"
#include "genericRagelLemonDriver.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace parsing
{
namespace evalStringToScalar
{
/*---------------------------------------------------------------------------*\
Class parseDriver Declaration
\*---------------------------------------------------------------------------*/
class parseDriver
:
public genericRagelLemonDriver
{
protected:
// Protected Data
//- The result
scalar value_;
// Protected Member Functions
// No copy copy construct
parseDriver(const parseDriver&) = delete;
// No copy assignment
void operator=(const parseDriver&) = delete;
public:
ClassName("evalStringToScalar::driver");
// Constructors
//- Construct null
parseDriver();
//- Destructor
virtual ~parseDriver() = default;
// Member Functions
// Perform parsing on string
scalar execute(const std::string& s);
//- Get value
scalar value() const
{
return value_;
}
//- Set value
void setValue(scalar val)
{
value_ = val;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace evalStringToScalar
} // End namespace parsing
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,35 @@
#define TOK_PLUS 1
#define TOK_MINUS 2
#define TOK_TIMES 3
#define TOK_DIVIDE 4
#define TOK_NEGATE 5
#define TOK_NUMBER 6
#define TOK_LPAREN 7
#define TOK_RPAREN 8
#define TOK_PI 9
#define TOK_DEG_TO_RAD 10
#define TOK_RAD_TO_DEG 11
#define TOK_EXP 12
#define TOK_LOG 13
#define TOK_LOG10 14
#define TOK_POW 15
#define TOK_COMMA 16
#define TOK_SQR 17
#define TOK_SQRT 18
#define TOK_CBRT 19
#define TOK_SIN 20
#define TOK_COS 21
#define TOK_TAN 22
#define TOK_ASIN 23
#define TOK_ACOS 24
#define TOK_ATAN 25
#define TOK_ATAN2 26
#define TOK_HYPOT 27
#define TOK_SINH 28
#define TOK_COSH 29
#define TOK_TANH 30
#define TOK_MIN 31
#define TOK_MAX 32
#define TOK_MAG 33
#define TOK_MAGSQR 34
#define TOK_RAND 35

View File

@ -0,0 +1,290 @@
%include {
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Lemon grammar of a simple string to scalar evaluation.
The generated parser is localized in an anonymous namespace.
Interface code wrapping is near the bottom of the file.
\*---------------------------------------------------------------------------*/
#include "evalStringToScalarDriver.H"
#include "evalStringToScalarParser.H"
#include "unitConversion.H"
#include "Random.H"
#include "error.H"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wsign-compare"
}
%namespace {}
// Use extra argument for the return value
%extra_context { Foam::parsing::evalStringToScalar::parseDriver* driver }
%parse_failure { driver->reportFatal("Parse failure, giving up..."); }
%syntax_error { driver->reportFatal("Syntax error"); }
%token_prefix TOK_
%token_type { Foam::scalar }
%left PLUS MINUS.
%left TIMES DIVIDE.
%left NEGATE.
eval(lhs) ::= exp(a).
{
lhs = a;
driver->setValue(lhs);
}
exp(lhs) ::= NUMBER(a).
{
lhs = a;
}
exp(lhs) ::= MINUS exp(a).
{
lhs = -a;
}
exp(lhs) ::= exp(a) PLUS exp(b).
{
lhs = a + b;
}
exp(lhs) ::= exp(a) MINUS exp(b).
{
lhs = a - b;
}
exp(lhs) ::= exp(a) TIMES exp(b).
{
lhs = a * b;
}
exp(lhs) ::= exp(a) DIVIDE exp(b).
{
lhs = a / b;
}
exp(lhs) ::= LPAREN exp(a) RPAREN.
{
lhs = a;
}
// Functions
exp(lhs) ::= PI LPAREN RPAREN.
{
lhs = Foam::constant::mathematical::pi;
}
exp(lhs) ::= DEG_TO_RAD LPAREN RPAREN.
{
lhs = Foam::degToRad();
}
exp(lhs) ::= RAD_TO_DEG LPAREN RPAREN.
{
lhs = Foam::radToDeg();
}
exp(lhs) ::= DEG_TO_RAD LPAREN exp(a) RPAREN.
{
lhs = Foam::degToRad(a);
}
exp(lhs) ::= RAD_TO_DEG LPAREN exp(a) RPAREN.
{
lhs = Foam::radToDeg(a);
}
exp(lhs) ::= EXP LPAREN exp(a) RPAREN.
{
lhs = Foam::exp(a);
}
exp(lhs) ::= LOG LPAREN exp(a) RPAREN.
{
lhs = Foam::log(a);
}
exp(lhs) ::= LOG10 LPAREN exp(a) RPAREN.
{
lhs = Foam::log10(a);
}
exp(lhs) ::= POW LPAREN exp(a) COMMA exp(b) RPAREN.
{
lhs = Foam::pow(a, b);
}
exp(lhs) ::= SQR LPAREN exp(a) RPAREN.
{
lhs = Foam::sqr(a);
}
exp(lhs) ::= SQRT LPAREN exp(a) RPAREN.
{
lhs = Foam::sqrt(a);
}
exp(lhs) ::= CBRT LPAREN exp(a) RPAREN.
{
lhs = Foam::cbrt(a);
}
exp(lhs) ::= SIN LPAREN exp(a) RPAREN.
{
lhs = Foam::sin(a);
}
exp(lhs) ::= COS LPAREN exp(a) RPAREN.
{
lhs = Foam::cos(a);
}
exp(lhs) ::= TAN LPAREN exp(a) RPAREN.
{
lhs = Foam::tan(a);
}
exp(lhs) ::= ASIN LPAREN exp(a) RPAREN.
{
lhs = Foam::asin(a);
}
exp(lhs) ::= ACOS LPAREN exp(a) RPAREN.
{
lhs = Foam::acos(a);
}
exp(lhs) ::= ATAN LPAREN exp(a) RPAREN.
{
lhs = Foam::atan(a);
}
exp(lhs) ::= ATAN2 LPAREN exp(a) COMMA exp(b) RPAREN.
{
lhs = Foam::atan2(a, b);
}
exp(lhs) ::= HYPOT LPAREN exp(a) COMMA exp(b) RPAREN.
{
lhs = Foam::hypot(a, b);
}
exp(lhs) ::= SINH LPAREN exp(a) RPAREN.
{
lhs = Foam::sinh(a);
}
exp(lhs) ::= COSH LPAREN exp(a) RPAREN.
{
lhs = Foam::cosh(a);
}
exp(lhs) ::= TANH LPAREN exp(a) RPAREN.
{
lhs = Foam::tanh(a);
}
exp(lhs) ::= MIN LPAREN exp(a) COMMA exp(b) RPAREN.
{
lhs = Foam::min(a, b);
}
exp(lhs) ::= MAX LPAREN exp(a) COMMA exp(b) RPAREN.
{
lhs = Foam::max(a, b);
}
exp(lhs) ::= MAG LPAREN exp(a) RPAREN.
{
lhs = Foam::mag(a);
}
exp(lhs) ::= MAGSQR LPAREN exp(a) RPAREN.
{
lhs = Foam::magSqr(a);
}
exp(lhs) ::= RAND LPAREN RPAREN.
{
lhs = Foam::Random().sample01<Foam::scalar>();
}
exp(lhs) ::= RAND LPAREN exp(seed) RPAREN.
{
lhs = Foam::Random(seed).sample01<Foam::scalar>();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
%code
{
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::parsing::evalStringToScalar::parser::stop()
{
if (lemon_)
{
ParseFree(lemon_, ::operator delete);
lemon_ = nullptr;
}
}
void Foam::parsing::evalStringToScalar::parser::start(parseDriver& driver)
{
this->stop();
lemon_ = ParseAlloc(::operator new, &driver);
}
void Foam::parsing::evalStringToScalar::parser::parse
(
int tokenId,
Foam::scalar val /* The value for the token */
)
{
Parse(lemon_, tokenId, val);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // Code
// ************************************************************************* //

View File

@ -0,0 +1,96 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::parsing::evalStringToScalar::parser
Description
Interface to lemon parser to simple string to scalar evaluation, which
is used by stringOps::toScalar
\*---------------------------------------------------------------------------*/
#ifndef evalStringToScalarParser_H
#define evalStringToScalarParser_H
namespace Foam
{
namespace parsing
{
namespace evalStringToScalar
{
// Forward Declarations
class parseDriver;
/*---------------------------------------------------------------------------*\
Class parser Declaration
\*---------------------------------------------------------------------------*/
class parser
{
// Private Data
//- The lemon parser (demand-driven)
void* lemon_;
public:
// Constructors
//- Construct null
parser() : lemon_(nullptr) {}
//- Destructor, delete lemon parser
~parser()
{
stop();
}
// Member Functions
//- Start parsing, with given driver context
void start(parseDriver& driver);
//- Stop parsing, freeing the allocated parser
void stop();
//- Push token/value to parser
void parse(int tokenId, Foam::scalar val);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace evalStringToScalar
} // End namespace parsing
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::parsing::evalStringToScalar::scanner
Description
Ragel lexer interface for lemon grammar of a simple string to
scalar evaluation, which is used by stringOps::toScalar
Note
Ragel code generated with the ./createCode script.
\*---------------------------------------------------------------------------*/
#ifndef evalStringToScalarScanner_H
#define evalStringToScalarScanner_H
#include <string>
namespace Foam
{
namespace parsing
{
namespace evalStringToScalar
{
// Forward Declarations
class parser;
class parseDriver;
/*---------------------------------------------------------------------------*\
Class scanner Declaration
\*---------------------------------------------------------------------------*/
class scanner
{
// Private Data
//- Wrapped lemon parser
parser* parser_;
// Ragel code state, action
int cs, act;
public:
//- Debug/tracing of scan
static int debug;
// Constructors
//- Construct null
scanner() : parser_(nullptr) {}
//- Destructor, deletes parser
~scanner();
// Member Functions
//- Evaluate string
bool process(const std::string& str, parseDriver& driver);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace evalStringToScalar
} // End namespace parsing
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Ragel lexer interface for lemon grammar of a simple string to
scalar evaluation
\*---------------------------------------------------------------------------*/
#include "evalStringToScalarScanner.H"
#include "evalStringToScalarDriver.H"
#include "evalStringToScalarLemonParser.h"
#include "evalStringToScalarParser.H"
#include "error.H"
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#ifndef FULLDEBUG
#define NDEBUG
#endif
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
int Foam::parsing::evalStringToScalar::scanner::debug = 0;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Ragel lexer with lemon parser integration
// Ragel machine definition
// Ragel variables (p, pe, eof, cs, top, stack, ts, te, act) defined later...
//
// Can use 'variable p xxx;' etc to change these names
%%{
machine evalScanner;
write data;
}%%
#define TOKEN_OF(T) TOK_##T
#define EMIT_TOKEN(T) \
/* Inform driver of last position */ \
driver.parsePosition() = (p-buf); \
DebugInfo<< "TOKEN_" #T << " at " << driver.parsePosition() << nl; \
parser_->parse(TOKEN_OF(T), 0)
%%{
machine evalScanner;
action setPosition
{
// Inform driver of last position
driver.parsePosition() = (p-buf);
}
action truncated
{
// Inform driver of last position
driver.parsePosition() = 0;
driver.reportFatal("Truncated input");
}
action emit_number {
// Inform driver of last position
driver.parsePosition() = (p-buf);
DebugInfo
<< "NUMBER:" << std::string(ts, te-ts).c_str()
<< " at " << driver.parsePosition() << nl;
scalar val;
if (readScalar(std::string(ts, te-ts), val))
{
// Emit number
parser_->parse(TOKEN_OF(NUMBER), val);
}
else
{
driver.reportFatal("Error reading scalar value");
}
}
decimal = ((digit* '.' digit+) | (digit+ '.'?)) ;
number = (digit+ | decimal) ([Ee][\-+]? digit+)? ;
dnl = (any* -- '\n') '\n'; # Discard up to and including newline
lfunc = space* '('; # Require functions to have '('
functions = (
'pi' lfunc @{ fhold; EMIT_TOKEN(PI); }
| 'degToRad' lfunc @{ fhold; EMIT_TOKEN(DEG_TO_RAD); }
| 'radToDeg' lfunc @{ fhold; EMIT_TOKEN(RAD_TO_DEG); }
| 'exp' lfunc @{ fhold; EMIT_TOKEN(EXP); }
| 'log' lfunc @{ fhold; EMIT_TOKEN(LOG); }
| 'log10' lfunc @{ fhold; EMIT_TOKEN(LOG10); }
| 'pow' lfunc @{ fhold; EMIT_TOKEN(POW); }
| 'sqr' lfunc @{ fhold; EMIT_TOKEN(SQR); }
| 'sqrt' lfunc @{ fhold; EMIT_TOKEN(SQRT); }
| 'cbrt' lfunc @{ fhold; EMIT_TOKEN(CBRT); }
| 'sin' lfunc @{ fhold; EMIT_TOKEN(SIN); }
| 'cos' lfunc @{ fhold; EMIT_TOKEN(COS); }
| 'tan' lfunc @{ fhold; EMIT_TOKEN(TAN); }
| 'asin' lfunc @{ fhold; EMIT_TOKEN(ASIN); }
| 'acos' lfunc @{ fhold; EMIT_TOKEN(ACOS); }
| 'atan' lfunc @{ fhold; EMIT_TOKEN(ATAN); }
| 'atan2' lfunc @{ fhold; EMIT_TOKEN(ATAN2); }
| 'hypot' lfunc @{ fhold; EMIT_TOKEN(HYPOT); }
| 'sinh' lfunc @{ fhold; EMIT_TOKEN(SINH); }
| 'cosh' lfunc @{ fhold; EMIT_TOKEN(COSH); }
| 'tanh' lfunc @{ fhold; EMIT_TOKEN(TANH); }
| 'min' lfunc @{ fhold; EMIT_TOKEN(MIN); }
| 'max' lfunc @{ fhold; EMIT_TOKEN(MAX); }
| 'mag' lfunc @{ fhold; EMIT_TOKEN(MAG); }
| 'magSqr' lfunc @{ fhold; EMIT_TOKEN(MAGSQR); }
| 'rand' lfunc @{ fhold; EMIT_TOKEN(RAND); }
);
operators = (
'(' @{ EMIT_TOKEN(LPAREN); }
| ')' @{ EMIT_TOKEN(RPAREN); }
| '+' @{ EMIT_TOKEN(PLUS); }
| '-' @{ EMIT_TOKEN(MINUS); }
| '*' @{ EMIT_TOKEN(TIMES); }
| '/' @{ EMIT_TOKEN(DIVIDE); }
| ',' @{ EMIT_TOKEN(COMMA); }
);
main := |*
space*;
number => emit_number;
functions;
operators;
'/*' any* :>> '*/' @setPosition; # Multi-line comment
'//' (any* -- '\n') '\n'* @setPosition; # (sloppy) 1-line comment
space*;
*|;
}%%
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::parsing::evalStringToScalar::scanner::~scanner()
{
if (parser_)
{
delete parser_;
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
bool Foam::parsing::evalStringToScalar::scanner::process
(
const std::string& str,
parseDriver& driver
)
{
if (!parser_)
{
parser_ = new parser();
}
driver.content(str);
parser_->start(driver);
// Ragel token start/end (required naming)
const char* ts;
const char* te;
// Local buffer data.
// - p, pe, eof are required Ragel naming
// - buf is our own naming
const char* buf = &(str[0]);
const char* eof = &(str[str.length()]);
const char* p = buf;
const char* pe = eof;
// Initialize FSM variables
%%{write init;}%% /* ^^^ FSM initialization here ^^^ */;
%%{write exec;}%% /* ^^^ FSM execution here ^^^ */;
if (%%{write error;}%% == cs)
{
driver.reportFatal("Parse error while scanning", (p-buf));
}
if (p != eof)
{
driver.reportFatal("Parsing failed with remaining content", (p-buf));
}
// Terminate parser execution
parser_->parse(0, 0);
parser_->stop();
return true;
}
// ************************************************************************* //