diff --git a/applications/test/dictionary/testDictCalc1 b/applications/test/dictionary/testDictCalc1
new file mode 100644
index 0000000000000000000000000000000000000000..93b52a9fb8e7d990799a2e3068b09b32e950cfb9
--- /dev/null
+++ b/applications/test/dictionary/testDictCalc1
@@ -0,0 +1,35 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  Any                                   |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      testDictCalc1;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+calc1 #calc #{    degToRad() *
+        constant::mathematical::pi *
+        cos(100.0) * mag(19) + 1 * constant::mathematical::pi
+            +
+        // Skip comments
+        constant::mathematical::pi * 15 + hypot(3.0,4.0) #};
+
+calc3   (#calc"hypot(3.0,4.0)", #calc"sqrt(2.0)", #calc"constant::mathematical::pi");
+
+calc4   #calc"$calc1 * 10";
+
+pi()    #calc #{ constant::mathematical::pi #};
+
+sinh(0.1)  #calc #{ sinh(0.1) #};
+cosh(0.1)  #calc #{ cosh(0.1) #};
+
+sqrt100    #calc #{((sqrt(100.0)))#};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictEval1 b/applications/test/dictionary/testDictEval1
new file mode 100644
index 0000000000000000000000000000000000000000..2fccaa7f418906d8c5e7f5a191ac668a7e437549
--- /dev/null
+++ b/applications/test/dictionary/testDictEval1
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  Any                                   |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      testDictEval1;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+eval1 #eval #{    degToRad() *
+        pi() *
+        cos(100) * mag(19) + 1 * pi()
+            +
+        // Skip comments
+        pi() * 15 + hypot(3,4) #};
+
+eval2 #eval{    degToRad() *
+        pi() *
+        cos(100) * mag(19) + 1 * pi()
+            +
+        // Skip comments
+        pi() * 15  + hypot(3,4) };
+
+eval3   (#eval{hypot(3,4)}, #eval{sqrt(2)}, #eval{pi()});
+
+eval4   #eval{$eval1 * 10};
+
+pi()    #eval{pi()};
+
+rand()  #eval{100*rand(123456)};
+
+sinh(0.1)  #eval{sinh(0.1)};
+cosh(0.1)  #eval{cosh(0.1)};
+
+sqrt100    #eval{((sqrt(100)))};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index 92e60ba056263404263a94b4ca9feb3b2dd15569..c8e5d89eb0d200c6c65720c764ea253df00b3352 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -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
diff --git a/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C
new file mode 100644
index 0000000000000000000000000000000000000000..5599f771a83b57318fd96e32e992a558159a24d5
--- /dev/null
+++ b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C
@@ -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;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.H b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.H
new file mode 100644
index 0000000000000000000000000000000000000000..ce19a2f8b8ac8e351279d2bf6474681daaee6003
--- /dev/null
+++ b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.C b/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.C
new file mode 100644
index 0000000000000000000000000000000000000000..1ce3749cfde2a2794a760f5b537acba614259b65
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.C
@@ -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);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.H b/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.H
new file mode 100644
index 0000000000000000000000000000000000000000..b093178f165cd9d6751cadfab7e948c15ca43be1
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/parsing/genericRagelLemonDriver.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/parsing/parsing.H b/src/OpenFOAM/primitives/strings/parsing/parsing.H
index ee069c5d017636b2f14027bad075c5f98f65c487..cc25fb67bd7b922fa1b8e6f838cf7b2ec60a72d8 100644
--- a/src/OpenFOAM/primitives/strings/parsing/parsing.H
+++ b/src/OpenFOAM/primitives/strings/parsing/parsing.H
@@ -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
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
index 6eb2499f9a6c951c61eac4ebf4880b679e402f55..516b00d0cf48ae594624cdbec01388a6b3b2e5f5 100644
--- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
@@ -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
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/createCode b/src/OpenFOAM/primitives/strings/stringOps/toScalar/createCode
new file mode 100755
index 0000000000000000000000000000000000000000..3be1331c8d92433d3876f5732c14928019251fe7
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/createCode
@@ -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 \
+    ;
+
+#------------------------------------------------------------------------------
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalar.H b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalar.H
new file mode 100644
index 0000000000000000000000000000000000000000..2415a2248c6643031a1bb420eb0794b9383e57a9
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalar.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.C b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.C
new file mode 100644
index 0000000000000000000000000000000000000000..f6bbf9be44a7f89af92cc0b1013ffa3fac77454a
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.C
@@ -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;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.H b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.H
new file mode 100644
index 0000000000000000000000000000000000000000..58ed93e163195eab53752358bdbe24f6b5b954f0
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarDriver.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.h b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.h
new file mode 100644
index 0000000000000000000000000000000000000000..e068ad5c1d96e578de0a7c3945a30d8315bc11e0
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.h
@@ -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
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.lyy b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.lyy
new file mode 100644
index 0000000000000000000000000000000000000000..2b89c8998639683b5bcb1566754c33dbed3a1fa8
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarLemonParser.lyy
@@ -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
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarParser.H b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarParser.H
new file mode 100644
index 0000000000000000000000000000000000000000..a82a8791f1cc0e3fff3bfff68bfcf4f23d11b7ef
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarParser.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.H b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.H
new file mode 100644
index 0000000000000000000000000000000000000000..84e4492f3380a3dca3ae748e12c56eb30a17e51b
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.H
@@ -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
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.cc b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4548dd8dd6534786e8fe9832edcc076c1f2d9bdf
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.cc
@@ -0,0 +1,1426 @@
+
+#line 1 "evalStringToScalarScanner.rl"
+/*--------------------------------*- 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
+
+
+#line 61 "evalStringToScalarScanner.cc"
+static const int evalScanner_start = 86;
+static const int evalScanner_first_final = 86;
+static const int evalScanner_error = 0;
+
+static const int evalScanner_en_main = 86;
+
+
+#line 60 "evalStringToScalarScanner.rl"
+
+
+#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)
+
+
+
+#line 163 "evalStringToScalarScanner.rl"
+
+
+
+// * * * * * * * * * * * * * * * * 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
+    
+#line 127 "evalStringToScalarScanner.cc"
+	{
+	cs = evalScanner_start;
+	ts = 0;
+	te = 0;
+	act = 0;
+	}
+
+#line 207 "evalStringToScalarScanner.rl"
+   /* ^^^ FSM initialization here ^^^ */;
+
+    
+#line 139 "evalStringToScalarScanner.cc"
+	{
+	if ( p == pe )
+		goto _test_eof;
+	switch ( cs )
+	{
+tr2:
+#line 86 "evalStringToScalarScanner.rl"
+	{{p = ((te))-1;}{
+        // 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");
+        }
+    }}
+	goto st86;
+tr5:
+#line 157 "evalStringToScalarScanner.rl"
+	{{p = ((te))-1;}}
+	goto st86;
+tr8:
+#line 74 "evalStringToScalarScanner.rl"
+	{
+        // Inform driver of last position
+        driver.parsePosition() = (p-buf);
+    }
+#line 159 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr14:
+#line 127 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(ACOS); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr17:
+#line 126 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(ASIN); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr21:
+#line 128 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(ATAN); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr23:
+#line 129 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(ATAN2); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr28:
+#line 122 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(CBRT); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr31:
+#line 124 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(COS); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr33:
+#line 132 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(COSH); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr41:
+#line 114 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(DEG_TO_RAD); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr44:
+#line 116 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(EXP); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr49:
+#line 130 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(HYPOT); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr53:
+#line 117 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(LOG); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr56:
+#line 118 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(LOG10); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr62:
+#line 136 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(MAG); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr66:
+#line 137 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(MAGSQR); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr67:
+#line 135 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(MAX); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr69:
+#line 134 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(MIN); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr72:
+#line 113 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(PI); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr74:
+#line 119 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(POW); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr83:
+#line 115 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(RAD_TO_DEG); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr85:
+#line 138 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(RAND); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr90:
+#line 123 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(SIN); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr92:
+#line 131 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(SINH); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr95:
+#line 120 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(SQR); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr97:
+#line 121 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(SQRT); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr101:
+#line 125 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(TAN); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr103:
+#line 133 "evalStringToScalarScanner.rl"
+	{ p--; EMIT_TOKEN(TANH); }
+#line 156 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr105:
+#line 142 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(LPAREN); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr106:
+#line 143 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(RPAREN); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr107:
+#line 146 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(TIMES); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr108:
+#line 144 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(PLUS); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr109:
+#line 148 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(COMMA); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr110:
+#line 145 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(MINUS); }
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p+1;}
+	goto st86;
+tr125:
+#line 153 "evalStringToScalarScanner.rl"
+	{te = p;p--;}
+	goto st86;
+tr126:
+#line 86 "evalStringToScalarScanner.rl"
+	{te = p;p--;{
+        // 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");
+        }
+    }}
+	goto st86;
+tr128:
+#line 157 "evalStringToScalarScanner.rl"
+	{te = p;p--;}
+	goto st86;
+tr130:
+#line 160 "evalStringToScalarScanner.rl"
+	{te = p;p--;}
+	goto st86;
+st86:
+#line 1 "NONE"
+	{ts = 0;}
+	if ( ++p == pe )
+		goto _test_eof86;
+case 86:
+#line 1 "NONE"
+	{ts = p;}
+#line 416 "evalStringToScalarScanner.cc"
+	switch( (*p) ) {
+		case 32: goto st87;
+		case 40: goto tr105;
+		case 41: goto tr106;
+		case 42: goto tr107;
+		case 43: goto tr108;
+		case 44: goto tr109;
+		case 45: goto tr110;
+		case 46: goto st1;
+		case 47: goto tr112;
+		case 97: goto st6;
+		case 99: goto st18;
+		case 100: goto st26;
+		case 101: goto st34;
+		case 104: goto st37;
+		case 108: goto st42;
+		case 109: goto st48;
+		case 112: goto st58;
+		case 114: goto st62;
+		case 115: goto st72;
+		case 116: goto st81;
+	}
+	if ( (*p) > 13 ) {
+		if ( 48 <= (*p) && (*p) <= 57 )
+			goto tr113;
+	} else if ( (*p) >= 9 )
+		goto st87;
+	goto st0;
+st0:
+cs = 0;
+	goto _out;
+st87:
+	if ( ++p == pe )
+		goto _test_eof87;
+case 87:
+	if ( (*p) == 32 )
+		goto st87;
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st87;
+	goto tr125;
+st1:
+	if ( ++p == pe )
+		goto _test_eof1;
+case 1:
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr0;
+	goto st0;
+tr0:
+#line 1 "NONE"
+	{te = p+1;}
+	goto st88;
+st88:
+	if ( ++p == pe )
+		goto _test_eof88;
+case 88:
+#line 472 "evalStringToScalarScanner.cc"
+	switch( (*p) ) {
+		case 69: goto st2;
+		case 101: goto st2;
+	}
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr0;
+	goto tr126;
+st2:
+	if ( ++p == pe )
+		goto _test_eof2;
+case 2:
+	switch( (*p) ) {
+		case 43: goto st3;
+		case 45: goto st3;
+	}
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st89;
+	goto tr2;
+st3:
+	if ( ++p == pe )
+		goto _test_eof3;
+case 3:
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st89;
+	goto tr2;
+st89:
+	if ( ++p == pe )
+		goto _test_eof89;
+case 89:
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto st89;
+	goto tr126;
+tr112:
+#line 1 "NONE"
+	{te = p+1;}
+#line 147 "evalStringToScalarScanner.rl"
+	{ EMIT_TOKEN(DIVIDE); }
+	goto st90;
+st90:
+	if ( ++p == pe )
+		goto _test_eof90;
+case 90:
+#line 515 "evalStringToScalarScanner.cc"
+	switch( (*p) ) {
+		case 42: goto st4;
+		case 47: goto st91;
+	}
+	goto tr128;
+st4:
+	if ( ++p == pe )
+		goto _test_eof4;
+case 4:
+	if ( (*p) == 42 )
+		goto st5;
+	goto st4;
+st5:
+	if ( ++p == pe )
+		goto _test_eof5;
+case 5:
+	switch( (*p) ) {
+		case 42: goto st5;
+		case 47: goto tr8;
+	}
+	goto st4;
+st91:
+	if ( ++p == pe )
+		goto _test_eof91;
+case 91:
+	if ( (*p) == 10 )
+		goto tr131;
+	goto st91;
+tr131:
+#line 74 "evalStringToScalarScanner.rl"
+	{
+        // Inform driver of last position
+        driver.parsePosition() = (p-buf);
+    }
+	goto st92;
+st92:
+	if ( ++p == pe )
+		goto _test_eof92;
+case 92:
+#line 555 "evalStringToScalarScanner.cc"
+	if ( (*p) == 10 )
+		goto tr131;
+	goto tr130;
+tr113:
+#line 1 "NONE"
+	{te = p+1;}
+	goto st93;
+st93:
+	if ( ++p == pe )
+		goto _test_eof93;
+case 93:
+#line 567 "evalStringToScalarScanner.cc"
+	switch( (*p) ) {
+		case 46: goto tr0;
+		case 69: goto st2;
+		case 101: goto st2;
+	}
+	if ( 48 <= (*p) && (*p) <= 57 )
+		goto tr113;
+	goto tr126;
+st6:
+	if ( ++p == pe )
+		goto _test_eof6;
+case 6:
+	switch( (*p) ) {
+		case 99: goto st7;
+		case 115: goto st10;
+		case 116: goto st13;
+	}
+	goto st0;
+st7:
+	if ( ++p == pe )
+		goto _test_eof7;
+case 7:
+	if ( (*p) == 111 )
+		goto st8;
+	goto st0;
+st8:
+	if ( ++p == pe )
+		goto _test_eof8;
+case 8:
+	if ( (*p) == 115 )
+		goto st9;
+	goto st0;
+st9:
+	if ( ++p == pe )
+		goto _test_eof9;
+case 9:
+	switch( (*p) ) {
+		case 32: goto st9;
+		case 40: goto tr14;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st9;
+	goto st0;
+st10:
+	if ( ++p == pe )
+		goto _test_eof10;
+case 10:
+	if ( (*p) == 105 )
+		goto st11;
+	goto st0;
+st11:
+	if ( ++p == pe )
+		goto _test_eof11;
+case 11:
+	if ( (*p) == 110 )
+		goto st12;
+	goto st0;
+st12:
+	if ( ++p == pe )
+		goto _test_eof12;
+case 12:
+	switch( (*p) ) {
+		case 32: goto st12;
+		case 40: goto tr17;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st12;
+	goto st0;
+st13:
+	if ( ++p == pe )
+		goto _test_eof13;
+case 13:
+	if ( (*p) == 97 )
+		goto st14;
+	goto st0;
+st14:
+	if ( ++p == pe )
+		goto _test_eof14;
+case 14:
+	if ( (*p) == 110 )
+		goto st15;
+	goto st0;
+st15:
+	if ( ++p == pe )
+		goto _test_eof15;
+case 15:
+	switch( (*p) ) {
+		case 32: goto st16;
+		case 40: goto tr21;
+		case 50: goto st17;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st16;
+	goto st0;
+st16:
+	if ( ++p == pe )
+		goto _test_eof16;
+case 16:
+	switch( (*p) ) {
+		case 32: goto st16;
+		case 40: goto tr21;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st16;
+	goto st0;
+st17:
+	if ( ++p == pe )
+		goto _test_eof17;
+case 17:
+	switch( (*p) ) {
+		case 32: goto st17;
+		case 40: goto tr23;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st17;
+	goto st0;
+st18:
+	if ( ++p == pe )
+		goto _test_eof18;
+case 18:
+	switch( (*p) ) {
+		case 98: goto st19;
+		case 111: goto st22;
+	}
+	goto st0;
+st19:
+	if ( ++p == pe )
+		goto _test_eof19;
+case 19:
+	if ( (*p) == 114 )
+		goto st20;
+	goto st0;
+st20:
+	if ( ++p == pe )
+		goto _test_eof20;
+case 20:
+	if ( (*p) == 116 )
+		goto st21;
+	goto st0;
+st21:
+	if ( ++p == pe )
+		goto _test_eof21;
+case 21:
+	switch( (*p) ) {
+		case 32: goto st21;
+		case 40: goto tr28;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st21;
+	goto st0;
+st22:
+	if ( ++p == pe )
+		goto _test_eof22;
+case 22:
+	if ( (*p) == 115 )
+		goto st23;
+	goto st0;
+st23:
+	if ( ++p == pe )
+		goto _test_eof23;
+case 23:
+	switch( (*p) ) {
+		case 32: goto st24;
+		case 40: goto tr31;
+		case 104: goto st25;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st24;
+	goto st0;
+st24:
+	if ( ++p == pe )
+		goto _test_eof24;
+case 24:
+	switch( (*p) ) {
+		case 32: goto st24;
+		case 40: goto tr31;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st24;
+	goto st0;
+st25:
+	if ( ++p == pe )
+		goto _test_eof25;
+case 25:
+	switch( (*p) ) {
+		case 32: goto st25;
+		case 40: goto tr33;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st25;
+	goto st0;
+st26:
+	if ( ++p == pe )
+		goto _test_eof26;
+case 26:
+	if ( (*p) == 101 )
+		goto st27;
+	goto st0;
+st27:
+	if ( ++p == pe )
+		goto _test_eof27;
+case 27:
+	if ( (*p) == 103 )
+		goto st28;
+	goto st0;
+st28:
+	if ( ++p == pe )
+		goto _test_eof28;
+case 28:
+	if ( (*p) == 84 )
+		goto st29;
+	goto st0;
+st29:
+	if ( ++p == pe )
+		goto _test_eof29;
+case 29:
+	if ( (*p) == 111 )
+		goto st30;
+	goto st0;
+st30:
+	if ( ++p == pe )
+		goto _test_eof30;
+case 30:
+	if ( (*p) == 82 )
+		goto st31;
+	goto st0;
+st31:
+	if ( ++p == pe )
+		goto _test_eof31;
+case 31:
+	if ( (*p) == 97 )
+		goto st32;
+	goto st0;
+st32:
+	if ( ++p == pe )
+		goto _test_eof32;
+case 32:
+	if ( (*p) == 100 )
+		goto st33;
+	goto st0;
+st33:
+	if ( ++p == pe )
+		goto _test_eof33;
+case 33:
+	switch( (*p) ) {
+		case 32: goto st33;
+		case 40: goto tr41;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st33;
+	goto st0;
+st34:
+	if ( ++p == pe )
+		goto _test_eof34;
+case 34:
+	if ( (*p) == 120 )
+		goto st35;
+	goto st0;
+st35:
+	if ( ++p == pe )
+		goto _test_eof35;
+case 35:
+	if ( (*p) == 112 )
+		goto st36;
+	goto st0;
+st36:
+	if ( ++p == pe )
+		goto _test_eof36;
+case 36:
+	switch( (*p) ) {
+		case 32: goto st36;
+		case 40: goto tr44;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st36;
+	goto st0;
+st37:
+	if ( ++p == pe )
+		goto _test_eof37;
+case 37:
+	if ( (*p) == 121 )
+		goto st38;
+	goto st0;
+st38:
+	if ( ++p == pe )
+		goto _test_eof38;
+case 38:
+	if ( (*p) == 112 )
+		goto st39;
+	goto st0;
+st39:
+	if ( ++p == pe )
+		goto _test_eof39;
+case 39:
+	if ( (*p) == 111 )
+		goto st40;
+	goto st0;
+st40:
+	if ( ++p == pe )
+		goto _test_eof40;
+case 40:
+	if ( (*p) == 116 )
+		goto st41;
+	goto st0;
+st41:
+	if ( ++p == pe )
+		goto _test_eof41;
+case 41:
+	switch( (*p) ) {
+		case 32: goto st41;
+		case 40: goto tr49;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st41;
+	goto st0;
+st42:
+	if ( ++p == pe )
+		goto _test_eof42;
+case 42:
+	if ( (*p) == 111 )
+		goto st43;
+	goto st0;
+st43:
+	if ( ++p == pe )
+		goto _test_eof43;
+case 43:
+	if ( (*p) == 103 )
+		goto st44;
+	goto st0;
+st44:
+	if ( ++p == pe )
+		goto _test_eof44;
+case 44:
+	switch( (*p) ) {
+		case 32: goto st45;
+		case 40: goto tr53;
+		case 49: goto st46;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st45;
+	goto st0;
+st45:
+	if ( ++p == pe )
+		goto _test_eof45;
+case 45:
+	switch( (*p) ) {
+		case 32: goto st45;
+		case 40: goto tr53;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st45;
+	goto st0;
+st46:
+	if ( ++p == pe )
+		goto _test_eof46;
+case 46:
+	if ( (*p) == 48 )
+		goto st47;
+	goto st0;
+st47:
+	if ( ++p == pe )
+		goto _test_eof47;
+case 47:
+	switch( (*p) ) {
+		case 32: goto st47;
+		case 40: goto tr56;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st47;
+	goto st0;
+st48:
+	if ( ++p == pe )
+		goto _test_eof48;
+case 48:
+	switch( (*p) ) {
+		case 97: goto st49;
+		case 105: goto st56;
+	}
+	goto st0;
+st49:
+	if ( ++p == pe )
+		goto _test_eof49;
+case 49:
+	switch( (*p) ) {
+		case 103: goto st50;
+		case 120: goto st55;
+	}
+	goto st0;
+st50:
+	if ( ++p == pe )
+		goto _test_eof50;
+case 50:
+	switch( (*p) ) {
+		case 32: goto st51;
+		case 40: goto tr62;
+		case 83: goto st52;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st51;
+	goto st0;
+st51:
+	if ( ++p == pe )
+		goto _test_eof51;
+case 51:
+	switch( (*p) ) {
+		case 32: goto st51;
+		case 40: goto tr62;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st51;
+	goto st0;
+st52:
+	if ( ++p == pe )
+		goto _test_eof52;
+case 52:
+	if ( (*p) == 113 )
+		goto st53;
+	goto st0;
+st53:
+	if ( ++p == pe )
+		goto _test_eof53;
+case 53:
+	if ( (*p) == 114 )
+		goto st54;
+	goto st0;
+st54:
+	if ( ++p == pe )
+		goto _test_eof54;
+case 54:
+	switch( (*p) ) {
+		case 32: goto st54;
+		case 40: goto tr66;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st54;
+	goto st0;
+st55:
+	if ( ++p == pe )
+		goto _test_eof55;
+case 55:
+	switch( (*p) ) {
+		case 32: goto st55;
+		case 40: goto tr67;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st55;
+	goto st0;
+st56:
+	if ( ++p == pe )
+		goto _test_eof56;
+case 56:
+	if ( (*p) == 110 )
+		goto st57;
+	goto st0;
+st57:
+	if ( ++p == pe )
+		goto _test_eof57;
+case 57:
+	switch( (*p) ) {
+		case 32: goto st57;
+		case 40: goto tr69;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st57;
+	goto st0;
+st58:
+	if ( ++p == pe )
+		goto _test_eof58;
+case 58:
+	switch( (*p) ) {
+		case 105: goto st59;
+		case 111: goto st60;
+	}
+	goto st0;
+st59:
+	if ( ++p == pe )
+		goto _test_eof59;
+case 59:
+	switch( (*p) ) {
+		case 32: goto st59;
+		case 40: goto tr72;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st59;
+	goto st0;
+st60:
+	if ( ++p == pe )
+		goto _test_eof60;
+case 60:
+	if ( (*p) == 119 )
+		goto st61;
+	goto st0;
+st61:
+	if ( ++p == pe )
+		goto _test_eof61;
+case 61:
+	switch( (*p) ) {
+		case 32: goto st61;
+		case 40: goto tr74;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st61;
+	goto st0;
+st62:
+	if ( ++p == pe )
+		goto _test_eof62;
+case 62:
+	if ( (*p) == 97 )
+		goto st63;
+	goto st0;
+st63:
+	if ( ++p == pe )
+		goto _test_eof63;
+case 63:
+	switch( (*p) ) {
+		case 100: goto st64;
+		case 110: goto st70;
+	}
+	goto st0;
+st64:
+	if ( ++p == pe )
+		goto _test_eof64;
+case 64:
+	if ( (*p) == 84 )
+		goto st65;
+	goto st0;
+st65:
+	if ( ++p == pe )
+		goto _test_eof65;
+case 65:
+	if ( (*p) == 111 )
+		goto st66;
+	goto st0;
+st66:
+	if ( ++p == pe )
+		goto _test_eof66;
+case 66:
+	if ( (*p) == 68 )
+		goto st67;
+	goto st0;
+st67:
+	if ( ++p == pe )
+		goto _test_eof67;
+case 67:
+	if ( (*p) == 101 )
+		goto st68;
+	goto st0;
+st68:
+	if ( ++p == pe )
+		goto _test_eof68;
+case 68:
+	if ( (*p) == 103 )
+		goto st69;
+	goto st0;
+st69:
+	if ( ++p == pe )
+		goto _test_eof69;
+case 69:
+	switch( (*p) ) {
+		case 32: goto st69;
+		case 40: goto tr83;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st69;
+	goto st0;
+st70:
+	if ( ++p == pe )
+		goto _test_eof70;
+case 70:
+	if ( (*p) == 100 )
+		goto st71;
+	goto st0;
+st71:
+	if ( ++p == pe )
+		goto _test_eof71;
+case 71:
+	switch( (*p) ) {
+		case 32: goto st71;
+		case 40: goto tr85;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st71;
+	goto st0;
+st72:
+	if ( ++p == pe )
+		goto _test_eof72;
+case 72:
+	switch( (*p) ) {
+		case 105: goto st73;
+		case 113: goto st77;
+	}
+	goto st0;
+st73:
+	if ( ++p == pe )
+		goto _test_eof73;
+case 73:
+	if ( (*p) == 110 )
+		goto st74;
+	goto st0;
+st74:
+	if ( ++p == pe )
+		goto _test_eof74;
+case 74:
+	switch( (*p) ) {
+		case 32: goto st75;
+		case 40: goto tr90;
+		case 104: goto st76;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st75;
+	goto st0;
+st75:
+	if ( ++p == pe )
+		goto _test_eof75;
+case 75:
+	switch( (*p) ) {
+		case 32: goto st75;
+		case 40: goto tr90;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st75;
+	goto st0;
+st76:
+	if ( ++p == pe )
+		goto _test_eof76;
+case 76:
+	switch( (*p) ) {
+		case 32: goto st76;
+		case 40: goto tr92;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st76;
+	goto st0;
+st77:
+	if ( ++p == pe )
+		goto _test_eof77;
+case 77:
+	if ( (*p) == 114 )
+		goto st78;
+	goto st0;
+st78:
+	if ( ++p == pe )
+		goto _test_eof78;
+case 78:
+	switch( (*p) ) {
+		case 32: goto st79;
+		case 40: goto tr95;
+		case 116: goto st80;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st79;
+	goto st0;
+st79:
+	if ( ++p == pe )
+		goto _test_eof79;
+case 79:
+	switch( (*p) ) {
+		case 32: goto st79;
+		case 40: goto tr95;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st79;
+	goto st0;
+st80:
+	if ( ++p == pe )
+		goto _test_eof80;
+case 80:
+	switch( (*p) ) {
+		case 32: goto st80;
+		case 40: goto tr97;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st80;
+	goto st0;
+st81:
+	if ( ++p == pe )
+		goto _test_eof81;
+case 81:
+	if ( (*p) == 97 )
+		goto st82;
+	goto st0;
+st82:
+	if ( ++p == pe )
+		goto _test_eof82;
+case 82:
+	if ( (*p) == 110 )
+		goto st83;
+	goto st0;
+st83:
+	if ( ++p == pe )
+		goto _test_eof83;
+case 83:
+	switch( (*p) ) {
+		case 32: goto st84;
+		case 40: goto tr101;
+		case 104: goto st85;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st84;
+	goto st0;
+st84:
+	if ( ++p == pe )
+		goto _test_eof84;
+case 84:
+	switch( (*p) ) {
+		case 32: goto st84;
+		case 40: goto tr101;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st84;
+	goto st0;
+st85:
+	if ( ++p == pe )
+		goto _test_eof85;
+case 85:
+	switch( (*p) ) {
+		case 32: goto st85;
+		case 40: goto tr103;
+	}
+	if ( 9 <= (*p) && (*p) <= 13 )
+		goto st85;
+	goto st0;
+	}
+	_test_eof86: cs = 86; goto _test_eof; 
+	_test_eof87: cs = 87; goto _test_eof; 
+	_test_eof1: cs = 1; goto _test_eof; 
+	_test_eof88: cs = 88; goto _test_eof; 
+	_test_eof2: cs = 2; goto _test_eof; 
+	_test_eof3: cs = 3; goto _test_eof; 
+	_test_eof89: cs = 89; goto _test_eof; 
+	_test_eof90: cs = 90; goto _test_eof; 
+	_test_eof4: cs = 4; goto _test_eof; 
+	_test_eof5: cs = 5; goto _test_eof; 
+	_test_eof91: cs = 91; goto _test_eof; 
+	_test_eof92: cs = 92; goto _test_eof; 
+	_test_eof93: cs = 93; goto _test_eof; 
+	_test_eof6: cs = 6; goto _test_eof; 
+	_test_eof7: cs = 7; goto _test_eof; 
+	_test_eof8: cs = 8; goto _test_eof; 
+	_test_eof9: cs = 9; goto _test_eof; 
+	_test_eof10: cs = 10; goto _test_eof; 
+	_test_eof11: cs = 11; goto _test_eof; 
+	_test_eof12: cs = 12; goto _test_eof; 
+	_test_eof13: cs = 13; goto _test_eof; 
+	_test_eof14: cs = 14; goto _test_eof; 
+	_test_eof15: cs = 15; goto _test_eof; 
+	_test_eof16: cs = 16; goto _test_eof; 
+	_test_eof17: cs = 17; goto _test_eof; 
+	_test_eof18: cs = 18; goto _test_eof; 
+	_test_eof19: cs = 19; goto _test_eof; 
+	_test_eof20: cs = 20; goto _test_eof; 
+	_test_eof21: cs = 21; goto _test_eof; 
+	_test_eof22: cs = 22; goto _test_eof; 
+	_test_eof23: cs = 23; goto _test_eof; 
+	_test_eof24: cs = 24; goto _test_eof; 
+	_test_eof25: cs = 25; goto _test_eof; 
+	_test_eof26: cs = 26; goto _test_eof; 
+	_test_eof27: cs = 27; goto _test_eof; 
+	_test_eof28: cs = 28; goto _test_eof; 
+	_test_eof29: cs = 29; goto _test_eof; 
+	_test_eof30: cs = 30; goto _test_eof; 
+	_test_eof31: cs = 31; goto _test_eof; 
+	_test_eof32: cs = 32; goto _test_eof; 
+	_test_eof33: cs = 33; goto _test_eof; 
+	_test_eof34: cs = 34; goto _test_eof; 
+	_test_eof35: cs = 35; goto _test_eof; 
+	_test_eof36: cs = 36; goto _test_eof; 
+	_test_eof37: cs = 37; goto _test_eof; 
+	_test_eof38: cs = 38; goto _test_eof; 
+	_test_eof39: cs = 39; goto _test_eof; 
+	_test_eof40: cs = 40; goto _test_eof; 
+	_test_eof41: cs = 41; goto _test_eof; 
+	_test_eof42: cs = 42; goto _test_eof; 
+	_test_eof43: cs = 43; goto _test_eof; 
+	_test_eof44: cs = 44; goto _test_eof; 
+	_test_eof45: cs = 45; goto _test_eof; 
+	_test_eof46: cs = 46; goto _test_eof; 
+	_test_eof47: cs = 47; goto _test_eof; 
+	_test_eof48: cs = 48; goto _test_eof; 
+	_test_eof49: cs = 49; goto _test_eof; 
+	_test_eof50: cs = 50; goto _test_eof; 
+	_test_eof51: cs = 51; goto _test_eof; 
+	_test_eof52: cs = 52; goto _test_eof; 
+	_test_eof53: cs = 53; goto _test_eof; 
+	_test_eof54: cs = 54; goto _test_eof; 
+	_test_eof55: cs = 55; goto _test_eof; 
+	_test_eof56: cs = 56; goto _test_eof; 
+	_test_eof57: cs = 57; goto _test_eof; 
+	_test_eof58: cs = 58; goto _test_eof; 
+	_test_eof59: cs = 59; goto _test_eof; 
+	_test_eof60: cs = 60; goto _test_eof; 
+	_test_eof61: cs = 61; goto _test_eof; 
+	_test_eof62: cs = 62; goto _test_eof; 
+	_test_eof63: cs = 63; goto _test_eof; 
+	_test_eof64: cs = 64; goto _test_eof; 
+	_test_eof65: cs = 65; goto _test_eof; 
+	_test_eof66: cs = 66; goto _test_eof; 
+	_test_eof67: cs = 67; goto _test_eof; 
+	_test_eof68: cs = 68; goto _test_eof; 
+	_test_eof69: cs = 69; goto _test_eof; 
+	_test_eof70: cs = 70; goto _test_eof; 
+	_test_eof71: cs = 71; goto _test_eof; 
+	_test_eof72: cs = 72; goto _test_eof; 
+	_test_eof73: cs = 73; goto _test_eof; 
+	_test_eof74: cs = 74; goto _test_eof; 
+	_test_eof75: cs = 75; goto _test_eof; 
+	_test_eof76: cs = 76; goto _test_eof; 
+	_test_eof77: cs = 77; goto _test_eof; 
+	_test_eof78: cs = 78; goto _test_eof; 
+	_test_eof79: cs = 79; goto _test_eof; 
+	_test_eof80: cs = 80; goto _test_eof; 
+	_test_eof81: cs = 81; goto _test_eof; 
+	_test_eof82: cs = 82; goto _test_eof; 
+	_test_eof83: cs = 83; goto _test_eof; 
+	_test_eof84: cs = 84; goto _test_eof; 
+	_test_eof85: cs = 85; goto _test_eof; 
+
+	_test_eof: {}
+	if ( p == eof )
+	{
+	switch ( cs ) {
+	case 87: goto tr125;
+	case 88: goto tr126;
+	case 2: goto tr2;
+	case 3: goto tr2;
+	case 89: goto tr126;
+	case 90: goto tr128;
+	case 4: goto tr5;
+	case 5: goto tr5;
+	case 91: goto tr130;
+	case 92: goto tr130;
+	case 93: goto tr126;
+	}
+	}
+
+	_out: {}
+	}
+
+#line 209 "evalStringToScalarScanner.rl"
+  /* ^^^ FSM execution here ^^^ */;
+
+    if (0 == 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;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.rl b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.rl
new file mode 100644
index 0000000000000000000000000000000000000000..5f540dee34bdabbe69eff7d8c0934a630acc8abc
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/stringOps/toScalar/evalStringToScalarScanner.rl
@@ -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;
+}
+
+
+// ************************************************************************* //