diff options
Diffstat (limited to 'src/fortranscanner.l')
-rw-r--r-- | src/fortranscanner.l | 194 |
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; } |