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:
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
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user