mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improve handling of mismatched brackets, forgotten ';' (issue #762)
- flags the following type of problems:
* mismatches:
keyword mismatch ( set of { brackets ) in the } entry;
* underflow (too many closing brackets:
keyword too many ( set of ) brackets ) in ) entry;
- a missing semi-colon
dict
{
keyword entry with missing semi-colon
}
will be flagged as 'underflow', since it parses through the '}' but
did not open with it.
Max monitoring depth is 60 levels of nesting, to avoid incurring any
memory allocation.
This commit is contained in:
49
applications/test/dictionary/testPrimitiveEntry
Normal file
49
applications/test/dictionary/testPrimitiveEntry
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
| ========= | |
|
||||||
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
|
| \\ / O peration | Version: plus |
|
||||||
|
| \\ / A nd | Web: www.OpenFOAM.com |
|
||||||
|
| \\/ M anipulation | |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
FoamFile
|
||||||
|
{
|
||||||
|
version 2.0;
|
||||||
|
format ascii;
|
||||||
|
class dictionary;
|
||||||
|
object testDict;
|
||||||
|
}
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
// Test parsing of primitive entry
|
||||||
|
// Can pass through foamDictionary -expand for test
|
||||||
|
|
||||||
|
dict1
|
||||||
|
{
|
||||||
|
entry1 no brackets;
|
||||||
|
|
||||||
|
entry2 balanced ( set of { brackets } in the ) entry;
|
||||||
|
|
||||||
|
entry3a mismatch ( set of { brackets ) in the } entry;
|
||||||
|
|
||||||
|
entry3b mismatch ( set of { brackets } in the } entry;
|
||||||
|
|
||||||
|
// Runs on
|
||||||
|
// entry3c too many ( set of ) brackets ) in ) entry;
|
||||||
|
|
||||||
|
//entry4 missing closing ( set of { brackets } in entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dict2
|
||||||
|
{
|
||||||
|
entry1 no brackets;
|
||||||
|
entry2 no brackets but missing semi-colon
|
||||||
|
}
|
||||||
|
|
||||||
|
dict3
|
||||||
|
{
|
||||||
|
entry1 anything;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||||
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
|
\\/ M anipulation | Copyright (C) 2017-2018 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -26,6 +26,27 @@ License
|
|||||||
#include "primitiveEntry.H"
|
#include "primitiveEntry.H"
|
||||||
#include "functionEntry.H"
|
#include "functionEntry.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// This is akin to a SafeIOWarning, which does not yet exist
|
||||||
|
inline void safeIOWarning
|
||||||
|
(
|
||||||
|
const Foam::IOstream& is,
|
||||||
|
const std::string& msg
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::cerr
|
||||||
|
<< "--> FOAM Warning :\n"
|
||||||
|
<< " Reading \"" << is.name() << "\" at line "
|
||||||
|
<< is.lineNumber() << '\n'
|
||||||
|
<< " " << msg << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
bool Foam::primitiveEntry::acceptToken
|
bool Foam::primitiveEntry::acceptToken
|
||||||
@ -86,6 +107,17 @@ bool Foam::primitiveEntry::read(const dictionary& dict, Istream& is)
|
|||||||
{
|
{
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
|
|
||||||
|
// Track balanced bracket/brace pairs, with max stack depth of 60.
|
||||||
|
// Use a bitmask to track the opening char: 0 = '()', 1 = '{}'
|
||||||
|
//
|
||||||
|
// Notes
|
||||||
|
// - the bitmask is set *before* increasing the depth since the left
|
||||||
|
// shift implicitly carries a 1-offset with it.
|
||||||
|
// Eg, (1u << 0) already corresponds to depth=1 (the first bit)
|
||||||
|
//
|
||||||
|
// - similarly, the bitmask is tested *after* decreasing depth
|
||||||
|
|
||||||
|
uint64_t balanced = 0u;
|
||||||
label depth = 0;
|
label depth = 0;
|
||||||
token tok;
|
token tok;
|
||||||
|
|
||||||
@ -98,13 +130,65 @@ bool Foam::primitiveEntry::read(const dictionary& dict, Istream& is)
|
|||||||
if (tok.isPunctuation())
|
if (tok.isPunctuation())
|
||||||
{
|
{
|
||||||
const char c = tok.pToken();
|
const char c = tok.pToken();
|
||||||
if (c == token::BEGIN_BLOCK || c == token::BEGIN_LIST)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
case token::BEGIN_LIST:
|
||||||
|
{
|
||||||
|
if (depth >= 0 && depth < 61)
|
||||||
|
{
|
||||||
|
balanced &= ~(1u << depth); // clear bit
|
||||||
|
}
|
||||||
++depth;
|
++depth;
|
||||||
}
|
}
|
||||||
else if (c == token::END_BLOCK || c == token::END_LIST)
|
break;
|
||||||
|
|
||||||
|
case token::BEGIN_BLOCK:
|
||||||
|
{
|
||||||
|
if (depth >= 0 && depth < 61)
|
||||||
|
{
|
||||||
|
balanced |= (1u << depth); // set bit
|
||||||
|
}
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token::END_LIST:
|
||||||
{
|
{
|
||||||
--depth;
|
--depth;
|
||||||
|
if (depth < 0)
|
||||||
|
{
|
||||||
|
safeIOWarning
|
||||||
|
(
|
||||||
|
is,
|
||||||
|
"Too many closing ')' ... was a ';' forgotten?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (depth < 61 && ((balanced >> depth) & 1u))
|
||||||
|
{
|
||||||
|
// Bit was set, but expected it to be unset.
|
||||||
|
safeIOWarning(is, "Imbalanced '{' with ')'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token::END_BLOCK:
|
||||||
|
{
|
||||||
|
--depth;
|
||||||
|
if (depth < 0)
|
||||||
|
{
|
||||||
|
safeIOWarning
|
||||||
|
(
|
||||||
|
is,
|
||||||
|
"Too many closing '}' ... was a ';' forgotten?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (depth < 61 && !((balanced >> depth) & 1u))
|
||||||
|
{
|
||||||
|
// Bit was unset, but expected it to be set.
|
||||||
|
safeIOWarning(is, "Imbalanced '(' with '}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +203,11 @@ bool Foam::primitiveEntry::read(const dictionary& dict, Istream& is)
|
|||||||
tok = token::punctuationToken::NULL_TOKEN;
|
tok = token::punctuationToken::NULL_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (depth)
|
||||||
|
{
|
||||||
|
safeIOWarning(is, "Imbalanced brackets");
|
||||||
|
}
|
||||||
|
|
||||||
is.fatalCheck(FUNCTION_NAME);
|
is.fatalCheck(FUNCTION_NAME);
|
||||||
return tok.good();
|
return tok.good();
|
||||||
}
|
}
|
||||||
@ -126,7 +215,7 @@ bool Foam::primitiveEntry::read(const dictionary& dict, Istream& is)
|
|||||||
|
|
||||||
void Foam::primitiveEntry::readEntry(const dictionary& dict, Istream& is)
|
void Foam::primitiveEntry::readEntry(const dictionary& dict, Istream& is)
|
||||||
{
|
{
|
||||||
label keywordLineNumber = is.lineNumber();
|
const label keywordLineNumber = is.lineNumber();
|
||||||
tokenIndex() = 0;
|
tokenIndex() = 0;
|
||||||
|
|
||||||
if (read(dict, is))
|
if (read(dict, is))
|
||||||
@ -242,7 +331,7 @@ Foam::Ostream& Foam::operator<<
|
|||||||
|
|
||||||
os << " primitiveEntry '" << e.keyword() << "' comprises ";
|
os << " primitiveEntry '" << e.keyword() << "' comprises ";
|
||||||
|
|
||||||
for (label i=0; i<min(e.size(), nPrintTokens); i++)
|
for (label i=0; i<min(e.size(), nPrintTokens); ++i)
|
||||||
{
|
{
|
||||||
os << nl << " " << e[i].info();
|
os << nl << " " << e[i].info();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user