ENH: minor code tidying, machine simplifications for wmkdepend parser

This commit is contained in:
Mark Olesen
2018-04-13 16:17:39 +02:00
parent c8d0e5ae03
commit b29a0119de
4 changed files with 2944 additions and 500 deletions

View File

@ -30,6 +30,7 @@
# -eENV Environment variable path substitutions. # -eENV Environment variable path substitutions.
# -oFile Write output to File. # -oFile Write output to File.
# -q Suppress 'No such file' warnings. # -q Suppress 'No such file' warnings.
# -v Verbose
# #
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
unset envChanges output unset envChanges output
@ -37,10 +38,10 @@ unset envChanges output
while [ "$#" -gt 1 ] while [ "$#" -gt 1 ]
do do
case "$1" in case "$1" in
-q*) # quiet - ignore -q* | -v*) # quiet/verbose- ignore
;; ;;
-e*) # -eENV - ignore for now -e*) # -eENV - Not working
envChanges="$envChanges ${1#-e}" envChanges="$envChanges ${1#-e}"
;; ;;

View File

@ -36,7 +36,7 @@ Description
which makes this faster than cpp. which makes this faster than cpp.
Usage Usage
wmkdep [-Idir..] [-iheader...] [-eENV...] [-oFile] [-q] filename wmkdep [-Idir..] [-iheader...] [-eENV...] [-oFile] [-q] [-v] filename
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
/* With cpp: /* With cpp:
@ -265,6 +265,7 @@ static void print_fileName(const char* fileName)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int optQuiet = 0; int optQuiet = 0;
int optVerbose = 0;
int nDirectories = 0; int nDirectories = 0;
char** directories = NULL; char** directories = NULL;
char* sourceFile = NULL; char* sourceFile = NULL;
@ -315,13 +316,14 @@ int main(int argc, char* argv[])
fputs fputs
( (
"\nUsage: " EXENAME "\nUsage: " EXENAME
" [-Idir...] [-iheader...] [-eENV...] [-oFile] [-q]" " [-Idir...] [-iheader...] [-eENV...] [-oFile] [-q] [-v]"
" filename\n\n" " filename\n\n"
" -Idir Directories to be searched for headers.\n" " -Idir Directories to be searched for headers.\n"
" -iheader Headers to be ignored.\n" " -iheader Headers to be ignored.\n"
" -eENV Environment variable path substitutions.\n" " -eENV Environment variable path substitutions.\n"
" -oFile Write output to File.\n" " -oFile Write output to File.\n"
" -q Suppress 'No such file' warnings.\n" " -q Suppress 'No such file' warnings.\n"
" -v Report each include file to stderr.\n"
"\nDependency list generator, similar to 'cpp -M'\n\n", "\nDependency list generator, similar to 'cpp -M'\n\n",
stderr stderr
); );
@ -332,6 +334,10 @@ int main(int argc, char* argv[])
++optQuiet; ++optQuiet;
break; break;
case 'v': /* Option: -v (verbose) */
++optVerbose;
break;
case 'I': /* Option: -Idir */ case 'I': /* Option: -Idir */
++nDirectories; ++nDirectories;
break; break;
@ -510,6 +516,12 @@ static FILE* fopen_file(const char* dirName, const char* fileName)
} }
} }
if (file && optVerbose)
{
fputs(fileName, stderr);
fputs("\n", stderr);
}
return file; return file;
} }

File diff suppressed because it is too large Load Diff

View File

