mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Add in calcEntry as a very rough draft
- needs Coco/R 16 Dec 2009 version
This commit is contained in:
@ -1,4 +1,7 @@
|
|||||||
calcEntry/calcEntry.C
|
|
||||||
dictionaryTest.C
|
dictionaryTest.C
|
||||||
|
|
||||||
|
calcEntry/calcEntry.C
|
||||||
|
calcEntry/calcEntryParser.cpp
|
||||||
|
calcEntry/calcEntryScanner.cpp
|
||||||
|
|
||||||
EXE = $(FOAM_USER_APPBIN)/dictionaryTest
|
EXE = $(FOAM_USER_APPBIN)/dictionaryTest
|
||||||
|
|||||||
145
applications/test/dictionary/calcEntry/CocoParserErrors.H
Normal file
145
applications/test/dictionary/calcEntry/CocoParserErrors.H
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2009-2009 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 2 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, write to the Free Software Foundation,
|
||||||
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::CocoParserErrors
|
||||||
|
|
||||||
|
Description
|
||||||
|
Templated class to shadow the error handling for Coco/R parsers
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef CocoParserErrors_H
|
||||||
|
#define CocoParserErrors_H
|
||||||
|
|
||||||
|
#include "error.H"
|
||||||
|
#include "wchar.H"
|
||||||
|
|
||||||
|
// avoid confusion about which Warning is meant
|
||||||
|
#undef WarningIn
|
||||||
|
#define WarningIn(fn) Foam::Warning(fn, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class CocoParserErrors Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template<class BaseClass>
|
||||||
|
class CocoParserErrors
|
||||||
|
:
|
||||||
|
public BaseClass
|
||||||
|
{
|
||||||
|
// Private data
|
||||||
|
|
||||||
|
//- The name issued in warnings and errors
|
||||||
|
word name_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct with given name
|
||||||
|
CocoParserErrors(const word& name)
|
||||||
|
:
|
||||||
|
BaseClass(),
|
||||||
|
name_(name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~CocoParserErrors()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// Member functions
|
||||||
|
|
||||||
|
//- Return the name issued for warnings
|
||||||
|
virtual const word& name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Return the name issued for warnings
|
||||||
|
virtual word& name()
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Error Handling
|
||||||
|
|
||||||
|
//- Handle a general warning 'msg'
|
||||||
|
virtual void Warning(const wchar_t* msg)
|
||||||
|
{
|
||||||
|
WarningIn(name_)
|
||||||
|
<< msg << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Handle a general warning 'msg'
|
||||||
|
virtual void Warning(int line, int col, const wchar_t* msg)
|
||||||
|
{
|
||||||
|
WarningIn(name_)
|
||||||
|
<<"line " << line << " col " << col << ": "
|
||||||
|
<< msg << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Handle general error 'msg' (eg, a semantic error)
|
||||||
|
virtual void Error(int line, int col, const wchar_t* msg)
|
||||||
|
{
|
||||||
|
FatalErrorIn(name_)
|
||||||
|
<< "line " << line << " col " << col <<": " << msg << endl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Handle general error 'msg' (eg, a semantic error)
|
||||||
|
virtual void Error(const wchar_t* msg)
|
||||||
|
{
|
||||||
|
FatalErrorIn(name_)
|
||||||
|
<< msg << endl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Handle a general exception 'msg'
|
||||||
|
virtual void Exception(const wchar_t* msg)
|
||||||
|
{
|
||||||
|
this->Error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
225
applications/test/dictionary/calcEntry/SimpleCalc.atg
Normal file
225
applications/test/dictionary/calcEntry/SimpleCalc.atg
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
compile with:
|
||||||
|
Coco \
|
||||||
|
-frames $WM_THIRD_PARTY_DIR/coco-r \
|
||||||
|
-prefix calcEntry \
|
||||||
|
-namespace Foam::functionEntries::calcEntryInternal \
|
||||||
|
SimpleCalc.atg
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dictionary.H"
|
||||||
|
#include "scalar.H"
|
||||||
|
#include "error.H"
|
||||||
|
#include "wchar.H"
|
||||||
|
|
||||||
|
|
||||||
|
COMPILER SimpleCalc
|
||||||
|
// Simple four function calculator for OpenFOAM dictionaries
|
||||||
|
|
||||||
|
//! with debug
|
||||||
|
static const int debug = 0;
|
||||||
|
|
||||||
|
//! The parent dictionary
|
||||||
|
mutable dictionary* dict_;
|
||||||
|
|
||||||
|
//! The calculation result
|
||||||
|
scalar val;
|
||||||
|
|
||||||
|
//! token -> scalar
|
||||||
|
scalar getScalar() const
|
||||||
|
{
|
||||||
|
return coco_string_toDouble(t->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! token -> string
|
||||||
|
std::string getString() const
|
||||||
|
{
|
||||||
|
char* str = coco_string_create_char(t->val);
|
||||||
|
std::string s(str);
|
||||||
|
coco_string_delete(str);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! attach a dictionary
|
||||||
|
void dict(const dictionary& dict) const
|
||||||
|
{
|
||||||
|
dict_ = const_cast<dictionary*>(&dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! lookup dictionary entry
|
||||||
|
scalar getDictLookup() const
|
||||||
|
{
|
||||||
|
scalar dictValue = 0;
|
||||||
|
|
||||||
|
if (!dict_)
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"SimpleCalc::getDictEntry() const"
|
||||||
|
) << "No dictionary attached!"
|
||||||
|
<< exit(FatalError);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* chars = coco_string_create_char
|
||||||
|
(
|
||||||
|
t->val,
|
||||||
|
1,
|
||||||
|
(coco_string_length(t->val) - 1)
|
||||||
|
);
|
||||||
|
word keyword(chars);
|
||||||
|
coco_string_delete(chars);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Info<<"lookup: " << keyword << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry* entryPtr = dict_->lookupEntryPtr(keyword, true, false);
|
||||||
|
if (entryPtr && !entryPtr->isDict())
|
||||||
|
{
|
||||||
|
entryPtr->stream() >> dictValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"SimpleCalc::getDictEntry() const"
|
||||||
|
) << "keyword " << keyword << " is undefined in dictionary "
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return dictValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scalar Result() const
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * CHARACTERS * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
CHARACTERS
|
||||||
|
letter = 'A'..'Z' + 'a'..'z'.
|
||||||
|
qualifier = '_' + ':'.
|
||||||
|
dollar = '$'.
|
||||||
|
digit = "0123456789".
|
||||||
|
sign = '+' + '-'.
|
||||||
|
cr = '\r'.
|
||||||
|
lf = '\n'.
|
||||||
|
tab = '\t'.
|
||||||
|
stringCh = ANY - '"' - '\\' - cr - lf.
|
||||||
|
printable = '\u0020' .. '\u007e'.
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * TOKENS * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
TOKENS
|
||||||
|
|
||||||
|
// identifier
|
||||||
|
ident =
|
||||||
|
letter { letter | digit | qualifier }.
|
||||||
|
|
||||||
|
// string
|
||||||
|
string =
|
||||||
|
'"' { stringCh | '\\' printable } '"'.
|
||||||
|
|
||||||
|
// dictionary lookup identifier
|
||||||
|
// starts with '$' and otherwise limited to a normal indentifier
|
||||||
|
variable =
|
||||||
|
dollar letter { letter | digit | qualifier }.
|
||||||
|
|
||||||
|
// floating point and integer numbers
|
||||||
|
number =
|
||||||
|
[sign] ('.' digit { digit } ) | ( digit { digit } [ '.' { digit } ])
|
||||||
|
[ ('E' | 'e') [sign] digit { digit } ].
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * PRAGMAS / COMMENTS / IGNORE * * * * * * * * * * * //
|
||||||
|
|
||||||
|
COMMENTS FROM "/*" TO "*/" NESTED
|
||||||
|
COMMENTS FROM "//" TO lf
|
||||||
|
|
||||||
|
// ignore unprintables
|
||||||
|
IGNORE ANY - printable
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * PRODUCTIONS * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
PRODUCTIONS
|
||||||
|
|
||||||
|
SimpleCalc (. val = 0;
|
||||||
|
if (debug){Info<<"start val"<< nl;}
|
||||||
|
.)
|
||||||
|
=
|
||||||
|
( '{' Expr<val> '}' | Expr<val> )
|
||||||
|
EOF
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
Expr<scalar& val> (. scalar val2 = 0;
|
||||||
|
if (debug) {Info<<"Expr:"<< val<< nl;}
|
||||||
|
.)
|
||||||
|
=
|
||||||
|
Term<val>
|
||||||
|
{
|
||||||
|
"+" Term<val2> (. if (debug) {Info<<"+Term:"<<val2 <<nl;}
|
||||||
|
val += val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl;}
|
||||||
|
.)
|
||||||
|
| "-" Term<val2> (. if (debug) {Info<<"-Term:"<<val2 <<nl;}
|
||||||
|
val -= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl;}
|
||||||
|
.)
|
||||||
|
}
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
Term<scalar& val> (. scalar val2 = 0;
|
||||||
|
if (debug) {Info<<"Term:"<< val<< nl;}
|
||||||
|
.)
|
||||||
|
=
|
||||||
|
Factor<val>
|
||||||
|
{
|
||||||
|
"*" Factor<val2> (. if (debug) {Info<<"*Factor:"<<val2 << nl;}
|
||||||
|
val *= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl; }
|
||||||
|
.)
|
||||||
|
| "/" Factor<val2> (. if (debug) {Info<<"/Factor:"<<val2 << nl;}
|
||||||
|
val /= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl; }
|
||||||
|
.)
|
||||||
|
}
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
Factor<scalar& val>
|
||||||
|
=
|
||||||
|
variable (. val = getDictLookup();
|
||||||
|
if (debug) {Info<<"lookup:"<<val<<nl;}
|
||||||
|
.)
|
||||||
|
| number (. val = getScalar();
|
||||||
|
if (debug) {Info<<"got num:"<<val<<nl;}
|
||||||
|
.)
|
||||||
|
| '-' '(' Expr<val> ')' (. val = -val;
|
||||||
|
if (debug) {Info<<"inv:"<<val<<nl;}
|
||||||
|
.)
|
||||||
|
| '(' Expr<val> ')' (. if (debug){Info<<"got Expr:"<<val<<nl;} .)
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
END SimpleCalc.
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
11
applications/test/dictionary/calcEntry/build.sh
Executable file
11
applications/test/dictionary/calcEntry/build.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#/bin/sh
|
||||||
|
cd ${0%/*} || exit 1 # run from this directory
|
||||||
|
|
||||||
|
# this will have to do until we make a makefile rule
|
||||||
|
|
||||||
|
Coco \
|
||||||
|
-frames $WM_THIRD_PARTY_DIR/coco-r \
|
||||||
|
-prefix calcEntry \
|
||||||
|
-namespace Foam::functionEntries::calcEntryInternal \
|
||||||
|
SimpleCalc.atg
|
||||||
|
|
||||||
@ -2,7 +2,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) 1991-2009 OpenCFD Ltd.
|
\\ / A nd | Copyright (C) 2009-2009 OpenCFD Ltd.
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
@ -30,6 +30,10 @@ License
|
|||||||
#include "OStringStream.H"
|
#include "OStringStream.H"
|
||||||
#include "addToMemberFunctionSelectionTable.H"
|
#include "addToMemberFunctionSelectionTable.H"
|
||||||
|
|
||||||
|
#include "ISstream.H"
|
||||||
|
#include "CocoParserErrors.H"
|
||||||
|
#include "calcEntryParser.h"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
@ -56,14 +60,121 @@ bool Foam::functionEntries::calcEntry::execute
|
|||||||
(
|
(
|
||||||
const dictionary& parentDict,
|
const dictionary& parentDict,
|
||||||
primitiveEntry& entry,
|
primitiveEntry& entry,
|
||||||
Istream& is
|
Istream& istr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
dictionary args(parentDict, is);
|
static const int maxLen = 1024;
|
||||||
OStringStream resultStream;
|
static const int errLen = 80; // truncate error message for readability
|
||||||
resultStream
|
static char buf[maxLen];
|
||||||
<< (args.lookup("x")[0].number() + args.lookup("y")[0].number());
|
|
||||||
entry.read(parentDict, IStringStream(resultStream.str())());
|
ISstream& is = dynamicCast<ISstream>(istr);
|
||||||
|
|
||||||
|
// get the { ... } argument without the enclosing brace brackets
|
||||||
|
//
|
||||||
|
// THIS NEEDS REWORKING (LATER) ...
|
||||||
|
|
||||||
|
char c = 0;
|
||||||
|
|
||||||
|
if (!is.read(c).good() || c != token::BEGIN_BLOCK)
|
||||||
|
{
|
||||||
|
is.setBad();
|
||||||
|
FatalIOErrorIn("functionEntries::calcEntry::execute()", is)
|
||||||
|
<< "Expected a '" << token::BEGIN_BLOCK
|
||||||
|
<< "', found '" << c << "'" << exit(FatalIOError);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
register int nChar = 0;
|
||||||
|
buf[nChar++] = token::BEGIN_BLOCK;
|
||||||
|
int listDepth = 1; // already saw the first '{'
|
||||||
|
|
||||||
|
while (is.get(c).good())
|
||||||
|
{
|
||||||
|
buf[nChar++] = c;
|
||||||
|
if (nChar == maxLen)
|
||||||
|
{
|
||||||
|
buf[errLen] = '\0';
|
||||||
|
|
||||||
|
FatalIOErrorIn("functionEntries::calcEntry::execute()", is)
|
||||||
|
<< "argument \"" << buf << "...\"\n"
|
||||||
|
<< " is too long (max. " << maxLen << " characters)"
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle nested blocks, even if we don't know what they'd
|
||||||
|
// be useful for
|
||||||
|
if (c == token::BEGIN_BLOCK)
|
||||||
|
{
|
||||||
|
++listDepth;
|
||||||
|
}
|
||||||
|
else if (c == token::END_BLOCK)
|
||||||
|
{
|
||||||
|
if (--listDepth == 0)
|
||||||
|
{
|
||||||
|
// done reading - overwrite the final '}'
|
||||||
|
// --nChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[nChar] = '\0';
|
||||||
|
|
||||||
|
|
||||||
|
// emit some info
|
||||||
|
Info<< "grabbed " << nChar << " characters:" << nl
|
||||||
|
<< "----------\n"
|
||||||
|
<< buf << nl
|
||||||
|
<< "----------\n"
|
||||||
|
<< nl;
|
||||||
|
|
||||||
|
|
||||||
|
// define parser error handler
|
||||||
|
CocoParserErrors<calcEntryInternal::Errors>
|
||||||
|
myErrorHandler("calcEntry::Parser--");
|
||||||
|
|
||||||
|
calcEntryInternal::Scanner scanner(buf, nChar);
|
||||||
|
calcEntryInternal::Parser parser(&scanner, &myErrorHandler);
|
||||||
|
|
||||||
|
// Attach dictionary context
|
||||||
|
parser.dict(parentDict);
|
||||||
|
|
||||||
|
parser.Parse();
|
||||||
|
|
||||||
|
// Info<<"got: " << parser.Result() << endl;
|
||||||
|
|
||||||
|
tokenList tokens(2);
|
||||||
|
tokens[0] = parser.Result();
|
||||||
|
tokens[1] = token::END_STATEMENT;
|
||||||
|
|
||||||
|
// Info<<"tokens[0] = " << tokens[0].info() <<nl;
|
||||||
|
// Info<<"tokens[1] = " << tokens[1].info() <<nl;
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// const tokenList& toks = entry;
|
||||||
|
//
|
||||||
|
// forAll(toks, tokI)
|
||||||
|
// {
|
||||||
|
// Info<< tokI <<":= " << toks[tokI].info() << endl;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
ITstream its("ParserResult", tokens);
|
||||||
|
entry.read(parentDict, its);
|
||||||
|
// Info<< "size: " << entry.size() << endl;
|
||||||
|
// entry = newente;
|
||||||
|
// entry.print(Info);
|
||||||
|
|
||||||
|
/// const tokenList& toks = entry;
|
||||||
|
///
|
||||||
|
/// forAll(toks, tokI)
|
||||||
|
/// {
|
||||||
|
/// Info<< tokI <<":= " << toks[tokI].info() << endl;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,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) 1991-2009 OpenCFD Ltd.
|
\\ / A nd | Copyright (C) 2009-2009 OpenCFD Ltd.
|
||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
@ -26,6 +26,8 @@ Class
|
|||||||
Foam::functionEntries::calcEntry
|
Foam::functionEntries::calcEntry
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
This dictionary function entry may or may not do anything particularly
|
||||||
|
useful - depending upon what is currently being used to test.
|
||||||
|
|
||||||
SourceFiles
|
SourceFiles
|
||||||
calcEntry.C
|
calcEntry.C
|
||||||
@ -45,7 +47,7 @@ namespace functionEntries
|
|||||||
{
|
{
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
Class calcEntry Declaration
|
Class calcEntry Declaration
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
class calcEntry
|
class calcEntry
|
||||||
@ -64,7 +66,7 @@ class calcEntry
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
//- Runtime type information
|
//- Runtime type information
|
||||||
ClassName("calc");
|
ClassName("test");
|
||||||
|
|
||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
|
|||||||
324
applications/test/dictionary/calcEntry/calcEntryParser.cpp
Normal file
324
applications/test/dictionary/calcEntry/calcEntryParser.cpp
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "calcEntryParser.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Foam {
|
||||||
|
namespace functionEntries {
|
||||||
|
namespace calcEntryInternal {
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parser Implementation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Parser::SynErr(int n) {
|
||||||
|
if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
|
||||||
|
errDist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::SemErr(const wchar_t* msg) {
|
||||||
|
if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
|
||||||
|
errDist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::Get() {
|
||||||
|
for (;;) {
|
||||||
|
t = la;
|
||||||
|
la = scanner->Scan();
|
||||||
|
if (la->kind <= maxT) {
|
||||||
|
++errDist;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dummyToken != t) {
|
||||||
|
dummyToken->kind = t->kind;
|
||||||
|
dummyToken->pos = t->pos;
|
||||||
|
dummyToken->col = t->col;
|
||||||
|
dummyToken->line = t->line;
|
||||||
|
dummyToken->next = NULL;
|
||||||
|
coco_string_delete(dummyToken->val);
|
||||||
|
dummyToken->val = coco_string_create(t->val);
|
||||||
|
t = dummyToken;
|
||||||
|
}
|
||||||
|
la = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::Expect(int n) {
|
||||||
|
if (la->kind == n) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SynErr(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::ExpectWeak(int n, int follow) {
|
||||||
|
if (la->kind == n) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SynErr(n);
|
||||||
|
while (!StartOf(follow)) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Parser::WeakSeparator(int n, int syFol, int repFol) {
|
||||||
|
if (la->kind == n) {
|
||||||
|
Get();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (StartOf(repFol)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SynErr(n);
|
||||||
|
while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
return StartOf(syFol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::SimpleCalc() {
|
||||||
|
val = 0;
|
||||||
|
if (debug){Info<<"start val"<< nl;}
|
||||||
|
|
||||||
|
if (la->kind == 5) {
|
||||||
|
Get();
|
||||||
|
Expr(val);
|
||||||
|
Expect(6);
|
||||||
|
} else if (StartOf(1)) {
|
||||||
|
Expr(val);
|
||||||
|
} else SynErr(14);
|
||||||
|
Expect(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::Expr(scalar& val) {
|
||||||
|
scalar val2 = 0;
|
||||||
|
if (debug) {Info<<"Expr:"<< val<< nl;}
|
||||||
|
|
||||||
|
Term(val);
|
||||||
|
while (la->kind == 7 || la->kind == 8) {
|
||||||
|
if (la->kind == 7) {
|
||||||
|
Get();
|
||||||
|
Term(val2);
|
||||||
|
if (debug) {Info<<"+Term:"<<val2 <<nl;}
|
||||||
|
val += val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl;}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Get();
|
||||||
|
Term(val2);
|
||||||
|
if (debug) {Info<<"-Term:"<<val2 <<nl;}
|
||||||
|
val -= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl;}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::Term(scalar& val) {
|
||||||
|
scalar val2 = 0;
|
||||||
|
if (debug) {Info<<"Term:"<< val<< nl;}
|
||||||
|
|
||||||
|
Factor(val);
|
||||||
|
while (la->kind == 9 || la->kind == 10) {
|
||||||
|
if (la->kind == 9) {
|
||||||
|
Get();
|
||||||
|
Factor(val2);
|
||||||
|
if (debug) {Info<<"*Factor:"<<val2 << nl;}
|
||||||
|
val *= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl; }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Get();
|
||||||
|
Factor(val2);
|
||||||
|
if (debug) {Info<<"/Factor:"<<val2 << nl;}
|
||||||
|
val /= val2;
|
||||||
|
if (debug) {Info<<"="<< val << nl; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::Factor(scalar& val) {
|
||||||
|
if (la->kind == 3) {
|
||||||
|
Get();
|
||||||
|
val = getDictLookup();
|
||||||
|
if (debug) {Info<<"lookup:"<<val<<nl;}
|
||||||
|
|
||||||
|
} else if (la->kind == 4) {
|
||||||
|
Get();
|
||||||
|
val = getScalar();
|
||||||
|
if (debug) {Info<<"got num:"<<val<<nl;}
|
||||||
|
|
||||||
|
} else if (la->kind == 8) {
|
||||||
|
Get();
|
||||||
|
Expect(11);
|
||||||
|
Expr(val);
|
||||||
|
Expect(12);
|
||||||
|
val = -val;
|
||||||
|
if (debug) {Info<<"inv:"<<val<<nl;}
|
||||||
|
|
||||||
|
} else if (la->kind == 11) {
|
||||||
|
Get();
|
||||||
|
Expr(val);
|
||||||
|
Expect(12);
|
||||||
|
if (debug){Info<<"got Expr:"<<val<<nl;}
|
||||||
|
} else SynErr(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::Parse() {
|
||||||
|
t = NULL;
|
||||||
|
if (dummyToken) { // safety: someone might call Parse() twice
|
||||||
|
delete dummyToken;
|
||||||
|
}
|
||||||
|
la = dummyToken = new Token();
|
||||||
|
la->val = coco_string_create(L"Dummy Token");
|
||||||
|
Get();
|
||||||
|
SimpleCalc();
|
||||||
|
|
||||||
|
Expect(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Parser::Parser(Scanner* scan, Errors* err)
|
||||||
|
:
|
||||||
|
dummyToken(NULL),
|
||||||
|
deleteErrorsDestruct_(!err),
|
||||||
|
minErrDist(2),
|
||||||
|
errDist(minErrDist),
|
||||||
|
scanner(scan),
|
||||||
|
errors(err),
|
||||||
|
t(NULL),
|
||||||
|
la(NULL)
|
||||||
|
{
|
||||||
|
maxT = 13;
|
||||||
|
|
||||||
|
if (!errors) { // add in default error handling
|
||||||
|
errors = new Errors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Parser::StartOf(int s) {
|
||||||
|
const bool T = true;
|
||||||
|
const bool x = false;
|
||||||
|
|
||||||
|
static bool set[2][15] = {
|
||||||
|
{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
|
||||||
|
{x,x,x,T, T,x,x,x, T,x,x,T, x,x,x}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return set[s][la->kind];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Parser::~Parser() {
|
||||||
|
if (deleteErrorsDestruct_) { // delete default error handling
|
||||||
|
delete errors;
|
||||||
|
}
|
||||||
|
delete dummyToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Errors Implementation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Errors::Errors()
|
||||||
|
:
|
||||||
|
count(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Errors::~Errors()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::clear() {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* Errors::strerror(int n)
|
||||||
|
{
|
||||||
|
wchar_t* s;
|
||||||
|
switch (n) {
|
||||||
|
case 0: s = coco_string_create(L"EOF expected"); break;
|
||||||
|
case 1: s = coco_string_create(L"ident expected"); break;
|
||||||
|
case 2: s = coco_string_create(L"string expected"); break;
|
||||||
|
case 3: s = coco_string_create(L"variable expected"); break;
|
||||||
|
case 4: s = coco_string_create(L"number expected"); break;
|
||||||
|
case 5: s = coco_string_create(L"\"{\" expected"); break;
|
||||||
|
case 6: s = coco_string_create(L"\"}\" expected"); break;
|
||||||
|
case 7: s = coco_string_create(L"\"+\" expected"); break;
|
||||||
|
case 8: s = coco_string_create(L"\"-\" expected"); break;
|
||||||
|
case 9: s = coco_string_create(L"\"*\" expected"); break;
|
||||||
|
case 10: s = coco_string_create(L"\"/\" expected"); break;
|
||||||
|
case 11: s = coco_string_create(L"\"(\" expected"); break;
|
||||||
|
case 12: s = coco_string_create(L"\")\" expected"); break;
|
||||||
|
case 13: s = coco_string_create(L"??? expected"); break;
|
||||||
|
case 14: s = coco_string_create(L"invalid SimpleCalc"); break;
|
||||||
|
case 15: s = coco_string_create(L"invalid Factor"); break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
wchar_t format[20];
|
||||||
|
coco_swprintf(format, 20, L"error %d", n);
|
||||||
|
s = coco_string_create(format);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Warning(const wchar_t* msg) {
|
||||||
|
wprintf(L"%ls\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Warning(int line, int col, const wchar_t* msg) {
|
||||||
|
wprintf(L"-- line %d col %d: %ls\n", line, col, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Error(int line, int col, const wchar_t* msg) {
|
||||||
|
wprintf(L"-- line %d col %d: %ls\n", line, col, msg);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::SynErr(int line, int col, int n) {
|
||||||
|
wchar_t* msg = this->strerror(n);
|
||||||
|
this->Error(line, col, msg);
|
||||||
|
coco_string_delete(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Exception(const wchar_t* msg) {
|
||||||
|
wprintf(L"%ls", msg);
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
192
applications/test/dictionary/calcEntry/calcEntryParser.h
Normal file
192
applications/test/dictionary/calcEntry/calcEntryParser.h
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef COCO_calcEntryPARSER_H__
|
||||||
|
#define COCO_calcEntryPARSER_H__
|
||||||
|
|
||||||
|
#include "dictionary.H"
|
||||||
|
#include "scalar.H"
|
||||||
|
#include "error.H"
|
||||||
|
#include "wchar.H"
|
||||||
|
|
||||||
|
|
||||||
|
#include "calcEntryScanner.h"
|
||||||
|
|
||||||
|
namespace Foam {
|
||||||
|
namespace functionEntries {
|
||||||
|
namespace calcEntryInternal {
|
||||||
|
|
||||||
|
|
||||||
|
//! Parser error handing
|
||||||
|
class Errors {
|
||||||
|
public:
|
||||||
|
int count; //!< The number of errors detected
|
||||||
|
|
||||||
|
//! Allocate and return a string describing the given error code.
|
||||||
|
/** It is the responsibility of the caller to free this string,
|
||||||
|
* eg, with coco_string_delete()
|
||||||
|
*/
|
||||||
|
static wchar_t* strerror(int n);
|
||||||
|
|
||||||
|
Errors(); //!< Construct null - start with no errors
|
||||||
|
virtual ~Errors(); //!< Destructor
|
||||||
|
virtual void clear(); //!< Clear the error count
|
||||||
|
|
||||||
|
//! Handle a general warning 'msg'
|
||||||
|
virtual void Warning(const wchar_t* msg);
|
||||||
|
//! Handle a general warning 'msg'
|
||||||
|
virtual void Warning(int line, int col, const wchar_t* msg);
|
||||||
|
//! Handle general error 'msg' (eg, a semantic error)
|
||||||
|
virtual void Error(int line, int col, const wchar_t* msg);
|
||||||
|
//! Handle syntax error 'n', uses strerror for the message, calls Error()
|
||||||
|
virtual void SynErr(int line, int col, int n);
|
||||||
|
//! Handle a general exception 'msg'
|
||||||
|
virtual void Exception(const wchar_t* msg);
|
||||||
|
|
||||||
|
}; // Errors
|
||||||
|
|
||||||
|
|
||||||
|
//! A Coco/R Parser
|
||||||
|
class Parser {
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
_EOF=0,
|
||||||
|
_ident=1,
|
||||||
|
_string=2,
|
||||||
|
_variable=3,
|
||||||
|
_number=4,
|
||||||
|
};
|
||||||
|
int maxT;
|
||||||
|
|
||||||
|
Token *dummyToken;
|
||||||
|
bool deleteErrorsDestruct_; //!< delete the 'errors' member in destructor
|
||||||
|
int minErrDist;
|
||||||
|
int errDist;
|
||||||
|
|
||||||
|
void SynErr(int n); //!< Handle syntax error 'n'
|
||||||
|
void Get();
|
||||||
|
void Expect(int n);
|
||||||
|
bool StartOf(int s);
|
||||||
|
void ExpectWeak(int n, int follow);
|
||||||
|
bool WeakSeparator(int n, int syFol, int repFol);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Scanner *scanner;
|
||||||
|
Errors *errors;
|
||||||
|
|
||||||
|
Token *t; //!< last recognized token
|
||||||
|
Token *la; //!< lookahead token
|
||||||
|
|
||||||
|
static const int debug = 0;
|
||||||
|
|
||||||
|
//! The parent dictionary
|
||||||
|
mutable dictionary* dict_;
|
||||||
|
|
||||||
|
//! The calculation result
|
||||||
|
scalar val;
|
||||||
|
|
||||||
|
//! token -> scalar
|
||||||
|
scalar getScalar() const
|
||||||
|
{
|
||||||
|
return coco_string_toDouble(t->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! token -> string
|
||||||
|
std::string getString() const
|
||||||
|
{
|
||||||
|
char* str = coco_string_create_char(t->val);
|
||||||
|
std::string s(str);
|
||||||
|
coco_string_delete(str);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! attach a dictionary
|
||||||
|
void dict(const dictionary& dict) const
|
||||||
|
{
|
||||||
|
dict_ = const_cast<dictionary*>(&dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! lookup dictionary entry
|
||||||
|
scalar getDictLookup() const
|
||||||
|
{
|
||||||
|
scalar dictValue = 0;
|
||||||
|
|
||||||
|
if (!dict_)
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"SimpleCalc::getDictEntry() const"
|
||||||
|
) << "No dictionary attached!"
|
||||||
|
<< exit(FatalError);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* chars = coco_string_create_char
|
||||||
|
(
|
||||||
|
t->val,
|
||||||
|
1,
|
||||||
|
(coco_string_length(t->val) - 1)
|
||||||
|
);
|
||||||
|
word keyword(chars);
|
||||||
|
coco_string_delete(chars);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
Info<<"lookup: " << keyword << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry* entryPtr = dict_->lookupEntryPtr(keyword, true, false);
|
||||||
|
if (entryPtr && !entryPtr->isDict())
|
||||||
|
{
|
||||||
|
entryPtr->stream() >> dictValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorIn
|
||||||
|
(
|
||||||
|
"SimpleCalc::getDictEntry() const"
|
||||||
|
) << "keyword " << keyword << " is undefined in dictionary "
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return dictValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scalar Result() const
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * CHARACTERS * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//! Construct for the specified scanner
|
||||||
|
/**
|
||||||
|
* Use the default error handling, or optionally provide an error
|
||||||
|
* handler, which will not be deleted upon destruction.
|
||||||
|
*/
|
||||||
|
Parser(Scanner* scan, Errors* err = 0);
|
||||||
|
~Parser(); //!< Destructor - cleanup errors and dummyToken
|
||||||
|
void SemErr(const wchar_t* msg); //!< Handle semantic error
|
||||||
|
|
||||||
|
void SimpleCalc();
|
||||||
|
void Expr(scalar& val);
|
||||||
|
void Term(scalar& val);
|
||||||
|
void Factor(scalar& val);
|
||||||
|
|
||||||
|
void Parse(); //!< Execute the parse operation
|
||||||
|
|
||||||
|
}; // end Parser
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // COCO_calcEntryPARSER_H__
|
||||||
|
|
||||||
825
applications/test/dictionary/calcEntry/calcEntryScanner.cpp
Normal file
825
applications/test/dictionary/calcEntry/calcEntryScanner.cpp
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "calcEntryScanner.h"
|
||||||
|
|
||||||
|
namespace Foam {
|
||||||
|
namespace functionEntries {
|
||||||
|
namespace calcEntryInternal {
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * Wide Character String Routines * * * * * * * * * * * //
|
||||||
|
|
||||||
|
// string handling, wide character
|
||||||
|
|
||||||
|
wchar_t* coco_string_create(const wchar_t* str) {
|
||||||
|
int len = coco_string_length(str);
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
if (len) {
|
||||||
|
wcsncpy(dest, str, len);
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t* coco_string_create(const wchar_t* str, int index, int length) {
|
||||||
|
int len = coco_string_length(str);
|
||||||
|
if (len) {
|
||||||
|
len = length;
|
||||||
|
}
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
if (len) {
|
||||||
|
wcsncpy(dest, &(str[index]), len);
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_upper(const wchar_t* str) {
|
||||||
|
if (!str) { return NULL; }
|
||||||
|
return coco_string_create_upper(str, 0, wcslen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_upper(const wchar_t* str, int index, int len) {
|
||||||
|
if (!str) { return NULL; }
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
const wchar_t ch = str[index + i];
|
||||||
|
if ((L'a' <= ch) && (ch <= L'z')) {
|
||||||
|
dest[i] = ch + (L'A' - L'a');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest[i] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest[len] = L'\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_lower(const wchar_t* str) {
|
||||||
|
if (!str) { return NULL; }
|
||||||
|
return coco_string_create_lower(str, 0, wcslen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_lower(const wchar_t* str, int index, int len) {
|
||||||
|
if (!str) { return NULL; }
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
const wchar_t ch = str[index + i];
|
||||||
|
if ((L'A' <= ch) && (ch <= L'Z')) {
|
||||||
|
dest[i] = ch - (L'A' - L'a');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dest[i] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest[len] = L'\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_append(const wchar_t* str1, const wchar_t* str2) {
|
||||||
|
int str1Len = coco_string_length(str1);
|
||||||
|
int str2Len = coco_string_length(str2);
|
||||||
|
|
||||||
|
wchar_t* dest = new wchar_t[str1Len + str2Len + 1];
|
||||||
|
|
||||||
|
if (str1Len) { wcscpy(dest, str1); }
|
||||||
|
if (str2Len) { wcscpy(dest + str1Len, str2); }
|
||||||
|
|
||||||
|
dest[str1Len + str2Len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t* coco_string_create_append(const wchar_t* str1, const wchar_t ch) {
|
||||||
|
int len = coco_string_length(str1);
|
||||||
|
wchar_t* dest = new wchar_t[len + 2];
|
||||||
|
wcsncpy(dest, str1, len); // or use if (len) { wcscpy(dest, str1); }
|
||||||
|
dest[len] = ch;
|
||||||
|
dest[len + 1] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void coco_string_delete(wchar_t* &str) {
|
||||||
|
delete [] str;
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coco_string_length(const wchar_t* str) {
|
||||||
|
return str ? wcslen(str) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool coco_string_endswith(const wchar_t* str, const wchar_t* endstr) {
|
||||||
|
int strLen = wcslen(str);
|
||||||
|
int endLen = wcslen(endstr);
|
||||||
|
return (endLen <= strLen) && (wcscmp(str + strLen - endLen, endstr) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int coco_string_indexof(const wchar_t* str, const wchar_t ch) {
|
||||||
|
const wchar_t* fnd = wcschr(str, ch);
|
||||||
|
return fnd ? (fnd - str) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coco_string_lastindexof(const wchar_t* str, const wchar_t ch) {
|
||||||
|
const wchar_t* fnd = wcsrchr(str, ch);
|
||||||
|
return fnd ? (fnd - str) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void coco_string_merge(wchar_t* &dest, const wchar_t* str) {
|
||||||
|
if (!str) { return; }
|
||||||
|
wchar_t* newstr = coco_string_create_append(dest, str);
|
||||||
|
delete [] dest;
|
||||||
|
dest = newstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool coco_string_equal(const wchar_t* str1, const wchar_t* str2) {
|
||||||
|
return wcscmp(str1, str2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coco_string_compareto(const wchar_t* str1, const wchar_t* str2) {
|
||||||
|
return wcscmp(str1, str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int coco_string_hash(const wchar_t* str) {
|
||||||
|
int h = 0;
|
||||||
|
if (!str) { return 0; }
|
||||||
|
while (*str != 0) {
|
||||||
|
h = (h * 7) ^ *str;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
if (h < 0) { h = -h; }
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double coco_string_toDouble(const wchar_t* str)
|
||||||
|
{
|
||||||
|
return str ? wcstod(str, NULL) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float coco_string_toFloat(const wchar_t* str)
|
||||||
|
{
|
||||||
|
return str ? wcstof(str, NULL) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// string handling, byte character
|
||||||
|
//
|
||||||
|
|
||||||
|
wchar_t* coco_string_create(const char* str) {
|
||||||
|
int len = str ? strlen(str) : 0;
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
dest[i] = (wchar_t) str[i];
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t* coco_string_create(const char* str, int index, int length) {
|
||||||
|
int len = str ? length : 0;
|
||||||
|
wchar_t* dest = new wchar_t[len + 1];
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
dest[i] = (wchar_t) str[index + i];
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* coco_string_create_char(const wchar_t* str) {
|
||||||
|
int len = coco_string_length(str);
|
||||||
|
char *dest = new char[len + 1];
|
||||||
|
for (int i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
dest[i] = (char) str[i];
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* coco_string_create_char(const wchar_t* str, int index, int length) {
|
||||||
|
int len = coco_string_length(str);
|
||||||
|
if (len) {
|
||||||
|
len = length;
|
||||||
|
}
|
||||||
|
char *dest = new char[len + 1];
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
dest[i] = (char) str[index + i];
|
||||||
|
}
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void coco_string_delete(char* &str) {
|
||||||
|
delete [] str;
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double coco_string_toDouble(const char* str)
|
||||||
|
{
|
||||||
|
return str ? strtod(str, NULL) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float coco_string_toFloat(const char* str)
|
||||||
|
{
|
||||||
|
return str ? strtof(str, NULL) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * End of Wide Character String Routines * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
|
Token::Token()
|
||||||
|
:
|
||||||
|
kind(0),
|
||||||
|
pos(0),
|
||||||
|
col(0),
|
||||||
|
line(0),
|
||||||
|
val(NULL),
|
||||||
|
next(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Token::~Token() {
|
||||||
|
coco_string_delete(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::Buffer(FILE* s, bool isUserStream) {
|
||||||
|
// ensure binary read on windows
|
||||||
|
#if _MSC_VER >= 1300
|
||||||
|
_setmode(_fileno(s), _O_BINARY);
|
||||||
|
#endif
|
||||||
|
stream = s; this->isUserStream = isUserStream;
|
||||||
|
if (CanSeek()) {
|
||||||
|
fseek(s, 0, SEEK_END);
|
||||||
|
fileLen = ftell(s);
|
||||||
|
fseek(s, 0, SEEK_SET);
|
||||||
|
bufLen = (fileLen < MAX_BUFFER_LENGTH) ? fileLen : MAX_BUFFER_LENGTH;
|
||||||
|
bufStart = INT_MAX; // nothing in the buffer so far
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fileLen = bufLen = bufStart = 0;
|
||||||
|
}
|
||||||
|
bufCapacity = (bufLen > 0) ? bufLen : MIN_BUFFER_LENGTH;
|
||||||
|
buf = new unsigned char[bufCapacity];
|
||||||
|
if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
|
||||||
|
else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
|
||||||
|
if (bufLen == fileLen && CanSeek()) Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::Buffer(Buffer* b) {
|
||||||
|
buf = b->buf;
|
||||||
|
bufCapacity = b->bufCapacity;
|
||||||
|
b->buf = NULL;
|
||||||
|
bufStart = b->bufStart;
|
||||||
|
bufLen = b->bufLen;
|
||||||
|
fileLen = b->fileLen;
|
||||||
|
bufPos = b->bufPos;
|
||||||
|
stream = b->stream;
|
||||||
|
b->stream = NULL;
|
||||||
|
isUserStream = b->isUserStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::Buffer(const unsigned char* buf, int len) {
|
||||||
|
this->buf = new unsigned char[len];
|
||||||
|
memcpy(this->buf, buf, len*sizeof(unsigned char));
|
||||||
|
bufStart = 0;
|
||||||
|
bufCapacity = bufLen = len;
|
||||||
|
fileLen = len;
|
||||||
|
bufPos = 0;
|
||||||
|
stream = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::Buffer(const char* buf, int len) {
|
||||||
|
this->buf = new unsigned char[len];
|
||||||
|
memcpy(this->buf, buf, len*sizeof(unsigned char));
|
||||||
|
bufStart = 0;
|
||||||
|
bufCapacity = bufLen = len;
|
||||||
|
fileLen = len;
|
||||||
|
bufPos = 0;
|
||||||
|
stream = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::~Buffer() {
|
||||||
|
Close();
|
||||||
|
if (buf != NULL) {
|
||||||
|
delete [] buf;
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::Close() {
|
||||||
|
if (!isUserStream && stream != NULL) {
|
||||||
|
fclose(stream);
|
||||||
|
stream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Buffer::Read() {
|
||||||
|
if (bufPos < bufLen) {
|
||||||
|
return buf[bufPos++];
|
||||||
|
} else if (GetPos() < fileLen) {
|
||||||
|
SetPos(GetPos()); // shift buffer start to Pos
|
||||||
|
return buf[bufPos++];
|
||||||
|
} else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
|
||||||
|
return buf[bufPos++];
|
||||||
|
} else {
|
||||||
|
return EoF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Buffer::Peek() {
|
||||||
|
int curPos = GetPos();
|
||||||
|
int ch = Read();
|
||||||
|
SetPos(curPos);
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wchar_t* Buffer::GetString(int beg, int end) {
|
||||||
|
int len = 0;
|
||||||
|
wchar_t *buf = new wchar_t[end - beg];
|
||||||
|
int oldPos = GetPos();
|
||||||
|
SetPos(beg);
|
||||||
|
while (GetPos() < end) buf[len++] = (wchar_t) Read();
|
||||||
|
SetPos(oldPos);
|
||||||
|
wchar_t *res = coco_string_create(buf, 0, len);
|
||||||
|
coco_string_delete(buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Buffer::GetPos() {
|
||||||
|
return bufPos + bufStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::SetPos(int value) {
|
||||||
|
if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
|
||||||
|
// Wanted position is after buffer and the stream
|
||||||
|
// is not seek-able e.g. network or console,
|
||||||
|
// thus we have to read the stream manually till
|
||||||
|
// the wanted position is in sight.
|
||||||
|
while ((value >= fileLen) && (ReadNextStreamChunk() > 0))
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value < 0) || (value > fileLen)) {
|
||||||
|
wprintf(L"--- buffer out of bounds access, position: %d\n", value);
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
|
||||||
|
bufPos = value - bufStart;
|
||||||
|
} else if (stream != NULL) { // must be swapped in
|
||||||
|
fseek(stream, value, SEEK_SET);
|
||||||
|
bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
|
||||||
|
bufStart = value; bufPos = 0;
|
||||||
|
} else {
|
||||||
|
bufPos = fileLen - bufStart; // make Pos return fileLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read the next chunk of bytes from the stream, increases the buffer
|
||||||
|
// if needed and updates the fields fileLen and bufLen.
|
||||||
|
// Returns the number of bytes read.
|
||||||
|
int Buffer::ReadNextStreamChunk() {
|
||||||
|
int freeLen = bufCapacity - bufLen;
|
||||||
|
if (freeLen == 0) {
|
||||||
|
// in the case of a growing input stream
|
||||||
|
// we can neither seek in the stream, nor can we
|
||||||
|
// foresee the maximum length, thus we must adapt
|
||||||
|
// the buffer size on demand.
|
||||||
|
bufCapacity = bufLen * 2;
|
||||||
|
unsigned char *newBuf = new unsigned char[bufCapacity];
|
||||||
|
memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
|
||||||
|
delete [] buf;
|
||||||
|
buf = newBuf;
|
||||||
|
freeLen = bufLen;
|
||||||
|
}
|
||||||
|
int read = fread(buf + bufLen, sizeof(unsigned char), freeLen, stream);
|
||||||
|
if (read > 0) {
|
||||||
|
fileLen = bufLen = (bufLen + read);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
// end of stream reached
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Buffer::CanSeek() {
|
||||||
|
return (stream != NULL) && (ftell(stream) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int UTF8Buffer::Read() {
|
||||||
|
int ch;
|
||||||
|
do {
|
||||||
|
ch = Buffer::Read();
|
||||||
|
// until we find a utf8 start (0xxxxxxx or 11xxxxxx)
|
||||||
|
} while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
|
||||||
|
if (ch < 128 || ch == EoF) {
|
||||||
|
// nothing to do, first 127 chars are the same in ascii and utf8
|
||||||
|
// 0xxxxxxx or end of file character
|
||||||
|
} else if ((ch & 0xF0) == 0xF0) {
|
||||||
|
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
int c1 = ch & 0x07; ch = Buffer::Read();
|
||||||
|
int c2 = ch & 0x3F; ch = Buffer::Read();
|
||||||
|
int c3 = ch & 0x3F; ch = Buffer::Read();
|
||||||
|
int c4 = ch & 0x3F;
|
||||||
|
ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
|
||||||
|
} else if ((ch & 0xE0) == 0xE0) {
|
||||||
|
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
int c1 = ch & 0x0F; ch = Buffer::Read();
|
||||||
|
int c2 = ch & 0x3F; ch = Buffer::Read();
|
||||||
|
int c3 = ch & 0x3F;
|
||||||
|
ch = (((c1 << 6) | c2) << 6) | c3;
|
||||||
|
} else if ((ch & 0xC0) == 0xC0) {
|
||||||
|
// 110xxxxx 10xxxxxx
|
||||||
|
int c1 = ch & 0x1F; ch = Buffer::Read();
|
||||||
|
int c2 = ch & 0x3F;
|
||||||
|
ch = (c1 << 6) | c2;
|
||||||
|
}
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scanner::Scanner(const unsigned char* buf, int len) {
|
||||||
|
buffer = new Buffer(buf, len);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scanner::Scanner(const char* buf, int len) {
|
||||||
|
buffer = new Buffer(buf, len);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scanner::Scanner(const wchar_t* fileName) {
|
||||||
|
FILE* stream;
|
||||||
|
char *chFileName = coco_string_create_char(fileName);
|
||||||
|
if ((stream = fopen(chFileName, "rb")) == NULL) {
|
||||||
|
wprintf(L"--- Cannot open file %ls\n", fileName);
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
coco_string_delete(chFileName);
|
||||||
|
buffer = new Buffer(stream, false);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scanner::Scanner(FILE* s) {
|
||||||
|
buffer = new Buffer(s, true);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scanner::~Scanner() {
|
||||||
|
char* cur = (char*) firstHeap;
|
||||||
|
|
||||||
|
while (cur != NULL) {
|
||||||
|
cur = *(char**) (cur + HEAP_BLOCK_SIZE);
|
||||||
|
free(firstHeap);
|
||||||
|
firstHeap = cur;
|
||||||
|
}
|
||||||
|
delete [] tval;
|
||||||
|
delete buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scanner::Init() {
|
||||||
|
maxT = 13;
|
||||||
|
noSym = 13;
|
||||||
|
int i;
|
||||||
|
for (i = 65; i <= 90; ++i) start.set(i, 1);
|
||||||
|
for (i = 97; i <= 122; ++i) start.set(i, 1);
|
||||||
|
for (i = 36; i <= 36; ++i) start.set(i, 5);
|
||||||
|
start.set(45, 20);
|
||||||
|
for (i = 48; i <= 57; ++i) start.set(i, 9);
|
||||||
|
start.set(34, 2);
|
||||||
|
start.set(46, 7);
|
||||||
|
start.set(123, 14);
|
||||||
|
start.set(125, 15);
|
||||||
|
start.set(43, 21);
|
||||||
|
start.set(42, 16);
|
||||||
|
start.set(47, 17);
|
||||||
|
start.set(40, 18);
|
||||||
|
start.set(41, 19);
|
||||||
|
start.set(Buffer::EoF, -1);
|
||||||
|
|
||||||
|
|
||||||
|
tvalLength = 128;
|
||||||
|
tval = new wchar_t[tvalLength]; // text of current token
|
||||||
|
|
||||||
|
// HEAP_BLOCK_SIZE byte heap + pointer to next heap block
|
||||||
|
heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
|
||||||
|
firstHeap = heap;
|
||||||
|
heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE);
|
||||||
|
*heapEnd = 0;
|
||||||
|
heapTop = heap;
|
||||||
|
if (sizeof(Token) > HEAP_BLOCK_SIZE) {
|
||||||
|
wprintf(L"--- Too small HEAP_BLOCK_SIZE\n");
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = -1; line = 1; col = 0;
|
||||||
|
oldEols = 0;
|
||||||
|
NextCh();
|
||||||
|
if (ch == 0xEF) { // check optional byte order mark for UTF-8
|
||||||
|
NextCh(); int ch1 = ch;
|
||||||
|
NextCh(); int ch2 = ch;
|
||||||
|
if (ch1 != 0xBB || ch2 != 0xBF) {
|
||||||
|
wprintf(L"Illegal byte order mark at start of file");
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
Buffer *oldBuf = buffer;
|
||||||
|
buffer = new UTF8Buffer(buffer); col = 0;
|
||||||
|
delete oldBuf; oldBuf = NULL;
|
||||||
|
NextCh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pt = tokens = CreateToken(); // first token is a dummy
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scanner::NextCh() {
|
||||||
|
if (oldEols > 0) {
|
||||||
|
ch = EOL;
|
||||||
|
oldEols--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pos = buffer->GetPos();
|
||||||
|
ch = buffer->Read(); col++;
|
||||||
|
// replace isolated '\r' by '\n' in order to make
|
||||||
|
// eol handling uniform across Windows, Unix and Mac
|
||||||
|
if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
|
||||||
|
if (ch == EOL) { line++; col = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scanner::AddCh() {
|
||||||
|
if (tlen >= tvalLength) {
|
||||||
|
tvalLength *= 2;
|
||||||
|
wchar_t *newBuf = new wchar_t[tvalLength];
|
||||||
|
memcpy(newBuf, tval, tlen*sizeof(wchar_t));
|
||||||
|
delete [] tval;
|
||||||
|
tval = newBuf;
|
||||||
|
}
|
||||||
|
if (ch != Buffer::EoF) {
|
||||||
|
tval[tlen++] = ch;
|
||||||
|
NextCh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Scanner::Comment0() {
|
||||||
|
int level = 1, pos0 = pos, line0 = line, col0 = col;
|
||||||
|
NextCh();
|
||||||
|
if (ch == L'/') {
|
||||||
|
NextCh();
|
||||||
|
for(;;) {
|
||||||
|
if (ch == 10) {
|
||||||
|
level--;
|
||||||
|
if (level == 0) { oldEols = line - line0; NextCh(); return true; }
|
||||||
|
NextCh();
|
||||||
|
} else if (ch == buffer->EoF) return false;
|
||||||
|
else NextCh();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer->SetPos(pos0); NextCh(); line = line0; col = col0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scanner::Comment1() {
|
||||||
|
int level = 1, pos0 = pos, line0 = line, col0 = col;
|
||||||
|
NextCh();
|
||||||
|
if (ch == L'*') {
|
||||||
|
NextCh();
|
||||||
|
for(;;) {
|
||||||
|
if (ch == L'*') {
|
||||||
|
NextCh();
|
||||||
|
if (ch == L'/') {
|
||||||
|
level--;
|
||||||
|
if (level == 0) { oldEols = line - line0; NextCh(); return true; }
|
||||||
|
NextCh();
|
||||||
|
}
|
||||||
|
} else if (ch == L'/') {
|
||||||
|
NextCh();
|
||||||
|
if (ch == L'*') {
|
||||||
|
level++; NextCh();
|
||||||
|
}
|
||||||
|
} else if (ch == buffer->EoF) return false;
|
||||||
|
else NextCh();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer->SetPos(pos0); NextCh(); line = line0; col = col0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scanner::CreateHeapBlock() {
|
||||||
|
void* newHeap;
|
||||||
|
char* cur = (char*) firstHeap;
|
||||||
|
|
||||||
|
while (((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) {
|
||||||
|
cur = *((char**) (cur + HEAP_BLOCK_SIZE));
|
||||||
|
free(firstHeap);
|
||||||
|
firstHeap = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEAP_BLOCK_SIZE byte heap + pointer to next heap block
|
||||||
|
newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
|
||||||
|
*heapEnd = newHeap;
|
||||||
|
heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE);
|
||||||
|
*heapEnd = 0;
|
||||||
|
heap = newHeap;
|
||||||
|
heapTop = heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Token* Scanner::CreateToken() {
|
||||||
|
Token *t;
|
||||||
|
if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
|
||||||
|
CreateHeapBlock();
|
||||||
|
}
|
||||||
|
t = (Token*) heapTop;
|
||||||
|
heapTop = (void*) ((char*) heapTop + sizeof(Token));
|
||||||
|
t->val = NULL;
|
||||||
|
t->next = NULL;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scanner::AppendVal(Token *t) {
|
||||||
|
int reqMem = (tlen + 1) * sizeof(wchar_t);
|
||||||
|
if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
|
||||||
|
if (reqMem > HEAP_BLOCK_SIZE) {
|
||||||
|
wprintf(L"--- Too long token value\n");
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
CreateHeapBlock();
|
||||||
|
}
|
||||||
|
t->val = (wchar_t*) heapTop;
|
||||||
|
heapTop = (void*) ((char*) heapTop + reqMem);
|
||||||
|
|
||||||
|
wcsncpy(t->val, tval, tlen);
|
||||||
|
t->val[tlen] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Token* Scanner::NextToken() {
|
||||||
|
while (ch == ' ' ||
|
||||||
|
ch <= 31 || (ch >= 127 && ch <= 65535)
|
||||||
|
) NextCh();
|
||||||
|
if ((ch == L'/' && Comment0()) || (ch == L'/' && Comment1())) return NextToken();
|
||||||
|
t = CreateToken();
|
||||||
|
t->pos = pos; t->col = col; t->line = line;
|
||||||
|
int state = start.state(ch);
|
||||||
|
tlen = 0; AddCh();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case -1: { t->kind = eofSym; break; } // NextCh already done
|
||||||
|
case 0: { t->kind = noSym; break; } // NextCh already done
|
||||||
|
case 1:
|
||||||
|
case_1:
|
||||||
|
if ((ch >= L'0' && ch <= L':') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_1;}
|
||||||
|
else {t->kind = 1; break;}
|
||||||
|
case 2:
|
||||||
|
case_2:
|
||||||
|
if (ch <= 9 || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= L'!') || (ch >= L'#' && ch <= L'[') || (ch >= L']' && ch <= 65535)) {AddCh(); goto case_2;}
|
||||||
|
else if (ch == L'"') {AddCh(); goto case_4;}
|
||||||
|
else if (ch == 92) {AddCh(); goto case_3;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 3:
|
||||||
|
case_3:
|
||||||
|
if ((ch >= L' ' && ch <= L'~')) {AddCh(); goto case_2;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 4:
|
||||||
|
case_4:
|
||||||
|
{t->kind = 2; break;}
|
||||||
|
case 5:
|
||||||
|
if ((ch >= L'A' && ch <= L'Z') || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_6;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 6:
|
||||||
|
case_6:
|
||||||
|
if ((ch >= L'0' && ch <= L':') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_6;}
|
||||||
|
else {t->kind = 3; break;}
|
||||||
|
case 7:
|
||||||
|
case_7:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_8;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 8:
|
||||||
|
case_8:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_8;}
|
||||||
|
else {t->kind = 4; break;}
|
||||||
|
case 9:
|
||||||
|
case_9:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_9;}
|
||||||
|
else if (ch == L'E' || ch == L'e') {AddCh(); goto case_10;}
|
||||||
|
else if (ch == L'.') {AddCh(); goto case_13;}
|
||||||
|
else {t->kind = 4; break;}
|
||||||
|
case 10:
|
||||||
|
case_10:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_12;}
|
||||||
|
else if (ch == L'+' || ch == L'-') {AddCh(); goto case_11;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 11:
|
||||||
|
case_11:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_12;}
|
||||||
|
else {t->kind = noSym; break;}
|
||||||
|
case 12:
|
||||||
|
case_12:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_12;}
|
||||||
|
else {t->kind = 4; break;}
|
||||||
|
case 13:
|
||||||
|
case_13:
|
||||||
|
if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_13;}
|
||||||
|
else if (ch == L'E' || ch == L'e') {AddCh(); goto case_10;}
|
||||||
|
else {t->kind = 4; break;}
|
||||||
|
case 14:
|
||||||
|
{t->kind = 5; break;}
|
||||||
|
case 15:
|
||||||
|
{t->kind = 6; break;}
|
||||||
|
case 16:
|
||||||
|
{t->kind = 9; break;}
|
||||||
|
case 17:
|
||||||
|
{t->kind = 10; break;}
|
||||||
|
case 18:
|
||||||
|
{t->kind = 11; break;}
|
||||||
|
case 19:
|
||||||
|
{t->kind = 12; break;}
|
||||||
|
case 20:
|
||||||
|
if (ch == L'.') {AddCh(); goto case_7;}
|
||||||
|
else {t->kind = 8; break;}
|
||||||
|
case 21:
|
||||||
|
if (ch == L'.') {AddCh(); goto case_7;}
|
||||||
|
else {t->kind = 7; break;}
|
||||||
|
|
||||||
|
}
|
||||||
|
AppendVal(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the next token (possibly a token already seen during peeking)
|
||||||
|
Token* Scanner::Scan() {
|
||||||
|
if (tokens->next == NULL) {
|
||||||
|
return pt = tokens = NextToken();
|
||||||
|
} else {
|
||||||
|
pt = tokens = tokens->next;
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// peek for the next token, ignore pragmas
|
||||||
|
Token* Scanner::Peek() {
|
||||||
|
do {
|
||||||
|
if (pt->next == NULL) {
|
||||||
|
pt->next = NextToken();
|
||||||
|
}
|
||||||
|
pt = pt->next;
|
||||||
|
} while (pt->kind > maxT); // skip pragmas
|
||||||
|
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// make sure that peeking starts at the current scan position
|
||||||
|
void Scanner::ResetPeek() {
|
||||||
|
pt = tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
379
applications/test/dictionary/calcEntry/calcEntryScanner.h
Normal file
379
applications/test/dictionary/calcEntry/calcEntryScanner.h
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef COCO_calcEntrySCANNER_H__
|
||||||
|
#define COCO_calcEntrySCANNER_H__
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
// io.h and fcntl are used to ensure binary read from streams on windows
|
||||||
|
#if _MSC_VER >= 1300
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400
|
||||||
|
#define coco_swprintf swprintf_s
|
||||||
|
#elif _MSC_VER >= 1300
|
||||||
|
#define coco_swprintf _snwprintf
|
||||||
|
#else
|
||||||
|
// assume every other compiler knows swprintf
|
||||||
|
#define coco_swprintf swprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define COCO_WCHAR_MAX 65535
|
||||||
|
#define MIN_BUFFER_LENGTH 1024
|
||||||
|
#define MAX_BUFFER_LENGTH (64*MIN_BUFFER_LENGTH)
|
||||||
|
#define HEAP_BLOCK_SIZE (64*1024)
|
||||||
|
|
||||||
|
|
||||||
|
namespace Foam {
|
||||||
|
namespace functionEntries {
|
||||||
|
namespace calcEntryInternal {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * Wide Character String Routines * * * * * * * * * * * //
|
||||||
|
|
||||||
|
//
|
||||||
|
// string handling, wide character
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
//! Create by copying str
|
||||||
|
wchar_t* coco_string_create(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Create a substring of str starting at index and length characters long
|
||||||
|
wchar_t* coco_string_create(const wchar_t* str, int index, int length);
|
||||||
|
|
||||||
|
//! Create an uppercase string from str
|
||||||
|
wchar_t* coco_string_create_upper(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Create an uppercase substring from str starting at index and length characters long
|
||||||
|
wchar_t* coco_string_create_upper(const wchar_t* str, int index, int length);
|
||||||
|
|
||||||
|
//! Create a lowercase string from str
|
||||||
|
wchar_t* coco_string_create_lower(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Create a lowercase substring from str starting at index and length characters long
|
||||||
|
wchar_t* coco_string_create_lower(const wchar_t* str, int index, int length);
|
||||||
|
|
||||||
|
//! Create a string by concatenating str1 and str2
|
||||||
|
wchar_t* coco_string_create_append(const wchar_t* str1, const wchar_t* str2);
|
||||||
|
|
||||||
|
//! Create a string by concatenating a character to the end of str
|
||||||
|
wchar_t* coco_string_create_append(const wchar_t* str, const wchar_t ch);
|
||||||
|
|
||||||
|
//! Free storage and nullify the argument
|
||||||
|
void coco_string_delete(wchar_t* &str);
|
||||||
|
|
||||||
|
//! The length of the str, or 0 if the str is NULL
|
||||||
|
int coco_string_length(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Return true if the str ends with the endstr
|
||||||
|
bool coco_string_endswith(const wchar_t* str, const wchar_t* endstr);
|
||||||
|
|
||||||
|
//! Return the index of the first occurrence of ch.
|
||||||
|
// Return -1 if nothing is found.
|
||||||
|
int coco_string_indexof(const wchar_t* str, const wchar_t ch);
|
||||||
|
|
||||||
|
//! Return the index of the last occurrence of ch.
|
||||||
|
// Return -1 if nothing is found.
|
||||||
|
int coco_string_lastindexof(const wchar_t* str, const wchar_t ch);
|
||||||
|
|
||||||
|
//! Append str to dest
|
||||||
|
void coco_string_merge(wchar_t* &dest, const wchar_t* str);
|
||||||
|
|
||||||
|
//! Compare strings, return true if they are equal
|
||||||
|
bool coco_string_equal(const wchar_t* str1, const wchar_t* str2);
|
||||||
|
|
||||||
|
//! Compare strings, return 0 if they are equal
|
||||||
|
int coco_string_compareto(const wchar_t* str1, const wchar_t* str2);
|
||||||
|
|
||||||
|
//! Simple string hashing function
|
||||||
|
int coco_string_hash(const wchar_t* str);
|
||||||
|
|
||||||
|
//
|
||||||
|
// String conversions
|
||||||
|
// ~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
//! Convert wide string to double
|
||||||
|
double coco_string_toDouble(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Convert wide string to float
|
||||||
|
float coco_string_toFloat(const wchar_t* str);
|
||||||
|
|
||||||
|
//
|
||||||
|
// String handling, byte character
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
//! Create by copying byte str
|
||||||
|
wchar_t* coco_string_create(const char* str);
|
||||||
|
|
||||||
|
//! Create a substring of byte str starting at index and length characters long
|
||||||
|
wchar_t* coco_string_create(const char* str, int index, int length);
|
||||||
|
|
||||||
|
//! Create a byte string by copying str
|
||||||
|
char* coco_string_create_char(const wchar_t* str);
|
||||||
|
|
||||||
|
//! Create a byte substring of str starting at index and length characters long
|
||||||
|
char* coco_string_create_char(const wchar_t* str, int index, int length);
|
||||||
|
|
||||||
|
//! Free storage and nullify the argument
|
||||||
|
void coco_string_delete(char* &str);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// String conversions, byte character
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
//! Convert byte string to double
|
||||||
|
double coco_string_toDouble(const char* str);
|
||||||
|
|
||||||
|
//! Convert byte string to float
|
||||||
|
float coco_string_toFloat(const char* str);
|
||||||
|
|
||||||
|
// * * * * * * * * * End of Wide Character String Routines * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//! Scanner Token
|
||||||
|
class Token
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int kind; //!< token kind
|
||||||
|
int pos; //!< token position in the source text (starting at 0)
|
||||||
|
int col; //!< token column (starting at 1)
|
||||||
|
int line; //!< token line (starting at 1)
|
||||||
|
wchar_t* val; //!< token value
|
||||||
|
Token *next; //!< Peek tokens are kept in linked list
|
||||||
|
|
||||||
|
Token(); //!< Construct null
|
||||||
|
~Token(); //!< Destructor - cleanup allocated val
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! Scanner Buffer
|
||||||
|
//
|
||||||
|
//! This Buffer supports the following cases:
|
||||||
|
//! -# seekable stream (file)
|
||||||
|
//! -# whole stream in buffer
|
||||||
|
//! -# part of stream in buffer
|
||||||
|
//! -# non seekable stream (network, console)
|
||||||
|
class Buffer {
|
||||||
|
private:
|
||||||
|
unsigned char *buf; //!< input buffer
|
||||||
|
int bufCapacity; //!< capacity of buf
|
||||||
|
int bufStart; //!< position of first byte in buffer relative to input stream
|
||||||
|
int bufLen; //!< length of buffer
|
||||||
|
int fileLen; //!< length of input stream (may change if the stream is no file)
|
||||||
|
int bufPos; //!< current position in buffer
|
||||||
|
FILE* stream; //!< input stream (seekable)
|
||||||
|
bool isUserStream; //!< was the stream opened by the user?
|
||||||
|
|
||||||
|
int ReadNextStreamChunk();
|
||||||
|
bool CanSeek(); //!< true if stream can be seeked otherwise false
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const int EoF = COCO_WCHAR_MAX + 1;
|
||||||
|
|
||||||
|
Buffer(FILE*, bool isUserStream);
|
||||||
|
Buffer(const unsigned char* buf, int len);
|
||||||
|
Buffer(const char* buf, int len);
|
||||||
|
Buffer(Buffer*);
|
||||||
|
virtual ~Buffer();
|
||||||
|
|
||||||
|
virtual void Close();
|
||||||
|
virtual int Read();
|
||||||
|
virtual int Peek();
|
||||||
|
virtual wchar_t* GetString(int beg, int end);
|
||||||
|
virtual int GetPos();
|
||||||
|
virtual void SetPos(int value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! A Scanner buffer that handles UTF-8 characters
|
||||||
|
class UTF8Buffer : public Buffer {
|
||||||
|
public:
|
||||||
|
UTF8Buffer(Buffer* b) : Buffer(b) {}
|
||||||
|
virtual int Read();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// StartStates
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//! maps characters to start states of tokens
|
||||||
|
class StartStates {
|
||||||
|
private:
|
||||||
|
class Elem {
|
||||||
|
public:
|
||||||
|
int key, val;
|
||||||
|
Elem *next;
|
||||||
|
Elem(int key, int val) {
|
||||||
|
this->key = key;
|
||||||
|
this->val = val;
|
||||||
|
next = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Elem **tab;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StartStates() {
|
||||||
|
tab = new Elem*[128];
|
||||||
|
memset(tab, 0, 128 * sizeof(Elem*));
|
||||||
|
}
|
||||||
|
virtual ~StartStates() {
|
||||||
|
for (int i = 0; i < 128; ++i) {
|
||||||
|
Elem *e = tab[i];
|
||||||
|
while (e != NULL) {
|
||||||
|
Elem *next = e->next;
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(int key, int val) {
|
||||||
|
Elem *e = new Elem(key, val);
|
||||||
|
int k = ((unsigned int) key) % 128;
|
||||||
|
e->next = tab[k];
|
||||||
|
tab[k] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int state(int key) {
|
||||||
|
Elem *e = tab[((unsigned int) key) % 128];
|
||||||
|
while (e != NULL && e->key != key) e = e->next;
|
||||||
|
return e == NULL ? 0 : e->val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// KeywordMap
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//! maps strings to integers (identifiers to keyword kinds)
|
||||||
|
class KeywordMap {
|
||||||
|
private:
|
||||||
|
class Elem {
|
||||||
|
public:
|
||||||
|
wchar_t *key;
|
||||||
|
int val;
|
||||||
|
Elem *next;
|
||||||
|
Elem(const wchar_t *key, int val) {
|
||||||
|
this->key = coco_string_create(key);
|
||||||
|
this->val = val;
|
||||||
|
next = NULL;
|
||||||
|
}
|
||||||
|
virtual ~Elem() {
|
||||||
|
coco_string_delete(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Elem **tab;
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeywordMap() {
|
||||||
|
tab = new Elem*[128];
|
||||||
|
memset(tab, 0, 128 * sizeof(Elem*));
|
||||||
|
}
|
||||||
|
virtual ~KeywordMap() {
|
||||||
|
for (int i = 0; i < 128; ++i) {
|
||||||
|
Elem *e = tab[i];
|
||||||
|
while (e != NULL) {
|
||||||
|
Elem *next = e->next;
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const wchar_t *key, int val) {
|
||||||
|
Elem *e = new Elem(key, val);
|
||||||
|
int k = coco_string_hash(key) % 128;
|
||||||
|
e->next = tab[k]; tab[k] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get(const wchar_t *key, int defaultVal) {
|
||||||
|
Elem *e = tab[coco_string_hash(key) % 128];
|
||||||
|
while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
|
||||||
|
return e == NULL ? defaultVal : e->val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! A Coco/R Scanner
|
||||||
|
class Scanner {
|
||||||
|
private:
|
||||||
|
static const unsigned char EOL = '\n'; // end-of-line character
|
||||||
|
static const int eofSym = 0; // end-of-file token id
|
||||||
|
|
||||||
|
void *firstHeap;
|
||||||
|
void *heap;
|
||||||
|
void *heapTop;
|
||||||
|
void **heapEnd;
|
||||||
|
|
||||||
|
int noSym; //!< noSym gets highest number, set in Parser
|
||||||
|
int maxT;
|
||||||
|
int charSetSize; //!< unused?
|
||||||
|
StartStates start;
|
||||||
|
KeywordMap keywords;
|
||||||
|
|
||||||
|
Token *t; //!< current token
|
||||||
|
wchar_t *tval; //!< text of current token
|
||||||
|
int tvalLength; //!< length of text of current token
|
||||||
|
int tlen; //!< length of current token
|
||||||
|
|
||||||
|
Token *tokens; //!< list of tokens already peeked (first token is a dummy)
|
||||||
|
Token *pt; //!< current peek token
|
||||||
|
|
||||||
|
int ch; //!< current input character
|
||||||
|
|
||||||
|
int pos; //!< byte position of current character
|
||||||
|
int line; //!< line number of current character
|
||||||
|
int col; //!< column number of current character
|
||||||
|
int oldEols; //!< EOLs that appeared in a comment;
|
||||||
|
|
||||||
|
void CreateHeapBlock();
|
||||||
|
Token* CreateToken();
|
||||||
|
void AppendVal(Token*);
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void NextCh();
|
||||||
|
void AddCh();
|
||||||
|
bool Comment0();
|
||||||
|
bool Comment1();
|
||||||
|
|
||||||
|
Token* NextToken();
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! scanner buffer
|
||||||
|
Buffer *buffer;
|
||||||
|
|
||||||
|
//! Attach scanner to an existing character buffer
|
||||||
|
Scanner(const unsigned char* buf, int len);
|
||||||
|
//! Attach scanner to an existing character buffer
|
||||||
|
Scanner(const char* buf, int len);
|
||||||
|
//! Open a file for reading and attach scanner
|
||||||
|
Scanner(const wchar_t* fileName);
|
||||||
|
//! Using an existing open file handle for the scanner
|
||||||
|
Scanner(FILE* s);
|
||||||
|
~Scanner();
|
||||||
|
Token* Scan();
|
||||||
|
Token* Peek();
|
||||||
|
void ResetPeek();
|
||||||
|
|
||||||
|
}; // end Scanner
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // COCO_calcEntrySCANNER_H__
|
||||||
|
|
||||||
@ -43,70 +43,86 @@ using namespace Foam;
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
argList::noParallel();
|
argList::noParallel();
|
||||||
argList args(argc, argv);
|
argList::validArgs.insert("dict .. dictN");
|
||||||
|
argList args(argc, argv, false, true);
|
||||||
|
|
||||||
Info<< nl
|
Info<< nl
|
||||||
<< "FOAM_CASE=" << getEnv("FOAM_CASE") << nl
|
<< "FOAM_CASE=" << getEnv("FOAM_CASE") << nl
|
||||||
<< "FOAM_CASENAME=" << getEnv("FOAM_CASENAME") << nl
|
<< "FOAM_CASENAME=" << getEnv("FOAM_CASENAME") << nl
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
|
if (args.additionalArgs().empty())
|
||||||
{
|
{
|
||||||
dictionary dict1(IFstream("testDict")());
|
{
|
||||||
Info<< "dict1: " << dict1 << nl
|
dictionary dict1(IFstream("testDict")());
|
||||||
<< "toc: " << dict1.toc() << nl
|
Info<< "dict1: " << dict1 << nl
|
||||||
<< "keys: " << dict1.keys() << nl
|
<< "toc: " << dict1.toc() << nl
|
||||||
<< "patterns: " << dict1.keys(true) << endl;
|
<< "keys: " << dict1.keys() << nl
|
||||||
|
<< "patterns: " << dict1.keys(true) << endl;
|
||||||
|
|
||||||
dictionary dict2(dict1.xfer());
|
dictionary dict2(dict1.xfer());
|
||||||
|
|
||||||
Info<< "dict1.toc(): " << dict1.name() << " " << dict1.toc() << nl
|
Info<< "dict1.toc(): " << dict1.name() << " " << dict1.toc() << nl
|
||||||
<< "dict2.toc(): " << dict2.name() << " " << dict2.toc() << endl;
|
<< "dict2.toc(): " << dict2.name() << " " << dict2.toc() << endl;
|
||||||
|
|
||||||
// copy back
|
// copy back
|
||||||
dict1 = dict2;
|
dict1 = dict2;
|
||||||
Info<< "dict1.toc(): " << dict1.name() << " " << dict1.toc() << endl;
|
Info<< "dict1.toc(): " << dict1.name() << " " << dict1.toc() << endl;
|
||||||
|
|
||||||
dictionary dict3(dict2.subDictPtr("boundaryField"));
|
dictionary dict3(dict2.subDictPtr("boundaryField"));
|
||||||
dictionary dict4(dict2.subDictPtr("NONEXISTENT"));
|
dictionary dict4(dict2.subDictPtr("NONEXISTENT"));
|
||||||
|
|
||||||
Info<< "dictionary construct from pointer" << nl
|
Info<< "dictionary construct from pointer" << nl
|
||||||
<< "ok = " << dict3.name() << " " << dict3.toc() << nl
|
<< "ok = " << dict3.name() << " " << dict3.toc() << nl
|
||||||
<< "no = " << dict4.name() << " " << dict4.toc() << endl;
|
<< "no = " << dict4.name() << " " << dict4.toc() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IOobject::writeDivider(Info);
|
||||||
|
|
||||||
|
{
|
||||||
|
dictionary dict(IFstream("testDictRegex")());
|
||||||
|
dict.add(keyType("fooba[rz]", true), "anything");
|
||||||
|
|
||||||
|
Info<< "dict:" << dict << nl
|
||||||
|
<< "toc: " << dict.toc() << nl
|
||||||
|
<< "keys: " << dict.keys() << nl
|
||||||
|
<< "patterns: " << dict.keys(true) << endl;
|
||||||
|
|
||||||
|
Info<< "Pattern find \"abc\" in top directory : "
|
||||||
|
<< dict.lookup("abc") << endl;
|
||||||
|
Info<< "Pattern find \"abc\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("abc")
|
||||||
|
<< endl;
|
||||||
|
Info<< "Recursive pattern find \"def\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("def", true)
|
||||||
|
<< endl;
|
||||||
|
Info<< "Recursive pattern find \"foo\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("foo", true)
|
||||||
|
<< endl;
|
||||||
|
Info<< "Recursive pattern find \"fooz\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("fooz", true)
|
||||||
|
<< endl;
|
||||||
|
Info<< "Recursive pattern find \"bar\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("bar", true)
|
||||||
|
<< endl;
|
||||||
|
Info<< "Recursive pattern find \"xxx\" in sub directory : "
|
||||||
|
<< dict.subDict("someDict").lookup("xxx", true)
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
IOobject::writeDivider(Info);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
dictionary dict(IFstream("testDictRegex")());
|
IOobject::writeDivider(Info);
|
||||||
dict.add(keyType("fooba[rz]", true), "anything");
|
forAll(args.additionalArgs(), argI)
|
||||||
|
{
|
||||||
|
const string& dictFile = args.additionalArgs()[argI];
|
||||||
|
IFstream is(dictFile);
|
||||||
|
|
||||||
Info<< "dict:" << dict << nl
|
dictionary dict(is);
|
||||||
<< "toc: " << dict.toc() << nl
|
|
||||||
<< "keys: " << dict.keys() << nl
|
|
||||||
<< "patterns: " << dict.keys(true) << endl;
|
|
||||||
|
|
||||||
Info<< "Pattern find \"abc\" in top directory : "
|
Info<< dict << endl;
|
||||||
<< dict.lookup("abc") << endl;
|
}
|
||||||
Info<< "Pattern find \"abc\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("abc")
|
|
||||||
<< endl;
|
|
||||||
Info<< "Recursive pattern find \"def\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("def", true)
|
|
||||||
<< endl;
|
|
||||||
Info<< "Recursive pattern find \"foo\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("foo", true)
|
|
||||||
<< endl;
|
|
||||||
Info<< "Recursive pattern find \"fooz\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("fooz", true)
|
|
||||||
<< endl;
|
|
||||||
Info<< "Recursive pattern find \"bar\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("bar", true)
|
|
||||||
<< endl;
|
|
||||||
Info<< "Recursive pattern find \"xxx\" in sub directory : "
|
|
||||||
<< dict.subDict("someDict").lookup("xxx", true)
|
|
||||||
<< endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
33
applications/test/dictionary/testDictCalc
Normal file
33
applications/test/dictionary/testDictCalc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
| ========= | |
|
||||||
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
|
| \\ / O peration | Version: Any |
|
||||||
|
| \\ / A nd | Web: www.OpenFOAM.org |
|
||||||
|
| \\/ M anipulation | |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
FoamFile
|
||||||
|
{
|
||||||
|
version 2.0;
|
||||||
|
format ascii;
|
||||||
|
class dictionary;
|
||||||
|
object testDictTest;
|
||||||
|
}
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
x 10 /* what ever */ 20;
|
||||||
|
y 20;
|
||||||
|
// z #test{ // this
|
||||||
|
// 123 - 456
|
||||||
|
// // comments // are
|
||||||
|
// /* stripped
|
||||||
|
// * 10
|
||||||
|
// * {}
|
||||||
|
// */
|
||||||
|
// + 1 /*100 */ 10
|
||||||
|
// };
|
||||||
|
|
||||||
|
p #test{ 1 + 2 + 10 * 15 + $x - $y };
|
||||||
|
|
||||||
|
foo 30;
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
Reference in New Issue
Block a user