From 74b12c6afd4e33bc49f33df861d4ef165e9a1d1a Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 19 Dec 2019 10:27:47 +0100
Subject: [PATCH] ENH: improved separation of scanner/parser debug selection

- now use debug 2 for scanner and debug 4 for parser.
  Provided better feedback about what is being parsed (debug mode)

- relocate debug application to applications/tools/foamExprParserInfo
---
 applications/Allwmake                         |   3 +
 applications/test/parserInfo/Make/files       |   3 -
 .../test/parserInfo/Test-parserInfo.C         | 131 ------------
 applications/tools/README.md                  |   5 +
 .../tools/foamExprParserInfo/Make/files       |   3 +
 .../foamExprParserInfo}/Make/options          |   0
 .../foamExprParserInfo/foamExprParserInfo.C   | 199 ++++++++++++++++++
 etc/controlDict                               |   3 +
 .../expressions/exprDriver/exprDriver.H       |   3 +-
 .../expressions/fields/fieldExprDriver.H      |   4 +
 .../fields/fieldExprLemonParser.lyy-m4        |   2 +-
 .../expressions/fields/fieldExprScanner.cc    |  40 ++--
 .../expressions/fields/fieldExprScanner.rl    |  22 +-
 .../expressions/patch/patchExprDriver.H       |  10 +-
 .../patch/patchExprLemonParser.lyy-m4         |   2 +-
 .../expressions/patch/patchExprScanner.cc     |  40 ++--
 .../expressions/patch/patchExprScanner.rl     |  22 +-
 .../expressions/volume/volumeExprDriver.H     |   9 +-
 .../volume/volumeExprLemonParser.lyy-m4       |   2 +-
 .../expressions/volume/volumeExprScanner.cc   |  40 ++--
 .../expressions/volume/volumeExprScanner.rl   |  22 +-
 21 files changed, 359 insertions(+), 206 deletions(-)
 delete mode 100644 applications/test/parserInfo/Make/files
 delete mode 100644 applications/test/parserInfo/Test-parserInfo.C
 create mode 100644 applications/tools/README.md
 create mode 100644 applications/tools/foamExprParserInfo/Make/files
 rename applications/{test/parserInfo => tools/foamExprParserInfo}/Make/options (100%)
 create mode 100644 applications/tools/foamExprParserInfo/foamExprParserInfo.C

