mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add C++-based wmkdepend parser (uses Coco/R grammar).
- This avoids dependency on lex/flex and provides better encapsulation for buffer switching. As a result, the maximum number of open files only corresponds to the include depth.
This commit is contained in:
@ -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) 1991-2010 OpenCFD Ltd.
|
||||||
# \\/ M anipulation |
|
# \\/ M anipulation |
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# License
|
# License
|
||||||
@ -60,16 +60,17 @@ include $(RULES)/$(WM_LINK_LANGUAGE)
|
|||||||
# targets
|
# targets
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
all: $(BIN)/dirToString $(BIN)/wmkdep
|
all: $(BIN)/dirToString $(BIN)/wmkdep $(BIN)/wmkdepend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN)/dirToString $(BIN)/wmkdep 2>/dev/null
|
rm -f $(BIN)/dirToString $(BIN)/wmkdep $(BIN)/wmkdepend 2>/dev/null
|
||||||
|
|
||||||
|
|
||||||
$(BIN)/dirToString: dirToString.c
|
$(BIN)/dirToString: dirToString.c
|
||||||
@mkdir -p $(BIN)
|
@mkdir -p $(BIN)
|
||||||
$(cc) $(cFLAGS) dirToString.c -o $(BIN)/dirToString
|
$(cc) $(cFLAGS) dirToString.c -o $(BIN)/dirToString
|
||||||
|
|
||||||
|
|
||||||
$(BIN)/wmkdep: wmkdep.l
|
$(BIN)/wmkdep: wmkdep.l
|
||||||
@mkdir -p $(BIN)
|
@mkdir -p $(BIN)
|
||||||
flex wmkdep.l
|
flex wmkdep.l
|
||||||
@ -77,4 +78,13 @@ $(BIN)/wmkdep: wmkdep.l
|
|||||||
@rm -f lex.yy.c 2>/dev/null
|
@rm -f lex.yy.c 2>/dev/null
|
||||||
|
|
||||||
|
|
||||||
|
# for bootstrapping - use generated files directly (instead of from .atg file)
|
||||||
|
$(BIN)/wmkdepend: wmkdepend.cpp \
|
||||||
|
wmkdependParser.cpp wmkdependScanner.cpp \
|
||||||
|
wmkdependParser.h wmkdependScanner.h
|
||||||
|
@mkdir -p $(BIN)
|
||||||
|
$(CC) $(c++FLAGS) \
|
||||||
|
wmkdepend.cpp wmkdependParser.cpp wmkdependScanner.cpp \
|
||||||
|
-o $(BIN)/wmkdepend
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|||||||
164
wmake/src/wmkdepend.cpp
Normal file
164
wmake/src/wmkdepend.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2010-2010 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
|
||||||
|
|
||||||
|
Application
|
||||||
|
wmkdepend
|
||||||
|
|
||||||
|
Description
|
||||||
|
A fast dependency list generator that emulates the behaviour and
|
||||||
|
output of cpp -M. However, the output contains no duplications and
|
||||||
|
is ~40% faster than cpp.
|
||||||
|
|
||||||
|
The algorithm uses flex to scan for includes and searches the files
|
||||||
|
found. Each file is entered into a hash table so that files are scanned
|
||||||
|
only once. This is why this program is faster than cpp.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
wmkdep [ -Idirectory ... -Idirectory ] filename
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "wmkdependParser.h"
|
||||||
|
|
||||||
|
// Note: since we use the Coco/R default error messages, we must use
|
||||||
|
// wide streams for stderr.
|
||||||
|
|
||||||
|
void printUsage(const char* message = NULL)
|
||||||
|
{
|
||||||
|
if (message)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"\nError: %s\n\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"Usage: wmkdepend [ -Idirectory ... -Idirectory ] filename\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
printUsage("Error: input file not supplied");
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=1; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (strncmp(argv[i], "-I", 2) == 0 && strlen(argv[i]) > 2)
|
||||||
|
{
|
||||||
|
std::string dirName(argv[i] + 2);
|
||||||
|
|
||||||
|
// add trailing slash if required
|
||||||
|
if (dirName.rfind('/') != dirName.size()-1)
|
||||||
|
{
|
||||||
|
dirName += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
wmake::Parser::includeDirs.push_back(dirName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sourceFile(argv[argc-1]);
|
||||||
|
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"Making dependency list for source file %s\n",
|
||||||
|
sourceFile.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string::size_type basePos = sourceFile.rfind('/');
|
||||||
|
if (basePos == std::string::npos)
|
||||||
|
{
|
||||||
|
basePos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
basePos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type dotPos = sourceFile.rfind('.');
|
||||||
|
if
|
||||||
|
(
|
||||||
|
dotPos == std::string::npos
|
||||||
|
|| dotPos == sourceFile.size()-1
|
||||||
|
|| dotPos <= basePos
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"Cannot find extension in source file name %s\n",
|
||||||
|
sourceFile.c_str()
|
||||||
|
);
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string depFile = sourceFile.substr(0, dotPos);
|
||||||
|
depFile += ".dep";
|
||||||
|
|
||||||
|
const std::string sourceExt = sourceFile.substr(dotPos);
|
||||||
|
if (sourceExt == ".java")
|
||||||
|
{
|
||||||
|
// import directories to ignore
|
||||||
|
wmake::Parser::ignoreDir("java.*");
|
||||||
|
wmake::Parser::ignoreDir("org.*");
|
||||||
|
wmake::Parser::ignoreDir("com.*");
|
||||||
|
wmake::Parser::ignoreDir("sunw.*");
|
||||||
|
wmake::Parser::ignoreDir("sun.*");
|
||||||
|
wmake::Parser::ignoreDir("launcher.*");
|
||||||
|
|
||||||
|
std::cout
|
||||||
|
<< "$(CLASSES_DIR)/"
|
||||||
|
<< sourceFile.substr(basePos, dotPos - basePos) << ".class: "
|
||||||
|
<< depFile << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout
|
||||||
|
<< "$(OBJECTS_DIR)/"
|
||||||
|
<< sourceFile.substr(basePos, dotPos - basePos) << ".o: "
|
||||||
|
<< depFile << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wmake::Parser::sourceFile = sourceFile;
|
||||||
|
wmake::Parser::depFile = depFile;
|
||||||
|
|
||||||
|
wmake::Parser::includeFile(sourceFile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
497
wmake/src/wmkdependParser.atg
Normal file
497
wmake/src/wmkdependParser.atg
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Attributed Grammar for Coco/R (-*- C++ -*- version)
|
||||||
|
compile with:
|
||||||
|
coco-cpp wmkdependParser.atg
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
[copy]
|
||||||
|
/*---------------------------------*- C++ -*---------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2010-2010 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
|
||||||
|
|
||||||
|
@file wmkdependParser.atg
|
||||||
|
|
||||||
|
Description
|
||||||
|
An attributed Coco/R grammar to parse C/C++, Fortran and Java files
|
||||||
|
for include and import statements.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
generated
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
[/copy]
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
//! @brief A simple HashTable implementation
|
||||||
|
/**
|
||||||
|
* @note This hash table is only vaguely STL-like. In accordance with
|
||||||
|
* its present purpose, this hash table only supports a constIterator
|
||||||
|
* and no deletions. For simplicity, the constIterator increment is
|
||||||
|
* simply via a next() method. Instead of comparing to an end value,
|
||||||
|
* the constIterator valid() method is used.
|
||||||
|
* For example,
|
||||||
|
* @code
|
||||||
|
* for
|
||||||
|
* (
|
||||||
|
* HashTable<foo>::constIterator iter = myHash.begin();
|
||||||
|
* iter.valid();
|
||||||
|
* iter.next()
|
||||||
|
* )
|
||||||
|
* {
|
||||||
|
* std::cerr<< "key: " << iter.key() << "\n";
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class StringHashSet
|
||||||
|
{
|
||||||
|
//! An entry within the HashTable
|
||||||
|
struct hashedEntry
|
||||||
|
{
|
||||||
|
const std::string key_; //<! The lookup key
|
||||||
|
hashedEntry *next_; //<! Pointer to next hashedEntry in sub-list
|
||||||
|
|
||||||
|
hashedEntry(const std::string& key, hashedEntry *next=0)
|
||||||
|
:
|
||||||
|
key_(key), next_(next)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int size_; //<! fixed HashTable size
|
||||||
|
hashedEntry** table_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Construct with a default size
|
||||||
|
StringHashSet(int size = 500)
|
||||||
|
:
|
||||||
|
size_(size),
|
||||||
|
table_(new hashedEntry*[size_])
|
||||||
|
{
|
||||||
|
memset(table_, 0, size_ * sizeof(hashedEntry*));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
~StringHashSet()
|
||||||
|
{
|
||||||
|
for (int hashIdx = 0; hashIdx < size_; ++hashIdx)
|
||||||
|
{
|
||||||
|
hashedEntry* ep = table_[hashIdx];
|
||||||
|
while (ep)
|
||||||
|
{
|
||||||
|
hashedEntry* del = ep;
|
||||||
|
ep = ep->next_;
|
||||||
|
delete del;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] table_;
|
||||||
|
table_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return hash index for lookup name in hash table
|
||||||
|
bool hashKeyIndex(const std::string& name) const
|
||||||
|
{
|
||||||
|
int hashIdx = 0;
|
||||||
|
|
||||||
|
// calculate hash index
|
||||||
|
for
|
||||||
|
(
|
||||||
|
std::string::const_iterator iter = name.begin();
|
||||||
|
iter != name.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
hashIdx = hashIdx << 1 ^ *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashIdx < 0)
|
||||||
|
{
|
||||||
|
hashIdx = -hashIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashIdx % size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Return true if name is found in hash table
|
||||||
|
bool found(const std::string& name) const
|
||||||
|
{
|
||||||
|
const int hashIdx = hashKeyIndex(name);
|
||||||
|
|
||||||
|
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||||
|
{
|
||||||
|
if (name == ep->key_)
|
||||||
|
{
|
||||||
|
// found
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Return true if name is found in hash table, insert if not found
|
||||||
|
bool foundOrInsert(const std::string& name)
|
||||||
|
{
|
||||||
|
const int hashIdx = hashKeyIndex(name);
|
||||||
|
|
||||||
|
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||||
|
{
|
||||||
|
if (name == ep->key_)
|
||||||
|
{
|
||||||
|
// found - return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found - insert it
|
||||||
|
table_[hashIdx] = new hashedEntry(name, table_[hashIdx]);
|
||||||
|
|
||||||
|
// entry not found (but was added) - return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
COMPILER wmkdepend
|
||||||
|
// grammar pragmas:
|
||||||
|
$namespace=wmake
|
||||||
|
$prefix=wmkdepend
|
||||||
|
$define=FORCE_UTF8
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! Hash of files already visited
|
||||||
|
static StringHashSet visitedFiles_;
|
||||||
|
|
||||||
|
//! Hash of (java) directories already visited
|
||||||
|
static StringHashSet visitedDirs_;
|
||||||
|
|
||||||
|
//! Replace all '.' with '/'
|
||||||
|
static void dotToSlash(std::string& name);
|
||||||
|
|
||||||
|
//! Import (java) directories
|
||||||
|
static void importDir(const std::string& dirName);
|
||||||
|
|
||||||
|
//! Import (java) file
|
||||||
|
static void importFile(const std::string& name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Include directories to search
|
||||||
|
static std::list<std::string> includeDirs;
|
||||||
|
|
||||||
|
//! The name of the top-level source file
|
||||||
|
static std::string sourceFile;
|
||||||
|
|
||||||
|
//! The name of the top-level dep file
|
||||||
|
static std::string depFile;
|
||||||
|
|
||||||
|
//! Add directory to list of visited dirs, thus effectively ignoring it
|
||||||
|
static void ignoreDir(const std::string& name);
|
||||||
|
|
||||||
|
//! Include file
|
||||||
|
static void includeFile(const std::string& name);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
[code]
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
StringHashSet Parser::visitedFiles_;
|
||||||
|
StringHashSet Parser::visitedDirs_;
|
||||||
|
|
||||||
|
std::list<std::string> Parser::includeDirs;
|
||||||
|
std::string Parser::sourceFile;
|
||||||
|
std::string Parser::depFile;
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::dotToSlash(std::string& name)
|
||||||
|
{
|
||||||
|
std::string::size_type start = 0;
|
||||||
|
|
||||||
|
while ((start = name.find('.', start)) != std::string::npos)
|
||||||
|
{
|
||||||
|
name.replace(start, 1, 1, '/');
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::ignoreDir(const std::string& name)
|
||||||
|
{
|
||||||
|
visitedDirs_.foundOrInsert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::includeFile(const std::string& name)
|
||||||
|
{
|
||||||
|
if (visitedFiles_.foundOrInsert(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use stdio and buffering within Coco/R -- (faster)
|
||||||
|
FILE *fh = fopen(name.c_str(), "r");
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
std::cout << depFile << ": " << name << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for
|
||||||
|
(
|
||||||
|
std::list<std::string>::const_iterator iter = includeDirs.begin();
|
||||||
|
iter != includeDirs.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const std::string pathName = *iter + name;
|
||||||
|
|
||||||
|
fh = fopen(pathName.c_str(), "r");
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
std::cout << depFile << ": " << pathName << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
Scanner scanner(fh);
|
||||||
|
Parser parser(&scanner);
|
||||||
|
|
||||||
|
parser.Parse();
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"could not open file %s for source file %s\n",
|
||||||
|
name.c_str(), sourceFile.c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::importFile(const std::string& name)
|
||||||
|
{
|
||||||
|
// check if a globbed form was already visited
|
||||||
|
std::string::size_type dotPos = name.find('.');
|
||||||
|
if (dotPos != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string dirGlob = name.substr(0, dotPos);
|
||||||
|
dirGlob += ".*";
|
||||||
|
|
||||||
|
if (visitedDirs_.found(dirGlob))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string javaFileName = name;
|
||||||
|
|
||||||
|
dotToSlash(javaFileName);
|
||||||
|
javaFileName += ".java";
|
||||||
|
|
||||||
|
includeFile(javaFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::importDir(const std::string& name)
|
||||||
|
{
|
||||||
|
if (visitedDirs_.foundOrInsert(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dirName = name;
|
||||||
|
dotToSlash(dirName);
|
||||||
|
|
||||||
|
DIR *source = opendir(dirName.c_str());
|
||||||
|
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
struct dirent *list;
|
||||||
|
|
||||||
|
// Read and parse all the entries in the directory
|
||||||
|
while ((list = readdir(source)) != NULL)
|
||||||
|
{
|
||||||
|
const char* ext = strstr(list->d_name, ".java");
|
||||||
|
|
||||||
|
// avoid matching on something like '.java~'
|
||||||
|
if (ext && strlen(ext) == 5)
|
||||||
|
{
|
||||||
|
std::string pathName = dirName + list->d_name;
|
||||||
|
includeFile(pathName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"could not open directory %s\n",
|
||||||
|
dirName.c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
CHARACTERS
|
||||||
|
letter = 'A'..'Z' + 'a'..'z' + '_'.
|
||||||
|
digit = "0123456789".
|
||||||
|
cr = '\r'.
|
||||||
|
lf = '\n'.
|
||||||
|
tab = '\t'.
|
||||||
|
stringCh = ANY - '"' - '\\' - cr - lf.
|
||||||
|
printable = '\u0020' .. '\u007e'.
|
||||||
|
java_letter = letter + '$'.
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * TOKENS * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
TOKENS
|
||||||
|
|
||||||
|
// string
|
||||||
|
string =
|
||||||
|
'"' { stringCh | '\\' printable } '"'.
|
||||||
|
|
||||||
|
// single-quoted string (eg, Fortran)
|
||||||
|
sqstring =
|
||||||
|
'\'' { stringCh | '\\' printable } '\''.
|
||||||
|
|
||||||
|
// for java import
|
||||||
|
package_name =
|
||||||
|
java_letter { java_letter | digit }
|
||||||
|
{ '.' java_letter { java_letter | digit } } .
|
||||||
|
|
||||||
|
// for java import
|
||||||
|
package_dir =
|
||||||
|
java_letter { java_letter | digit }
|
||||||
|
{ '.' java_letter { java_letter | digit } } ".*" .
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * PRAGMAS / COMMENTS / IGNORE * * * * * * * * * * * //
|
||||||
|
|
||||||
|
COMMENTS FROM "/*" TO "*/" NESTED
|
||||||
|
COMMENTS FROM "//" TO lf
|
||||||
|
|
||||||
|
IGNORE tab
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * PRODUCTIONS * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
PRODUCTIONS
|
||||||
|
|
||||||
|
wmkdepend
|
||||||
|
=
|
||||||
|
{
|
||||||
|
// C/C++-style includes
|
||||||
|
'#'
|
||||||
|
[
|
||||||
|
"include"
|
||||||
|
[
|
||||||
|
string (.
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
includeFile(t->toStringUTF8(1, t->length()-2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
includeFile(t->toString(1, t->length()-2));
|
||||||
|
}
|
||||||
|
.)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ ANY { ANY } ] '\n' // skip trailing junk
|
||||||
|
|
||||||
|
// Fortran-style includes
|
||||||
|
| "include"
|
||||||
|
[
|
||||||
|
sqstring (.
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
includeFile(t->toStringUTF8(1, t->length()-2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
includeFile(t->toString(1, t->length()-2));
|
||||||
|
}
|
||||||
|
.)
|
||||||
|
]
|
||||||
|
[ ANY { ANY } ] '\n' // skip trailing junk
|
||||||
|
|
||||||
|
// Java imports
|
||||||
|
| "import"
|
||||||
|
(
|
||||||
|
package_dir (.
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
importDir(t->toStringUTF8());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
importDir(t->toString());
|
||||||
|
}
|
||||||
|
.)
|
||||||
|
| package_name (.
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
importFile(t->toStringUTF8());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
importFile(t->toString());
|
||||||
|
}
|
||||||
|
.)
|
||||||
|
)
|
||||||
|
';'
|
||||||
|
[ ANY { ANY } ] '\n' // skip trailing junk
|
||||||
|
|
||||||
|
| [ ANY { ANY } ] '\n' // skip any other lines
|
||||||
|
|
||||||
|
}
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
END wmkdepend.
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
575
wmake/src/wmkdependParser.cpp
Normal file
575
wmake/src/wmkdependParser.cpp
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
/*---------------------------------*- C++ -*---------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2010-2010 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
|
||||||
|
|
||||||
|
@file wmkdependParser.atg
|
||||||
|
|
||||||
|
Description
|
||||||
|
An attributed Coco/R grammar to parse C/C++, Fortran and Java files
|
||||||
|
for include and import statements.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
generated
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
// This file was generated with Coco/R C++ (7 Feb 2010)
|
||||||
|
// http://www.ssw.uni-linz.ac.at/coco/
|
||||||
|
// with these defines:
|
||||||
|
// - FORCE_UTF8
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "wmkdependParser.h"
|
||||||
|
|
||||||
|
namespace wmake {
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
StringHashSet Parser::visitedFiles_;
|
||||||
|
StringHashSet Parser::visitedDirs_;
|
||||||
|
|
||||||
|
std::list<std::string> Parser::includeDirs;
|
||||||
|
std::string Parser::sourceFile;
|
||||||
|
std::string Parser::depFile;
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::dotToSlash(std::string& name)
|
||||||
|
{
|
||||||
|
std::string::size_type start = 0;
|
||||||
|
|
||||||
|
while ((start = name.find('.', start)) != std::string::npos)
|
||||||
|
{
|
||||||
|
name.replace(start, 1, 1, '/');
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::ignoreDir(const std::string& name)
|
||||||
|
{
|
||||||
|
visitedDirs_.foundOrInsert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::includeFile(const std::string& name)
|
||||||
|
{
|
||||||
|
if (visitedFiles_.foundOrInsert(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use stdio and buffering within Coco/R -- (faster)
|
||||||
|
FILE *fh = fopen(name.c_str(), "r");
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
std::cout << depFile << ": " << name << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for
|
||||||
|
(
|
||||||
|
std::list<std::string>::const_iterator iter = includeDirs.begin();
|
||||||
|
iter != includeDirs.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const std::string pathName = *iter + name;
|
||||||
|
|
||||||
|
fh = fopen(pathName.c_str(), "r");
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
std::cout << depFile << ": " << pathName << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fh)
|
||||||
|
{
|
||||||
|
Scanner scanner(fh);
|
||||||
|
Parser parser(&scanner);
|
||||||
|
|
||||||
|
parser.Parse();
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"could not open file %s for source file %s\n",
|
||||||
|
name.c_str(), sourceFile.c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::importFile(const std::string& name)
|
||||||
|
{
|
||||||
|
// check if a globbed form was already visited
|
||||||
|
std::string::size_type dotPos = name.find('.');
|
||||||
|
if (dotPos != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string dirGlob = name.substr(0, dotPos);
|
||||||
|
dirGlob += ".*";
|
||||||
|
|
||||||
|
if (visitedDirs_.found(dirGlob))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string javaFileName = name;
|
||||||
|
|
||||||
|
dotToSlash(javaFileName);
|
||||||
|
javaFileName += ".java";
|
||||||
|
|
||||||
|
includeFile(javaFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::importDir(const std::string& name)
|
||||||
|
{
|
||||||
|
if (visitedDirs_.foundOrInsert(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dirName = name;
|
||||||
|
dotToSlash(dirName);
|
||||||
|
|
||||||
|
DIR *source = opendir(dirName.c_str());
|
||||||
|
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
struct dirent *list;
|
||||||
|
|
||||||
|
// Read and parse all the entries in the directory
|
||||||
|
while ((list = readdir(source)) != NULL)
|
||||||
|
{
|
||||||
|
const char* ext = strstr(list->d_name, ".java");
|
||||||
|
|
||||||
|
// avoid matching on something like '.java~'
|
||||||
|
if (ext && strlen(ext) == 5)
|
||||||
|
{
|
||||||
|
std::string pathName = dirName + list->d_name;
|
||||||
|
includeFile(pathName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fwprintf
|
||||||
|
(
|
||||||
|
stderr,
|
||||||
|
L"could not open directory %s\n",
|
||||||
|
dirName.c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//! @cond fileScope
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create by copying str - only used locally
|
||||||
|
inline static wchar_t* coco_string_create(const wchar_t* str)
|
||||||
|
{
|
||||||
|
const int len = wcslen(str);
|
||||||
|
wchar_t* dst = new wchar_t[len + 1];
|
||||||
|
wcsncpy(dst, str, len);
|
||||||
|
dst[len] = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Free storage and nullify the argument
|
||||||
|
inline static void coco_string_delete(wchar_t* &str)
|
||||||
|
{
|
||||||
|
delete[] str;
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//! @endcond fileScope
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parser Implementation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Parser::SynErr(int n)
|
||||||
|
{
|
||||||
|
if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
|
||||||
|
errDist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::SemErr(const std::wstring& msg)
|
||||||
|
{
|
||||||
|
if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
|
||||||
|
errDist = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Parser::isUTF8() const
|
||||||
|
{
|
||||||
|
return scanner && scanner->buffer && scanner->buffer->isUTF8();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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::wmkdepend()
|
||||||
|
{
|
||||||
|
while (StartOf(1)) {
|
||||||
|
if (la->kind == 5) {
|
||||||
|
Get();
|
||||||
|
if (la->kind == 6) {
|
||||||
|
Get();
|
||||||
|
if (la->kind == 1) {
|
||||||
|
Get();
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
includeFile(t->toStringUTF8(1, t->length()-2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
includeFile(t->toString(1, t->length()-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StartOf(2)) {
|
||||||
|
Get();
|
||||||
|
while (StartOf(3)) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(7);
|
||||||
|
} else if (la->kind == 6) {
|
||||||
|
Get();
|
||||||
|
if (la->kind == 2) {
|
||||||
|
Get();
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
includeFile(t->toStringUTF8(1, t->length()-2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
includeFile(t->toString(1, t->length()-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (StartOf(4)) {
|
||||||
|
Get();
|
||||||
|
while (StartOf(3)) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(7);
|
||||||
|
} else if (la->kind == 8) {
|
||||||
|
Get();
|
||||||
|
if (la->kind == 4) {
|
||||||
|
Get();
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
importDir(t->toStringUTF8());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
importDir(t->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (la->kind == 3) {
|
||||||
|
Get();
|
||||||
|
if (isUTF8())
|
||||||
|
{
|
||||||
|
importFile(t->toStringUTF8());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
importFile(t->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else SynErr(11);
|
||||||
|
Expect(9);
|
||||||
|
if (StartOf(3)) {
|
||||||
|
Get();
|
||||||
|
while (StartOf(3)) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(7);
|
||||||
|
} else {
|
||||||
|
if (StartOf(5)) {
|
||||||
|
Get();
|
||||||
|
while (StartOf(3)) {
|
||||||
|
Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Parser::Parse()
|
||||||
|
{
|
||||||
|
t = NULL;
|
||||||
|
// might call Parse() twice
|
||||||
|
if (dummyToken) {
|
||||||
|
coco_string_delete(dummyToken->val);
|
||||||
|
delete dummyToken;
|
||||||
|
}
|
||||||
|
dummyToken = new Token(coco_string_create(L"Dummy Token"));
|
||||||
|
la = dummyToken;
|
||||||
|
Get();
|
||||||
|
wmkdepend();
|
||||||
|
Expect(0); // expect end-of-file automatically added
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Parser::Parser(Scanner* scan, Errors* err)
|
||||||
|
:
|
||||||
|
dummyToken(NULL),
|
||||||
|
deleteErrorsDestruct_(!err),
|
||||||
|
errDist(minErrDist),
|
||||||
|
scanner(scan),
|
||||||
|
errors(err),
|
||||||
|
t(NULL),
|
||||||
|
la(NULL)
|
||||||
|
{
|
||||||
|
if (!errors) // add in default error handling
|
||||||
|
{
|
||||||
|
errors = new Errors();
|
||||||
|
}
|
||||||
|
// user-defined initializations:
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Parser::StartOf(int s)
|
||||||
|
{
|
||||||
|
const bool T = true;
|
||||||
|
const bool x = false;
|
||||||
|
|
||||||
|
static const bool set[6][12] =
|
||||||
|
{
|
||||||
|
{T,x,x,x, x,x,x,x, x,x,x,x},
|
||||||
|
{x,T,T,T, T,T,T,T, T,T,T,x},
|
||||||
|
{x,x,T,T, T,T,x,x, T,T,T,x},
|
||||||
|
{x,T,T,T, T,T,T,x, T,T,T,x},
|
||||||
|
{x,T,x,T, T,T,T,x, T,T,T,x},
|
||||||
|
{x,T,T,T, T,x,x,x, x,T,T,x}
|
||||||
|
};
|
||||||
|
|
||||||
|
return set[s][la->kind];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Parser::~Parser()
|
||||||
|
{
|
||||||
|
if (deleteErrorsDestruct_) { delete errors; } // delete default error handling
|
||||||
|
if (dummyToken) {
|
||||||
|
coco_string_delete(dummyToken->val);
|
||||||
|
delete dummyToken;
|
||||||
|
}
|
||||||
|
// user-defined destruction:
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Errors Implementation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Errors::Errors()
|
||||||
|
:
|
||||||
|
count(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Errors::~Errors()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::clear()
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::wstring Errors::strerror(int n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 0: return L"EOF expected"; break;
|
||||||
|
case 1: return L"string expected"; break;
|
||||||
|
case 2: return L"sqstring expected"; break;
|
||||||
|
case 3: return L"package_name expected"; break;
|
||||||
|
case 4: return L"package_dir expected"; break;
|
||||||
|
case 5: return L"\"#\" expected"; break;
|
||||||
|
case 6: return L"\"include\" expected"; break;
|
||||||
|
case 7: return L"\"\\n\" expected"; break;
|
||||||
|
case 8: return L"\"import\" expected"; break;
|
||||||
|
case 9: return L"\";\" expected"; break;
|
||||||
|
case 10: return L"??? expected"; break;
|
||||||
|
case 11: return L"invalid wmkdepend"; break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// std::wostringstream buf; (this typedef might be missing)
|
||||||
|
std::basic_ostringstream<wchar_t> buf;
|
||||||
|
buf << "error " << n;
|
||||||
|
return buf.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Warning(const std::wstring& msg)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"%ls\n", msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Warning(int line, int col, const std::wstring& msg)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"-- line %d col %d: %ls\n", line, col, msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Error(int line, int col, const std::wstring& msg)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"-- line %d col %d: %ls\n", line, col, msg.c_str());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::SynErr(int line, int col, int n)
|
||||||
|
{
|
||||||
|
this->Error(line, col, this->strerror(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Errors::Exception(const std::wstring& msg)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"%ls", msg.c_str());
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
310
wmake/src/wmkdependParser.h
Normal file
310
wmake/src/wmkdependParser.h
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*---------------------------------*- C++ -*---------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2010-2010 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
|
||||||
|
|
||||||
|
@file wmkdependParser.atg
|
||||||
|
|
||||||
|
Description
|
||||||
|
An attributed Coco/R grammar to parse C/C++, Fortran and Java files
|
||||||
|
for include and import statements.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
generated
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
// This file was generated with Coco/R C++ (7 Feb 2010)
|
||||||
|
// http://www.ssw.uni-linz.ac.at/coco/
|
||||||
|
// with these defines:
|
||||||
|
// - FORCE_UTF8
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COCO_wmkdependPARSER_H__
|
||||||
|
#define COCO_wmkdependPARSER_H__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
//! @brief A simple HashTable implementation
|
||||||
|
/**
|
||||||
|
* @note This hash table is only vaguely STL-like. In accordance with
|
||||||
|
* its present purpose, this hash table only supports a constIterator
|
||||||
|
* and no deletions. For simplicity, the constIterator increment is
|
||||||
|
* simply via a next() method. Instead of comparing to an end value,
|
||||||
|
* the constIterator valid() method is used.
|
||||||
|
* For example,
|
||||||
|
* @code
|
||||||
|
* for
|
||||||
|
* (
|
||||||
|
* HashTable<foo>::constIterator iter = myHash.begin();
|
||||||
|
* iter.valid();
|
||||||
|
* iter.next()
|
||||||
|
* )
|
||||||
|
* {
|
||||||
|
* std::cerr<< "key: " << iter.key() << "\n";
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class StringHashSet
|
||||||
|
{
|
||||||
|
//! An entry within the HashTable
|
||||||
|
struct hashedEntry
|
||||||
|
{
|
||||||
|
const std::string key_; //<! The lookup key
|
||||||
|
hashedEntry *next_; //<! Pointer to next hashedEntry in sub-list
|
||||||
|
|
||||||
|
hashedEntry(const std::string& key, hashedEntry *next=0)
|
||||||
|
:
|
||||||
|
key_(key), next_(next)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int size_; //<! fixed HashTable size
|
||||||
|
hashedEntry** table_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Construct with a default size
|
||||||
|
StringHashSet(int size = 500)
|
||||||
|
:
|
||||||
|
size_(size),
|
||||||
|
table_(new hashedEntry*[size_])
|
||||||
|
{
|
||||||
|
memset(table_, 0, size_ * sizeof(hashedEntry*));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
~StringHashSet()
|
||||||
|
{
|
||||||
|
for (int hashIdx = 0; hashIdx < size_; ++hashIdx)
|
||||||
|
{
|
||||||
|
hashedEntry* ep = table_[hashIdx];
|
||||||
|
while (ep)
|
||||||
|
{
|
||||||
|
hashedEntry* del = ep;
|
||||||
|
ep = ep->next_;
|
||||||
|
delete del;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] table_;
|
||||||
|
table_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return hash index for lookup name in hash table
|
||||||
|
bool hashKeyIndex(const std::string& name) const
|
||||||
|
{
|
||||||
|
int hashIdx = 0;
|
||||||
|
|
||||||
|
// calculate hash index
|
||||||
|
for
|
||||||
|
(
|
||||||
|
std::string::const_iterator iter = name.begin();
|
||||||
|
iter != name.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
hashIdx = hashIdx << 1 ^ *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashIdx < 0)
|
||||||
|
{
|
||||||
|
hashIdx = -hashIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashIdx % size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Return true if name is found in hash table
|
||||||
|
bool found(const std::string& name) const
|
||||||
|
{
|
||||||
|
const int hashIdx = hashKeyIndex(name);
|
||||||
|
|
||||||
|
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||||
|
{
|
||||||
|
if (name == ep->key_)
|
||||||
|
{
|
||||||
|
// found
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Return true if name is found in hash table, insert if not found
|
||||||
|
bool foundOrInsert(const std::string& name)
|
||||||
|
{
|
||||||
|
const int hashIdx = hashKeyIndex(name);
|
||||||
|
|
||||||
|
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
|
||||||
|
{
|
||||||
|
if (name == ep->key_)
|
||||||
|
{
|
||||||
|
// found - return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found - insert it
|
||||||
|
table_[hashIdx] = new hashedEntry(name, table_[hashIdx]);
|
||||||
|
|
||||||
|
// entry not found (but was added) - return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "wmkdependScanner.h"
|
||||||
|
|
||||||
|
namespace wmake {
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Errors Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! Parser error handing
|
||||||
|
class Errors
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int count; //!< The number of errors detected
|
||||||
|
|
||||||
|
//! Return a string describing the given error code.
|
||||||
|
static std::wstring 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 std::wstring& msg);
|
||||||
|
//! Handle a general warning 'msg'
|
||||||
|
virtual void Warning(int line, int col, const std::wstring& msg);
|
||||||
|
//! Handle general error 'msg' (eg, a semantic error)
|
||||||
|
virtual void Error(int line, int col, const std::wstring& 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 std::wstring& msg);
|
||||||
|
|
||||||
|
}; // Errors
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Parser Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! A Coco/R Parser
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
_EOF=0,
|
||||||
|
_string=1,
|
||||||
|
_sqstring=2,
|
||||||
|
_package_name=3,
|
||||||
|
_package_dir=4,
|
||||||
|
maxT = 10 //<! max term (w/o pragmas)
|
||||||
|
};
|
||||||
|
static const int minErrDist = 2; //!< min. distance before reporting errors
|
||||||
|
|
||||||
|
Token *dummyToken;
|
||||||
|
bool deleteErrorsDestruct_; //!< delete the 'errors' member in destructor
|
||||||
|
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
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! Hash of files already visited
|
||||||
|
static StringHashSet visitedFiles_;
|
||||||
|
|
||||||
|
//! Hash of (java) directories already visited
|
||||||
|
static StringHashSet visitedDirs_;
|
||||||
|
|
||||||
|
//! Replace all '.' with '/'
|
||||||
|
static void dotToSlash(std::string& name);
|
||||||
|
|
||||||
|
//! Import (java) directories
|
||||||
|
static void importDir(const std::string& dirName);
|
||||||
|
|
||||||
|
//! Import (java) file
|
||||||
|
static void importFile(const std::string& name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Include directories to search
|
||||||
|
static std::list<std::string> includeDirs;
|
||||||
|
|
||||||
|
//! The name of the top-level source file
|
||||||
|
static std::string sourceFile;
|
||||||
|
|
||||||
|
//! The name of the top-level dep file
|
||||||
|
static std::string depFile;
|
||||||
|
|
||||||
|
//! Add directory to list of visited dirs, thus effectively ignoring it
|
||||||
|
static void ignoreDir(const std::string& name);
|
||||||
|
|
||||||
|
//! Include file
|
||||||
|
static void includeFile(const std::string& name);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//! 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();
|
||||||
|
void Parse(); //!< Execute the parse operation
|
||||||
|
void SemErr(const std::wstring& msg); //!< Handle semantic error
|
||||||
|
bool isUTF8() const; //!< Return true if scanner buffer is UTF8
|
||||||
|
|
||||||
|
void wmkdepend();
|
||||||
|
|
||||||
|
}; // end Parser
|
||||||
|
|
||||||
|
} // End namespace
|
||||||
|
|
||||||
|
#endif // COCO_wmkdependPARSER_H__
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
1022
wmake/src/wmkdependScanner.cpp
Normal file
1022
wmake/src/wmkdependScanner.cpp
Normal file
File diff suppressed because it is too large
Load Diff
477
wmake/src/wmkdependScanner.h
Normal file
477
wmake/src/wmkdependScanner.h
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
/*---------------------------------*- C++ -*---------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2010-2010 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
|
||||||
|
|
||||||
|
@file wmkdependParser.atg
|
||||||
|
|
||||||
|
Description
|
||||||
|
An attributed Coco/R grammar to parse C/C++, Fortran and Java files
|
||||||
|
for include and import statements.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
generated
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
// This file was generated with Coco/R C++ (7 Feb 2010)
|
||||||
|
// http://www.ssw.uni-linz.ac.at/coco/
|
||||||
|
// with these defines:
|
||||||
|
// - FORCE_UTF8
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COCO_wmkdependSCANNER_H__
|
||||||
|
#define COCO_wmkdependSCANNER_H__
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace wmake {
|
||||||
|
|
||||||
|
// * * * * * * * * * * * Miscellaneous String Routines * * * * * * * * * * * //
|
||||||
|
|
||||||
|
//! Simple lower-case string transformation
|
||||||
|
template<class StringT>
|
||||||
|
inline void coco_string_toLower(StringT& str)
|
||||||
|
{
|
||||||
|
for
|
||||||
|
(
|
||||||
|
typename StringT::iterator iter = str.begin();
|
||||||
|
iter != str.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (*iter >= 'A' && *iter <= 'Z')
|
||||||
|
{
|
||||||
|
*iter += ('a' - 'A'); // lower-case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Simple string hashing function
|
||||||
|
template<class StringT>
|
||||||
|
inline int coco_string_hash(const StringT& str)
|
||||||
|
{
|
||||||
|
int h = 0;
|
||||||
|
for
|
||||||
|
(
|
||||||
|
typename StringT::const_iterator iter = str.begin();
|
||||||
|
iter != str.end();
|
||||||
|
++iter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
h = (h * 7) ^ *iter;
|
||||||
|
}
|
||||||
|
return h < 0 ? -h : h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// String conversions
|
||||||
|
// ~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
//! Convert wide string to double
|
||||||
|
inline double coco_string_toDouble(const wchar_t* str)
|
||||||
|
{
|
||||||
|
return str ? wcstod(str, NULL) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Convert wide string to long
|
||||||
|
inline long coco_string_toLong(const wchar_t* str)
|
||||||
|
{
|
||||||
|
return str ? wcstol(str, NULL, 10) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! A byte string (restricted to 8bit values) by copying str
|
||||||
|
std::string coco_stdString(const wchar_t* str);
|
||||||
|
|
||||||
|
//! A byte string (restricted to 8bit values) by copying str,
|
||||||
|
//! up to length characters long
|
||||||
|
std::string coco_stdString(const wchar_t* str, unsigned length);
|
||||||
|
|
||||||
|
//! A byte substring (restricted to 8bit values) of str,
|
||||||
|
//! starting at index and length characters long
|
||||||
|
std::string coco_stdString(const wchar_t* str, unsigned index, unsigned length);
|
||||||
|
|
||||||
|
//! A UTF8 byte string by copying str
|
||||||
|
std::string coco_stdStringUTF8(const wchar_t* str);
|
||||||
|
|
||||||
|
//! A UTF8 byte string by copying str, up to length characters long
|
||||||
|
std::string coco_stdStringUTF8(const wchar_t* str, unsigned length);
|
||||||
|
|
||||||
|
//! A UTF8 byte substring, starting at index and length characters long
|
||||||
|
std::string coco_stdStringUTF8(const wchar_t* str, unsigned index, unsigned length);
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * End of String Routines * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Token Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
/*!
|
||||||
|
* @brief Scanner Token
|
||||||
|
*
|
||||||
|
* @note since each Token is allocated by the internal heap mechanism,
|
||||||
|
* the destructor does not clean up the val member.
|
||||||
|
*/
|
||||||
|
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 (normally allocated from the internal heap)
|
||||||
|
Token *next; //!< Peek tokens are kept in linked list
|
||||||
|
|
||||||
|
int length() const; //!< The length of val, or 0 if val is NULL
|
||||||
|
|
||||||
|
//! Construct null Token, optionally with pointer to a string value
|
||||||
|
Token(wchar_t* value = 0);
|
||||||
|
~Token(); //!< Destructor - does not cleanup val member
|
||||||
|
|
||||||
|
//! Token val as byte string (restricted to 8bit values)
|
||||||
|
inline std::string toString() const
|
||||||
|
{
|
||||||
|
return coco_stdString(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Token val as byte string (restricted to 8bit values), up to length characters long
|
||||||
|
inline std::string toString(unsigned length) const
|
||||||
|
{
|
||||||
|
return coco_stdString(val, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Token val as byte string (restricted to 8bit values), starting at index and length characters long
|
||||||
|
inline std::string toString(unsigned index, unsigned length) const
|
||||||
|
{
|
||||||
|
return coco_stdString(val, index, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Token val as UTF8 byte string
|
||||||
|
inline std::string toStringUTF8() const
|
||||||
|
{
|
||||||
|
return coco_stdStringUTF8(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Token val as UTF8 byte string, up to length characters long
|
||||||
|
inline std::string toStringUTF8(unsigned length) const
|
||||||
|
{
|
||||||
|
return coco_stdStringUTF8(val, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Token val as UTF8 byte substring, starting at index and length characters long
|
||||||
|
inline std::string toStringUTF8(unsigned index, unsigned length) const
|
||||||
|
{
|
||||||
|
return coco_stdStringUTF8(this->val, index, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Buffer Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
/*!
|
||||||
|
* @brief Scanner Buffer Token
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
unsigned char *buf; //!< input buffer
|
||||||
|
int bufCapacity; //!< capacity of buf
|
||||||
|
int bufLen; //!< length of buffer
|
||||||
|
int bufPos; //!< current position in buffer
|
||||||
|
int bufStart; //!< position of first byte in buffer relative to input stream
|
||||||
|
int fileLen; //!< length of input stream (may change if the stream is no file)
|
||||||
|
FILE* cStream; //!< input stdio stream (normally seekable)
|
||||||
|
std::istream* stdStream; //!< STL std stream (seekable)
|
||||||
|
bool isUserStream_; //!< was the stream opened by the user?
|
||||||
|
|
||||||
|
int ReadNextStreamChunk();
|
||||||
|
bool CanSeek() const; //!< true if stream can be seeked otherwise false
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Buffer(Buffer*); //!< for the UTF8Buffer
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! max unicode characters is 0xFFFF (16bit storage)
|
||||||
|
static const int MaxChar = 65535;
|
||||||
|
static const int EoF = MaxChar + 1;
|
||||||
|
|
||||||
|
//! Copy buffer contents from constant character string
|
||||||
|
Buffer(const char* chars, int len);
|
||||||
|
|
||||||
|
//! Copy buffer contents from constant character string
|
||||||
|
Buffer(const unsigned char* chars, int len);
|
||||||
|
|
||||||
|
//! @brief Attach buffer to a stdio stream.
|
||||||
|
//! User streams are not closed in the destructor
|
||||||
|
Buffer(FILE*, bool isUserStream = true);
|
||||||
|
|
||||||
|
//! @brief Attach buffer to an STL standard stream
|
||||||
|
//! User streams are not closed in the destructor
|
||||||
|
explicit Buffer(std::istream*, bool isUserStream = true);
|
||||||
|
|
||||||
|
//! Close stream (but not user streams) and free buf (if any)
|
||||||
|
virtual ~Buffer();
|
||||||
|
|
||||||
|
virtual void Close(); //!< Close stream (but not user streams)
|
||||||
|
virtual int Read(); //!< Get character from stream or buffer
|
||||||
|
virtual int Peek(); //!< Peek character from stream or buffer
|
||||||
|
|
||||||
|
virtual int GetPos() const;
|
||||||
|
virtual void SetPos(int value);
|
||||||
|
virtual bool isUTF8() const; //!< Return false - buffer is not UTF8
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class UTF8Buffer Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! A Scanner Buffer variant that decodes UTF-8 characters into 16bit unicode
|
||||||
|
class UTF8Buffer : public Buffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UTF8Buffer(Buffer* b) : Buffer(b) {}
|
||||||
|
virtual int Read();
|
||||||
|
virtual bool isUTF8() const; //!< Return true - buffer is UTF8
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class StartStates Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! maps characters (integers) to start states of tokens as a HashTable
|
||||||
|
class StartStates
|
||||||
|
{
|
||||||
|
//! HashTable entry
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
int key; //<! The lookup key
|
||||||
|
int val; //<! The data
|
||||||
|
Entry *next; //<! Pointer next Entry in sub-list
|
||||||
|
|
||||||
|
Entry(int k, int v, Entry *n=0)
|
||||||
|
:
|
||||||
|
key(k), val(v), next(n)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int size_ = 128; //<! fixed HashTable size
|
||||||
|
Entry **table_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StartStates()
|
||||||
|
:
|
||||||
|
table_(new Entry*[size_])
|
||||||
|
{
|
||||||
|
memset(table_, 0, size_*sizeof(Entry*));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~StartStates()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size_; ++i)
|
||||||
|
{
|
||||||
|
Entry *e = table_[i];
|
||||||
|
while (e)
|
||||||
|
{
|
||||||
|
Entry *next = e->next;
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] table_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(int key, int val)
|
||||||
|
{
|
||||||
|
const int hashIndex = unsigned(key) % size_;
|
||||||
|
table_[hashIndex] = new Entry(key, val, table_[hashIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int state(int key)
|
||||||
|
{
|
||||||
|
Entry *e = table_[unsigned(key) % size_];
|
||||||
|
while (e && e->key != key) e = e->next;
|
||||||
|
return e ? e->val : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class KeywordMap Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! maps strings to integers (identifiers to keyword kinds) as a HashTable
|
||||||
|
class KeywordMap
|
||||||
|
{
|
||||||
|
//! HashTable entry
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
const std::wstring key; //<! The lookup key
|
||||||
|
int val; //<! The data
|
||||||
|
Entry *next; //<! Pointer next Entry in sub-list
|
||||||
|
|
||||||
|
Entry(const std::wstring& k, int v, Entry *n=0)
|
||||||
|
:
|
||||||
|
key(k), val(v), next(n)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int size_ = 128; //<! fixed HashTable size
|
||||||
|
Entry **table_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeywordMap()
|
||||||
|
:
|
||||||
|
table_(new Entry*[size_])
|
||||||
|
{
|
||||||
|
memset(table_, 0, size_*sizeof(Entry*));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~KeywordMap()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size_; ++i)
|
||||||
|
{
|
||||||
|
Entry *e = table_[i];
|
||||||
|
while (e)
|
||||||
|
{
|
||||||
|
Entry *next = e->next;
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] table_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const std::wstring& key, int val)
|
||||||
|
{
|
||||||
|
const int hashIndex = coco_string_hash(key) % size_;
|
||||||
|
table_[hashIndex] = new Entry(key, val, table_[hashIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get(const std::wstring& key, int defaultVal)
|
||||||
|
{
|
||||||
|
Entry *e = table_[coco_string_hash(key) % size_];
|
||||||
|
while (e && e->key != key) e = e->next;
|
||||||
|
return e ? e->val : defaultVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Scanner Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
//! A Coco/R Scanner
|
||||||
|
class Scanner
|
||||||
|
{
|
||||||
|
static const int maxT = 10;
|
||||||
|
static const int noSym = 10;
|
||||||
|
static const int eofSym = 0; //!< end-of-file token id
|
||||||
|
static const char EOL = '\n'; //!< end-of-line character
|
||||||
|
|
||||||
|
void *firstHeap; //!< the start of the heap management
|
||||||
|
void *heap; //!< the currently active block
|
||||||
|
void *heapTop; //!< the top of the heap
|
||||||
|
void **heapEnd; //!< the end of the last heap block
|
||||||
|
|
||||||
|
StartStates start; //!< A map of start states for particular characters
|
||||||
|
KeywordMap keywords; //!< A hash of keyword literals to token kind
|
||||||
|
|
||||||
|
Token *t; //!< current token
|
||||||
|
wchar_t *tval; //!< text of current token
|
||||||
|
int tvalLength; //!< maximum capacity (length) for tval
|
||||||
|
int tlen; //!< length of tval
|
||||||
|
|
||||||
|
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; //!< the number of EOLs that appeared in a comment
|
||||||
|
|
||||||
|
void CreateHeapBlock(); //!< add a heap block, freeing unused ones
|
||||||
|
Token* CreateToken(); //!< fit token on the heap
|
||||||
|
void AppendVal(Token* tok); //!< adjust tok->val to point to the heap and copy tval into it
|
||||||
|
void SetScannerBehindT();
|
||||||
|
|
||||||
|
void Init(); //!< complete the initialization for the constructors
|
||||||
|
void NextCh(); //!< get the next input character into ch
|
||||||
|
void AddCh(); //!< append the character ch to tval
|
||||||
|
bool Comment0();
|
||||||
|
bool Comment1();
|
||||||
|
Token* NextToken(); //!< get the next token
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! The scanner buffer
|
||||||
|
Buffer *buffer;
|
||||||
|
|
||||||
|
//! Attach scanner to an existing character buffer
|
||||||
|
Scanner(const char* chars, int len);
|
||||||
|
|
||||||
|
//! Attach scanner to an existing character buffer
|
||||||
|
Scanner(const unsigned char* chars, int len);
|
||||||
|
|
||||||
|
//! Attach scanner to an existing open file handle
|
||||||
|
Scanner(FILE*);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
//! Open a file for reading and attach scanner - Windows only
|
||||||
|
explicit Scanner(const std::wstring& fileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Open a file for reading and attach scanner
|
||||||
|
explicit Scanner(const std::string& fileName);
|
||||||
|
|
||||||
|
//! Attach scanner to an existing open STL standard stream
|
||||||
|
explicit Scanner(std::istream&);
|
||||||
|
|
||||||
|
~Scanner(); //!< free heap and allocated memory
|
||||||
|
Token* Scan(); //!< get the next token (possibly a token already seen during peeking)
|
||||||
|
Token* Peek(); //!< peek for the next token, ignore pragmas
|
||||||
|
void ResetPeek(); //!< ensure that peeking starts at the current scan position
|
||||||
|
|
||||||
|
int Line() const; //!< Return the current line
|
||||||
|
void Line(int lineNo); //!< Define the starting line for reporting errors
|
||||||
|
|
||||||
|
}; // end Scanner
|
||||||
|
|
||||||
|
} // End namespace
|
||||||
|
|
||||||
|
#endif // COCO_wmkdependSCANNER_H__
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user