@ -86,12 +86,16 @@ void usage()
" -eENV Environment variable path substitutions.\n" " -eENV Environment variable path substitutions.\n"
" -oFile Write output to File.\n" " -oFile Write output to File.\n"
" -q Suppress 'No such file' warnings.\n" " -q Suppress 'No such file' warnings.\n"
" -v Report each include file to stderr.\n"
"\nDependency list generator, similar to 'cpp -M'\n\n"; "\nDependency list generator, similar to 'cpp -M'\n\n";
} }
// Suppress some error messages //- Suppress some error messages
bool optQuiet = false; bool optQuiet = false;
//- Verbose progress
bool optVerbose = false;
//- The top-level source file being processed //- The top-level source file being processed
std::string sourceFile; std::string sourceFile;
@ -136,45 +140,55 @@ namespace Files
} }
//- Add environ replacements //- Add environ replacement
// //
// Eg, // Eg for 'WM_PROJECT_DIR' stores the pair
// /openfoam/project/path/directory/xyz // '$(WM_PROJECT_DIR)/'
// -> $(WM_PROJECT_DIR)/directory/xyz // '/path/openfoam/project/'
void addEnv(std::string key) //
{ // No-op if the environment does not exists or is empty
const char *val = ::getenv(key.c_str()); void addEnv(const char* key)
{
if (val && *val) const size_t keylen = key ? strlen(key) : 0;
{ if (!keylen) return;
// "$(ENV)/" -> "/env/value/"
std::string orig(val); const char *val = ::getenv(key);
if (orig.back() != '/')
{ if (!val || !*val) return;
orig.append("/");
} // The "$(ENV)/" portion
std::string oldText;
envlist.emplace_front("$(" + key + ")/", std::move(orig)); oldText.reserve(keylen+4);
} oldText.append("$(").append(key,keylen).append(")/");
}
// The "/env/value/" portion
std::string newText(val);
if (newText.back() != '/')
{
newText.append(1, '/');
}
envlist.emplace_front(std::move(oldText), std::move(newText));
}
//- Open a file for reading and emit its qualified name to stdout.
// //
// Open a file for reading and emit its qualified name to stdout.
// Uses env substitutions at the beginning of the path // Uses env substitutions at the beginning of the path
// //
// Eg, // Eg,
// /openfoam/project/path/directory/xyz // /path/openfoam/project/directory/name
// -> $(WM_PROJECT_DIR)/directory/xyz // -> $(WM_PROJECT_DIR)/directory/name
// //
FILE* fopen_file(const std::string& fileName) // \return nullptr on failure
FILE* openAndEmit(const std::string& fileName)
{ {
const auto len = fileName.size(); const auto len = fileName.size();
const char *fname = fileName.c_str(); const char *fname = fileName.c_str();
FILE *filePtr = ::fopen(fname, "r"); FILE *infile = ::fopen(fname, "r");
if (filePtr) if (infile)
{ {
// Mark as having been visited // Mark as having been visited
visited.insert(fileName); visited.insert(fileName);
@ -187,14 +201,14 @@ namespace Files
&& !fileName.compare(0, entry.len, entry.value) && !fileName.compare(0, entry.len, entry.value)
) )
{ {
fname += entry.len; fname += entry.len; // Now positioned after the '/'
::fputs(entry.name.c_str(), stdout); fputs(entry.name.c_str(), stdout);
break; break;
} }
} }
::fputs(fname, stdout); fputs(fname, stdout);
::fputs(" \\\n", stdout); fputs(" \\\n", stdout);
} }
else if (errno == EMFILE) else if (errno == EMFILE)
{ {
@ -204,15 +218,16 @@ namespace Files
<< "Please change your open descriptor limit\n"; << "Please change your open descriptor limit\n";
} }
return filePtr; return infile;
} }
// Open a not previously visited file for reading, using the include dirs //- Open a not previously visited file for reading,
// as required. // using the include dirs as required.
// //
// On success, emits the resolved name on stdout // On success, emits the resolved name on stdout
// //
// \return nullptr on failure
FILE* open(const std::string& fileName) FILE* open(const std::string& fileName)
{ {
// Bad file name, or already visited // Bad file name, or already visited
@ -221,8 +236,8 @@ namespace Files
return nullptr; return nullptr;
} }
FILE* filePtr = fopen_file(fileName); FILE* infile = openAndEmit(fileName);
if (!filePtr) if (!infile)
{ {
std::string fullName; std::string fullName;
@ -243,9 +258,9 @@ namespace Files
} }
fullName.append(fileName); fullName.append(fileName);
filePtr = fopen_file(fullName); infile = openAndEmit(fullName);
if (filePtr) if (infile)
{ {
break; break;
} }
@ -257,10 +272,10 @@ namespace Files
visited.insert(fileName); visited.insert(fileName);
// Report failues // Report failues
if (!filePtr && !optQuiet) if (!infile && !optQuiet)
{ {
std::cerr std::cerr
<< EXENAME ": could not open file '" << EXENAME ": could not open '"
<< fileName << "' for source file '" << fileName << "' for source file '"
<< sourceFile << "'"; << sourceFile << "'";
@ -272,7 +287,7 @@ namespace Files
std::cerr << '\n' << std::flush; std::cerr << '\n' << std::flush;
} }
return filePtr; return infile;
} }
} // end of namespace Files } // end of namespace Files
@ -280,36 +295,28 @@ namespace Files
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Ragel machine requirements: token start/end, action, code state // Ragel machine definition
// are defined later (prior to use) // Ragel variables (p, pe, eof, cs, top, stack, ts, te, act) defined later...
//
// Can use 'variable p xxx;' etc to change these names
%%{ %%{
machine wmkdep; machine wmkdep;
write data nofinal;
hashInclude = space* '#' space* 'include' space* ; ## include directive action buffer { tok = p; /* Local token start */ }
includeName = [^\"<>]+ ; ## Text between "" or <> action process { processFile(std::string(tok, (p - tok))); }
action begInclude { ts_inclName = fpc; } ## Remember start position comment := any* :>> '*/' @{ fgoto main; };
## No 'if (ts_inclName) ...' guard needed (implicit via the FSM)
action endInclude
{
// std::cerr << std::string(ts, (te-ts)) << '\n';
processFile(std::string(ts_inclName, (fpc - ts_inclName)));
}
consume_comment := any* :>> '*/' @{ fgoto main; };
main := |* main := |*
^space* '#' space* 'include' space* ('"' [^\"]+ >buffer %process '"');
# Single and double quoted strings # Single and double quoted strings
( 'L'? "'" ( [^'\\\n] | /\\./ )* "'") ; # " swallow ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'") ; # " swallow
( 'L'? '"' ( [^"\\\n] | /\\./ )* '"') ; # ' swallow ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"') ; # ' swallow
hashInclude '"' %begInclude includeName %endInclude '"' ; '/*' { fgoto comment; };
'/*' { fgoto consume_comment; };
'//' [^\n]* '\n'; '//' [^\n]* '\n';
[^\n]* '\n'; # Swallow all other lines [^\n]* '\n'; # Swallow all other lines
@ -317,6 +324,13 @@ namespace Files
}%% }%%
//
// FSM globals
//
%% write data nofinal;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// //
@ -325,17 +339,21 @@ namespace Files
void processFile(const std::string& fileName) void processFile(const std::string& fileName)
{ {
FILE* infile = Files::open(fileName); FILE* infile = Files::open(fileName);
if (optVerbose)
{
std::cerr << fileName << '\n';
}
if (!infile) return; if (!infile) return;
// ts, te = Ragel token start/end points (required naming) // ts, te = Ragel token start/end points (default naming)
// act, cs = Ragel action, code state, respectively (required naming) // act, cs = Ragel action, code state, respectively (default naming)
char *ts, *te; char *ts, *te;
unsigned act, cs; int act, cs;
%% write init ; ## /* FSM initialization here */; %%{write init;}%% /* ^^^ FSM initialization here ^^^ */;
// Token start of include filename (for begInclude, endInclude actions) // Local token start
char *ts_inclName = nullptr; char *tok = nullptr;
// Buffering // Buffering
char inbuf[READ_BUFLEN]; char inbuf[READ_BUFLEN];
@ -344,9 +362,10 @@ void processFile(const std::string& fileName)
// Processing loop (as per Ragel pdf example) // Processing loop (as per Ragel pdf example)
for (bool good = true; good; /*nil*/) for (bool good = true; good; /*nil*/)
{ {
const size_t avail = READ_BUFLEN - pending; char *data = inbuf + pending; // current data buffer
const size_t buflen = READ_BUFLEN - pending; // space left in buffer
if (!avail) if (!buflen)
{ {
// We overfilled the buffer while trying to scan a token... // We overfilled the buffer while trying to scan a token...
std::cerr std::cerr
@ -355,25 +374,29 @@ void processFile(const std::string& fileName)
break; break;
} }
// p, pe = Ragel parsing point and parsing end (required naming) // p,pe = Ragel parsing point and parsing end (default naming)
// eof = Ragel EOF point (required naming) // eof = Ragel EOF point (default naming)
char *p = inbuf + pending; const size_t gcount = ::fread(data, 1, buflen, infile);
const size_t gcount = ::fread(p, 1, avail, infile);
char *p = data;
char *pe = p + gcount; char *pe = p + gcount;
char *eof = nullptr; char *eof = nullptr;
if (!gcount) // Could also use feof(infile) if (::feof(infile))
{ {
// Tag 'pe' as being the EOF for the FSM as well // Tag 'pe' as being the EOF for the FSM as well
eof = pe; eof = pe;
good = false; good = false;
} }
else if (!gcount)
{
break;
}
%% write exec ; ## /* FSM execution here */; %%{write exec;}%% /* ^^^ FSM execution here ^^^ */;
if (cs == wmkdep_error) if (%%{write error;}%% == cs)
{ {
// FSM failed before finding a token // FSM failed before finding a token
std::cerr std::cerr
@ -386,7 +409,7 @@ void processFile(const std::string& fileName)
{ {
// Preserve incomplete token // Preserve incomplete token
pending = pe - ts; pending = pe - ts;
::memmove(inbuf, ts, pending); memmove(inbuf, ts, pending);
te = inbuf + (te - ts); // token end (after memmove) te = inbuf + (te - ts); // token end (after memmove)
ts = inbuf; // token start ts = inbuf; // token start
} }
@ -428,6 +451,10 @@ int main(int argc, char* argv[])
optQuiet = true; optQuiet = true;
break; break;
case 'v': // Option: -v (verbose)
optVerbose = true;
break;
case 'I': // Option: -Idir case 'I': // Option: -Idir
++nIncDirs; ++nIncDirs;
break; break;
@ -445,7 +472,7 @@ int main(int argc, char* argv[])
if (dot == std::string::npos || sourceFile[dot] != '.') if (dot == std::string::npos || sourceFile[dot] != '.')
{ {
std::cerr std::cerr
<< EXENAME ": cannot find extension in source file name '" << EXENAME ": no file extension in source file name '"
<< sourceFile << "'\n"; << sourceFile << "'\n";
return 1; return 1;
@ -493,29 +520,22 @@ int main(int argc, char* argv[])
} }
} }
if (outputFile.size() && !freopen(outputFile.c_str(), "w", stdout))
// Start of output
if (outputFile.size())
{
FILE *reopened = freopen(outputFile.c_str(), "w", stdout);
if (!reopened)
{ {
std::cerr std::cerr
<< EXENAME ": could not open file '" << EXENAME ": could not open file '"
<< outputFile << "' for output: " << strerror(errno) << outputFile << "' for output: " << strerror(errno) << "\n";
<< "\n";
return 1; return 1;
} }
}
::fputs("$(OBJECTS_DIR)/", stdout); fputs("$(OBJECTS_DIR)/", stdout);
::fputs(sourceFile.c_str(), stdout); fputs(sourceFile.c_str(), stdout);
::fputs(".dep: \\\n", stdout); fputs(".dep: \\\n", stdout);
processFile(sourceFile); processFile(sourceFile);
::fputs("\n\n", stdout); fputs("\n\n", stdout);
::fflush(stdout); fflush(stdout);
return 0; return 0;
} }