diff --git a/applications/Allwmake b/applications/Allwmake
index 93499ae1cd1..ad65e141120 100755
--- a/applications/Allwmake
+++ b/applications/Allwmake
@@ -19,4 +19,7 @@ wmakeCheckPwd "$WM_PROJECT_DIR/applications" 2>/dev/null || {
 wmake -all $targetType solvers
 wmake -all $targetType utilities
 
+# Optional
+## wmake -all $targetType tools
+
 #------------------------------------------------------------------------------
diff --git a/applications/test/parserInfo/Make/files b/applications/test/parserInfo/Make/files
deleted file mode 100644
index 2b9262c86b9..00000000000
--- a/applications/test/parserInfo/Make/files
+++ /dev/null
@@ -1,3 +0,0 @@
-Test-parserInfo.C
-
-EXE = $(FOAM_USER_APPBIN)/Test-parserInfo
diff --git a/applications/test/parserInfo/Test-parserInfo.C b/applications/test/parserInfo/Test-parserInfo.C
deleted file mode 100644
index c9fdb8ba4e5..00000000000
--- a/applications/test/parserInfo/Test-parserInfo.C
+++ /dev/null
@@ -1,131 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | www.openfoam.com
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-    Copyright (C) 2019 OpenCFD Ltd.
--------------------------------------------------------------------------------
-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
-    Output some (expressions) parser information
-
-\*---------------------------------------------------------------------------*/
-
-#include "argList.H"
-#include "IOstreams.H"
-#include "List.H"
-#include "fieldExprParser.H"
-#include "patchExprParser.H"
-#include "volumeExprParser.H"
-
-using namespace Foam;
-
-template<class Parser>
-void printInformation
-(
-    Ostream& os,
-    const word& name,
-    const bool printNames,
-    const bool printRules
-)
-{
-    if (printNames)
-    {
-        os << nl << name << " tokenNames:" << nl;
-        Parser::printTokenNames(os);
-    }
-
-    if (printRules)
-    {
-        os << nl << name << " rules:" << nl;
-        Parser::printRules(os);
-    }
-}
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-// Main program:
-
-int main(int argc, char *argv[])
-{
-    argList::noBanner();
-    argList::addNote
-    (
-        "Display token names or rules for specified expression parser(s)."
-        " Without options, displays everything."
-    );
-
-    argList::addBoolOption("rules", "Print parser rules");
-    argList::addBoolOption("tokens", "Print token names");
-
-    argList::addBoolOption("field", "Field expression parser");
-    argList::addBoolOption("patch", "Patch expression parser");
-    argList::addBoolOption("volume", "Volume expression parser");
-
-    argList args(argc, argv);
-
-    // Defaults
-    const bool all = !args.count({"field", "patch", "volume"});
-    const bool both = !args.count({"tokens", "rules"});
-
-    const bool printNames = both || args.found("tokens");
-    const bool printRules = both || args.found("rules");
-
-
-    if (all || args.found("field"))
-    {
-        printInformation<Foam::expressions::fieldExpr::parser>
-        (
-            Info,
-            "field",
-            printNames,
-            printRules
-        );
-    }
-
-    if (all || args.found("patch"))
-    {
-        printInformation<Foam::expressions::patchExpr::parser>
-        (
-            Info,
-            "patch",
-            printNames,
-            printRules
-        );
-    }
-
-    if (all || args.found("volume"))
-    {
-        printInformation<Foam::expressions::volumeExpr::parser>
-        (
-            Info,
-            "volume",
-            printNames,
-            printRules
-        );
-    }
-
-    Info<< "\nEnd\n" << endl;
-
-    return 0;
-}
-
-
-// ************************************************************************* //
diff --git a/applications/tools/README.md b/applications/tools/README.md
new file mode 100644
index 00000000000..5fc0f7b98f8
--- /dev/null
+++ b/applications/tools/README.md
@@ -0,0 +1,5 @@
+The applications/tools directory contains tools that may be useful for
+developers or advanced users, but which will not normally be built.
+
+The user should note that the types of tools, their behaviour and
+syntax are subject to much more fluctuation than regular utilities.
diff --git a/applications/tools/foamExprParserInfo/Make/files b/applications/tools/foamExprParserInfo/Make/files
new file mode 100644
index 00000000000..8875a6ac43b
--- /dev/null
+++ b/applications/tools/foamExprParserInfo/Make/files
@@ -0,0 +1,3 @@
+foamExprParserInfo.C
+
+EXE = $(FOAM_APPBIN)/foamExprParserInfo
diff --git a/applications/test/parserInfo/Make/options b/applications/tools/foamExprParserInfo/Make/options
similarity index 100%
rename from applications/test/parserInfo/Make/options
rename to applications/tools/foamExprParserInfo/Make/options
diff --git a/applications/tools/foamExprParserInfo/foamExprParserInfo.C b/applications/tools/foamExprParserInfo/foamExprParserInfo.C
new file mode 100644
index 00000000000..0a5ada752da
--- /dev/null
+++ b/applications/tools/foamExprParserInfo/foamExprParserInfo.C
@@ -0,0 +1,199 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2019 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    foamExprParserInfo
+
+Group
+    grpTools
+
+Description
+    Display token names or rules for specified expression parsers.
+
+    In the Lemon grammar, terminals (uppercase) are listed first.
+    Non-terminals (lowercase) are listed second.
+
+    The current OpenFOAM grammar short naming conventions:
+    - svalue : scalar value
+    - sfield : scalar field
+    - lfield : logic field
+    - vfield : vector field
+    - tfield : tensor field
+    - hfield : sphericalTensor field
+    - yfield : symmTensor field
+    .
+    Prefixes: 's' (surface) or 'p' (point).
+    For example, psfield for a point scalar field
+
+Usage
+    \b foamExprParserInfo [OPTION]
+
+    Options:
+      - \par -rules
+        Print parser rules
+
+      - \par -tokens
+        Print token names (default)
+
+      - \par -all
+        Display information for all parsers
+
+      - \par -field
+        Field expression parser information
+
+      - \par -patch
+        Patch expression parser information
+
+      - \par -volume
+        Volume expression parser information
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "IOstreams.H"
+#include "List.H"
+#include "fieldExprParser.H"
+#include "patchExprParser.H"
+#include "volumeExprParser.H"
+
+using namespace Foam;
+
+template<class Parser>
+void printInformation
+(
+    Ostream& os,
+    const word& name,
+    const bool printNames,
+    const bool printRules
+)
+{
+    if (printNames)
+    {
+        os << nl << "# Tokens for " << name << nl;
+        Parser::printTokenNames(os);
+    }
+
+    if (printRules)
+    {
+        os << nl << "# Rules for " << name << nl;
+        Parser::printRules(os);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noBanner();
+    argList::noParallel();
+    argList::setAdvanced("case");  // Hide -case : has no meaning here
+
+    argList::addNote
+    (
+        "Display token names or rules for specified expression parsers.\n"
+        "In the Lemon grammar, terminals (uppercase) are listed first.\n"
+        "Non-terminals (lowercase) are listed second.\n \n"
+        "The current OpenFOAM grammar short naming conventions:\n"
+        "  * svalue : scalar value\n"
+        "  * sfield : scalar field\n"
+        "  * lfield : logic field\n"
+        "  * vfield : vector field\n"
+        "  * tfield : tensor field\n"
+        "  * hfield : sphericalTensor field\n"
+        "  * yfield : symmTensor field\n"
+        " \n"
+        "Prefixes: 's' (surface) or 'p' (point).\n"
+        "Eg, psfield for a point scalar field\n"
+    );
+
+    argList::addBoolOption("rules", "Print parser rules");
+    argList::addBoolOption("tokens", "Print token names (default)");
+
+    argList::addBoolOption("all", "Display information for all parsers");
+    argList::addBoolOption("field", "Field expression parser information");
+    argList::addBoolOption("patch", "Patch expression parser information");
+    argList::addBoolOption("volume", "Volume expression parser information");
+
+    argList args(argc, argv);
+
+    const bool all = args.found("all");
+    const bool printRules = args.found("rules");
+    const bool printNames = args.found("tokens") || !printRules;
+
+    label count = 0;
+
+    if (all || args.found("field"))
+    {
+        ++count;
+        printInformation<expressions::fieldExpr::parser>
+        (
+            Info,
+            "field",
+            printNames,
+            printRules
+        );
+    }
+
+    if (all || args.found("patch"))
+    {
+        ++count;
+        printInformation<expressions::patchExpr::parser>
+        (
+            Info,
+            "patch",
+            printNames,
+            printRules
+        );
+    }
+
+    if (all || args.found("volume"))
+    {
+        ++count;
+        printInformation<expressions::volumeExpr::parser>
+        (
+            Info,
+            "volume",
+            printNames,
+            printRules
+        );
+    }
+
+    if (!count)
+    {
+        InfoErr
+            << "Error: no parser selected." << nl
+            << "See '" << args.executable() << " -help' for usage" << nl
+            << nl;
+
+        return 1;
+    }
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/etc/controlDict b/etc/controlDict
index 02bdf85dbd4..ee7736337e7 100644
--- a/etc/controlDict
+++ b/etc/controlDict
@@ -542,6 +542,7 @@ DebugSwitches
     faceZone            0;
     fan                 0;
     featureEdgeMesh     0;
+    fieldExpr           0;
     fieldToCell         0;
     file                0;
     fileName            2;
@@ -759,6 +760,7 @@ DebugSwitches
     partialSlip         0;
     passiveParticle     0;
     patch               0;
+    patchExpr           0;
     patchToFace         0;
     patchZones          0;
     pdf                 0;
@@ -966,6 +968,7 @@ DebugSwitches
     volTensorField::Internal 0;
     volVectorField      0;
     volVectorField::Internal 0;
+    volumeExpr          0;
     vtk                 0;
     walkPatch           0;
     wall                0;
diff --git a/src/OpenFOAM/expressions/exprDriver/exprDriver.H b/src/OpenFOAM/expressions/exprDriver/exprDriver.H
index 77cc3fb090a..723d45a53d1 100644
--- a/src/OpenFOAM/expressions/exprDriver/exprDriver.H
+++ b/src/OpenFOAM/expressions/exprDriver/exprDriver.H
@@ -395,7 +395,8 @@ public:
 
     // Evaluation
 
-        //- Execute the parser
+        //- Execute the parser.
+        //  The return value currently has no meaning.
         virtual unsigned parse
         (
             const std::string& expr,
diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.H b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
index bd45757845f..0221efe4aa8 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprDriver.H
+++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
@@ -39,6 +39,9 @@ Description
         rand        | Random field                          | 0/1 |
     \endtable
 
+Note
+    Use namespace debug switch \c fieldExpr for scanner (2), parser (4)
+
 SourceFiles
     fieldExprDriver.C
     fieldExprDriverFields.C
@@ -133,6 +136,7 @@ public:
         using genericRagelLemonDriver::content;
 
         //- Execute the parser
+        //  The return value currently has no meaning.
         virtual unsigned parse
         (
             const std::string& expr,
diff --git a/src/OpenFOAM/expressions/fields/fieldExprLemonParser.lyy-m4 b/src/OpenFOAM/expressions/fields/fieldExprLemonParser.lyy-m4
index 63d6832a595..485c74c59a8 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprLemonParser.lyy-m4
+++ b/src/OpenFOAM/expressions/fields/fieldExprLemonParser.lyy-m4
@@ -381,7 +381,7 @@ void Foam::expressions::fieldExpr::parser::start(parseDriver& driver_)
     this->stop();
     lemon_ = ParseAlloc(::operator new, &driver_);
 
-    if (debug || driver_.debugParser())
+    if ((debug & 0x4) || driver_.debugParser())
     {
         #ifndef NDEBUG
         ParseTrace(stderr, const_cast<char*>(prompt_));
diff --git a/src/OpenFOAM/expressions/fields/fieldExprScanner.cc b/src/OpenFOAM/expressions/fields/fieldExprScanner.cc
index 8a46b8c6232..da8256024a9 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprScanner.cc
+++ b/src/OpenFOAM/expressions/fields/fieldExprScanner.cc
@@ -42,7 +42,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -157,7 +157,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -349,9 +349,14 @@ bool Foam::expressions::fieldExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -383,12 +388,12 @@ bool Foam::expressions::fieldExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -398,7 +403,7 @@ bool Foam::expressions::fieldExpr::scanner::process
 
     // Initialize FSM variables
     
-#line 402 "fieldExprScanner.cc"
+#line 407 "fieldExprScanner.cc"
 	{
 	cs = fieldExpr_start;
 	ts = 0;
@@ -406,11 +411,11 @@ bool Foam::expressions::fieldExpr::scanner::process
 	act = 0;
 	}
 
-#line 528 "fieldExprScanner.rl"
+#line 533 "fieldExprScanner.rl"
    /* ^^^ FSM initialization here ^^^ */;
 
     
-#line 414 "fieldExprScanner.cc"
+#line 419 "fieldExprScanner.cc"
 	{
 	if ( p == pe )
 		goto _test_eof;
@@ -748,7 +753,7 @@ st11:
 case 11:
 #line 1 "NONE"
 	{ts = p;}
-#line 752 "fieldExprScanner.cc"
+#line 757 "fieldExprScanner.cc"
 	switch( (*p) ) {
 		case 32: goto st12;
 		case 33: goto st13;
@@ -875,7 +880,7 @@ st16:
 	if ( ++p == pe )
 		goto _test_eof16;
 case 16:
-#line 879 "fieldExprScanner.cc"
+#line 884 "fieldExprScanner.cc"
 	switch( (*p) ) {
 		case 69: goto st5;
 		case 101: goto st5;
@@ -926,7 +931,7 @@ st19:
 	if ( ++p == pe )
 		goto _test_eof19;
 case 19:
-#line 930 "fieldExprScanner.cc"
+#line 935 "fieldExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr57;
 		case 69: goto st5;
@@ -1163,7 +1168,7 @@ st23:
 	if ( ++p == pe )
 		goto _test_eof23;
 case 23:
-#line 1167 "fieldExprScanner.cc"
+#line 1172 "fieldExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr67;
 		case 95: goto tr67;
@@ -2929,7 +2934,7 @@ st120:
 	if ( ++p == pe )
 		goto _test_eof120;
 case 120:
-#line 2933 "fieldExprScanner.cc"
+#line 2938 "fieldExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr67;
 		case 58: goto st8;
@@ -3350,7 +3355,7 @@ case 10:
 	_out: {}
 	}
 
-#line 530 "fieldExprScanner.rl"
+#line 535 "fieldExprScanner.rl"
    /* ^^^ FSM execution here ^^^ */;
 
     if (0 == cs)
@@ -3367,6 +3372,11 @@ case 10:
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
diff --git a/src/OpenFOAM/expressions/fields/fieldExprScanner.rl b/src/OpenFOAM/expressions/fields/fieldExprScanner.rl
index ffcc8c55096..a1e8b3fe28f 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprScanner.rl
+++ b/src/OpenFOAM/expressions/fields/fieldExprScanner.rl
@@ -40,7 +40,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -155,7 +155,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -477,9 +477,14 @@ bool Foam::expressions::fieldExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -511,12 +516,12 @@ bool Foam::expressions::fieldExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -543,6 +548,11 @@ bool Foam::expressions::fieldExpr::scanner::process
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
diff --git a/src/finiteVolume/expressions/patch/patchExprDriver.H b/src/finiteVolume/expressions/patch/patchExprDriver.H
index 294c902cf41..919030ba06e 100644
--- a/src/finiteVolume/expressions/patch/patchExprDriver.H
+++ b/src/finiteVolume/expressions/patch/patchExprDriver.H
@@ -30,13 +30,12 @@ Description
     Driver for patch expressions
 
     In addition to the standard mathematical functions, operations and
-    logical and relational operations, the volume expression support the
+    logical and relational operations, the patch expressions support the
     following driver-specific functions:
 
     Functions
     \table
         Function    | Description                      | Number of arguments |
-        vol         | The cell volumes                      | 0 |
         pos         | The face centres                      | 0 |
         pts         | The face points                       | 0 |
         area        | The face area magnitudes              | 0 |
@@ -49,6 +48,10 @@ Description
         rand        | Random field                          | 0/1 |
     \endtable
 
+Note
+    Use namespace debug switch \c patchExpr for scanner (2), parser (4)
+    or dictionary controls as per Foam::expressions::exprDriver.
+
 SourceFiles
     patchExprDriver.C
     patchExprDriverFields.C
@@ -176,7 +179,8 @@ public:
         //- Perform parsing on (sub) string
         using genericRagelLemonDriver::content;
 
-        //- Execute the parser
+        //- Execute the parser.
+        //  The return value currently has no meaning.
         virtual unsigned parse
         (
             const std::string& expr,
diff --git a/src/finiteVolume/expressions/patch/patchExprLemonParser.lyy-m4 b/src/finiteVolume/expressions/patch/patchExprLemonParser.lyy-m4
index 5e6ea91dd0c..6080db3477e 100644
--- a/src/finiteVolume/expressions/patch/patchExprLemonParser.lyy-m4
+++ b/src/finiteVolume/expressions/patch/patchExprLemonParser.lyy-m4
@@ -527,7 +527,7 @@ void Foam::expressions::patchExpr::parser::start(parseDriver& driver_)
     this->stop();
     lemon_ = ParseAlloc(::operator new, &driver_);
 
-    if (debug || driver_.debugParser())
+    if ((debug & 0x4) || driver_.debugParser())
     {
         #ifndef NDEBUG
         ParseTrace(stderr, const_cast<char*>(prompt_));
diff --git a/src/finiteVolume/expressions/patch/patchExprScanner.cc b/src/finiteVolume/expressions/patch/patchExprScanner.cc
index d7d7c68012d..c78ac70e72e 100644
--- a/src/finiteVolume/expressions/patch/patchExprScanner.cc
+++ b/src/finiteVolume/expressions/patch/patchExprScanner.cc
@@ -42,7 +42,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -281,7 +281,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -473,9 +473,14 @@ bool Foam::expressions::patchExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -507,12 +512,12 @@ bool Foam::expressions::patchExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -522,7 +527,7 @@ bool Foam::expressions::patchExpr::scanner::process
 
     // Initialize FSM variables
     
-#line 526 "patchExprScanner.cc"
+#line 531 "patchExprScanner.cc"
 	{
 	cs = patchExpr_start;
 	ts = 0;
@@ -530,11 +535,11 @@ bool Foam::expressions::patchExpr::scanner::process
 	act = 0;
 	}
 
-#line 654 "patchExprScanner.rl"
+#line 659 "patchExprScanner.rl"
    /* ^^^ FSM initialization here ^^^ */;
 
     
-#line 538 "patchExprScanner.cc"
+#line 543 "patchExprScanner.cc"
 	{
 	if ( p == pe )
 		goto _test_eof;
@@ -881,7 +886,7 @@ st11:
 case 11:
 #line 1 "NONE"
 	{ts = p;}
-#line 885 "patchExprScanner.cc"
+#line 890 "patchExprScanner.cc"
 	switch( (*p) ) {
 		case 32: goto st12;
 		case 33: goto st13;
@@ -1009,7 +1014,7 @@ st16:
 	if ( ++p == pe )
 		goto _test_eof16;
 case 16:
-#line 1013 "patchExprScanner.cc"
+#line 1018 "patchExprScanner.cc"
 	switch( (*p) ) {
 		case 69: goto st5;
 		case 101: goto st5;
@@ -1060,7 +1065,7 @@ st19:
 	if ( ++p == pe )
 		goto _test_eof19;
 case 19:
-#line 1064 "patchExprScanner.cc"
+#line 1069 "patchExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr58;
 		case 69: goto st5;
@@ -1315,7 +1320,7 @@ st23:
 	if ( ++p == pe )
 		goto _test_eof23;
 case 23:
-#line 1319 "patchExprScanner.cc"
+#line 1324 "patchExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr68;
 		case 95: goto tr68;
@@ -3082,7 +3087,7 @@ st120:
 	if ( ++p == pe )
 		goto _test_eof120;
 case 120:
-#line 3086 "patchExprScanner.cc"
+#line 3091 "patchExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr68;
 		case 58: goto st8;
@@ -3824,7 +3829,7 @@ case 10:
 	_out: {}
 	}
 
-#line 656 "patchExprScanner.rl"
+#line 661 "patchExprScanner.rl"
    /* ^^^ FSM execution here ^^^ */;
 
     if (0 == cs)
@@ -3841,6 +3846,11 @@ case 10:
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
diff --git a/src/finiteVolume/expressions/patch/patchExprScanner.rl b/src/finiteVolume/expressions/patch/patchExprScanner.rl
index 963718e24f1..84b5f3b0a33 100644
--- a/src/finiteVolume/expressions/patch/patchExprScanner.rl
+++ b/src/finiteVolume/expressions/patch/patchExprScanner.rl
@@ -40,7 +40,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -279,7 +279,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -603,9 +603,14 @@ bool Foam::expressions::patchExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -637,12 +642,12 @@ bool Foam::expressions::patchExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -669,6 +674,11 @@ bool Foam::expressions::patchExpr::scanner::process
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
diff --git a/src/finiteVolume/expressions/volume/volumeExprDriver.H b/src/finiteVolume/expressions/volume/volumeExprDriver.H
index 0ddb6a2104e..3d738c27de4 100644
--- a/src/finiteVolume/expressions/volume/volumeExprDriver.H
+++ b/src/finiteVolume/expressions/volume/volumeExprDriver.H
@@ -36,7 +36,7 @@ Description
     \endtable
 
     In addition to the standard mathematical functions, operations and
-    logical and relational operations, the volume expression support the
+    logical and relational operations, the volume expressions support the
     following driver-specific functions:
 
     Functions
@@ -70,6 +70,10 @@ Description
         pzone   | Logical point field corresponding to pointZone| 1 |
     \endtable
 
+Note
+    Use namespace debug switch \c volumeExpr for scanner (2), parser (4)
+    or dictionary controls as per Foam::expressions::exprDriver.
+
 SourceFiles
     volumeExprDriver.C
 
@@ -242,7 +246,8 @@ public:
         //- Perform parsing on (sub) string
         using genericRagelLemonDriver::content;
 
-        //- Execute the parser
+        //- Execute the parser.
+        //  The return value currently has no meaning.
         virtual unsigned parse
         (
             const std::string& expr,
diff --git a/src/finiteVolume/expressions/volume/volumeExprLemonParser.lyy-m4 b/src/finiteVolume/expressions/volume/volumeExprLemonParser.lyy-m4
index 77c1efe91d9..bc9638fac40 100644
--- a/src/finiteVolume/expressions/volume/volumeExprLemonParser.lyy-m4
+++ b/src/finiteVolume/expressions/volume/volumeExprLemonParser.lyy-m4
@@ -790,7 +790,7 @@ void Foam::expressions::volumeExpr::parser::start(parseDriver& driver_)
     this->stop();
     lemon_ = ParseAlloc(::operator new, &driver_);
 
-    if (debug || driver_.debugParser())
+    if ((debug & 0x4) || driver_.debugParser())
     {
         #ifndef NDEBUG
         ParseTrace(stderr, const_cast<char*>(prompt_));
diff --git a/src/finiteVolume/expressions/volume/volumeExprScanner.cc b/src/finiteVolume/expressions/volume/volumeExprScanner.cc
index 28c4d5ca401..91e6d01ad7e 100644
--- a/src/finiteVolume/expressions/volume/volumeExprScanner.cc
+++ b/src/finiteVolume/expressions/volume/volumeExprScanner.cc
@@ -42,7 +42,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -310,7 +310,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -502,9 +502,14 @@ bool Foam::expressions::volumeExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -536,12 +541,12 @@ bool Foam::expressions::volumeExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -551,7 +556,7 @@ bool Foam::expressions::volumeExpr::scanner::process
 
     // Initialize FSM variables
     
-#line 555 "volumeExprScanner.cc"
+#line 560 "volumeExprScanner.cc"
 	{
 	cs = volumeExpr_start;
 	ts = 0;
@@ -559,11 +564,11 @@ bool Foam::expressions::volumeExpr::scanner::process
 	act = 0;
 	}
 
-#line 683 "volumeExprScanner.rl"
+#line 688 "volumeExprScanner.rl"
    /* ^^^ FSM initialization here ^^^ */;
 
     
-#line 567 "volumeExprScanner.cc"
+#line 572 "volumeExprScanner.cc"
 	{
 	if ( p == pe )
 		goto _test_eof;
@@ -910,7 +915,7 @@ st11:
 case 11:
 #line 1 "NONE"
 	{ts = p;}
-#line 914 "volumeExprScanner.cc"
+#line 919 "volumeExprScanner.cc"
 	switch( (*p) ) {
 		case 32: goto st12;
 		case 33: goto st13;
@@ -1038,7 +1043,7 @@ st16:
 	if ( ++p == pe )
 		goto _test_eof16;
 case 16:
-#line 1042 "volumeExprScanner.cc"
+#line 1047 "volumeExprScanner.cc"
 	switch( (*p) ) {
 		case 69: goto st5;
 		case 101: goto st5;
@@ -1089,7 +1094,7 @@ st19:
 	if ( ++p == pe )
 		goto _test_eof19;
 case 19:
-#line 1093 "volumeExprScanner.cc"
+#line 1098 "volumeExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr58;
 		case 69: goto st5;
@@ -1344,7 +1349,7 @@ st23:
 	if ( ++p == pe )
 		goto _test_eof23;
 case 23:
-#line 1348 "volumeExprScanner.cc"
+#line 1353 "volumeExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr68;
 		case 95: goto tr68;
@@ -3111,7 +3116,7 @@ st120:
 	if ( ++p == pe )
 		goto _test_eof120;
 case 120:
-#line 3115 "volumeExprScanner.cc"
+#line 3120 "volumeExprScanner.cc"
 	switch( (*p) ) {
 		case 46: goto tr68;
 		case 58: goto st8;
@@ -3853,7 +3858,7 @@ case 10:
 	_out: {}
 	}
 
-#line 685 "volumeExprScanner.rl"
+#line 690 "volumeExprScanner.rl"
    /* ^^^ FSM execution here ^^^ */;
 
     if (0 == cs)
@@ -3870,6 +3875,11 @@ case 10:
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
diff --git a/src/finiteVolume/expressions/volume/volumeExprScanner.rl b/src/finiteVolume/expressions/volume/volumeExprScanner.rl
index d82441dde58..d20c43c7c37 100644
--- a/src/finiteVolume/expressions/volume/volumeExprScanner.rl
+++ b/src/finiteVolume/expressions/volume/volumeExprScanner.rl
@@ -40,7 +40,7 @@ Description
 
 // Debugging to stderr
 #undef  DebugInfo
-#define DebugInfo if (debug) InfoErr
+#define DebugInfo if (debug & 0x2) InfoErr
 
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -308,7 +308,7 @@ static int driverTokenType
 
 #define EMIT_TOKEN(T)                                                         \
     driver_.parsePosition() = (ts-buf);                                       \
-    DebugInfo<< STRINGIFY(T) << ": " << driver_.parsePosition() << nl;        \
+    DebugInfo<< STRINGIFY(T) << " at " << driver_.parsePosition() << nl;      \
     parser_->parse(TOKEN_OF(T), nullptr);                                     \
     driver_.parsePosition() = (p-buf);
 
@@ -632,9 +632,14 @@ bool Foam::expressions::volumeExpr::scanner::process
     // Save debug value
     const int oldDebug = debug;
 
-    if (driver_.debugScanner())
+    if (driver_.debugScanner()) { debug |= 0x2; }
+    if (driver_.debugParser())  { debug |= 0x4; }
+
+    if (debug & 0x6)
     {
-        debug |= 4;
+        InfoErr
+            << "Begin parse {"
+            << str.substr(strBeg, strLen).c_str() << '}' << nl;
     }
 
     if (!parser_)
@@ -666,12 +671,12 @@ bool Foam::expressions::volumeExpr::scanner::process
     // Scan token type
     scanToken scanTok;
 
-    // Ragel token start/end (required naming)
+    // Token start/end (Ragel naming)
     const char* ts;
     const char* te;
 
     // Local buffer data.
-    // - p, pe, eof are required Ragel naming
+    // - p, pe, eof are Ragel naming
     // - buf is our own naming
 
     const char* buf = &(str[strBeg]);
@@ -698,6 +703,11 @@ bool Foam::expressions::volumeExpr::scanner::process
     parser_->parse(0, nullptr);
     parser_->stop();
 
+    if (debug & 0x6)
+    {
+        InfoErr<< "Done parse." << nl;
+    }
+
     // Restore debug value
     debug = oldDebug;
 
-- 
GitLab