summaryrefslogtreecommitdiffstats
path: root/Source/cmFortranParserImpl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFortranParserImpl.cxx')
-rw-r--r--Source/cmFortranParserImpl.cxx355
1 files changed, 355 insertions, 0 deletions
diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx
new file mode 100644
index 0000000..30a33b4
--- /dev/null
+++ b/Source/cmFortranParserImpl.cxx
@@ -0,0 +1,355 @@
+/*============================================================================
+ 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 <assert.h>
+
+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);
+ }
+ // 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<std::string>::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<std::string> const& includes,
+ std::set<std::string> 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(CM_NULLPTR, 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(CM_NULLPTR, 16384, parser->Scanner);
+ cmFortran_yy_switch_to_buffer(buffer, parser->Scanner);
+ parser->FileStack.push(f);
+ return 1;
+ }
+ 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;
+ }
+ 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* /*unused*/, const char* /*unused*/)
+{
+ // 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_RuleLineDirective(cmFortranParser* parser,
+ const char* filename)
+{
+ // This is a #line directive naming a file encountered during preprocessing.
+ std::string included = filename;
+
+ // Skip #line directives referencing non-files like
+ // "<built-in>" or "<command-line>".
+ if (included.empty() || included[0] == '<') {
+ return;
+ }
+
+ // Fix windows file path separators since our lexer does not
+ // process escape sequences in string literals.
+ cmSystemTools::ReplaceString(included, "\\\\", "\\");
+ cmSystemTools::ConvertToUnixSlashes(included);
+
+ // Save the named file as included in the source.
+ if (cmSystemTools::FileExists(included, true)) {
+ parser->Info.Includes.insert(included);
+ }
+}
+
+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<std::string>::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--;
+ }
+}