summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in2
-rw-r--r--src/classdef.cpp1
-rw-r--r--src/code.l4
-rw-r--r--src/commentscan.l7
-rw-r--r--src/declinfo.l2
-rw-r--r--src/defargs.h3
-rw-r--r--src/defargs.l9
-rw-r--r--src/doctokenizer.l7
-rw-r--r--src/doxygen.cpp59
-rw-r--r--src/fortrancode.h35
-rw-r--r--src/fortrancode.l959
-rw-r--r--src/fortranscanner.h50
-rw-r--r--src/fortranscanner.l1333
-rw-r--r--src/htmlgen.cpp1
-rw-r--r--src/htmlhelp.cpp5
-rw-r--r--src/index.cpp26
-rw-r--r--src/latexgen.cpp32
-rw-r--r--src/libdoxygen.pro.in4
-rw-r--r--src/libdoxygen.t6
-rw-r--r--src/memberdef.cpp28
-rw-r--r--src/memberdef.h1
-rw-r--r--src/msc.cpp2
-rw-r--r--src/pagedef.cpp2
-rw-r--r--src/pre.h2
-rw-r--r--src/pre.l3
-rw-r--r--src/scanner.l100
-rw-r--r--src/util.cpp109
-rw-r--r--src/util.h2
-rw-r--r--src/xmlgen.cpp3
29 files changed, 2676 insertions, 121 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index bef323e..880902f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -48,6 +48,6 @@ distclean: clean
-$(RM) scanner.cpp code.cpp config.cpp pre.cpp ce_lex.cpp \
ce_parse.cpp ce_parse.h doxytag.cpp tag.cpp commentscan.cpp \
declinfo.cpp defargs.cpp commentcnv.cpp doctokenizer.cpp \
- pycode.cpp pyscanner.cpp
+ pycode.cpp pyscanner.cpp fortrancode.cpp fortranscanner.cpp
FORCE:
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 1991a4a..58be2bb 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -2709,6 +2709,7 @@ void ClassDef::setGroupDefForAllMembers(GroupDef *gd,Grouping::GroupPri_t pri,co
void ClassDef::addInnerCompound(Definition *d)
{
+ //printf("**** %s::addInnerCompound(%s)\n",name().data(),d->name().data());
if (d->definitionType()==Definition::TypeClass) // only classes can be
// nested in classes.
{
diff --git a/src/code.l b/src/code.l
index fd5722a..1f123b2 100644
--- a/src/code.l
+++ b/src/code.l
@@ -2607,8 +2607,8 @@ OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
g_code->codify(yytext);
}
<MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
- addParmType();
- g_parmName=yytext;
+ //addParmType();
+ //g_parmName=yytext;
startFontClass("keyword");
g_code->codify(yytext);
endFontClass();
diff --git a/src/commentscan.l b/src/commentscan.l
index 1b55244..a91dc97 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -354,6 +354,7 @@ static OutputContext inContext; // are we inside the brief, details
static bool briefEndsAtDot; // does the brief description stop at a dot?
static QCString formulaText; // Running text of a formula
static QCString formulaEnv; // environment name
+static int formulaNewLines; // amount of new lines in the formula
static QCString *pOutputString; // pointer to string to which the output is appended.
static QCString outputXRef; // temp argument of todo/test/../xrefitem commands
static QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...)
@@ -566,6 +567,8 @@ static QCString addFormula()
{
formLabel.sprintf("\\form#%d",f->getId());
}
+ int i;
+ for (i=0;i<formulaNewLines;i++) formLabel+='\n';
return formLabel;
}
@@ -955,14 +958,17 @@ MAILADR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]
formulaText="\\begin";
formulaEnv=&yytext[2];
formulaText+=formulaEnv;
+ formulaNewLines=0;
BEGIN(ReadFormulaLong);
}
<Comment>{CMD}"f$" { // start of a inline formula
formulaText="$";
+ formulaNewLines=0;
BEGIN(ReadFormulaShort);
}
<Comment>{CMD}"f[" { // start of a block formula
formulaText="\\[";
+ formulaNewLines=0;
BEGIN(ReadFormulaLong);
}
<Comment>{CMD}"{" { // begin of a group
@@ -1056,6 +1062,7 @@ MAILADR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]
formulaText+=yytext;
}
<ReadFormulaLong,ReadFormulaShort>\n { // new line
+ formulaNewLines++;
formulaText+=*yytext;
yyLineNr++;
}
diff --git a/src/declinfo.l b/src/declinfo.l
index 3ca4c97..54c0a2a 100644
--- a/src/declinfo.l
+++ b/src/declinfo.l
@@ -155,7 +155,7 @@ ID ([a-z_A-Z][a-z_A-Z0-9]*)|(@[0-9]+)
<Start>{B}+ {
addType();
}
-<Start>{B}*"("({ID}"::")*{B}*"*"({B}*("const"|"volatile"){B}+)? {
+<Start>{B}*"("({ID}"::")*{B}*[&*]({B}*("const"|"volatile"){B}+)? {
addType();
QCString text=yytext;
type+=text.stripWhiteSpace();
diff --git a/src/defargs.h b/src/defargs.h
index fe9ea28..b7c6aa1 100644
--- a/src/defargs.h
+++ b/src/defargs.h
@@ -23,6 +23,7 @@
class ArgumentList;
-extern void stringToArgumentList(const char *argsString,ArgumentList* &argList);
+extern void stringToArgumentList(const char *argsString,ArgumentList* &argList,
+ QCString *extraTypeChars=0);
#endif
diff --git a/src/defargs.l b/src/defargs.l
index 94578ff..5939504 100644
--- a/src/defargs.l
+++ b/src/defargs.l
@@ -71,6 +71,7 @@ static QCString g_curArgName;
static QCString g_curArgDocs;
static QCString g_curArgAttrib;
static QCString g_curArgArray;
+static QCString g_extraTypeChars;
static int g_argRoundCount;
static int g_argSharpCount;
static int g_argCurlyCount;
@@ -359,6 +360,10 @@ ID [a-z_A-Z][a-z_A-Z0-9]*
<FuncQual>"="{B}*"0" {
g_argList->pureSpecifier=TRUE;
}
+<FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array,
+ // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]"
+ g_extraTypeChars=yytext;
+ }
<ReadDocBlock>[^\*\n]+ {
g_curArgDocs+=yytext;
}
@@ -402,7 +407,7 @@ ID [a-z_A-Z][a-z_A-Z0-9]*
* \param al a reference to resulting argument list pointer.
*/
-void stringToArgumentList(const char *argsString,ArgumentList* &al)
+void stringToArgumentList(const char *argsString,ArgumentList* &al,QCString *extraTypeChars)
{
if (al==0) return;
if (argsString==0) return;
@@ -411,6 +416,7 @@ void stringToArgumentList(const char *argsString,ArgumentList* &al)
g_curArgDocs.resize(0);
g_curArgAttrib.resize(0);
g_curArgArray.resize(0);
+ g_extraTypeChars.resize(0);
g_argRoundCount = 0;
g_argSharpCount = 0;
g_argCurlyCount = 0;
@@ -425,6 +431,7 @@ void stringToArgumentList(const char *argsString,ArgumentList* &al)
defargsYYrestart( defargsYYin );
BEGIN( Start );
defargsYYlex();
+ if (extraTypeChars) *extraTypeChars=g_extraTypeChars;
//printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data());
}
diff --git a/src/doctokenizer.l b/src/doctokenizer.l
index 8fd3856..901773e 100644
--- a/src/doctokenizer.l
+++ b/src/doctokenizer.l
@@ -321,11 +321,12 @@ FUNCARG "("{FUNCCHAR}*")"({BLANK}*("volatile"|"const"))?
OPNEW {BLANK}+"new"({BLANK}*"[]")?
OPDEL {BLANK}+"delete"({BLANK}*"[]")?
OPNORM {OPNEW}|{OPDEL}|"+"|"-"|"*"|"/"|"%"|"^"|"&"|"|"|"~"|"!"|"="|"<"|">"|"+="|"-="|"*="|"/="|"%="|"^="|"&="|"|="|"<<"|">>"|"<<="|">>="|"=="|"!="|"<="|">="|"&&"|"||"|"++"|"--"|","|"->*"|"->"|"[]"|"()"
-OPCAST {BLANK}+[^(\r\n.,]+
-OPMASK ({BLANK}*{OPNORM}{FUNCARG}?)|({OPCAST}{FUNCARG})
+OPCAST {BLANK}+[^<(\r\n.,][^(\r\n.,]*
+OPMASK ({BLANK}*{OPNORM}{FUNCARG})
+OPMASKOPT ({BLANK}*{OPNORM}{FUNCARG}?)|({OPCAST}{FUNCARG})
LNKWORD1 ("::"|"#")?{SCOPEMASK}
CVSPEC {BLANK}*("const"|"volatile")
-LNKWORD2 {SCOPEPRE}*"operator"{OPMASK}
+LNKWORD2 ({SCOPEPRE}*"operator"{OPMASK})|(("::"|"#"){SCOPEPRE}*"operator"{OPMASKOPT})
LNKWORD3 ([0-9a-z_A-Z\-]+("/"|"\\"))*[0-9a-z_A-Z\-]+("."[0-9a-z_A-Z]+)+
CHARWORD [^ \t\n\r\\@<>()\[\]:;\?{}&%$#,.]
CHARWORDQ [^ \t\n\r\\@<>()\[\]:;\?{}&%$#,."]
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 49ea331..3fba678 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -68,6 +68,7 @@
#include "parserintf.h"
#include "htags.h"
#include "pyscanner.h"
+#include "fortranscanner.h"
#include "code.h"
#include "objcache.h"
#include "store.h"
@@ -1149,8 +1150,6 @@ static void addClassToContext(EntryNav *rootNav)
else // new class
{
ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
- Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n",
- fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
QCString className;
QCString namespaceName;
@@ -1168,6 +1167,8 @@ static void addClassToContext(EntryNav *rootNav)
}
cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
tagName,refFileName);
+ Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d cd=%p\n",
+ fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1,cd);
cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
cd->setIsObjectiveC(root->objc);
@@ -1279,6 +1280,7 @@ static void resolveClassNestingRelations()
{
QCString c,n;
extractNamespaceName(cd->name(),c,n,TRUE);
+ n = stripAnonymousNamespaceScope(n);
if (cd->name().contains("::")==nestingLevel && !n.isEmpty())
{
cd->visited=TRUE;
@@ -1316,14 +1318,15 @@ static void resolveClassNestingRelations()
if (cd->name().contains("::")==nestingLevel && !cd->visited)
{
cd->visited=TRUE;
+ QCString name = stripAnonymousNamespaceScope(cd->name());
//printf("Level=%d processing=%s\n",nestingLevel,cd->name().data());
// also add class to the correct structural context
Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
- cd->name(),cd->getFileDef());
+ name,cd->getFileDef());
if (d==0) // we didn't find anything, create the scope artificially
// anyway, so we can at least relate scopes properly.
{
- Definition *d = buildScopeFromQualifiedName(cd->name(),cd->name().contains("::"));
+ Definition *d = buildScopeFromQualifiedName(name,name.contains("::"));
if (d!=cd) // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
// for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
{
@@ -1331,7 +1334,7 @@ static void resolveClassNestingRelations()
cd->setOuterScope(d);
warn(cd->getDefFileName(),cd->getDefLine(),
"Warning: Internal inconsistency: scope for class %s not "
- "found!",cd->name().data()
+ "found while looking in the global scope!",name.data()
);
}
}
@@ -2127,8 +2130,10 @@ static MemberDef *addVariableToFile(
{
if (md->getFileDef() &&
! // not a php array
- (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
- (md->argsString()!=root->args && root->args.find('[')!=-1)
+ (
+ (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
+ (md->argsString()!=root->args && root->args.find('[')!=-1)
+ )
)
// not a php array variable
{
@@ -2600,7 +2605,7 @@ static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
FileDef *fd=rootNav->fileDef();
int l,i;
- static QRegExp re("([a-z_A-Z0-9: ]*[ *]*[ ]*");
+ static QRegExp re("([a-z_A-Z0-9: ]*[ &*]*[ ]*");
if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable
{
@@ -2784,10 +2789,6 @@ static void buildFunctionList(EntryNav *rootNav)
ClassDef *cd=0;
// check if this function's parent is a class
- static QRegExp re("([a-z_A-Z0-9: ]*[ *]*[ ]*");
- //printf("root->parent=`%s' %x cd=%p root->type.find(re,0)=%d\n",
- // root->parent->name.data(),root->parent->section,getClass(root->parent->name),
- // root->type.find(re,0));
QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
scope=stripTemplateSpecifiersFromScope(scope,FALSE);
@@ -2826,12 +2827,14 @@ static void buildFunctionList(EntryNav *rootNav)
}
+ static QRegExp re("([a-z_A-Z0-9: ]*[ &*]*[ ]*");
if (!rootNav->parent()->name().isEmpty() &&
(rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
cd &&
// do some fuzzy things to exclude function pointers
- (root->type.isEmpty() || root->type.find(re,0)==-1 ||
- root->type.find(")(")!=-1 || root->type.find("operator")!=-1
+ (root->type.isEmpty() ||
+ (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer
+ root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"
)
)
{
@@ -3122,6 +3125,10 @@ static void buildFunctionList(EntryNav *rootNav)
//printf("unrelated function %d `%s' `%s' `%s'\n",
// root->parent->section,root->type.data(),rname.data(),root->args.data());
}
+ else
+ {
+ Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());
+ }
}
else if (rname.isEmpty())
{
@@ -4030,7 +4037,7 @@ static bool findClassRelation(
// int *tempArgIndex;
// for (;(tempArgIndex=qdi.current());++qdi)
// {
- // printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex);
+ // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
// }
//}
//printf("\n");
@@ -4077,8 +4084,8 @@ static bool findClassRelation(
);
//printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
// baseClassName.data(),baseClass,cd,explicitGlobalScope);
- //printf(" root->name=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
- // root->name.data(),
+ //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
+ // cd ? cd->name().data():"<none>",
// baseClassName.data(),
// baseClass?baseClass->name().data():"<none>",
// templSpec.data()
@@ -4091,11 +4098,12 @@ static bool findClassRelation(
if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
{
Debug::print(
- Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s)\n",
+ Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
baseClassName.data(),
rootNav->name().data(),
(bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
- (bi->virt==Normal)?"normal":"virtual"
+ (bi->virt==Normal)?"normal":"virtual",
+ templSpec.data()
);
int i=baseClassName.find('<');
@@ -4142,17 +4150,19 @@ static bool findClassRelation(
bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
if (!found && si!=-1)
{
+ QCString tmpTemplSpec;
// replace any namespace aliases
replaceNamespaceAliases(baseClassName,si);
baseClass=getResolvedClass(cd,
cd->getFileDef(),
baseClassName,
&baseClassTypeDef,
- &templSpec,
+ &tmpTemplSpec,
mode==Undocumented,
TRUE
);
found=baseClass!=0 && baseClass!=cd;
+ if (found) templSpec = tmpTemplSpec;
}
//printf("root->name=%s biName=%s baseClassName=%s\n",
@@ -4227,6 +4237,8 @@ static bool findClassRelation(
else
{
baseClass=Doxygen::classSDict->find(baseClassName);
+ //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
+ // baseClassName.data(),baseClass,biName.data(),templSpec.data());
if (baseClass==0)
{
baseClass=new ClassDef(root->fileName,root->startLine,
@@ -5384,8 +5396,8 @@ static void findMember(EntryNav *rootNav,
// don't be fooled by anonymous scopes
tcd=cd;
}
- //printf("Looking for %s inside nd=%s result=%p\n",
- // scopeName.data(),nd?nd->name().data():"<none>",tcd);
+ //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
+ // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
if (cd && tcd==cd) // member's classes match
{
@@ -8825,6 +8837,9 @@ void initDoxygen()
ParserInterface *defaultParser = new CLanguageScanner;
Doxygen::parserManager = new ParserManager(defaultParser);
Doxygen::parserManager->registerParser(".py",new PythonLanguageScanner);
+ Doxygen::parserManager->registerParser(".f90", new FortranLanguageScanner);
+ Doxygen::parserManager->registerParser(".F90", new FortranLanguageScanner);
+
// register any additional parsers here...
diff --git a/src/fortrancode.h b/src/fortrancode.h
new file mode 100644
index 0000000..5f0366e
--- /dev/null
+++ b/src/fortrancode.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 1997-2006 by Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef CODE_H
+#define CODE_H
+
+#include "qtbc.h"
+#include <stdio.h>
+
+class CodeOutputInterface;
+class FileDef;
+class MemberDef;
+
+void parseFortranCode(CodeOutputInterface &,const char *,const QCString &,
+ bool ,const char *,FileDef *fd=0,
+ int startLine=-1,int endLine=-1,bool inlineFragment=FALSE,
+ MemberDef *memberDef=0);
+void resetFortranCodeParserState();
+void codeFreeScanner();
+
+#endif
diff --git a/src/fortrancode.l b/src/fortrancode.l
new file mode 100644
index 0000000..b780052
--- /dev/null
+++ b/src/fortrancode.l
@@ -0,0 +1,959 @@
+/******************************************************************************
+ *
+ * Parser for syntax hightlighting and references for Fortran90 F subset
+ *
+ * Copyright (C) by Anke Visser
+ * based on the work of Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+/**
+ @TODO - continutation lines not always recognized
+ - merging of use-statements with same module name and different only-names
+ - rename part of use-statement
+ - links to interface functions
+ - references to variables
+**/
+
+%{
+
+/*
+ * includes
+ */
+#include "qtbc.h"
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include "entry.h"
+#include "doxygen.h"
+#include "message.h"
+#include "outputlist.h"
+#include "util.h"
+#include "membername.h"
+#include "searchindex.h"
+#include "defargs.h"
+
+#define YY_NEVER_INTERACTIVE 1
+#define YY_NO_TOP_STATE 1
+
+//--------------------------------------------------------------------------------
+
+/**
+ data of an use-statement
+*/
+class UseEntry
+{
+ public:
+ QCString module; // just for debug
+ QStringList onlyNames; /* entries of the ONLY-part */
+};
+
+/**
+ module name -> list of ONLY/remote entries
+ (module name = name of the module, which can be accessed via use-directive)
+*/
+class UseSDict : public SDict<UseEntry>
+{
+ public:
+ UseSDict() : SDict<UseEntry>(17) {}
+};
+
+/*===================================================================*/
+/*
+ * statics
+ */
+
+static QCString docBlock; //!< contents of all lines of a documentation block
+static QCString currentModule=0; //!< name of the current enclosing module
+static UseSDict *useMembers= new UseSDict; //!< info about used modules
+static UseEntry *useEntry = 0; //!< current use statement info
+static QStack<QStringList> useStack; //!< contains names of used modules for current program tree
+static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
+static QCString str=""; //!> contents of fortran string
+
+static CodeOutputInterface * g_code;
+
+// TODO: is this still needed? if so, make it work
+static QCString g_parmType;
+static QCString g_parmName;
+
+static const char * g_inputString; //!< the code fragment as text
+static int g_inputPosition; //!< read offset during parsing
+static int g_inputLines; //!< number of line in the code fragment
+static int g_yyLineNr; //!< current line number
+static bool g_needsTermination;
+
+static bool g_insideBody; //!< inside subprog/program body? => create links
+static const char * g_currentFontClass;
+
+static bool g_exampleBlock;
+static QCString g_exampleName;
+static QCString g_exampleFile;
+
+static FileDef * g_sourceFileDef;
+static Definition * g_currentDefinition;
+static MemberDef * g_currentMemberDef;
+static bool g_includeCodeFragment;
+
+
+static void endFontClass()
+{
+ if (g_currentFontClass)
+ {
+ g_code->endFontClass();
+ g_currentFontClass=0;
+ }
+}
+
+static void startFontClass(const char *s)
+{
+ endFontClass();
+ g_code->startFontClass(s);
+ g_currentFontClass=s;
+}
+
+static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
+{
+ static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
+ if (searchEngineEnabled)
+ {
+ Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
+ }
+}
+
+static void addToSearchIndex(const char *text)
+{
+ static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
+ if (searchEngineEnabled)
+ {
+ Doxygen::searchIndex->addWord(text,FALSE);
+ }
+}
+
+/*! start a new line of code, inserting a line number if g_sourceFileDef
+ * is TRUE. If a definition starts at the current line, then the line
+ * number is linked to the documentation of that definition.
+ */
+static void startCodeLine()
+{
+ if (g_sourceFileDef)
+ {
+ //QCString lineNumber,lineAnchor;
+ //lineNumber.sprintf("%05d",g_yyLineNr);
+ //lineAnchor.sprintf("l%05d",g_yyLineNr);
+
+ Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
+ //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>");
+ if (!g_includeCodeFragment && d)
+ {
+ g_currentDefinition = d;
+ g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
+ g_insideBody = FALSE;
+ g_parmType.resize(0);
+ g_parmName.resize(0);
+ QCString lineAnchor;
+ lineAnchor.sprintf("l%05d",g_yyLineNr);
+ if (g_currentMemberDef)
+ {
+ g_code->writeLineNumber(g_currentMemberDef->getReference(),
+ g_currentMemberDef->getOutputFileBase(),
+ g_currentMemberDef->anchor(),g_yyLineNr);
+ setCurrentDoc(
+ g_currentMemberDef->qualifiedName(),
+ g_sourceFileDef->getSourceFileBase(),
+ lineAnchor);
+ }
+ else if (d->isLinkableInProject())
+ {
+ g_code->writeLineNumber(d->getReference(),
+ d->getOutputFileBase(),
+ 0,g_yyLineNr);
+ setCurrentDoc(
+ d->qualifiedName(),
+ g_sourceFileDef->getSourceFileBase(),
+ lineAnchor);
+ }
+ }
+ else
+ {
+ g_code->writeLineNumber(0,0,0,g_yyLineNr);
+ }
+ }
+ g_code->startCodeLine();
+ if (g_currentFontClass)
+ {
+ g_code->startFontClass(g_currentFontClass);
+ }
+}
+
+
+static void endFontClass();
+static void endCodeLine()
+{
+ if (g_currentFontClass) { g_code->endFontClass(); }
+ g_code->endCodeLine();
+}
+
+/*! write a code fragment `text' that may span multiple lines, inserting
+ * line numbers for each line.
+ */
+static void codifyLines(char *text)
+{
+ //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
+ char *p=text,*sp=p;
+ char c;
+ bool done=FALSE;
+ while (!done)
+ {
+ sp=p;
+ while ((c=*p++) && c!='\n');
+ if (c=='\n')
+ {
+ g_yyLineNr++;
+ *(p-1)='\0';
+ g_code->codify(sp);
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else
+ {
+ g_code->codify(sp);
+ done=TRUE;
+ }
+ }
+}
+
+static void codifyLines(QCString str)
+{
+ char *tmp= (char *) malloc(str.length()+1);
+ strcpy(tmp, str);
+ codifyLines(tmp);
+ free(tmp);
+}
+
+/*! writes a link to a fragment \a text that may span multiple lines, inserting
+ * line numbers for each line. If \a text contains newlines, the link will be
+ * split into multiple links with the same destination, one for each line.
+ */
+static void writeMultiLineCodeLink(CodeOutputInterface &ol,
+ const char *ref,const char *file,
+ const char *anchor,const char *text)
+{
+ bool done=FALSE;
+ char *p=(char *)text;
+ while (!done)
+ {
+ char *sp=p;
+ char c;
+ while ((c=*p++) && c!='\n');
+ if (c=='\n')
+ {
+ g_yyLineNr++;
+ *(p-1)='\0';
+ //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+ ol.writeCodeLink(ref,file,anchor,sp,0);
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else
+ {
+ //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+ ol.writeCodeLink(ref,file,anchor,sp,0);
+ done=TRUE;
+ }
+ }
+}
+
+/**
+ generates dictionay entries that are used if REFERENCED_BY_RELATION ... options are set
+ (e.g. the "referenced by ..." list after the function documentation)
+*/
+
+static void addDocCrossReference(MemberDef *src, MemberDef *dst)
+{
+ if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
+ //printf("======= addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
+ if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) &&
+ (src->isFunction()))
+ {
+ dst->addSourceReferencedBy(src);
+ }
+ if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && (src->isFunction()))
+ {
+ src->addSourceReferences(dst);
+ }
+}
+
+//-------------------------------------------------------------------------------
+/**
+ searches for definition of a type
+ @param memberName the name of the type
+ @param moduleName name of enclosing module or null, if global entry
+ @param cd the entry, if found or null
+ @param useList array of data of USE-statement
+ @returns true, if type is found
+*/
+static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
+ ClassDef *&cd, UseSDict *usedict=0)
+{
+ if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
+
+ //cout << "=== search for type: " << tname << endl;
+
+ // search for type
+ if ((cd=Doxygen::classSDict->find(tname)))
+ {
+ //cout << "=== type found in global module" << endl;
+ return TRUE;
+ }
+ else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname)))
+ {
+ //cout << "=== type found in local module" << endl;
+ return TRUE;
+ }
+ else
+ {
+ UseEntry *use;
+ for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di)
+ if ((cd= Doxygen::classSDict->find(use->module+"::"+tname)))
+ {
+ //cout << "=== type found in used module" << endl;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ searches for definition of function memberName
+ @param memberName the name of the function/variable
+ @param moduleName name of enclosing module or null, if global entry
+ @param memberDef the entry, if found or null
+ @param useList array of data of USE-statement
+ @returns true, if found
+*/
+static bool getFortranDefs(const QCString &memberName, const QCString &moduleName,
+ MemberDef *&md, UseSDict *usedict=0)
+{
+ if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */
+
+ // search for function
+ MemberName *mn = Doxygen::functionNameSDict->find(memberName);
+
+ if (mn) // name is known
+ {
+ MemberListIterator mli(*mn);
+ for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name
+ {
+ FileDef *fd=md->getFileDef();
+ GroupDef *gd=md->getGroupDef();
+
+ //cout << "found link with same name: " << fd->fileName() << " " << memberName;
+ //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
+
+ if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
+ {
+ NamespaceDef *nspace= md->getNamespaceDef();
+
+ if (nspace == 0)
+ { // found function in global scope
+ return TRUE;
+ }
+ else if (moduleName == nspace->name())
+ { // found in local scope
+ return TRUE;
+ }
+ else
+ { // else search in used modules
+ QCString moduleName= nspace->name();
+ UseEntry *ue= usedict->find(moduleName);
+ if (ue)
+ {
+ // check if only-list exists and if current entry exists is this list
+ QStringList &only= ue->onlyNames;
+ if (only.isEmpty())
+ {
+ //cout << " found in module " << moduleName << " entry " << memberName << endl;
+ return TRUE; // whole module used
+ }
+ else
+ {
+ for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
+ {
+ //cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl;
+ if (memberName == (QCString)(*it))
+ return TRUE; // found in ONLY-part of use list
+ }
+ }
+ }
+ }
+ } // if linkable
+ } // for
+ }
+ return FALSE;
+}
+
+/**
+ gets the link to a generic procedure which depends not on the name, but on the parameter list
+ @TODO implementation
+*/
+static bool getGenericProcedureLink(const ClassDef *cd,
+ const char *memberText,
+ CodeOutputInterface &ol)
+{
+ (void)cd;
+ (void)memberText;
+ (void)ol;
+ return FALSE;
+}
+
+static bool getLink(UseSDict *usedict, // dictonary with used modules
+ const char *memberText, // exact member text
+ CodeOutputInterface &ol,
+ const char *text)
+{
+ MemberDef *md;
+ QCString memberName= removeRedundantWhiteSpace(memberText);
+ //printf("Trying `%s'::`%s'\n",c.data(),m.data());
+
+ if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable())
+ {
+ //if (md->isVariable()) return FALSE; // variables aren't handled yet
+
+ Definition *d = md->getOuterScope()==Doxygen::globalScope ?
+ md->getBodyDef() : md->getOuterScope();
+ if (md->getGroupDef()) d = md->getGroupDef();
+ if (d && d->isLinkable())
+ {
+ if (g_currentDefinition && g_currentMemberDef && md!=g_currentMemberDef && g_insideBody)
+ {
+ addDocCrossReference(g_currentMemberDef,md);
+ }
+ ol.linkableSymbol(g_yyLineNr,md->name(),md,
+ g_currentMemberDef ? g_currentMemberDef : g_currentDefinition);
+ writeMultiLineCodeLink(ol,md->getReference(),
+ md->getOutputFileBase(),
+ md->anchor(),
+ text ? text : memberText);
+ addToSearchIndex(text ? text : memberText);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+static void generateLink(CodeOutputInterface &ol, char *lname)
+{
+ ClassDef *cd=0;
+
+ // check if lname is a linkable type or interface
+ if ( (getFortranTypeDefs(lname, currentModule, cd, useMembers)) && cd->isLinkable() )
+ {
+ if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
+ (getGenericProcedureLink(cd, lname, ol)) )
+ {
+ //cout << "=== generic procedure resolved" << endl;
+ }
+ else
+ { // write type or interface link
+ ol.linkableSymbol(g_yyLineNr, lname, cd, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
+ writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,lname);
+ addToSearchIndex(lname);
+ }
+ }
+ // check for function/variable
+ else if (getLink(useMembers, lname, ol, lname))
+ {
+ //cout << "=== found link for " << lname << endl;
+ }
+ else
+ {
+ // nothing found, just write out the word
+ ol.linkableSymbol(g_yyLineNr, lname, 0, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
+ //startFontClass("charliteral"); //test
+ codifyLines(lname);
+ //endFontClass(); //test
+ addToSearchIndex(lname);
+ }
+}
+
+/*! counts the number of lines in the input */
+static int countLines()
+{
+ const char *p=g_inputString;
+ char c;
+ int count=1;
+ while ((c=*p))
+ {
+ p++ ;
+ if (c=='\n') count++;
+ }
+ if (p>g_inputString && *(p-1)!='\n')
+ { // last line does not end with a \n, so we add an extra
+ // line and explicitly terminate the line after parsing.
+ count++,
+ g_needsTermination=TRUE;
+ }
+ return count;
+}
+
+//----------------------------------------------------------------------------
+/** start use list */
+void startUseScope()
+{
+ //fprintf("===> startUse %s",yytext);
+ useStack.push(currentUseNames);
+ currentUseNames= new QStringList;
+}
+
+/** end use list */
+void endUseScope()
+{
+ //fprintf(stderr,"===> endUse %s",yytext);
+ //UseSDict::Iterator di(*useMembers); UseEntry *ue;
+ //for (di.toFirst(); ue=di.current(); ++di){cout << ue->module ;} cout << endl;
+
+ for ( QStringList::Iterator it = currentUseNames->begin(); it != currentUseNames->end(); ++it)
+ {
+ useMembers->remove(*it);
+ }
+ delete currentUseNames;
+ currentUseNames= useStack.pop();
+ if (currentUseNames == 0)
+ {
+ fprintf(stderr,"fortrancode.l: stack empty!");
+ //exit(-1);
+ }
+}
+
+void addUse(QString moduleName)
+{
+ currentUseNames->append(moduleName);
+}
+//----------------------------------------------------------------------------
+
+/* -----------------------------------------------------------------*/
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
+
+static int yyread(char *buf,int max_size)
+{
+ int c=0;
+ while( c < max_size && g_inputString[g_inputPosition] )
+ {
+ *buf = g_inputString[g_inputPosition++] ;
+ c++; buf++;
+ }
+ return c;
+}
+
+%}
+
+IDSYM [a-z_A-Z0-9]
+ID [a-z_A-Z]+{IDSYM}*
+SUBPROG (subroutine|function)
+B [ \t]
+BS [ \t]*
+BS_ [ \t]+
+COMMA {BS},{BS}
+ARGS {BS}("("[^)]*")"){BS}
+
+NUM_TYPE (complex|integer|logical|real)
+KIND {ARGS}
+CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"([0-9]+|{ARGS}))
+TYPE_SPEC (({NUM_TYPE}("*"[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}PRECISION|{CHAR})
+
+INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
+ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET)
+ACCESS_SPEC (PRIVATE|PUBLIC)
+/* Assume that attribute statements are almost the same as attributes. */
+ATTR_STMT {ATTR_SPEC}|DIMENSION
+COMMANDS (BLOCK{BS}DATA|DO|SELECT|CASE|WHERE|IF|THEN|ELSE|MODULE{BS_}PROCEDURE)
+IGNORE (IMPLICIT{BS}NONE|CONTAINS|WRITE|READ|ALLOCATE|DEALLOCATE|SIZE)
+
+/* | */
+
+%option noyywrap
+%option stack
+%option caseless
+/*%option debug*/
+
+%x Start
+%x SubCall
+%x FuncDef
+%x ClassName
+%x ClassVar
+%x Subprog
+%x DocBlock
+%x Use
+%x UseOnly
+%x TypeDecl
+%x Declaration
+%x DeclContLine
+%x Parameterlist
+%x String
+
+%%
+ /*==================================================================*/
+
+ /*-------- ignore ------------------------------------------------------------*/
+
+<Start>{IGNORE}/{BS}"("? { // do not search keywords, intrinsics... @TODO: complete list
+ codifyLines(yytext);
+ }
+ /*-------- inner construct ---------------------------------------------------*/
+
+<Start>{COMMANDS}/[,( \t\n].* { // hightlight rest of fortran statements
+ /* font class is defined e.g. in doxygen.css */
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+<Start>"end"{BS}{COMMANDS}/[ \t\n].* {
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+
+ /*-------- use statement -------------------------------------------*/
+<Start>"use"{BS_} {
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(Use);
+ }
+<Use>{ID} {
+ startFontClass("keywordflow");
+ codifyLines(yytext);
+ endFontClass();
+
+ /* append module name to use dict */
+ useEntry = new UseEntry();
+ useEntry->module = yytext;
+ useMembers->append(yytext, useEntry);
+ addUse(yytext);
+ }
+<Use>,{BS}"ONLY" { // TODO: rename
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(UseOnly);
+ }
+<UseOnly>{BS},{BS} { codifyLines(yytext); }
+<UseOnly>{ID} {
+ codifyLines(yytext);
+ useEntry->onlyNames.append(yytext);
+ }
+<Use,UseOnly>"\n" {
+ unput(*yytext);
+ yy_pop_state();
+ }
+
+ /*-------- fortran module -----------------------------------------*/
+<Start>("program"|"module"|"type"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
+ startUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ yy_push_state(YY_START);
+ BEGIN(ClassName);
+ if (!strcmp(yytext,"module")) currentModule="module";
+ }
+<ClassName>{ID} {
+ if (currentModule == "module") currentModule=yytext;
+ generateLink(*g_code,yytext);
+ yy_pop_state();
+ }
+<ClassName>\n { // interface may be without name
+ yy_pop_state();
+ REJECT;
+ }
+<Start>"end"{BS}"module".* { // just reset currentModule, rest is done in following rule
+ currentModule=0;
+ REJECT;
+ }
+<Start>"end"{BS}("program"|"module"|"type"|"interface") { //
+ endUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+
+ /*-------- subprog definition -------------------------------------*/
+<Start>{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+<Start>{SUBPROG}{BS_} { // Fortran subroutine or function found
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ yy_push_state(YY_START);
+ BEGIN(Subprog);
+ }
+<Subprog>{ID} { // subroutine/function name
+ //cout << "===> start procedure " << yytext << endl;
+ startUseScope();
+ generateLink(*g_code,yytext);
+ }
+<Subprog>"(".* { // ignore rest of line
+ codifyLines(yytext);
+ }
+<Subprog>"\n" { codifyLines(yytext);
+ yy_pop_state();
+ }
+<Start>"end"{BS}{SUBPROG}.* { // Fortran subroutine or function ends
+ //cout << "===> end function " << yytext << endl;
+ endUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*-------- variable declaration ----------------------------------*/
+<Start>"TYPE"{BS}"(" {
+ yy_push_state(YY_START);
+ BEGIN(TypeDecl);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<TypeDecl>{ID} { // link type
+ g_insideBody=TRUE;
+ generateLink(*g_code,yytext);
+ g_insideBody=FALSE;
+ }
+<TypeDecl>")" {
+ BEGIN(Declaration);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Start>{TYPE_SPEC}/[,:( ] {
+ yy_push_state(YY_START);
+ BEGIN(Declaration);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Start>{ATTR_SPEC} {
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Declaration>"&" { // continuation line
+ yy_push_state(YY_START);
+ BEGIN(DeclContLine);
+ }
+<DeclContLine>"\n" { // declaration not yet finished
+ codifyLines(yytext);
+ yy_pop_state();
+ }
+<Declaration>"\n" { // end declaration line
+ codifyLines(yytext);
+ yy_pop_state();
+ }
+
+ /*-------- subprog calls -----------------------------------------*/
+
+<Start>"call"{BS_} {
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(SubCall);
+ }
+<SubCall>{ID} { // subroutine call
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ yy_pop_state();
+ }
+<Start>{ID}{BS}/"(" { // function call
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ }
+
+ /*-------- comments ---------------------------------------------------*/
+<Start>\n?{BS}"!>" { // start comment line or comment block
+ yy_push_state(YY_START);
+ BEGIN(DocBlock);
+ docBlock=yytext;
+ }
+
+<DocBlock>.* { // contents of current comment line
+ docBlock+=yytext;
+ }
+<DocBlock>"\n"{BS}("!>"|"!"+) { //| comment block (next line is also comment line)
+ docBlock+=yytext;
+ }
+<DocBlock>"\n" { // comment block ends at the end of this line
+ docBlock+=yytext;
+ // remove special comment (default config)
+ if (Config_getBool("STRIP_CODE_COMMENTS"))
+ {
+ g_yyLineNr+=((QCString)docBlock).contains('\n');
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else // do not remove comment
+ {
+ startFontClass("comment");
+ codifyLines(docBlock);
+ endFontClass();
+ }
+ yy_pop_state();
+ }
+
+<*>"!"[^>\n].*|"!"$ { // normal comment
+ startFontClass("comment");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*------ preprocessor --------------------------------------------*/
+<Start>"#".*\n { startFontClass("preprocessor");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*------ variable references? -------------------------------------*/
+<Start>{ID} {
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ }
+
+ /*------ strings --------------------------------------------------*/
+<*>"\\\\" { str+=yytext; /* ignore \\ */}
+<*>"\\\"" { str+=yytext; /* ignore \" */}
+
+<String>\" { // string ends with next quote without previous backspace
+ str+=yytext;
+ startFontClass("stringliteral");
+ codifyLines(str);
+ endFontClass();
+ yy_pop_state();
+ }
+<*>\" { /* string starts */
+ yy_push_state(YY_START);
+ BEGIN(String);
+ str=yytext;
+ }
+<String>. {str+=yytext;}
+
+
+ /*-----------------------------------------------------------------------------*/
+
+<*>\n {
+ codifyLines(yytext);
+ }
+<*>. {
+ g_code->codify(yytext);
+ }
+%%
+
+/*@ ----------------------------------------------------------------------------
+ */
+
+/*===================================================================*/
+
+void resetFortranCodeParserState() {}
+
+void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s,
+ bool exBlock, const char *exName,FileDef *fd,
+ int startLine,int endLine,bool inlineFragment,
+ MemberDef *memberDef)
+{
+ //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
+
+ // used parameters
+ (void)memberDef;
+ (void)className;
+
+ if (s.isEmpty()) return;
+ g_code = &od;
+ g_inputString = s;
+ g_inputPosition = 0;
+ g_currentFontClass = 0;
+ g_needsTermination = FALSE;
+ if (endLine!=-1)
+ g_inputLines = endLine+1;
+ else
+ g_inputLines = countLines();
+
+ if (startLine!=-1)
+ g_yyLineNr = startLine;
+ else
+ g_yyLineNr = 1;
+
+ g_exampleBlock = exBlock;
+ g_exampleName = exName;
+ g_sourceFileDef = fd;
+ if (exBlock && fd==0)
+ {
+ // create a dummy filedef for the example
+ g_sourceFileDef = new FileDef("",exName);
+ }
+ if (g_sourceFileDef)
+ {
+ setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase());
+ }
+ g_currentDefinition = 0;
+ g_currentMemberDef = 0;
+ if (!g_exampleName.isEmpty())
+ {
+ g_exampleFile = convertNameToFile(g_exampleName+"-example");
+ }
+ g_includeCodeFragment = inlineFragment;
+ startCodeLine();
+ g_parmName.resize(0);
+ g_parmType.resize(0);
+ fcodeYYrestart( fcodeYYin );
+ BEGIN( Start );
+ fcodeYYlex();
+ if (g_needsTermination)
+ {
+ endFontClass();
+ g_code->endCodeLine();
+ }
+ if (exBlock && g_sourceFileDef)
+ {
+ // delete the temporary file definition used for this example
+ delete g_sourceFileDef;
+ g_sourceFileDef=0;
+ }
+ return;
+}
+
+#if !defined(YY_FLEX_SUBMINOR_VERSION)
+extern "C" { // some bogus code to keep the compiler happy
+ void fcodeYYdummy() { yy_flex_realloc(0,0); }
+}
+#elif YY_FLEX_SUBMINOR_VERSION<33
+#error "You seem to be using a version of flex newer than 2.5.4 but older than 2.5.33. These versions do NOT work with doxygen! Please use version <=2.5.4 or >=2.5.33 or expect things to be parsed wrongly!"
+#endif
+
diff --git a/src/fortranscanner.h b/src/fortranscanner.h
new file mode 100644
index 0000000..2e16c67
--- /dev/null
+++ b/src/fortranscanner.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 1997-2006 by Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef SCANNER_FORTRAN_H
+#define SCANNER_FORTRAN_H
+
+#include "parserintf.h"
+
+/** \brief Fortran language parser using state-based lexical scanning.
+ *
+ * This is the Fortran language parser for doxygen.
+ */
+class FortranLanguageScanner : public ParserInterface
+{
+ public:
+ virtual ~FortranLanguageScanner() {}
+ void parseInput(const char *fileName,
+ const char *fileBuf,
+ Entry *root);
+ bool needsPreprocessing(const QCString &extension);
+ void parseCode(CodeOutputInterface &codeOutIntf,
+ const char *scopeName,
+ const QCString &input,
+ bool isExampleBlock,
+ const char *exampleName=0,
+ FileDef *fileDef=0,
+ int startLine=-1,
+ int endLine=-1,
+ bool inlineFragment=FALSE,
+ MemberDef *memberDef=0
+ );
+ void resetCodeParserState();
+ void parsePrototype(const char *text);
+};
+
+#endif
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
new file mode 100644
index 0000000..e4ef1f8
--- /dev/null
+++ b/src/fortranscanner.l
@@ -0,0 +1,1333 @@
+/* -*- mode: fundamental; indent-tabs-mode: 1; -*- */
+/*****************************************************************************
+ * Parser for Fortran90 F subset
+ *
+ * Copyright (C) by Anke Visser
+ * based on the work of Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+/* Developer notes.
+ *
+ * - Consider using startScope(), endScope() functions with module, program,
+ * subroutine or any other scope in fortran program.
+ *
+ * - Symbol modifiers (attributes) are collected using SymbolModifiers |= operator during
+ * substructure parsing. When substructure ends all modifiers are applied to actual
+ * entries in applyModifiers() functions.
+ *
+ * - How case insensitiveness should be handled in code?
+ * On one side we have arg->name and entry->name, on another side modifierMap[name].
+ * In entries and arguments case is the same as in code, in modifier map case is lowered and
+ * then it is compared to lowered entry/argument names.
+ *
+ * - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space
+ * with separate rule?: It seems it is often necessary, because we may parse something like
+ * "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]'
+ * are desired.
+ */
+
+%{
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "qtbc.h"
+#include <qarray.h>
+#include <qstack.h>
+#include <qregexp.h>
+#include <unistd.h>
+#include <qfile.h>
+#include <qmap.h>
+
+#include "fortranscanner.h"
+#include "entry.h"
+#include "message.h"
+#include "config.h"
+#include "doxygen.h"
+#include "util.h"
+#include "defargs.h"
+#include "language.h"
+#include "commentscan.h"
+#include "fortrancode.h"
+#include "pre.h"
+
+#define YY_NEVER_INTERACTIVE 1
+
+enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER};
+
+// {{{ ----- Helper structs -----
+//! Holds modifiers (ie attributes) for one symbol (variable, function, etc)
+struct SymbolModifiers {
+ enum Protection {NONE_P, PUBLIC, PRIVATE};
+ enum Direction {NONE_D, IN, OUT, INOUT};
+
+ //!< This is only used with function return value.
+ QString type, returnName;
+ Protection protection;
+ Direction direction;
+ bool optional;
+ QString dimension;
+ bool allocatable;
+ bool external;
+ bool intrinsic;
+ bool parameter;
+ bool pointer;
+ bool target;
+ bool save;
+
+ SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D),
+ optional(FALSE), dimension(), allocatable(FALSE),
+ external(FALSE), intrinsic(FALSE), parameter(FALSE),
+ pointer(FALSE), target(FALSE), save(FALSE) {}
+
+ SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
+ SymbolModifiers& operator|=(QString mdfrString);
+};
+
+//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs);
+
+static const char *directionStrs[] =
+{
+ "", "intent(in)", "intent(out)", "intent(inout)"
+};
+
+// }}}
+
+/* -----------------------------------------------------------------
+ *
+ * statics
+ */
+static ParserInterface *g_thisParser;
+static const char * inputString;
+static int inputPosition;
+static QFile inputFile;
+static QCString yyFileName;
+static int yyLineNr = 1 ;
+static Entry* current_root = 0 ;
+static Entry* global_root = 0 ;
+static Entry* file_root = 0 ;
+static Entry* current = 0 ;
+static Entry* last_entry = 0 ;
+static ScanVar v_type = V_IGNORE; // type of parsed variable
+static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved
+ // module procedures
+static QCString docBlock;
+static QCString docBlockName;
+static bool docBlockInBody;
+static bool docBlockJavaStyle;
+
+static MethodTypes mtype;
+static bool gstat;
+static Specifier virt;
+
+static QString debugStr;
+static QCString result; // function result
+static Argument *parameter; // element of parameter list
+static QCString argType; // fortran type of an argument of a parameter list
+static QCString argName; // last identifier name in variable list
+static QCString initializer; // initial value of a variable
+static QCString useModuleName; // name of module in the use statement
+static Protection defaultProtection;
+
+static char stringStartSymbol; // single or double quote
+
+//! Accumulated modifiers of current statement, eg variable declaration.
+static SymbolModifiers currentModifiers;
+//! Holds program scope->symbol name->symbol modifiers.
+static QMap<Entry*,QMap<QString,SymbolModifiers> > modifiers;
+
+//-----------------------------------------------------------------------------
+
+static int yyread(char *buf,int max_size);
+static void startCommentBlock(bool);
+static void handleCommentBlock(const QCString &doc,bool brief);
+static void addCurrentEntry();
+static void addInterface(QString name);
+static Argument *addFortranParameter(const QCString &type,const QCString &name, const QString docs);
+static void scanner_abort();
+
+static void startScope(Entry *scope);
+static bool endScope(Entry *scope);
+static QString getFullName(Entry *e);
+static bool isTypeName(QString name);
+static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
+
+//-----------------------------------------------------------------------------
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
+//-----------------------------------------------------------------------------
+
+%}
+
+ //-----------------------------------------------------------------------------
+ //-----------------------------------------------------------------------------
+IDSYM [a-z_A-Z0-9]
+NOTIDSYM [^a-z_A-Z0-9]
+SEPARATE [:, \t]
+ID [a-z_A-Z]+{IDSYM}*
+PP_ID {ID}
+LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]*
+SUBPROG (subroutine|function)
+B [ \t]
+BS [ \t]*
+BS_ [ \t]+
+COMMA {BS},{BS}
+ARGS {BS}("("[^)]*")"){BS}
+NOARGS {BS}"\n"
+
+NUM_TYPE (complex|integer|logical|real)
+KIND {ARGS}
+CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"([0-9]+|{ARGS}))
+TYPE_SPEC (({NUM_TYPE}("*"[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}PRECISION|{CHAR}|TYPE{ARGS})
+
+INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
+ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET)
+ACCESS_SPEC (PRIVATE|PUBLIC)
+/* Assume that attribute statements are almost the same as attributes. */
+ATTR_STMT {ATTR_SPEC}|DIMENSION
+
+%option noyywrap
+%option stack
+%option caseless
+/*%option debug */
+
+ //---------------------------------------------------------------------------------
+
+ /** fortran parsing states */
+%x Subprog
+%x Parameterlist
+%x SubprogBody
+%x Start
+%x Comment
+%x Module
+%x ModuleBody
+%x AttributeList
+%x Variable
+%x Initialization
+%x ArrayInitializer
+%x Typedef
+%x TypedefBody
+%x InterfaceBody
+%x StrIgnore
+%x String
+%x Use
+%x UseOnly
+%x ModuleProcedure
+
+ /** comment parsing states */
+%x DocBlock
+%x DocBackLine
+%x EndDoc
+
+%%
+
+ /*-----------------------------------------------------------------------------------*/
+
+<*>"&".*"\n" { if (YY_START == String) REJECT; // "&" is ignored in strings
+ yyLineNr++;} /* line not finished -> read next line (text after "&" may be
+ comment and has to be ignored */
+
+ /*------ ignore strings */
+<*>"\\\\" { /* ignore \\ */}
+<*>"\\\""|\\\' { /* ignore \" and \' */}
+
+<String>\"|\' { // string ends with next quote without previous backspace
+ if(yytext[0]!=stringStartSymbol) REJECT; // single vs double quote
+ // cout << "string end: " << debugStr << endl;
+ yy_pop_state();
+ }
+
+<String>. {debugStr+=yytext;} // ignore String contents (especially '!')
+
+<*>\"|\' { /* string starts */
+ if(YY_START == StrIgnore) REJECT; // ignore in simple comments
+ // cout << "string start: " << yytext[0] << yyLineNr << endl;
+ yy_push_state(YY_START);
+ stringStartSymbol=yytext[0]; // single or double quote
+ BEGIN(String); debugStr="!^!";
+ }
+
+ /*------ ignore simple comment (not documentation comments) */
+
+<*>"!"/[^<>\n] { if (YY_START == String) REJECT; // "!" is ignored in strings
+ // skip comment line (without docu comments "!>" "!<" )
+ /* ignore further "!" and ignore comments in Strings */
+ if ((YY_START != StrIgnore) && (YY_START != String)) {
+ yy_push_state(YY_START);
+ BEGIN(StrIgnore);
+ debugStr="*!";
+ //cout << "start comment "<< yyLineNr << endl;
+ }
+ }
+<StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character
+ //cout << "end comment " << yyLineNr <<" "<< debugStr << endl;
+ } // comment line ends
+<StrIgnore>. { debugStr+=yytext; }
+
+
+ /*------ use handling ------------------------------------------------------------*/
+
+<Start,ModuleBody,TypedefBody,SubprogBody>"use"{BS_} {
+ yy_push_state(YY_START);
+ BEGIN(Use);
+ }
+<Use>{ID} {
+ //cout << "using dir "<< yytext << endl;
+ current->name=yytext;
+ current->fileName = yyFileName;
+ current->section=Entry::USINGDIR_SEC;
+ current_root->addSubEntry(current);
+ current = new Entry;
+ yy_pop_state();
+ }
+<Use>{ID}/, {
+ useModuleName=yytext;
+ }
+<Use>,{BS}"ONLY" { BEGIN(UseOnly);
+ }
+<UseOnly>{BS},{BS} {}
+<UseOnly>{ID} {
+ current->name= useModuleName+"::"+yytext;
+ current->fileName = yyFileName;
+ current->section=Entry::USINGDECL_SEC;
+ current_root->addSubEntry(current);
+ current = new Entry ;
+ }
+<Use,UseOnly>"\n" {
+ unput(*yytext);
+ yy_pop_state();
+ }
+
+ /*------ ignore special fortran statements */
+<Start,ModuleBody,SubprogBody>(^|[ \t])interface({BS_}{ID})?/[ \t\n] { // handle interface block
+ QString name = yytext;
+ int index = name.find("interface", 0, FALSE);
+ index = name.find(QRegExp("[^ \\t]"), index+9);
+ //cout<<name<<", "<<index<<endl;
+ if(index!=-1)
+ name = name.right(name.length()-index);
+ else // interface without name, must be inside subprog
+ name = "interface";
+ addInterface(name);
+ yy_push_state(InterfaceBody);
+ startScope(last_entry);
+ }
+<InterfaceBody>"end"{BS}"interface".* {
+ if(!endScope(current_root))
+ yyterminate();
+ yy_pop_state();
+ //cout << "end interface " << yyLineNr
+ // <<", "<<Interface<<endl;
+ }
+<InterfaceBody>module{BS}procedure { yy_push_state(YY_START);
+ BEGIN(ModuleProcedure);
+ }
+<ModuleProcedure>{ID} {
+ current->section = Entry::FUNCTION_SEC ;
+ current->name = yytext;
+ moduleProcedures.append(current);
+ addCurrentEntry();
+ }
+<ModuleProcedure>"\n" { unput(*yytext);
+ yy_pop_state();
+ }
+<InterfaceBody>. {}
+
+ /*------ module handling ------------------------------------------------------------*/
+<Start>module|program{BS_} { //
+ BEGIN(Module);
+ defaultProtection = Public;
+ }
+<Start,ModuleBody>"end"{BS}(module|program).* { // end module
+ resolveModuleProcedures(moduleProcedures, current_root);
+ if(!endScope(current_root))
+ yyterminate();
+ defaultProtection = Public;
+ BEGIN(Start);
+ }
+<Module>{ID} {
+ //cout << "0=========> got module " << yytext << endl;
+ current->section = Entry::NAMESPACE_SEC;
+ current->name = yytext;
+ current->type = "module";
+ current->fileName = yyFileName;
+ current->bodyLine = yyLineNr; // used for source reference
+ current->protection = Public ;
+
+ addCurrentEntry();
+ startScope(last_entry);
+
+ BEGIN(ModuleBody);
+ }
+
+ /*------- access specification --------------------------------------------------------------------------*/
+
+<ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private; }
+<ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public; }
+
+ /*------- type definition -------------------------------------------------------------------------------*/
+
+<Start,ModuleBody>"type"({BS_}|({COMMA}{ACCESS_SPEC})) { /* type definition found : TYPE , access-spec::type-name |*/
+ yy_push_state(YY_START);
+ BEGIN(Typedef);
+ current->protection = defaultProtection;
+ }
+<Typedef>{ACCESS_SPEC} {
+ QString type= yytext;
+ }
+<Typedef>{ID} { /* type name found */
+ //cout << "=========> got typedef " << yytext << ": " << yyLineNr << endl;
+ current->section = Entry::CLASS_SEC; // was Entry::STRUCT_SEC;
+ current->spec = Entry::Struct;
+ current->name = yytext;
+
+ /* if type is part of a module, mod name is necessary for output */
+ if ((current_root) &&
+ (current_root->section == Entry::CLASS_SEC ||
+ current_root->section == Entry::NAMESPACE_SEC))
+ //current_root->section == Entry::INTERFACE_SEC))
+ {
+ current->name= current_root->name+"::"+current->name;
+ }
+ current->fileName = yyFileName;
+ current->bodyLine = yyLineNr;
+ addCurrentEntry();
+ startScope(last_entry);
+ BEGIN(TypedefBody);
+ }
+<TypedefBody>"end"{BS}"type".* { /* end type definition */
+ //cout << "=========> got typedef end "<< endl;
+ if(!endScope(current_root))
+ yyterminate();
+ yy_pop_state();
+ }
+
+ /*------- module/global/typedef variable ---------------------------------------------------*/
+
+<Start,ModuleBody,TypedefBody,SubprogBody>{
+{TYPE_SPEC}/{SEPARATE} {
+ /* variable declaration starts */
+ //cout << "4=========> got variable type: " << yytext << endl;
+ QString help=yytext;
+ help= help.simplifyWhiteSpace();
+ argType= help.latin1();
+ yy_push_state(AttributeList);
+ }
+^{BS}{PP_ID}{KIND}? { /* check for preprocessor symbol expand to type */
+ QString str = yytext;
+ str = str.stripWhiteSpace();
+ DefineDict* defines = getFileDefineDict();
+ QString name;
+ int index = str.find("(");
+ if(index != -1)
+ name = str.left(index).stripWhiteSpace();
+ else
+ name = str;
+
+ Define *define = (*defines)[name];
+ if(define != NULL && isTypeName(define->definition)) {
+ argType = str;
+ yy_push_state(AttributeList);
+ } else {
+ REJECT;
+ }
+ }
+{ATTR_STMT}{BS}/{ID} {
+ /* attribute statement starts */
+ //cout << "5=========> Attribute statement: "<< yytext << endl;
+ QString tmp = yytext;
+ currentModifiers |= tmp.stripWhiteSpace();
+ argType="";
+ yy_push_state(YY_START);
+ /* goto attribute parsing, however there must not be one,
+ just catch "::" if it is there. */
+ BEGIN( AttributeList ) ;
+ }
+}
+<AttributeList>{
+{COMMA} {}
+{BS} {}
+{ATTR_SPEC} { /* update current modifiers */
+ QString tmp = yytext;
+ currentModifiers |= (tmp);
+ }
+"::" { /* end attribute list */
+ BEGIN( Variable );
+ }
+. { /* unknown attribute, consider variable name */
+ //cout<<"start variables, unput "<<*yytext<<endl;
+ unput(*yytext);
+ BEGIN( Variable );
+ }
+}
+
+<Variable>{BS} {}
+<Variable>{ID} { /* parse variable declaration */
+ //cout << "5=========> got variable: " << argType << "::" << yytext << endl;
+ /* work around for bug in QCString.replace (QString works) */
+ QString name=yytext;
+ /* remember attributes for the symbol */
+ modifiers[current_root][name.lower()] |= currentModifiers;
+ argName= name.latin1();
+ int last= yy_top_state();
+
+ v_type= V_IGNORE;
+ if (!argType.isEmpty() && last != SubprogBody) { // new variable entry
+ v_type = V_VARIABLE;
+ current->section = Entry::VARIABLE_SEC;
+ current->name = argName;
+ current->type = argType;
+ current->fileName = yyFileName;
+ current->bodyLine = yyLineNr; // used for source reference
+ addCurrentEntry();
+ } else if(!argType.isEmpty()){ // deklaration of parameter list: add type for corr. parameter
+ parameter= addFortranParameter(argType,argName,docBlock);
+ if (parameter) v_type= V_PARAMETER;
+ // save, it may be function return type
+ modifiers[current_root][name.lower()].type = argType;
+ // any accumulated doc for argument should be emptied,
+ // because it is handled other way and this doc can be
+ // unexpectedly passed to the next member.
+ current->doc.resize(0);
+ current->brief.resize(0);
+ }
+ }
+<Variable>{ARGS} { /* dimension of the previous entry. */
+ QString name(argName);
+ QString attr("dimension");
+ attr += yytext;
+ modifiers[current_root][name] |= attr;
+ }
+<Variable>{COMMA} {}
+<Variable>{BS}"=" { yy_push_state(YY_START);
+ initializer="";
+ BEGIN(Initialization);
+ }
+<Variable>"\n" { currentModifiers = SymbolModifiers();
+ yy_pop_state(); // end variable deklaration list
+ yyLineNr++;
+ docBlock.resize(0);
+ }
+
+<Initialization>"(/" { initializer+=yytext;
+ BEGIN(ArrayInitializer); // initializer may contain comma
+ }
+<ArrayInitializer>. { initializer+=yytext; }
+<ArrayInitializer>"/)" { initializer+=yytext;
+ yy_pop_state(); // end initialization
+ if (v_type == V_VARIABLE) last_entry->initializer= initializer;
+ }
+<Initialization>{COMMA} { yy_pop_state(); // end initialization
+ if (v_type == V_VARIABLE) last_entry->initializer= initializer;
+ }
+<Initialization>"\n"|"!" { //|
+ yy_pop_state(); // end initialization
+ if (v_type == V_VARIABLE) last_entry->initializer= initializer;
+ unput(*yytext);
+ }
+<Initialization>. { initializer+=yytext; }
+
+ /*------ fortran subroutine/function handling ------------------------------------------------------------*/
+ /* Start is initial condition */
+
+<Start,ModuleBody,InterfaceBody>{TYPE_SPEC}{BS}/{SUBPROG}{BS_} {
+ // TYPE_SPEC is for old function style function result
+ result= yytext;
+ result= result.stripWhiteSpace();
+ current->type = result;
+ }
+<Start,ModuleBody,SubprogBody,InterfaceBody>{BS}{SUBPROG}{BS_} { // Fortran subroutine or function found
+ //cout << "1=========> got subprog, type:" << yytext <<endl;
+ current->section = Entry::FUNCTION_SEC ;
+ QCString subtype = yytext; subtype=subtype.lower().stripWhiteSpace();
+ if (!current->type) current->type = subtype;
+ current->fileName = yyFileName;
+ current->bodyLine = yyLineNr; // used for source reference
+ current->startLine = -1; // ??? what is startLine for?
+ current->args.resize(0);
+ current->argList->clear();
+ yy_push_state(Subprog);
+ docBlock.resize(0);
+ }
+<Subprog>{BS} { /* ignore white space */ }
+<Subprog>{ID} { current->name = yytext;
+ //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
+ modifiers[current_root][current->name.lower()].returnName = current->name;
+ BEGIN(Parameterlist);
+ }
+<Parameterlist>{ARGS} {
+ //current->type not yet available
+ QString arglist= yytext;
+ //cout << "3=========> got parameterlist " << yytext << endl;
+ yyLineNr+= arglist.contains('\n');
+ arglist = arglist.replace(QRegExp("&[^\n]*\n"),"");
+ //cout << "3=========> got parameterlist " << arglist << endl;
+ current->args = arglist;
+ current->args = removeRedundantWhiteSpace(current->args);
+ stringToArgumentList(current->args, current->argList);
+ addCurrentEntry();
+ startScope(last_entry);
+ BEGIN(SubprogBody);
+ }
+<Parameterlist>{NOARGS} {
+ yyLineNr++;
+ //cout << "3=========> without parameterlist " <<endl;
+ stringToArgumentList("", current->argList);
+ addCurrentEntry();
+ startScope(last_entry);
+ BEGIN(SubprogBody);
+}
+<SubprogBody>result{BS}\({BS}{ID} {
+ result= yytext;
+ result= result.right(result.length()-result.find("(")-1);
+ result= result.stripWhiteSpace();
+ modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
+ //cout << "=====> got result " << result << endl;
+ }
+<SubprogBody>"end"{BS}{SUBPROG}.* {
+ //cout << "1e=========> got end subprog: " << yytext << endl;
+
+ /* args is used for parameters in list of functions, argList for
+ parameters in detailed function descripttion */
+ //current->args = argListToString(current->argList);
+ //current->endBodyLine = yyLineNr; // ??? what ist endBodyLine for
+ if(!endScope(current_root))
+ yyterminate();
+ yy_pop_state() ;
+ }
+
+ /*---- documentation comments --------------------------------------------------------------------*/
+
+<Variable>"!<" { /* backward docu comment (only one line) */
+ if (v_type != V_IGNORE) {
+ yy_push_state(YY_START);
+ current->docLine = yyLineNr;
+ docBlockJavaStyle = FALSE;
+ docBlock.resize(0);
+ docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
+ startCommentBlock(TRUE);
+ BEGIN(DocBackLine);
+ }
+ }
+<DocBackLine>.* { // contents of current comment line
+ docBlock=yytext;
+ if (v_type == V_VARIABLE) {
+ Entry *tmp_entry = current;
+ current = last_entry; // temporarily switch to the previous entry
+ handleCommentBlock(docBlock,TRUE);
+ current=tmp_entry;
+ }
+ else if (v_type == V_PARAMETER) {
+ parameter->docs=docBlock;
+ }
+ yy_pop_state();
+ }
+
+<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody>"!>" {
+ yy_push_state(YY_START);
+ current->docLine = yyLineNr;
+ docBlockJavaStyle = FALSE;
+ docBlock.resize(0);
+ docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
+ startCommentBlock(TRUE);
+ BEGIN(DocBlock);
+ //cout << "start DocBlock " << endl;
+ }
+
+<DocBlock>.* { // contents of current comment line
+ docBlock+=yytext;
+ }
+<DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line)
+ docBlock+="\n"; // \n is necessary for lists
+ yyLineNr++;
+ }
+<DocBlock>"\n" { // comment block ends at the end of this line
+ //cout <<"3=========> comment block : "<< docBlock << endl;
+ unput(*yytext);
+ handleCommentBlock(docBlock,TRUE);
+ yy_pop_state();
+ }
+
+ /*------------------------------------------------------------------------------------------------*/
+
+<*>"\n" {yyLineNr++;
+ //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
+ debugStr="";
+ }
+
+ /*---- error: EOF in wrong state --------------------------------------------------------------------*/
+ <SubprogBody,ModuleBody,String,StrIgnore,InterfaceBody><<EOF>> {
+ fprintf(stderr,"==== Error: EOF reached in wrong state (end missing)");
+ scanner_abort();
+ yyterminate();
+ }
+ <*>. {debugStr+=yytext;} // ignore remaining text
+
+ /**********************************************************************************/
+ /**********************************************************************************/
+ /**********************************************************************************/
+%%
+//----------------------------------------------------------------------------
+
+/** used to copy entry to an interface module procedure */
+static void copyEntry(Entry *dest, Entry *src)
+{
+ dest->type = src->type;
+ dest->fileName = src->fileName;
+ dest->bodyLine = src->bodyLine;
+ dest->args = src->args;
+ dest->argList = new ArgumentList(*src->argList);
+}
+
+/** fill empty interface module procedures with info from
+ corresponding module subprogs
+ @TODO: handle procedures in used modules
+*/
+void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
+{
+ if (moduleProcedures.isEmpty()) return;
+
+ EntryListIterator eli1(moduleProcedures);
+ // for all module procedures
+ for (Entry *ce1; (ce1=eli1.current()); ++eli1)
+ {
+ // check all entries in this module
+ EntryListIterator eli2(*current_root->children());
+ for (Entry *ce2; (ce2=eli2.current()); ++eli2)
+ {
+ if (ce1->name == ce2->name)
+ {
+ copyEntry(ce1, ce2);
+ }
+ } // for procedures in current module
+ } // for all interface module procedures
+ moduleProcedures.clear();
+}
+
+static bool isTypeName(QString name)
+{
+ name = name.lower();
+ return name=="integer" || name == "real" ||
+ name=="complex" || name == "logical";
+}
+
+/*! Extracts string which resides within parentheses of provided string. */
+static QString extractFromParens(const QString name)
+{
+ QString extracted = name;
+ int start = extracted.find("(");
+ if(start != -1)
+ {
+ extracted.remove(0, start+1);
+ }
+ int end = extracted.findRev(")");
+ if(end != -1)
+ {
+ int length = extracted.length();
+ extracted.remove(end, length);
+ }
+ extracted = extracted.stripWhiteSpace();
+
+ return extracted;
+}
+
+/*! Adds passed modifiers to these modifiers.*/
+SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
+{
+ if(mdfs.protection!=NONE_P) protection = mdfs.protection;
+ if(mdfs.direction!=NONE_D) direction = mdfs.direction;
+ optional |= mdfs.optional;
+ if(!mdfs.dimension.isNull()) dimension = mdfs.dimension;
+ allocatable |= mdfs.allocatable;
+ external |= mdfs.external;
+ intrinsic |= mdfs.intrinsic;
+ parameter |= mdfs.parameter;
+ pointer |= mdfs.pointer;
+ target |= mdfs.target;
+ save |= mdfs.save;
+ return *this;
+}
+
+/*! Extracts and adds passed modifier to these modifiers.*/
+SymbolModifiers& SymbolModifiers::operator|=(QString mdfString)
+{
+ mdfString = mdfString.lower();
+ SymbolModifiers newMdf;
+
+ if (mdfString.startsWith("dimension"))
+ {
+ newMdf.dimension=mdfString;
+ }
+ else if (mdfString.contains("intent"))
+ {
+ QString tmp = extractFromParens(mdfString);
+ bool isin = tmp.contains("in");
+ bool isout = tmp.contains("out");
+ if(isin && isout) newMdf.direction = SymbolModifiers::INOUT;
+ else if(isin) newMdf.direction = SymbolModifiers::IN;
+ else if(isout) newMdf.direction = SymbolModifiers::OUT;
+ }
+ else if (mdfString=="public")
+ {
+ newMdf.protection = SymbolModifiers::PUBLIC;
+ }
+ else if (mdfString=="private")
+ {
+ newMdf.protection = SymbolModifiers::PRIVATE;
+ }
+ else if (mdfString=="optional")
+ {
+ newMdf.optional = TRUE;
+ }
+ else if (mdfString=="allocatable")
+ {
+ newMdf.allocatable = TRUE;
+ }
+ else if (mdfString=="external")
+ {
+ newMdf.external = TRUE;
+ }
+ else if(mdfString=="intrinsic")
+ {
+ newMdf.intrinsic = TRUE;
+ }
+ else if(mdfString=="parameter")
+ {
+ newMdf.parameter = TRUE;
+ }
+ else if(mdfString=="pointer")
+ {
+ newMdf.pointer = TRUE;
+ }
+ else if(mdfString=="target")
+ {
+ newMdf.target = TRUE;
+ }
+ else if(mdfString=="save")
+ {
+ newMdf.save = TRUE;
+ }
+
+ (*this) |= newMdf;
+ return *this;
+}
+
+/*! For debugging purposes. */
+//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
+//{
+// out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
+// ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
+// ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
+//
+// return out;
+//}
+
+/*! Find argument with given name in \a subprog entry. */
+static Argument *findArgument(Entry* subprog, QString name, bool byTypeName = FALSE)
+{
+ QCString cname(name.lower());
+ for (unsigned int i=0; i<subprog->argList->count(); i++)
+ {
+ Argument *arg = subprog->argList->at(i);
+ if(!byTypeName && arg->name.lower() == cname ||
+ byTypeName && arg->type.lower() == cname)
+ return arg;
+ }
+
+ return NULL;
+}
+
+/*! Find function with given name in \a entry. */
+#if 0
+static Entry *findFunction(Entry* entry, QString name)
+{
+ QCString cname(name.lower());
+
+ EntryListIterator eli(*entry->children());
+ Entry *ce;
+ for (;(ce=eli.current());++eli)
+ {
+ if(ce->section != Entry::FUNCTION_SEC)
+ continue;
+
+ if(ce->name.lower() == cname)
+ return ce;
+ }
+
+ return NULL;
+}
+#endif
+
+/*! Apply modifiers stored in \a mdfs to the \a typeName string. */
+static QString applyModifiers(QString typeName, SymbolModifiers& mdfs)
+{
+ if(!mdfs.dimension.isNull())
+ {
+ typeName += ",";
+ typeName += mdfs.dimension;
+ }
+ if(mdfs.direction!=SymbolModifiers::NONE_D)
+ {
+ typeName += ",";
+ typeName += directionStrs[mdfs.direction];
+ }
+ if(mdfs.optional)
+ {
+ typeName += ",";
+ typeName += "optional";
+ }
+ if(mdfs.allocatable)
+ {
+ typeName += ",";
+ typeName += "allocatable";
+ }
+ if(mdfs.external)
+ {
+ typeName += ",";
+ typeName += "external";
+ }
+ if(mdfs.intrinsic)
+ {
+ typeName += ",";
+ typeName += "intrinsic";
+ }
+ if(mdfs.parameter)
+ {
+ typeName += ",";
+ typeName += "parameter";
+ }
+ if(mdfs.pointer)
+ {
+ typeName += ",";
+ typeName += "pointer";
+ }
+ if(mdfs.target)
+ {
+ typeName += ",";
+ typeName += "target";
+ }
+ if(mdfs.save)
+ {
+ typeName += ",";
+ typeName += "save";
+ }
+
+ return typeName;
+}
+
+/*! Apply modifiers stored in \a mdfs to the \a arg argument. */
+static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
+{
+ QString tmp = arg->type;
+ arg->type = applyModifiers(tmp, mdfs);
+}
+
+/*! Apply modifiers stored in \a mdfs to the \a ent entry. */
+static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
+{
+ QString tmp = ent->type;
+ ent->type = applyModifiers(tmp, mdfs);
+
+ if(mdfs.protection == SymbolModifiers::PUBLIC)
+ ent->protection = Public;
+ else if(mdfs.protection == SymbolModifiers::PRIVATE)
+ ent->protection = Private;
+}
+
+/*! Starts the new scope in fortran program. Consider using this function when
+ * starting module, interface, function or other program block.
+ * \see endScope()
+ */
+static void startScope(Entry *scope)
+{
+ //cout<<"start scope: "<<scope->name<<endl;
+ current_root= scope; /* start substructure */
+
+ QMap<QString,SymbolModifiers> mdfMap;
+ modifiers.insert(scope, mdfMap);
+}
+
+/*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
+ * \see startScope()
+ */
+static bool endScope(Entry *scope)
+{
+ //cout<<"end scope: "<<scope->name<<endl;
+ if (current_root->parent())
+ {
+ current_root= current_root->parent(); /* end substructure */
+ }
+ else
+ {
+ fprintf(stderr,"parse error in end <scopename>");
+ scanner_abort();
+ return FALSE;
+ }
+
+ // update variables or subprogram arguments with modifiers
+ QMap<QString,SymbolModifiers>& mdfsMap = modifiers[scope];
+
+ if(scope->section == Entry::FUNCTION_SEC)
+ {
+ // iterate all symbol modifiers of the scope
+ for(QMap<QString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) {
+ //cout<<it.key()<<": "<<it.data()<<endl;
+ Argument *arg = findArgument(scope, it.key());
+
+ if(arg)
+ applyModifiers(arg, it.data());
+ }
+
+ // find return type for function
+ //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
+ QString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
+ if(modifiers[scope].contains(returnName))
+ {
+ scope->type = modifiers[scope][returnName].type; // returning type works
+ applyModifiers(scope, modifiers[scope][returnName]); // returning array works
+ }
+
+ }
+ else if(scope->section == Entry::CLASS_SEC)
+ { // was INTERFACE_SEC
+ if(scope->parent()->section == Entry::FUNCTION_SEC)
+ { // interface within function
+ // iterate functions of interface and
+ // try to find types for dummy(ie. argument) procedures.
+ //cout<<"Search in "<<scope->name<<endl;
+ EntryListIterator eli(*scope->children());
+ Entry *ce;
+ for (;(ce=eli.current());++eli)
+ {
+ if(ce->section != Entry::FUNCTION_SEC)
+ continue;
+
+ Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
+ if(arg != NULL)
+ {
+ // set type of dummy procedure argument to interface
+ arg->name = arg->type;
+ arg->type = scope->name;
+ }
+ }
+ }
+
+ }
+ else
+ { // not function section or interface
+ // iterate variables: get and apply modifiers
+ EntryListIterator eli(*scope->children());
+ Entry *ce;
+ for (;(ce=eli.current());++eli)
+ {
+ if(ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
+ continue;
+
+ //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
+ if(mdfsMap.contains(ce->name.lower()))
+ applyModifiers(ce, mdfsMap[ce->name.lower()]);
+ }
+ }
+
+ // clear all modifiers of the scope
+ modifiers.remove(scope);
+
+ return TRUE;
+}
+
+//! Return full name of the entry. Sometimes we must combine several names recursively.
+static QString getFullName(Entry *e)
+{
+ QString name = e->name;
+ if(e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC
+ || !e->parent() || e->parent()->name.isEmpty())
+ return name;
+
+ return getFullName(e->parent())+"::"+name;
+}
+
+static int yyread(char *buf,int max_size)
+{
+ int c=0;
+ while( c < max_size && inputString[inputPosition] )
+ {
+ *buf = inputString[inputPosition++] ;
+ c++; buf++;
+ }
+ return c;
+}
+
+static void initParser()
+{
+ last_entry = 0;
+}
+
+static void initEntry()
+{
+ current->protection = defaultProtection ;
+ current->mtype = mtype;
+ current->virt = virt;
+ current->stat = gstat;
+ initGroupInfo(current);
+}
+
+/**
+ adds current entry to current_root and creates new current
+*/
+static void addCurrentEntry()
+{
+ //cout << "Adding entry " <<current->name.data() << endl;
+ current_root->addSubEntry(current);
+ last_entry = current;
+ current = new Entry ;
+ initEntry();
+}
+
+/*! Adds interface to the root entry.
+ * \note Code was brought to this procedure from the parser,
+ * because there was/is idea to use it in several parts of the parser.
+ */
+static void addInterface(QString name)
+{
+ current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
+ current->spec = Entry::Interface;
+ current->name = name;
+
+ /* if type is part of a module, mod name is necessary for output */
+ if ((current_root) &&
+ (current_root->section == Entry::CLASS_SEC ||
+ current_root->section == Entry::NAMESPACE_SEC))
+ {
+ current->name= current_root->name+"::"+current->name;
+ }
+ if ((current_root) &&
+ (current_root->section == Entry::FUNCTION_SEC))
+ {
+ current->name = getFullName(current_root) + "__" + QString(current->name);
+ }
+
+ current->fileName = yyFileName;
+ current->bodyLine = yyLineNr;
+ addCurrentEntry();
+}
+
+
+//-----------------------------------------------------------------------------
+
+/*! Update the argument \a name with additional \a type info.
+ */
+static Argument *addFortranParameter(const QCString &type,const QCString &name, const QString docs)
+{
+ //cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QString("null"):docs)<<endl;
+ Argument *ret = 0;
+ if (current_root->argList==0) return FALSE;
+ ArgumentListIterator ali(*current_root->argList);
+ Argument *a;
+ for (ali.toFirst();(a=ali.current());++ali)
+ {
+ if (a->type.lower()==name.lower())
+ {
+ ret=a;
+//cout << "addParameter found: " << type << " , " << name << endl;
+ a->type=type.stripWhiteSpace();
+ a->name=name.stripWhiteSpace();
+ if(!docs.isNull())
+ a->docs = docs;
+ break;
+ }
+ } // for
+ return ret;
+}
+
+ //----------------------------------------------------------------------------
+static void startCommentBlock(bool brief)
+{
+ if (brief)
+ {
+ current->briefFile = yyFileName;
+ current->briefLine = yyLineNr;
+ }
+ else
+ {
+ current->docFile = yyFileName;
+ current->docLine = yyLineNr;
+ }
+}
+
+ //----------------------------------------------------------------------------
+static void handleCommentBlock(const QCString &doc,bool brief)
+{
+ docBlockInBody = FALSE;
+ bool needsEntry = FALSE;
+ static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS");
+ int position=0;
+ if (docBlockInBody && hideInBodyDocs) return;
+ //fprintf(stderr,"call parseCommentBlock [%s]\n",doc.data());
+ while (parseCommentBlock(
+ g_thisParser,
+ docBlockInBody ? last_entry : current,
+ doc, // text
+ yyFileName, // file
+ brief ? current->briefLine : current->docLine, // line of block start
+ docBlockInBody ? FALSE : brief,
+ docBlockInBody ? FALSE : docBlockJavaStyle,
+ docBlockInBody,
+ defaultProtection,
+ position,
+ needsEntry
+ ))
+ {
+ //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry);
+ if (needsEntry) addCurrentEntry();
+ }
+ //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry);
+
+ if (needsEntry) addCurrentEntry();
+}
+
+//----------------------------------------------------------------------------
+static int level=0;
+static void debugCompounds(Entry *rt) // print Entry structure (for debugging)
+{
+ level++;
+ printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
+ EntryListIterator eli(*rt->children());
+ Entry *ce;
+ for (;(ce=eli.current());++eli)
+ {
+ debugCompounds(ce);
+ }
+level--;
+}
+
+
+static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
+{
+ initParser();
+
+ defaultProtection = Public;
+ inputString = fileBuf;
+ inputPosition = 0;
+
+ //anonCount = 0; // don't reset per file
+ mtype = Method;
+ gstat = FALSE;
+ virt = Normal;
+ current_root = rt;
+ global_root = rt;
+ inputFile.setName(fileName);
+ if (inputFile.open(IO_ReadOnly))
+ {
+ yyLineNr= 1 ;
+ yyFileName = fileName;
+ msg("Parsing file %s...\n",yyFileName.data());
+
+ current_root = rt ;
+ initParser();
+ groupEnterFile(yyFileName,yyLineNr);
+
+ current = new Entry;
+ current->name = yyFileName;
+ current->section = Entry::SOURCE_SEC;
+ current_root->addSubEntry(current);
+ file_root = current;
+ current = new Entry;
+
+ fscanYYrestart( fscanYYin );
+ {
+ BEGIN( Start );
+ }
+
+ fscanYYlex();
+ groupLeaveFile(yyFileName,yyLineNr);
+
+ //debugCompounds(rt); //debug
+
+ rt->program.resize(0);
+ delete current; current=0;
+ moduleProcedures.clear();
+
+ inputFile.close();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+void FortranLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
+{
+ g_thisParser = this;
+ ::parseMain(fileName,fileBuf,root);
+}
+
+void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
+ const char * scopeName,
+ const QCString & input,
+ bool isExampleBlock,
+ const char * exampleName,
+ FileDef * fileDef,
+ int startLine,
+ int endLine,
+ bool inlineFragment,
+ MemberDef *memberDef
+ )
+{
+ ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
+ fileDef,startLine,endLine,inlineFragment,memberDef);
+}
+
+bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
+{
+ (void)extension;
+ return TRUE;
+}
+void FortranLanguageScanner::resetCodeParserState()
+{
+ ::resetFortranCodeParserState();
+}
+
+void FortranLanguageScanner::parsePrototype(const char *text)
+{
+ (void)text;
+}
+
+static void scanner_abort()
+{
+ fprintf(stderr,"********************************************************************\n");
+ fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START);
+ fprintf(stderr,"********************************************************************\n");
+
+ EntryListIterator eli(*global_root->children());
+ Entry *ce;
+ bool start=FALSE;
+
+ for (;(ce=eli.current());++eli)
+ {
+ if (ce == file_root) start=TRUE;
+ if (start) ce->reset();
+ }
+
+ return;
+ //exit(-1);
+}
+
+//----------------------------------------------------------------------------
+
+#if !defined(YY_FLEX_SUBMINOR_VERSION)
+//----------------------------------------------------------------------------
+extern "C" { // some bogus code to keep the compiler happy
+ void fscannerYYdummy() { yy_flex_realloc(0,0); }
+}
+#endif
+
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 5442ed7..1cf596d 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -930,6 +930,7 @@ void HtmlGenerator::writeCodeLink(const char *ref,const char *f,
const char *tooltip)
{
QCString *dest;
+ //printf("writeCodeLink(ref=%s,f=%s,anchor=%s,name=%s,tooltip=%s)\n",ref,f,anchor,name,tooltip);
if (ref)
{
t << "<a class=\"codeRef\" ";
diff --git a/src/htmlhelp.cpp b/src/htmlhelp.cpp
index 5cbb5c7..d40e50a 100644
--- a/src/htmlhelp.cpp
+++ b/src/htmlhelp.cpp
@@ -450,6 +450,11 @@ void HtmlHelp::createProjectFile()
t << "tab_b.gif" << endl;
t << "tab_l.gif" << endl;
t << "tab_r.gif" << endl;
+ if (Config_getBool("HTML_DYNAMIC_SECTIONS"))
+ {
+ t << "open.gif" << endl;
+ t << "closed.gif" << endl;
+ }
f.close();
}
else
diff --git a/src/index.cpp b/src/index.cpp
index c745659..316963e 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -2589,7 +2589,7 @@ void writeGroupIndexItem(GroupDef *gd,MemberList *ml,const QCString &title,
first=FALSE;
if (htmlHelp)
{
- htmlHelp->addContentsItem(TRUE, convertToHtml(title), gd->getOutputFileBase(),0);
+ htmlHelp->addContentsItem(TRUE, convertToHtml(title,TRUE), gd->getOutputFileBase(),0);
htmlHelp->incContentsDepth();
}
if (ftvHelp)
@@ -2715,7 +2715,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
SectionInfo *si=0;
if (!pd->name().isEmpty()) si=Doxygen::sectionDict[pd->name()];
if (htmlHelp) htmlHelp->addContentsItem(FALSE,
- convertToHtml(pd->title()),
+ convertToHtml(pd->title(),TRUE),
gd->getOutputFileBase(),
si ? si->label.data() : 0
);
@@ -2723,7 +2723,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
gd->getReference(),
gd->getOutputFileBase(),
si ? si->label.data() : 0,
- convertToHtml(pd->title())
+ convertToHtml(pd->title(),TRUE)
);
}
@@ -2762,7 +2762,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
{
if (htmlHelp)
{
- htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trNamespaces()), gd->getOutputFileBase(), 0);
+ htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trNamespaces(),TRUE), gd->getOutputFileBase(), 0);
htmlHelp->incContentsDepth();
}
@@ -2779,11 +2779,11 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
{
if (htmlHelp)
{
- htmlHelp->addContentsItem(FALSE, convertToHtml(nsd->name()), nsd->getOutputFileBase());
+ htmlHelp->addContentsItem(FALSE, convertToHtml(nsd->name(),TRUE), nsd->getOutputFileBase());
}
if (ftvHelp)
{
- ftvHelp->addContentsItem(FALSE, nsd->getReference(), nsd->getOutputFileBase(), 0, convertToHtml(nsd->name()));
+ ftvHelp->addContentsItem(FALSE, nsd->getReference(), nsd->getOutputFileBase(), 0, convertToHtml(nsd->name(),TRUE));
}
}
if (htmlHelp) htmlHelp->decContentsDepth();
@@ -2795,7 +2795,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
{
if (htmlHelp)
{
- htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trClasses()), gd->getOutputFileBase(), 0);
+ htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trClasses(),TRUE), gd->getOutputFileBase(), 0);
htmlHelp->incContentsDepth();
}
@@ -2832,7 +2832,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
if (htmlHelp)
{
htmlHelp->addContentsItem(TRUE,
- convertToHtml(theTranslator->trFile(TRUE,FALSE)),
+ convertToHtml(theTranslator->trFile(TRUE,FALSE),TRUE),
gd->getOutputFileBase(), 0);
htmlHelp->incContentsDepth();
}
@@ -2850,9 +2850,9 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
while (fd)
{
if (htmlHelp)
- htmlHelp->addContentsItem(FALSE,convertToHtml(fd->name()),fd->getOutputFileBase());
+ htmlHelp->addContentsItem(FALSE,convertToHtml(fd->name(),TRUE),fd->getOutputFileBase());
if (ftvHelp)
- ftvHelp->addContentsItem(FALSE, fd->getReference(), fd->getOutputFileBase(), 0, convertToHtml(fd->name()));
+ ftvHelp->addContentsItem(FALSE, fd->getReference(), fd->getOutputFileBase(), 0, convertToHtml(fd->name(),TRUE));
fd=fileList->next();
}
if (htmlHelp)
@@ -2866,7 +2866,7 @@ void writeGroupTreeNode(OutputList &ol, GroupDef *gd,int level)
{
if (htmlHelp)
{
- htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trExamples()), gd->getOutputFileBase(), 0);
+ htmlHelp->addContentsItem(TRUE, convertToHtml(theTranslator->trExamples(),TRUE), gd->getOutputFileBase(), 0);
htmlHelp->incContentsDepth();
}
@@ -2991,9 +2991,9 @@ void writeDirTreeNode(OutputList &ol, DirDef *dd,int level)
while (fd)
{
if (htmlHelp)
- htmlHelp->addContentsItem(FALSE,convertToHtml(fd->name()),fd->getOutputFileBase());
+ htmlHelp->addContentsItem(FALSE,convertToHtml(fd->name(),TRUE),fd->getOutputFileBase());
if (ftvHelp)
- ftvHelp->addContentsItem(FALSE, fd->getReference(), fd->getOutputFileBase(), 0, convertToHtml(fd->name()));
+ ftvHelp->addContentsItem(FALSE, fd->getReference(), fd->getOutputFileBase(), 0, convertToHtml(fd->name(),TRUE));
fd=fileList->next();
}
}
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index d7257f1..9a02020 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -53,10 +53,12 @@
//}
-static QCString escapeLabelName(const char *s)
+static QCString escapeLabelName(LatexGenerator *g,const char *s)
{
QCString result;
const char *p=s;
+ char str[2];
+ str[1]=0;
char c;
while ((c=*p++))
{
@@ -65,7 +67,7 @@ static QCString escapeLabelName(const char *s)
case '%': result+="\\%"; break;
case '|': result+="\\tt{\"|}"; break;
case '!': result+="\"!"; break;
- default: result+=c;
+ default: str[0]=c; g->docify(str); break;
}
}
return result;
@@ -1069,7 +1071,7 @@ void LatexGenerator::endTitleHead(const char *fileName,const char *name)
if (name)
{
t << "\\label{" << fileName << "}\\index{"
- << name << "@{";
+ << escapeLabelName(this,name) << "@{";
escapeMakeIndexChars(this,t,name);
t << "}}" << endl;
}
@@ -1139,15 +1141,15 @@ void LatexGenerator::startMemberDoc(const char *clname,
t << "\\index{";
if (clname)
{
- t << clname << "@{";
- docify(clname);
+ t << escapeLabelName(this,clname) << "@{";
+ escapeMakeIndexChars(this,t,clname);
t << "}!";
}
- t << escapeLabelName(memname) << "@{";
+ t << escapeLabelName(this,memname) << "@{";
escapeMakeIndexChars(this,t,memname);
t << "}}" << endl;
- t << "\\index{" << escapeLabelName(memname) << "@{";
+ t << "\\index{" << escapeLabelName(this,memname) << "@{";
escapeMakeIndexChars(this,t,memname);
t << "}";
if (clname)
@@ -1221,12 +1223,12 @@ void LatexGenerator::addIndexItem(const char *s1,const char *s2)
{
if (s1)
{
- t << "\\index{" << escapeLabelName(s1) << "@{";
+ t << "\\index{" << escapeLabelName(this,s1) << "@{";
escapeMakeIndexChars(this,t,s1);
t << "}";
if (s2)
{
- t << "!" << escapeLabelName(s2) << "@{";
+ t << "!" << escapeLabelName(this,s2) << "@{";
escapeMakeIndexChars(this,t,s2);
t << "}";
}
@@ -1356,9 +1358,9 @@ void LatexGenerator::startAnonTypeScope(int indent)
{
t << "\\begin{tabbing}" << endl;
t << "xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=\\kill" << endl;
- //printf("LatexGenerator::startMemberItem() insideTabbing=TRUE\n");
insideTabbing=TRUE;
}
+ m_indent=indent;
}
void LatexGenerator::endAnonTypeScope(int indent)
@@ -1368,6 +1370,7 @@ void LatexGenerator::endAnonTypeScope(int indent)
t << endl << "\\end{tabbing}";
insideTabbing=FALSE;
}
+ m_indent=indent;
}
void LatexGenerator::startMemberTemplateParams()
@@ -1401,7 +1404,7 @@ void LatexGenerator::endMemberItem()
if (insideTabbing)
{
t << "\\\\";
- }
+ }
templateMemberItem = FALSE;
t << endl;
}
@@ -1414,7 +1417,7 @@ void LatexGenerator::startMemberDescription()
}
else
{
- for (int i=0;i<m_indent+1;i++) t << "\\>";
+ for (int i=0;i<m_indent+2;i++) t << "\\>";
t << "{\\em ";
}
}
@@ -1427,18 +1430,17 @@ void LatexGenerator::endMemberDescription()
}
else
{
- t << "}\\\\";
- m_indent=0;
+ t << "}\\\\\n";
}
}
void LatexGenerator::writeNonBreakableSpace(int)
{
+ //printf("writeNonBreakbleSpace()\n");
if (insideTabbing)
{
t << "\\>";
- m_indent++;
}
else
t << "~";
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index 12dfbd7..78ed341 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -82,6 +82,8 @@ HEADERS = bufstr.h \
printdocvisitor.h \
pycode.h \
pyscanner.h \
+ fortrancode.h \
+ fortranscanner.h \
qtbc.h \
reflist.h \
rtfdocvisitor.h \
@@ -190,6 +192,8 @@ SOURCES = ce_lex.cpp \
pre.cpp \
pycode.cpp \
pyscanner.cpp \
+ fortrancode.cpp \
+ fortranscanner.cpp \
reflist.cpp \
rtfdocvisitor.cpp \
rtfgen.cpp \
diff --git a/src/libdoxygen.t b/src/libdoxygen.t
index 541ec97..f2cc6cb 100644
--- a/src/libdoxygen.t
+++ b/src/libdoxygen.t
@@ -57,6 +57,12 @@ sub GenerateDep {
#$ GenerateDep("pycode.cpp","pycode.l");
$(LEX) -PpycodeYY -t pycode.l | $(INCBUFSIZE) >pycode.cpp
+#$ GenerateDep("fortranscanner.cpp","fortranscanner.l");
+ $(LEX) -i -PfscanYY -t fortranscanner.l | $(INCBUFSIZE) >fortranscanner.cpp
+
+#$ GenerateDep("fortrancode.cpp","fortrancode.l");
+ $(LEX) -i -PfcodeYY -t fortrancode.l | $(INCBUFSIZE) >fortrancode.cpp
+
#$ GenerateDep("pre.cpp","pre.l");
$(LEX) -PpreYY -t pre.l | $(INCBUFSIZE) >pre.cpp
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 14d1c2d..49a1794 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -259,6 +259,10 @@ static bool writeDefArgumentList(OutputList &ol,ClassDef *cd,
ol.endParameterName(TRUE,TRUE,!md->isObjCMethod());
}
ol.popGeneratorState();
+ if (md->extraTypeChars())
+ {
+ ol.docify(md->extraTypeChars());
+ }
if (defArgList->constSpecifier)
{
ol.docify(" const");
@@ -334,6 +338,7 @@ class MemberDefImpl
QCString write; // property write accessor
QCString exception; // exceptions that can be thrown
QCString initializer; // initializer
+ QCString extraTypeChars; // extra type info found after the argument list
int initLines; // number of lines in the initializer
int memSpec; // The specifiers present for this member
@@ -525,7 +530,7 @@ void MemberDefImpl::init(Definition *def,
if (!args.isEmpty())
{
declArgList = new ArgumentList;
- stringToArgumentList(args,declArgList);
+ stringToArgumentList(args,declArgList,&extraTypeChars);
//printf("setDeclArgList %s to %p const=%d\n",args.data(),
// declArgList,declArgList->constSpecifier);
}
@@ -725,6 +730,11 @@ QCString MemberDef::getOutputFileBase() const
QCString MemberDef::getReference() const
{
makeResident();
+ QCString ref = Definition::getReference();
+ if (!ref.isEmpty())
+ {
+ return ref;
+ }
if (m_impl->templateMaster)
{
return m_impl->templateMaster->getReference();
@@ -1406,7 +1416,10 @@ void MemberDef::writeDeclaration(OutputList &ol,
//printf("endMember %s annoClassDef=%p annEnumType=%p\n",
// name().data(),annoClassDef,annEnumType);
ol.endMemberItem();
- if (endAnonScopeNeeded) ol.endAnonTypeScope(--s_indentLevel);
+ if (endAnonScopeNeeded)
+ {
+ ol.endAnonTypeScope(--s_indentLevel);
+ }
// write brief description
if (!briefDescription().isEmpty() &&
@@ -2872,6 +2885,7 @@ void MemberDef::setTagInfo(TagInfo *ti)
if (ti)
{
makeResident();
+ //printf("%s: Setting tag name=%s anchor=%s\n",name().data(),ti->tagName.data(),ti->anchor.data());
m_impl->anc=ti->anchor;
setReference(ti->tagName);
m_impl->explicitOutputFileBase = stripExtension(ti->fileName);
@@ -2905,7 +2919,13 @@ const char *MemberDef::declaration() const
const char *MemberDef::definition() const
{
makeResident();
- return m_impl->def;
+ return m_impl->def;
+}
+
+const char *MemberDef::extraTypeChars() const
+{
+ makeResident();
+ return m_impl->extraTypeChars;
}
const char *MemberDef::typeString() const
@@ -3661,6 +3681,7 @@ void MemberDef::flushToDisk() const
marshalQCString (Doxygen::symbolStorage,m_impl->write);
marshalQCString (Doxygen::symbolStorage,m_impl->exception);
marshalQCString (Doxygen::symbolStorage,m_impl->initializer);
+ marshalQCString (Doxygen::symbolStorage,m_impl->extraTypeChars);
marshalInt (Doxygen::symbolStorage,m_impl->initLines);
marshalInt (Doxygen::symbolStorage,m_impl->memSpec);
marshalInt (Doxygen::symbolStorage,(int)m_impl->mtype);
@@ -3760,6 +3781,7 @@ void MemberDef::loadFromDisk() const
m_impl->write = unmarshalQCString (Doxygen::symbolStorage);
m_impl->exception = unmarshalQCString (Doxygen::symbolStorage);
m_impl->initializer = unmarshalQCString (Doxygen::symbolStorage);
+ m_impl->extraTypeChars = unmarshalQCString (Doxygen::symbolStorage);
m_impl->initLines = unmarshalInt (Doxygen::symbolStorage);
m_impl->memSpec = unmarshalInt (Doxygen::symbolStorage);
m_impl->mtype = (MemberDef::MemberType)unmarshalInt (Doxygen::symbolStorage);
diff --git a/src/memberdef.h b/src/memberdef.h
index 385b353..8715ec9 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -89,6 +89,7 @@ class MemberDef : public Definition
const char *argsString() const;
const char *excpString() const;
const char *bitfieldString() const;
+ const char *extraTypeChars() const;
const QCString &initializer() const;
int initializerLines() const;
int getMemberSpecifiers() const;
diff --git a/src/msc.cpp b/src/msc.cpp
index f68858a..eb1ae6d 100644
--- a/src/msc.cpp
+++ b/src/msc.cpp
@@ -148,7 +148,7 @@ QString getMscImageMapFromFile(const QString& inFile, const QString& outDir,
QDir::setCurrent(outDir);
//printf("Going to dir %s\n",QDir::currentDirPath().data());
- QCString mscExe = "mscgen";
+ QCString mscExe = Config_getString("MSCGEN_PATH")+"mscgen"+portable_commandExtension();
QCString mscArgs = "-T ismap -i \"";
mscArgs+=inFile + ".msc\" -o \"";
mscArgs+=outFile + "\"";
diff --git a/src/pagedef.cpp b/src/pagedef.cpp
index 7ed229f..3859640 100644
--- a/src/pagedef.cpp
+++ b/src/pagedef.cpp
@@ -79,7 +79,7 @@ void PageDef::writeDocumentation(OutputList &ol)
(si=Doxygen::sectionDict.find(pageName))!=0)
{
ol.startSection(si->label,si->title,si->type);
- ol.docify(si->title);
+ ol.parseDoc(docFile(),docLine(),this,0,si->title,TRUE,FALSE);
stringToSearchIndex(getOutputFileBase(),
theTranslator->trPage(TRUE,TRUE)+" "+si->title,
si->title);
diff --git a/src/pre.h b/src/pre.h
index e015d56..5bc0f8b 100644
--- a/src/pre.h
+++ b/src/pre.h
@@ -21,9 +21,11 @@
#include "qtbc.h"
#include <stdio.h>
//#include <qfile.h>
+#include "define.h"
class BufStr;
+DefineDict* getFileDefineDict();
void initPreprocessor();
void cleanUpPreprocessor();
void addSearchDir(const char *dir);
diff --git a/src/pre.l b/src/pre.l
index f46a138..cc92d66 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -104,6 +104,9 @@ static QStack<bool> g_condStack;
static bool g_lexInit = FALSE;
+DefineDict* getFileDefineDict() {
+ return g_fileDefineDict;
+}
static void setFileName(const char *name)
{
diff --git a/src/scanner.l b/src/scanner.l
index 584f1b2..4fd024a 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -666,6 +666,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
%x MemberSpecSkip
%x EndTemplate
%x FuncPtr
+%x FuncPtrOperator
%x EndFuncPtr
%x ReadFuncArgType
%x ReadTempArgs
@@ -686,6 +687,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
%x FuncFunc
%x FuncFuncEnd
%x FuncFuncType
+%x FuncFuncArray
%x CopyArgString
%x CopyArgPHPString
%x CopyArgRound
@@ -1866,6 +1868,8 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
}
}
}
+<FindMembers>[0-9]{ID} { // some number where we did not expect one
+ }
<FindMembers>"." {
if (insideJava || insideCS || insideD)
{
@@ -2691,14 +2695,18 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
}
<IDLProp>. {
}
-<Array>"]" { current->args += *yytext ;
+<Array>"]" { current->args += *yytext ;
if (--squareCount<=0)
BEGIN( FindMembers ) ;
}
-<Array>"[" { current->args += *yytext ;
+<FuncFuncArray>"]" { current->args += *yytext ;
+ if (--squareCount<=0)
+ BEGIN( Function ) ;
+ }
+<Array,FuncFuncArray>"[" { current->args += *yytext ;
squareCount++;
}
-<Array>. { current->args += *yytext ; }
+<Array,FuncFuncArray>. { current->args += *yytext ; }
<SkipSquare>"[" { squareCount++; }
<SkipSquare>"]" {
if (--squareCount<=0)
@@ -3155,7 +3163,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
<ReadBody,ReadNSBody,ReadBodyIntf>. { current->program += yytext ; }
<FindMembers>"("/{BN}*({TSCOPE}{BN}*"::")*{TSCOPE}{BN}*")"{BN}*"(" | /* typedef void (A<int>::func_t)(args...) */
-<FindMembers>("("({BN}*{TSCOPE}{BN}*"::")*({BN}*"*"{BN}*)+)+ { /* typedef void (A::*ptr_t)(args...) */
+<FindMembers>("("({BN}*{TSCOPE}{BN}*"::")*({BN}*[*&]{BN}*)+)+ { /* typedef void (A::*ptr_t)(args...) or int (*func(int))[] */
current->bodyLine = yyLineNr;
lineCount();
addType(current);
@@ -3166,18 +3174,41 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
}
<FuncPtr>{SCOPENAME} {
current->name = yytext;
- if (current->name=="const" || current->name=="volatile")
+ if (nameIsOperator(current->name))
{
- funcPtrType += current->name;
+ BEGIN( FuncPtrOperator );
}
else
{
- BEGIN( EndFuncPtr );
+ if (current->name=="const" || current->name=="volatile")
+ {
+ funcPtrType += current->name;
+ }
+ else
+ {
+ BEGIN( EndFuncPtr );
+ }
}
}
<FuncPtr>. {
//printf("Error: FuncPtr `%c' unexpected at line %d of %s\n",*yytext,yyLineNr,yyFileName);
}
+<FuncPtrOperator>"("{BN}*")"{BN}*/"(" {
+ current->name += yytext;
+ current->name = current->name.simplifyWhiteSpace();
+ lineCount();
+ }
+<FuncPtrOperator>\n {
+ yyLineNr++;
+ current->name += *yytext;
+ }
+<FuncPtrOperator>"(" {
+ unput(*yytext);
+ BEGIN( EndFuncPtr );
+ }
+<FuncPtrOperator>. {
+ current->name += *yytext;
+ }
<EndFuncPtr>")"{BN}*/";" { // a variable with extra braces
lineCount();
current->type+=funcPtrType.data()+1;
@@ -3194,10 +3225,16 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
current->args += ")";
BEGIN(FindMembers);
}
-<EndFuncPtr>"(" { // a function returning a function
+<EndFuncPtr>"(" { // a function returning a function or
+ // a function returning a pointer to an array
current->args += *yytext ;
- roundCount=0;
- BEGIN( FuncFunc );
+ //roundCount=0;
+ //BEGIN( FuncFunc );
+ current->bodyLine = yyLineNr;
+ currentArgumentContext = FuncFuncEnd;
+ fullArgString=current->args.copy();
+ copyArgString=&current->args;
+ BEGIN( ReadFuncArgType ) ;
}
<EndFuncPtr>"["[^\n\]]*"]" {
funcPtrType+=yytext;
@@ -3228,6 +3265,12 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
current->type+=funcPtrType.data()+1;
BEGIN(Function);
}
+<FuncFuncEnd>")"{BN}*/"[" { // function returning a pointer to an array
+ lineCount();
+ current->type+=funcPtrType;
+ current->args+=")";
+ BEGIN(FuncFuncArray);
+ }
<FuncFuncEnd>. {
current->args += *yytext;
}
@@ -3827,31 +3870,27 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
// was: current->args.simplifyWhiteSpace();
current->fileName = yyFileName;
current->startLine = yyLineNr;
+ static QRegExp re("([^)]*\\[*&][^)]*)"); // (...*...)
if (*yytext!=';' || (current_root->section&Entry::COMPOUND_MASK) )
{
int tempArg=current->name.find('<');
QCString tempName;
- static QRegExp re("operator[^a-z_A-Z0-9]");
if (tempArg==-1) tempName=current->name; else tempName=current->name.left(tempArg);
- if (/*(current->type.isEmpty() && tempName.find(re)==-1) || */
- current->type.left(8)=="typedef "
- )
+ if (current->type.isEmpty() &&
+ (current->type.find(re,0)!=-1 || current->type.left(8)=="typedef "))
{
- //printf("Scanner.l: found in class variable: `%s' `%s' `%s'\n",
- // current->type.data(),current->name.data(),current->args.data());
+ //printf("Scanner.l: found in class variable: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data());
current->section = Entry::VARIABLE_SEC ;
}
else
{
- //printf("Scanner.l: found in class function: `%s' `%s' `%s'\n",
- // current->type.data(),current->name.data(),current->args.data());
+ //printf("Scanner.l: found in class function: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data());
current->section = Entry::FUNCTION_SEC ;
current->proto = *yytext==';';
}
}
else // a global function prototype or function variable
{
- static QRegExp re("([^)]*\\*[^)]*)"); // (...*...)
//printf("Scanner.l: prototype? type=`%s' name=`%s' args=`%s'\n",current->type.data(),current->name.data(),current->args.data());
if (!current->type.isEmpty() &&
(current->type.find(re,0)!=-1 || current->type.left(8)=="typedef "))
@@ -4975,14 +5014,14 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
<Prototype>"operator"{B}*"("{B}*")" {
current->name+=yytext;
}
-<Prototype>"(" {
+<Prototype>"(" {
current->args+=*yytext;
currentArgumentContext = PrototypeQual;
fullArgString = current->args.copy();
copyArgString = &current->args;
BEGIN( ReadFuncArgType ) ;
}
-<Prototype>"("({ID}"::")*({B}*"*")+ {
+<Prototype>"("({ID}"::")*({B}*[&*])+ {
current->type+=current->name+yytext;
current->name.resize(0);
BEGIN( PrototypePtr );
@@ -4990,10 +5029,20 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
<PrototypePtr>{SCOPENAME} {
current->name+=yytext;
}
+<PrototypePtr>"(" {
+ current->args+=*yytext;
+ currentArgumentContext = PrototypeQual;
+ fullArgString = current->args.copy();
+ copyArgString = &current->args;
+ BEGIN( ReadFuncArgType ) ;
+ }
<PrototypePtr>")" {
current->type+=')';
BEGIN( Prototype );
}
+<PrototypePtr>. {
+ current->name+=yytext;
+ }
<PrototypeQual>"{" {
BEGIN( PrototypeSkipLine);
}
@@ -5010,7 +5059,7 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
current->virt = Pure;
current->argList->pureSpecifier=TRUE;
}
-<PrototypeQual>"throw"{B}*"(" {
+<PrototypeQual>"throw"{B}*"(" {
current->exception = "throw(";
BEGIN(PrototypeExc);
}
@@ -5018,10 +5067,13 @@ TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
current->exception += ')';
BEGIN(PrototypeQual);
}
-<PrototypeExc>. {
+<PrototypeExc>. {
current->exception += *yytext;
}
-<Prototype,PrototypeQual>. {
+<PrototypeQual>. {
+ current->args += *yytext;
+ }
+<Prototype>. {
current->name += *yytext;
}
<PrototypeSkipLine>. {
diff --git a/src/util.cpp b/src/util.cpp
index 5ab4a29..0a271c4 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -690,17 +690,20 @@ static Definition *followPath(Definition *start,FileDef *fileScope,const QCStrin
int l;
Definition *current=start;
ps=0;
+ //printf("followPath: start='%s' path='%s'\n",start?start->name().data():"<none>",path.data());
// for each part of the explicit scope
while ((is=getScopeFragment(path,ps,&l))!=-1)
{
// try to resolve the part if it is a typedef
MemberDef *typeDef=0;
QCString qualScopePart = substTypedef(current,fileScope,path.mid(is,l),&typeDef);
+ //printf(" qualScopePart=%s\n",qualScopePart.data());
if (typeDef)
{
ClassDef *type = newResolveTypedef(fileScope,typeDef);
if (type)
{
+ //printf("Found type %s\n",type->name().data());
return type;
}
}
@@ -714,14 +717,15 @@ static Definition *followPath(Definition *start,FileDef *fileScope,const QCStrin
//printf("==> next==0!\n");
if (current->definitionType()==Definition::TypeNamespace)
{
- current = endOfPathIsUsedClass(
+ next = endOfPathIsUsedClass(
((NamespaceDef *)current)->getUsedClasses(),qualScopePart);
}
else if (current->definitionType()==Definition::TypeFile)
{
- current = endOfPathIsUsedClass(
+ next = endOfPathIsUsedClass(
((FileDef *)current)->getUsedClasses(),qualScopePart);
}
+ current = next;
if (current==0) break;
}
else // continue to follow scope
@@ -875,7 +879,7 @@ int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item)
// repeat for the parent scope
i=isAccessibleFrom(scope->getOuterScope(),fileScope,item);
//printf("> result=%d\n",i);
- result= (i==-1) ? -1 : i+1;
+ result= (i==-1) ? -1 : i+2;
}
done:
visitedDict.remove(key);
@@ -914,7 +918,7 @@ int isAccessibleFromWithExpScope(Definition *scope,FileDef *fileScope,
if (visitedDict.find(key)) return -1; // already looked at this
visitedDict.insert(key,(void *)0x8);
- //printf("<isAccessibleFromWithExpScope(%s,%s,%s)\n",scope?scope->name().data():"<global>",
+ //printf(" <isAccessibleFromWithExpScope(%s,%s,%s)\n",scope?scope->name().data():"<global>",
// item?item->name().data():"<none>",
// explicitScopePart.data());
int result=0; // assume we found it
@@ -922,12 +926,12 @@ int isAccessibleFromWithExpScope(Definition *scope,FileDef *fileScope,
if (newScope) // explicitScope is inside scope => newScope is the result
{
Definition *itemScope = item->getOuterScope();
- //printf("scope traversal successful %s<->%s!\n",item->getOuterScope()->name().data(),newScope->name().data());
- if (newScope && newScope->definitionType()==Definition::TypeClass)
- {
- //ClassDef *cd = (ClassDef *)newScope;
- //printf("---> Class %s: bases=%p\n",cd->name().data(),cd->baseClasses());
- }
+ //printf(" scope traversal successful %s<->%s!\n",item->getOuterScope()->name().data(),newScope->name().data());
+ //if (newScope && newScope->definitionType()==Definition::TypeClass)
+ //{
+ // ClassDef *cd = (ClassDef *)newScope;
+ // printf("---> Class %s: bases=%p\n",cd->name().data(),cd->baseClasses());
+ //}
if (itemScope==newScope) // exact match of scopes => distance==0
{
//printf("> found it\n");
@@ -941,9 +945,14 @@ int isAccessibleFromWithExpScope(Definition *scope,FileDef *fileScope,
// inheritance is also ok. Example: looking for B::I, where
// class A { public: class I {} };
// class B : public A {}
+ // but looking for B::I, where
+ // class A { public: class I {} };
+ // class B { public: class I {} };
+ // will find A::I, so we still prefer a direct match and give this one a distance of 1
+ result=1;
- //printf("outerScope(%s) is base class of newScope(%s)\n",
- // outerScope->name().data(),newScope->name().data());
+ //printf("scope(%s) is base class of newScope(%s)\n",
+ // scope->name().data(),newScope->name().data());
}
else
{
@@ -998,7 +1007,7 @@ int isAccessibleFromWithExpScope(Definition *scope,FileDef *fileScope,
item,explicitScopePart);
}
//printf("> result=%d\n",i);
- result = (i==-1) ? -1 : i+1;
+ result = (i==-1) ? -1 : i+2;
}
}
else // failed to resolve explicitScope
@@ -1033,11 +1042,11 @@ int isAccessibleFromWithExpScope(Definition *scope,FileDef *fileScope,
int i=isAccessibleFromWithExpScope(scope->getOuterScope(),fileScope,
item,explicitScopePart);
//printf("> result=%d\n",i);
- result= (i==-1) ? -1 : i+1;
+ result= (i==-1) ? -1 : i+2;
}
}
done:
- //printf("> result=%d\n",result);
+ //printf(" > result=%d\n",result);
visitedDict.remove(key);
//Doxygen::lookupCache.insert(key,new int(result));
return result;
@@ -1060,7 +1069,7 @@ static void getResolvedSymbol(Definition *scope,
QCString &bestResolvedType
)
{
- //printf(" found type %x name=%s d=%p\n",
+ //printf(" => found type %x name=%s d=%p\n",
// d->definitionType(),d->name().data(),d);
// only look at classes and members that are enums or typedefs
@@ -1160,6 +1169,13 @@ static void getResolvedSymbol(Definition *scope,
bestTemplSpec = "";
bestResolvedType = enumType->qualifiedName();
}
+ else if (md->isReference()) // external reference
+ {
+ bestMatch = 0;
+ bestTypedef = md;
+ bestTemplSpec = spec;
+ bestResolvedType = type;
+ }
else
{
//printf(" no match\n");
@@ -1285,6 +1301,9 @@ ClassDef *getResolvedClassRec(Definition *scope,
//printf("Searching for %s result=%p\n",key.data(),pval);
if (pval)
{
+ //printf("LookupInfo %p %p '%s' %p\n",
+ // pval->classDef, pval->typeDef, pval->templSpec.data(),
+ // pval->resolvedType.data());
if (pTemplSpec) *pTemplSpec=pval->templSpec;
if (pTypeDef) *pTypeDef=pval->typeDef;
if (pResolvedType) *pResolvedType=pval->resolvedType;
@@ -1662,10 +1681,12 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,
MemberDef *md=0;
NamespaceDef *nd=0;
GroupDef *gd=0;
+ //printf("** Match word '%s'\n",matchWord.data());
MemberDef *typeDef=0;
if ((cd=getResolvedClass(scope,fileScope,matchWord,&typeDef)))
{
+ //printf("Found class %s\n",cd->name().data());
// add link to the result
if (external ? cd->isLinkable() : cd->isLinkableInProject())
{
@@ -1675,6 +1696,7 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,
}
else if (typeDef)
{
+ //printf("Found typedef %s\n",typeDef->name().data());
if (external ? typeDef->isLinkable() : typeDef->isLinkableInProject())
{
out.writeLink(typeDef->getReference(),
@@ -1693,6 +1715,10 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,
found=TRUE;
}
}
+ else
+ {
+ //printf(" -> nothing\n");
+ }
QCString scopeName;
if (scope &&
@@ -1714,14 +1740,11 @@ void linkifyText(const TextGeneratorIntf &out,Definition *scope,
)
{
//printf("Found ref scope=%s\n",d?d->name().data():"<global>");
- if ((external ? md->isLinkable() : md->isLinkableInProject()))
- {
- //ol.writeObjectLink(d->getReference(),d->getOutputFileBase(),
- // md->anchor(),word);
- out.writeLink(md->getReference(),md->getOutputFileBase(),
- md->anchor(),word);
- found=TRUE;
- }
+ //ol.writeObjectLink(d->getReference(),d->getOutputFileBase(),
+ // md->anchor(),word);
+ out.writeLink(md->getReference(),md->getOutputFileBase(),
+ md->anchor(),word);
+ found=TRUE;
}
}
@@ -4854,7 +4877,7 @@ QCString convertToXML(const char *s)
}
/*! Converts a string to a HTML-encoded string */
-QCString convertToHtml(const char *s)
+QCString convertToHtml(const char *s,bool keepEntities)
{
QCString result;
if (s==0) return result;
@@ -4866,7 +4889,30 @@ QCString convertToHtml(const char *s)
{
case '<': result+="&lt;"; break;
case '>': result+="&gt;"; break;
- case '&': result+="&amp;"; break;
+ case '&': if (keepEntities)
+ {
+ const char *e=p;
+ char ce;
+ while ((ce=*e++))
+ {
+ if (ce==';' || (!(isId(ce) || ce=='#'))) break;
+ }
+ if (ce==';') // found end of an entity
+ {
+ // copy entry verbatim
+ result+=c;
+ while (p<e) result+=*p++;
+ }
+ else
+ {
+ result+="&amp;";
+ }
+ }
+ else
+ {
+ result+="&amp;";
+ }
+ break;
case '\'': result+="&#39;"; break;
case '"': result+="&quot;"; break;
default: result+=c; break;
@@ -6193,27 +6239,28 @@ QCString expandAliasRec(const QCString s)
static QCString replaceAliasArgument(const QCString &aliasValue,int paramNum,
const QCString &paramValue)
{
- QCString result = aliasValue;
+ QCString result;
QCString paramMarker;
paramMarker.sprintf("\\%d",paramNum);
int markerLen = paramMarker.length();
int p=0,i;
while ((i=aliasValue.find(paramMarker,p))!=-1) // search for marker
{
+ result+=aliasValue.mid(p,i-p);
//printf("Found marker '%s' at %d len=%d for param '%s' in '%s'\n",
// paramMarker.data(),i,markerLen,paramValue.data(),aliasValue.data());
if (i==0 || aliasValue.at(i-1)!='\\') // found unescaped marker
{
- QCString before = result.left(i);
- QCString after = result.mid(i+markerLen);
- result = before + paramValue + after;
- p=i+paramValue.length();
+ result += paramValue;
+ p=i+markerLen;
}
else // ignore escaped markers
{
+ result += aliasValue.mid(i,markerLen);
p=i+1;
}
}
+ result+=aliasValue.right(aliasValue.length()-p);
result = expandAliasRec(substitute(result,"\\,",","));
//printf("replaceAliasArgument('%s',%d,'%s')->%s\n",
// aliasValue.data(),paramNum,paramValue.data(),result.data());
diff --git a/src/util.h b/src/util.h
index d594a2e..00f44bc 100644
--- a/src/util.h
+++ b/src/util.h
@@ -234,7 +234,7 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te
QCString stripScope(const char *name);
-QCString convertToHtml(const char *s);
+QCString convertToHtml(const char *s,bool keepEntities=TRUE);
QCString convertToXML(const char *s);
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index e66bea3..fb21518 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -1170,6 +1170,8 @@ static void generateXMLForClass(ClassDef *cd,QTextStream &ti)
if (cd->name().find('@')!=-1) return; // skip anonymous compounds.
if (cd->templateMaster()!=0) return; // skip generated template instances.
+ msg("Generating XML output for class %s\n",cd->name().data());
+
ti << " <compound refid=\"" << cd->getOutputFileBase()
<< "\" kind=\"" << cd->compoundTypeString()
<< "\"><name>" << convertToXML(cd->name()) << "</name>" << endl;
@@ -1886,7 +1888,6 @@ void generateXML()
ClassDef *cd;
for (cli.toFirst();(cd=cli.current());++cli)
{
- msg("Generating XML output for class %s\n",cd->name().data());
generateXMLForClass(cd,t);
}
}