summaryrefslogtreecommitdiff
path: root/src/fortranscanner.l
diff options
context:
space:
mode:
Diffstat (limited to 'src/fortranscanner.l')
-rw-r--r--src/fortranscanner.l194
1 files changed, 143 insertions, 51 deletions
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 64a49ca..4875606 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -99,13 +99,15 @@ struct SymbolModifiers {
bool nonoverridable;
bool nopass;
bool pass;
+ bool contiguous;
+ bool volat; /* volatile is a reserverd name */
QCString passVar;
SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D),
optional(FALSE), protect(FALSE), dimension(), allocatable(FALSE),
external(FALSE), intrinsic(FALSE), parameter(FALSE),
pointer(FALSE), target(FALSE), save(FALSE), deferred(FALSE), nonoverridable(FALSE),
- nopass(FALSE), pass(FALSE), passVar() {}
+ nopass(FALSE), pass(FALSE), contiguous(FALSE), volat(FALSE), passVar() {}
SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
SymbolModifiers& operator|=(QCString mdfrString);
@@ -258,11 +260,12 @@ CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
-ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE)
+ATTR_SPEC (EXTERNAL|ALLOCATABLE|DIMENSION{ARGS}|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE|CONTIGUOUS|VOLATILE)
ACCESS_SPEC (PRIVATE|PUBLIC)
LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
/* Assume that attribute statements are almost the same as attributes. */
ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
+EXTERNAL_STMT (EXTERNAL)
CONTAINS CONTAINS
PREFIX (RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,3}(RECURSIVE|IMPURE|PURE|ELEMENTAL)?
@@ -469,6 +472,7 @@ SCOPENAME ({ID}{BS}"::"{BS})*
}
^{BS}interface{BS_}{ID}{ARGS}? { ifType = IF_GENERIC;
+ current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
yy_push_state(InterfaceBody);
// extract generic name
@@ -481,6 +485,7 @@ SCOPENAME ({ID}{BS}"::"{BS})*
<InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? {
// end scope only if GENERIC interface
+ last_entry->parent()->endBodyLine = yyLineNr - 1;
if (ifType == IF_GENERIC && !endScope(current_root))
yyterminate();
@@ -608,6 +613,7 @@ private {
current->name = yytext;
current->fileName = yyFileName;
current->bodyLine = yyLineNr;
+ current->startLine = yyLineNr;
/* if type is part of a module, mod name is necessary for output */
if ((current_root) &&
@@ -648,6 +654,7 @@ private {
current->name = name;
current->fileName = yyFileName;
current->bodyLine = yyLineNr;
+ current->startLine = yyLineNr;
addCurrentEntry(1);
}
{BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */
@@ -663,6 +670,7 @@ private {
<TypedefBody,TypedefBodyContains>{
^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
+ last_entry->parent()->endBodyLine = yyLineNr;
if (!endScope(current_root))
yyterminate();
typeMode = false;
@@ -678,6 +686,7 @@ private {
// in a scope of their own, even if multiple
// are group in one INTERFACE/END INTERFACE block.
//
+ last_entry->endBodyLine = yyLineNr - 1;
if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
endScope(current_root);
@@ -692,6 +701,8 @@ private {
}
<Start,ModuleBody,TypedefBody,SubprogBody>{
^{BS}{TYPE_SPEC}/{SEPARATE} {
+ current->bodyLine = yyLineNr + 1;
+ current->endBodyLine = yyLineNr + lineCountPrepass;
/* variable declaration starts */
if(YY_START == Start)
{
@@ -726,6 +737,18 @@ private {
}
}
*/
+{EXTERNAL_STMT}/({BS}"::"|{BS_}{ID}) {
+ /* external can be a "type" or an attribute */
+ if(YY_START == Start)
+ {
+ addModule(NULL);
+ yy_push_state(ModuleBody); //anon program
+ }
+ QCString tmp = yytext;
+ currentModifiers |= tmp.stripWhiteSpace();
+ argType = QCString(yytext).simplifyWhiteSpace().lower();
+ yy_push_state(AttributeList);
+ }
{ATTR_STMT}/{BS_}{ID} |
{ATTR_STMT}/{BS}"::" {
/* attribute statement starts */
@@ -744,7 +767,7 @@ private {
<AttributeList>{
{COMMA} {}
{BS} {}
-{ATTR_SPEC}. { /* update current modifierswhen it is an ATTR_SPEC and not a variable name */
+{ATTR_SPEC}. { /* update current modifiers when it is an ATTR_SPEC and not a variable name */
/* bug_625519 */
QChar chr = yytext[(int)yyleng-1];
if (chr.isLetter() || chr.isDigit() || (chr == '_'))
@@ -791,6 +814,7 @@ private {
current->type = argType;
current->fileName = yyFileName;
current->bodyLine = yyLineNr; // used for source reference
+ current->startLine = yyLineNr;
addCurrentEntry(1);
}
else if (!argType.isEmpty())
@@ -870,7 +894,8 @@ private {
// locate !< comment
updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
}
-<Variable>{BS}"=" { yy_push_state(YY_START);
+<Variable>{BS}"=" {
+ yy_push_state(YY_START);
initializer="=";
initializerScope = initializerArrayScope = 0;
BEGIN(Initialization);
@@ -971,6 +996,8 @@ private {
result = QCString(yytext).stripWhiteSpace();
addSubprogram(result);
yy_push_state(Subprog);
+ current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
+ current->startLine = yyLineNr;
}
<Subprog>{BS} { /* ignore white space */ }
@@ -1478,7 +1505,9 @@ static void copyEntry(Entry *dest, Entry *src)
{
dest->type = src->type;
dest->fileName = src->fileName;
+ dest->startLine = src->startLine;
dest->bodyLine = src->bodyLine;
+ dest->endBodyLine = src->endBodyLine;
dest->args = src->args;
dest->argList = new ArgumentList(*src->argList);
dest->doc = src->doc;
@@ -1559,6 +1588,8 @@ SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
nopass |= mdfs.nopass;
pass |= mdfs.pass;
passVar = mdfs.passVar;
+ contiguous |= mdfs.contiguous;
+ volat |= mdfs.volat;
return *this;
}
@@ -1637,6 +1668,14 @@ SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
{
newMdf.nonoverridable = TRUE;
}
+ else if (mdfString=="contiguous")
+ {
+ newMdf.contiguous = TRUE;
+ }
+ else if (mdfString=="volatile")
+ {
+ newMdf.volat = TRUE;
+ }
else if (mdfString.contains("pass"))
{
newMdf.pass = TRUE;
@@ -1723,8 +1762,11 @@ static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs)
}
if (mdfs.external)
{
- if (!typeName.isEmpty()) typeName += ", ";
- typeName += "external";
+ if (!typeName.contains("external"))
+ {
+ if (!typeName.isEmpty()) typeName += ", ";
+ typeName += "external";
+ }
}
if (mdfs.intrinsic)
{
@@ -1788,6 +1830,16 @@ static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs)
if (!typeName.isEmpty()) typeName += ", ";
typeName += "protected";
}
+ if (mdfs.contiguous)
+ {
+ if (!typeName.isEmpty()) typeName += ", ";
+ typeName += "contiguous";
+ }
+ if (mdfs.volat)
+ {
+ if (!typeName.isEmpty()) typeName += ", ";
+ typeName += "volatile";
+ }
return typeName;
}
@@ -1991,7 +2043,7 @@ static void addModule(const char *name, bool isModule)
DBG_CTX((stderr, "0=========> got module %s\n", name));
if (isModule)
- current->section = Entry::CLASS_SEC;
+ current->section = Entry::NAMESPACE_SEC;
else
current->section = Entry::FUNCTION_SEC;
@@ -2010,6 +2062,7 @@ static void addModule(const char *name, bool isModule)
current->type = "program";
current->fileName = yyFileName;
current->bodyLine = yyLineNr; // used for source reference
+ current->startLine = yyLineNr;
current->protection = Public ;
addCurrentEntry(1);
startScope(last_entry);
@@ -2026,8 +2079,8 @@ static void addSubprogram(const char *text)
current->type += " " + subtype;
current->type = current->type.stripWhiteSpace();
current->fileName = yyFileName;
- current->bodyLine = yyLineNr; // used for source reference
- current->startLine = -1; // ??? what is startLine for?
+ current->bodyLine = yyLineNr; // used for source reference start of body of routine
+ current->startLine = yyLineNr; // used for source reference start of definition
current->args.resize(0);
current->argList->clear();
docBlock.resize(0);
@@ -2075,6 +2128,7 @@ static void addInterface(QCString name, InterfaceType type)
current->fileName = yyFileName;
current->bodyLine = yyLineNr;
+ current->startLine = yyLineNr;
addCurrentEntry(1);
}
@@ -2155,79 +2209,117 @@ static void handleCommentBlock(const QCString &doc,bool brief)
}
//----------------------------------------------------------------------------
-
+/// Handle parameter description as defined after the declaration of the parameter
static void subrHandleCommentBlock(const QCString &doc,bool brief)
{
QCString loc_doc;
+ loc_doc = doc.stripWhiteSpace();
+
Entry *tmp_entry = current;
current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
// Still in the specification section so no inbodyDocs yet, but parameter documentation
current->inbodyDocs = "";
- if (docBlock.stripWhiteSpace().find("\\param") == 0)
+ // strip \\param or @param, so we can do some extra checking. We will add it later on again.
+ if (loc_doc.find("\\param") == 0)
{
- handleCommentBlock("\n\n"+doc,brief);
+ loc_doc = loc_doc.right(loc_doc.length()-strlen("\\param")).stripWhiteSpace();
}
- else if (docBlock.stripWhiteSpace().find("@param") == 0)
+ else if (loc_doc.find("@param") == 0)
{
- handleCommentBlock("\n\n"+doc,brief);
+ loc_doc = loc_doc.right(loc_doc.length()-strlen("@param")).stripWhiteSpace();
}
- else
+
+ // direction as defined with the declaration of the parameter
+ int dir1 = modifiers[current_root][argName.lower()].direction;
+ // in description [in] is specified
+ if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
{
- int dir1 = modifiers[current_root][argName.lower()].direction;
- loc_doc = doc.stripWhiteSpace();
- if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
+ // check if with the declaration intent(in) or nothing has been specified
+ if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
+ (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
{
- if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
- (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
- {
- handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " +
- argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN])),brief);
- }
- else
+ // strip direction
+ loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN]));
+ // in case of emty documentation or (now) just name, consider it as no documemntation
+ if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
{
- warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
- handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
- argName + " " + doc,brief);
+ // reset current back to the part inside the routine
+ current=tmp_entry;
+ return;
}
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " +
+ argName + " " + loc_doc,brief);
}
- else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
+ else
{
- if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
- (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
- {
- handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " +
- argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT])),brief);
- }
- else
- {
- warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
- handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
- argName + " " + doc,brief);
- }
+ // something different specified, give warning and leave error.
+ warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
+ " inconsistency between intent attribute and documentation for parameter: " + argName);
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
+ argName + " " + loc_doc,brief);
}
- else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
+ }
+ // analogous to the [in] case, here [out] direction specified
+ else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
+ {
+ if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
+ (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
{
- if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
- (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
+ loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT]));
+ if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
{
- handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " +
- argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT])),brief);
+ current=tmp_entry;
+ return;
}
- else
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " +
+ argName + " " + loc_doc,brief);
+ }
+ else
+ {
+ warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
+ " inconsistency between intent attribute and documentation for parameter: " + argName);
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
+ argName + " " + loc_doc,brief);
+ }
+ }
+ // analogous to the [in] case, here [in,out] direction specified
+ else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
+ {
+ if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
+ (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
+ {
+ loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT]));
+ if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
{
- warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
- handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
- argName + " " + doc,brief);
+ current=tmp_entry;
+ return;
}
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " +
+ argName + " " + loc_doc,brief);
}
else
{
+ warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
+ " inconsistency between intent attribute and documentation for parameter: " + argName);
handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
- argName + " " + doc,brief);
+ argName + " " + loc_doc,brief);
}
}
+ // analogous to the [in] case; here no direction specified
+ else
+ {
+ if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
+ {
+ current=tmp_entry;
+ return;
+ }
+ handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
+ argName + " " + loc_doc,brief);
+ }
+
+ // reset current back to the part inside the routine
current=tmp_entry;
}