From eebe732bb61bb69f50edae9b7fb171266b216752 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 22 Jul 2015 14:03:00 -0400 Subject: [PATCH] cmFortranParser: Factor out of cmDependsFortran Move the main parser class and method implementations out of cmDependsFortran.cxx and into separate source files. --- Source/CMakeLists.txt | 1 + Source/cmDependsFortran.cxx | 465 --------------------------------- Source/cmFortranParser.h | 79 ++++++ Source/cmFortranParserImpl.cxx | 408 +++++++++++++++++++++++++++++ 4 files changed, 488 insertions(+), 465 deletions(-) create mode 100644 Source/cmFortranParserImpl.cxx diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 7e393863f..92fee8aba 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -244,6 +244,7 @@ set(SRCS cmFortranLexer.h cmFortranParser.cxx cmFortranParser.h + cmFortranParserImpl.cxx cmGeneratedFileStream.cxx cmGeneratorExpressionContext.cxx cmGeneratorExpressionContext.h diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index a422a989f..13c6409d9 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -19,83 +19,11 @@ #include "cmFortranParser.h" /* Interface to parser object. */ #include #include -#include // TODO: Test compiler for the case of the mod file. Some always // use lower case and some always use upper case. I do not know if any // use the case from the source code. -//---------------------------------------------------------------------------- -// Information about a single source file. -class cmFortranSourceInfo -{ -public: - // The name of the source file. - std::string Source; - - // Set of provided and required modules. - std::set Provides; - std::set Requires; - - // Set of files included in the translation unit. - std::set Includes; -}; - -//---------------------------------------------------------------------------- -// Parser methods not included in generated interface. - -// Get the current buffer processed by the lexer. -YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner); - -// The parser entry point. -int cmFortran_yyparse(yyscan_t); - -//---------------------------------------------------------------------------- -// Define parser object internal structure. -struct cmFortranFile -{ - cmFortranFile(FILE* file, YY_BUFFER_STATE buffer, - const std::string& dir): - File(file), Buffer(buffer), Directory(dir) {} - FILE* File; - YY_BUFFER_STATE Buffer; - std::string Directory; -}; - -struct cmFortranParser_s -{ - cmFortranParser_s(std::vector const& includes, - std::set const& defines, - cmFortranSourceInfo& info); - ~cmFortranParser_s(); - - bool FindIncludeFile(const char* dir, const char* includeName, - std::string& fileName); - - // The include file search path. - std::vector IncludePath; - - // Lexical scanner instance. - yyscan_t Scanner; - - // Stack of open files in the translation unit. - std::stack FileStack; - - // Buffer for string literals. - std::string TokenString; - - // Flag for whether lexer is reading from inside an interface. - bool InInterface; - - int OldStartcond; - std::set PPDefinitions; - size_t InPPFalseBranch; - std::stack SkipToEnd; - - // Information about the parsed source. - cmFortranSourceInfo& Info; -}; - //---------------------------------------------------------------------------- class cmDependsFortranInternals { @@ -882,396 +810,3 @@ bool cmDependsFortran::ModulesDiffer(const char* modFile, // The modules are different. return true; } - -//---------------------------------------------------------------------------- -bool cmFortranParser_s::FindIncludeFile(const char* dir, - const char* includeName, - std::string& fileName) -{ - // If the file is a full path, include it directly. - if(cmSystemTools::FileIsFullPath(includeName)) - { - fileName = includeName; - return cmSystemTools::FileExists(fileName.c_str(), true); - } - else - { - // Check for the file in the directory containing the including - // file. - std::string fullName = dir; - fullName += "/"; - fullName += includeName; - if(cmSystemTools::FileExists(fullName.c_str(), true)) - { - fileName = fullName; - return true; - } - - // Search the include path for the file. - for(std::vector::const_iterator i = - this->IncludePath.begin(); i != this->IncludePath.end(); ++i) - { - fullName = *i; - fullName += "/"; - fullName += includeName; - if(cmSystemTools::FileExists(fullName.c_str(), true)) - { - fileName = fullName; - return true; - } - } - } - return false; -} - -//---------------------------------------------------------------------------- -cmFortranParser_s -::cmFortranParser_s(std::vector const& includes, - std::set const& defines, - cmFortranSourceInfo& info): - IncludePath(includes), PPDefinitions(defines), Info(info) -{ - this->InInterface = 0; - this->InPPFalseBranch = 0; - - // Initialize the lexical scanner. - cmFortran_yylex_init(&this->Scanner); - cmFortran_yyset_extra(this, this->Scanner); - - // Create a dummy buffer that is never read but is the fallback - // buffer when the last file is popped off the stack. - YY_BUFFER_STATE buffer = - cmFortran_yy_create_buffer(0, 4, this->Scanner); - cmFortran_yy_switch_to_buffer(buffer, this->Scanner); -} - -//---------------------------------------------------------------------------- -cmFortranParser_s::~cmFortranParser_s() -{ - cmFortran_yylex_destroy(this->Scanner); -} - -//---------------------------------------------------------------------------- -bool cmFortranParser_FilePush(cmFortranParser* parser, - const char* fname) -{ - // Open the new file and push it onto the stack. Save the old - // buffer with it on the stack. - if(FILE* file = cmsys::SystemTools::Fopen(fname, "rb")) - { - YY_BUFFER_STATE current = - cmFortranLexer_GetCurrentBuffer(parser->Scanner); - std::string dir = cmSystemTools::GetParentDirectory(fname); - cmFortranFile f(file, current, dir); - YY_BUFFER_STATE buffer = - cmFortran_yy_create_buffer(0, 16384, parser->Scanner); - cmFortran_yy_switch_to_buffer(buffer, parser->Scanner); - parser->FileStack.push(f); - return 1; - } - else - { - return 0; - } -} - -//---------------------------------------------------------------------------- -bool cmFortranParser_FilePop(cmFortranParser* parser) -{ - // Pop one file off the stack and close it. Switch the lexer back - // to the next one on the stack. - if(parser->FileStack.empty()) - { - return 0; - } - else - { - cmFortranFile f = parser->FileStack.top(); parser->FileStack.pop(); - fclose(f.File); - YY_BUFFER_STATE current = - cmFortranLexer_GetCurrentBuffer(parser->Scanner); - cmFortran_yy_delete_buffer(current, parser->Scanner); - cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner); - return 1; - } -} - -//---------------------------------------------------------------------------- -int cmFortranParser_Input(cmFortranParser* parser, - char* buffer, size_t bufferSize) -{ - // Read from the file on top of the stack. If the stack is empty, - // the end of the translation unit has been reached. - if(!parser->FileStack.empty()) - { - FILE* file = parser->FileStack.top().File; - return (int)fread(buffer, 1, bufferSize, file); - } - return 0; -} - -//---------------------------------------------------------------------------- -void cmFortranParser_StringStart(cmFortranParser* parser) -{ - parser->TokenString = ""; -} - -//---------------------------------------------------------------------------- -const char* cmFortranParser_StringEnd(cmFortranParser* parser) -{ - return parser->TokenString.c_str(); -} - -//---------------------------------------------------------------------------- -void cmFortranParser_StringAppend(cmFortranParser* parser, - char c) -{ - parser->TokenString += c; -} - -//---------------------------------------------------------------------------- -void cmFortranParser_SetInInterface(cmFortranParser* parser, - bool in) -{ - if(parser->InPPFalseBranch) - { - return; - } - - parser->InInterface = in; -} - -//---------------------------------------------------------------------------- -bool cmFortranParser_GetInInterface(cmFortranParser* parser) -{ - return parser->InInterface; -} - -//---------------------------------------------------------------------------- -void cmFortranParser_SetOldStartcond(cmFortranParser* parser, - int arg) -{ - parser->OldStartcond = arg; -} - -//---------------------------------------------------------------------------- -int cmFortranParser_GetOldStartcond(cmFortranParser* parser) -{ - return parser->OldStartcond; -} - -//---------------------------------------------------------------------------- -void cmFortranParser_Error(cmFortranParser*, const char*) -{ - // If there is a parser error just ignore it. The source will not - // compile and the user will edit it. Then dependencies will have - // to be regenerated anyway. -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleUse(cmFortranParser* parser, - const char* name) -{ - if(!parser->InPPFalseBranch) - { - parser->Info.Requires.insert(cmSystemTools::LowerCase(name) ); - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleInclude(cmFortranParser* parser, - const char* name) -{ - if(parser->InPPFalseBranch) - { - return; - } - - // If processing an include statement there must be an open file. - assert(!parser->FileStack.empty()); - - // Get the directory containing the source in which the include - // statement appears. This is always the first search location for - // Fortran include files. - std::string dir = parser->FileStack.top().Directory; - - // Find the included file. If it cannot be found just ignore the - // problem because either the source will not compile or the user - // does not care about depending on this included source. - std::string fullName; - if(parser->FindIncludeFile(dir.c_str(), name, fullName)) - { - // Found the included file. Save it in the set of included files. - parser->Info.Includes.insert(fullName); - - // Parse it immediately to translate the source inline. - cmFortranParser_FilePush(parser, fullName.c_str()); - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleModule(cmFortranParser* parser, - const char* name) -{ - if(!parser->InPPFalseBranch && !parser->InInterface) - { - parser->Info.Provides.insert(cmSystemTools::LowerCase(name)); - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleDefine(cmFortranParser* parser, - const char* macro) -{ - if(!parser->InPPFalseBranch) - { - parser->PPDefinitions.insert(macro); - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleUndef(cmFortranParser* parser, - const char* macro) -{ - if(!parser->InPPFalseBranch) - { - std::set::iterator match; - match = parser->PPDefinitions.find(macro); - if(match != parser->PPDefinitions.end()) - { - parser->PPDefinitions.erase(match); - } - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleIfdef(cmFortranParser* parser, - const char* macro) -{ - // A new PP branch has been opened - parser->SkipToEnd.push(false); - - if (parser->InPPFalseBranch) - { - parser->InPPFalseBranch++; - } - else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end()) - { - parser->InPPFalseBranch=1; - } - else - { - parser->SkipToEnd.top() = true; - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleIfndef(cmFortranParser* parser, - const char* macro) -{ - // A new PP branch has been opened - parser->SkipToEnd.push(false); - - if (parser->InPPFalseBranch) - { - parser->InPPFalseBranch++; - } - else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end()) - { - parser->InPPFalseBranch = 1; - } - else - { - // ignore other branches - parser->SkipToEnd.top() = true; - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleIf(cmFortranParser* parser) -{ - /* Note: The current parser is _not_ able to get statements like - * #if 0 - * #if 1 - * #if MYSMBOL - * #if defined(MYSYMBOL) - * #if defined(MYSYMBOL) && ... - * right. The same for #elif. Thus in - * #if SYMBOL_1 - * .. - * #elif SYMBOL_2 - * ... - * ... - * #elif SYMBOL_N - * .. - * #else - * .. - * #endif - * _all_ N+1 branches are considered. If you got something like this - * #if defined(MYSYMBOL) - * #if !defined(MYSYMBOL) - * use - * #ifdef MYSYMBOL - * #ifndef MYSYMBOL - * instead. - */ - - // A new PP branch has been opened - // Never skip! See note above. - parser->SkipToEnd.push(false); -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleElif(cmFortranParser* parser) -{ - /* Note: There are parser limitations. See the note at - * cmFortranParser_RuleIf(..) - */ - - // Always taken unless an #ifdef or #ifndef-branch has been taken - // already. If the second condition isn't meet already - // (parser->InPPFalseBranch == 0) correct it. - if(!parser->SkipToEnd.empty() && - parser->SkipToEnd.top() && !parser->InPPFalseBranch) - { - parser->InPPFalseBranch = 1; - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleElse(cmFortranParser* parser) -{ - // if the parent branch is false do nothing! - if(parser->InPPFalseBranch > 1) - { - return; - } - - // parser->InPPFalseBranch is either 0 or 1. We change it depending on - // parser->SkipToEnd.top() - if(!parser->SkipToEnd.empty() && - parser->SkipToEnd.top()) - { - parser->InPPFalseBranch = 1; - } - else - { - parser->InPPFalseBranch = 0; - } -} - -//---------------------------------------------------------------------------- -void cmFortranParser_RuleEndif(cmFortranParser* parser) -{ - if(!parser->SkipToEnd.empty()) - { - parser->SkipToEnd.pop(); - } - - // #endif doesn't know if there was a "#else" in before, so it - // always decreases InPPFalseBranch - if(parser->InPPFalseBranch) - { - parser->InPPFalseBranch--; - } -} diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h index 4c28fd0a3..156c38a74 100644 --- a/Source/cmFortranParser.h +++ b/Source/cmFortranParser.h @@ -12,6 +12,10 @@ #ifndef cmFortranParser_h #define cmFortranParser_h +#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx) +# include "cmStandardIncludes.h" +#endif + #include /* size_t */ /* Forward declare parser object type. */ @@ -93,4 +97,79 @@ int cmFortran_yylex(YYSTYPE* yylvalp, yyscan_t yyscanner) #endif #endif +#if !defined(cmFortranLexer_cxx) && !defined(cmFortranParser_cxx) +#include + +//---------------------------------------------------------------------------- +// Information about a single source file. +class cmFortranSourceInfo +{ +public: + // The name of the source file. + std::string Source; + + // Set of provided and required modules. + std::set Provides; + std::set Requires; + + // Set of files included in the translation unit. + std::set Includes; +}; + +//---------------------------------------------------------------------------- +// Parser methods not included in generated interface. + +// Get the current buffer processed by the lexer. +YY_BUFFER_STATE cmFortranLexer_GetCurrentBuffer(yyscan_t yyscanner); + +// The parser entry point. +int cmFortran_yyparse(yyscan_t); + +//---------------------------------------------------------------------------- +// Define parser object internal structure. +struct cmFortranFile +{ + cmFortranFile(FILE* file, YY_BUFFER_STATE buffer, + const std::string& dir): + File(file), Buffer(buffer), Directory(dir) {} + FILE* File; + YY_BUFFER_STATE Buffer; + std::string Directory; +}; + +struct cmFortranParser_s +{ + cmFortranParser_s(std::vector const& includes, + std::set const& defines, + cmFortranSourceInfo& info); + ~cmFortranParser_s(); + + bool FindIncludeFile(const char* dir, const char* includeName, + std::string& fileName); + + // The include file search path. + std::vector IncludePath; + + // Lexical scanner instance. + yyscan_t Scanner; + + // Stack of open files in the translation unit. + std::stack FileStack; + + // Buffer for string literals. + std::string TokenString; + + // Flag for whether lexer is reading from inside an interface. + bool InInterface; + + int OldStartcond; + std::set PPDefinitions; + size_t InPPFalseBranch; + std::stack SkipToEnd; + + // Information about the parsed source. + cmFortranSourceInfo& Info; +}; +#endif + #endif diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx new file mode 100644 index 000000000..a09c54598 --- /dev/null +++ b/Source/cmFortranParserImpl.cxx @@ -0,0 +1,408 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2015 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmFortranParser.h" + +#include "cmSystemTools.h" +#include + +//---------------------------------------------------------------------------- +bool cmFortranParser_s::FindIncludeFile(const char* dir, + const char* includeName, + std::string& fileName) +{ + // If the file is a full path, include it directly. + if(cmSystemTools::FileIsFullPath(includeName)) + { + fileName = includeName; + return cmSystemTools::FileExists(fileName.c_str(), true); + } + else + { + // Check for the file in the directory containing the including + // file. + std::string fullName = dir; + fullName += "/"; + fullName += includeName; + if(cmSystemTools::FileExists(fullName.c_str(), true)) + { + fileName = fullName; + return true; + } + + // Search the include path for the file. + for(std::vector::const_iterator i = + this->IncludePath.begin(); i != this->IncludePath.end(); ++i) + { + fullName = *i; + fullName += "/"; + fullName += includeName; + if(cmSystemTools::FileExists(fullName.c_str(), true)) + { + fileName = fullName; + return true; + } + } + } + return false; +} + +//---------------------------------------------------------------------------- +cmFortranParser_s +::cmFortranParser_s(std::vector const& includes, + std::set const& defines, + cmFortranSourceInfo& info): + IncludePath(includes), PPDefinitions(defines), Info(info) +{ + this->InInterface = 0; + this->InPPFalseBranch = 0; + + // Initialize the lexical scanner. + cmFortran_yylex_init(&this->Scanner); + cmFortran_yyset_extra(this, this->Scanner); + + // Create a dummy buffer that is never read but is the fallback + // buffer when the last file is popped off the stack. + YY_BUFFER_STATE buffer = + cmFortran_yy_create_buffer(0, 4, this->Scanner); + cmFortran_yy_switch_to_buffer(buffer, this->Scanner); +} + +//---------------------------------------------------------------------------- +cmFortranParser_s::~cmFortranParser_s() +{ + cmFortran_yylex_destroy(this->Scanner); +} + +//---------------------------------------------------------------------------- +bool cmFortranParser_FilePush(cmFortranParser* parser, + const char* fname) +{ + // Open the new file and push it onto the stack. Save the old + // buffer with it on the stack. + if(FILE* file = cmsys::SystemTools::Fopen(fname, "rb")) + { + YY_BUFFER_STATE current = + cmFortranLexer_GetCurrentBuffer(parser->Scanner); + std::string dir = cmSystemTools::GetParentDirectory(fname); + cmFortranFile f(file, current, dir); + YY_BUFFER_STATE buffer = + cmFortran_yy_create_buffer(0, 16384, parser->Scanner); + cmFortran_yy_switch_to_buffer(buffer, parser->Scanner); + parser->FileStack.push(f); + return 1; + } + else + { + return 0; + } +} + +//---------------------------------------------------------------------------- +bool cmFortranParser_FilePop(cmFortranParser* parser) +{ + // Pop one file off the stack and close it. Switch the lexer back + // to the next one on the stack. + if(parser->FileStack.empty()) + { + return 0; + } + else + { + cmFortranFile f = parser->FileStack.top(); parser->FileStack.pop(); + fclose(f.File); + YY_BUFFER_STATE current = + cmFortranLexer_GetCurrentBuffer(parser->Scanner); + cmFortran_yy_delete_buffer(current, parser->Scanner); + cmFortran_yy_switch_to_buffer(f.Buffer, parser->Scanner); + return 1; + } +} + +//---------------------------------------------------------------------------- +int cmFortranParser_Input(cmFortranParser* parser, + char* buffer, size_t bufferSize) +{ + // Read from the file on top of the stack. If the stack is empty, + // the end of the translation unit has been reached. + if(!parser->FileStack.empty()) + { + FILE* file = parser->FileStack.top().File; + return (int)fread(buffer, 1, bufferSize, file); + } + return 0; +} + +//---------------------------------------------------------------------------- +void cmFortranParser_StringStart(cmFortranParser* parser) +{ + parser->TokenString = ""; +} + +//---------------------------------------------------------------------------- +const char* cmFortranParser_StringEnd(cmFortranParser* parser) +{ + return parser->TokenString.c_str(); +} + +//---------------------------------------------------------------------------- +void cmFortranParser_StringAppend(cmFortranParser* parser, + char c) +{ + parser->TokenString += c; +} + +//---------------------------------------------------------------------------- +void cmFortranParser_SetInInterface(cmFortranParser* parser, + bool in) +{ + if(parser->InPPFalseBranch) + { + return; + } + + parser->InInterface = in; +} + +//---------------------------------------------------------------------------- +bool cmFortranParser_GetInInterface(cmFortranParser* parser) +{ + return parser->InInterface; +} + +//---------------------------------------------------------------------------- +void cmFortranParser_SetOldStartcond(cmFortranParser* parser, + int arg) +{ + parser->OldStartcond = arg; +} + +//---------------------------------------------------------------------------- +int cmFortranParser_GetOldStartcond(cmFortranParser* parser) +{ + return parser->OldStartcond; +} + +//---------------------------------------------------------------------------- +void cmFortranParser_Error(cmFortranParser*, const char*) +{ + // If there is a parser error just ignore it. The source will not + // compile and the user will edit it. Then dependencies will have + // to be regenerated anyway. +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleUse(cmFortranParser* parser, + const char* name) +{ + if(!parser->InPPFalseBranch) + { + parser->Info.Requires.insert(cmSystemTools::LowerCase(name) ); + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleInclude(cmFortranParser* parser, + const char* name) +{ + if(parser->InPPFalseBranch) + { + return; + } + + // If processing an include statement there must be an open file. + assert(!parser->FileStack.empty()); + + // Get the directory containing the source in which the include + // statement appears. This is always the first search location for + // Fortran include files. + std::string dir = parser->FileStack.top().Directory; + + // Find the included file. If it cannot be found just ignore the + // problem because either the source will not compile or the user + // does not care about depending on this included source. + std::string fullName; + if(parser->FindIncludeFile(dir.c_str(), name, fullName)) + { + // Found the included file. Save it in the set of included files. + parser->Info.Includes.insert(fullName); + + // Parse it immediately to translate the source inline. + cmFortranParser_FilePush(parser, fullName.c_str()); + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleModule(cmFortranParser* parser, + const char* name) +{ + if(!parser->InPPFalseBranch && !parser->InInterface) + { + parser->Info.Provides.insert(cmSystemTools::LowerCase(name)); + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleDefine(cmFortranParser* parser, + const char* macro) +{ + if(!parser->InPPFalseBranch) + { + parser->PPDefinitions.insert(macro); + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleUndef(cmFortranParser* parser, + const char* macro) +{ + if(!parser->InPPFalseBranch) + { + std::set::iterator match; + match = parser->PPDefinitions.find(macro); + if(match != parser->PPDefinitions.end()) + { + parser->PPDefinitions.erase(match); + } + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleIfdef(cmFortranParser* parser, + const char* macro) +{ + // A new PP branch has been opened + parser->SkipToEnd.push(false); + + if (parser->InPPFalseBranch) + { + parser->InPPFalseBranch++; + } + else if(parser->PPDefinitions.find(macro) == parser->PPDefinitions.end()) + { + parser->InPPFalseBranch=1; + } + else + { + parser->SkipToEnd.top() = true; + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleIfndef(cmFortranParser* parser, + const char* macro) +{ + // A new PP branch has been opened + parser->SkipToEnd.push(false); + + if (parser->InPPFalseBranch) + { + parser->InPPFalseBranch++; + } + else if(parser->PPDefinitions.find(macro) != parser->PPDefinitions.end()) + { + parser->InPPFalseBranch = 1; + } + else + { + // ignore other branches + parser->SkipToEnd.top() = true; + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleIf(cmFortranParser* parser) +{ + /* Note: The current parser is _not_ able to get statements like + * #if 0 + * #if 1 + * #if MYSMBOL + * #if defined(MYSYMBOL) + * #if defined(MYSYMBOL) && ... + * right. The same for #elif. Thus in + * #if SYMBOL_1 + * .. + * #elif SYMBOL_2 + * ... + * ... + * #elif SYMBOL_N + * .. + * #else + * .. + * #endif + * _all_ N+1 branches are considered. If you got something like this + * #if defined(MYSYMBOL) + * #if !defined(MYSYMBOL) + * use + * #ifdef MYSYMBOL + * #ifndef MYSYMBOL + * instead. + */ + + // A new PP branch has been opened + // Never skip! See note above. + parser->SkipToEnd.push(false); +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleElif(cmFortranParser* parser) +{ + /* Note: There are parser limitations. See the note at + * cmFortranParser_RuleIf(..) + */ + + // Always taken unless an #ifdef or #ifndef-branch has been taken + // already. If the second condition isn't meet already + // (parser->InPPFalseBranch == 0) correct it. + if(!parser->SkipToEnd.empty() && + parser->SkipToEnd.top() && !parser->InPPFalseBranch) + { + parser->InPPFalseBranch = 1; + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleElse(cmFortranParser* parser) +{ + // if the parent branch is false do nothing! + if(parser->InPPFalseBranch > 1) + { + return; + } + + // parser->InPPFalseBranch is either 0 or 1. We change it depending on + // parser->SkipToEnd.top() + if(!parser->SkipToEnd.empty() && + parser->SkipToEnd.top()) + { + parser->InPPFalseBranch = 1; + } + else + { + parser->InPPFalseBranch = 0; + } +} + +//---------------------------------------------------------------------------- +void cmFortranParser_RuleEndif(cmFortranParser* parser) +{ + if(!parser->SkipToEnd.empty()) + { + parser->SkipToEnd.pop(); + } + + // #endif doesn't know if there was a "#else" in before, so it + // always decreases InPPFalseBranch + if(parser->InPPFalseBranch) + { + parser->InPPFalseBranch--; + } +}