diff options
Diffstat (limited to 'trunk/src/fortranscanner.l')
-rw-r--r-- | trunk/src/fortranscanner.l | 2252 |
1 files changed, 0 insertions, 2252 deletions
diff --git a/trunk/src/fortranscanner.l b/trunk/src/fortranscanner.l deleted file mode 100644 index 0a11483..0000000 --- a/trunk/src/fortranscanner.l +++ /dev/null @@ -1,2252 +0,0 @@ -/* -*- 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. - * - * - Must track yyLineNr when using REJECT, unput() or similar commands. - */ - -%{ - -#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" -#include "arguments.h" - -#define YY_NEVER_INTERACTIVE 1 - -class Arguments; - -enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER}; -enum InterfaceType { IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT }; - -// {{{ ----- 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. - QCString type, returnName; - Protection protection; - Direction direction; - bool optional; - QCString dimension; - bool allocatable; - bool external; - bool intrinsic; - bool parameter; - bool pointer; - bool target; - bool save; - bool deferred; - bool nonoverridable; - bool nopass; - bool pass; - QCString passVar; - - 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), deferred(FALSE), nonoverridable(FALSE), - nopass(FALSE), pass(FALSE), passVar() {} - - SymbolModifiers& operator|=(const SymbolModifiers &mdfs); - SymbolModifiers& operator|=(QCString mdfrString); -}; - -//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs); - -static const char *directionStrs[] = -{ - "", "intent(in)", "intent(out)", "intent(inout)" -}; -static const char *directionParam[] = -{ - "", "[in]", "[out]", "[in,out]" -}; - -// }}} - -/* ----------------------------------------------------------------- - * - * statics - */ -static ParserInterface *g_thisParser; -static const char * inputString; -static int inputPosition; -static bool isFixedForm; -static QCString inputStringPrepass; ///< Input string for prepass of line cont. '&' -static QCString inputStringSemi; ///< Input string after command separetor ';' -static unsigned int inputPositionPrepass; -static int lineCountPrepass = 0; - -static QList<Entry> subrCurrent; - -struct CommentInPrepass { - int column; - QCString str; - CommentInPrepass(int column, QCString str) : column(column), str(str) {} -}; -static QList<CommentInPrepass> comments; - -#define MAX_INCLUDE_DEPTH 10 -YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; -int include_stack_ptr = 0; - -static QFile inputFile; -static QCString yyFileName; -static int yyLineNr = 1 ; -static int yyColNr = 0 ; -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 QCString 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 int initializerArrayScope; // number if nested array scopes in initializer -static int initializerScope; // number if nested function calls in initializer -static QCString useModuleName; // name of module in the use statement -static Protection defaultProtection; -static Protection typeProtection; -static int typeMode = false; -static InterfaceType ifType = IF_NONE; -static bool functionLine = FALSE; - -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<QCString,SymbolModifiers> > modifiers; - -//----------------------------------------------------------------------------- - -static int yyread(char *buf,int max_size); -static void startCommentBlock(bool); -static void handleCommentBlock(const QCString &doc,bool brief); -static void subrHandleCommentBlock(const QCString &doc,bool brief); -static void addCurrentEntry(); -static void addModule(const char *name, bool isModule=FALSE); -static void addSubprogram(const char *text); -static void addInterface(QCString name, InterfaceType type); -static Argument *getParameter(const QCString &name); -static void scanner_abort(); - -static void startScope(Entry *scope); -static bool endScope(Entry *scope, bool isGlobalRoot=FALSE); -static QCString getFullName(Entry *e); -//static bool isTypeName(QCString name); -static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root); -static int getAmpersandAtTheStart(const char *buf, int length); -static int getAmpOrExclAtTheEnd(const char *buf, int length); -static void truncatePrepass(int index); -static void pushBuffer(QCString &buffer); -static void popBuffer(); -//static void extractPrefix(QCString& text); -static QCString extractFromParens(const QCString name); -static CommentInPrepass* locatePrepassComment(int from, int to); -static void updateVariablePrepassComment(int from, int to); -static void newLine(); - -//----------------------------------------------------------------------------- -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); -#define YY_USER_ACTION yyColNr+=yyleng; -//----------------------------------------------------------------------------- - -%} - - //----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- -IDSYM [a-z_A-Z0-9] -NOTIDSYM [^a-z_A-Z0-9] -SEPARATE [:, \t] -ID [a-z_A-Z%]+{IDSYM}* -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_L0 ("("[^)]*")") -ARGS_L1a [^()]*"("[^)]*")"[^)]* -ARGS_L1 ("("{ARGS_L1a}*")") -ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")" -ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2}) -NOARGS {BS}"\n" - -NUM_TYPE (complex|integer|logical|real) -LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.) -KIND {ARGS} -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|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE) -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} - -CONTAINS CONTAINS -PREFIX (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTAL)? - -%option noyywrap -%option stack -%option caseless -/*%option debug */ - - //--------------------------------------------------------------------------------- - - /** fortran parsing states */ -%x Subprog -%x SubprogPrefix -%x Parameterlist -%x SubprogBody -%x SubprogBodyContains -%x Start -%x Comment -%x Module -%x Program -%x ModuleBody -%x ModuleBodyContains -%x AttributeList -%x Variable -%x Initialization -%x ArrayInitializer -%x Typedef -%x TypedefBody -%x TypedefBodyContains -%x InterfaceBody -%x StrIgnore -%x String -%x Use -%x UseOnly -%x ModuleProcedure - -%x Prepass - - /** comment parsing states */ -%x DocBlock -%x DocBackLine -%x EndDoc - -%x BlockData -%% - - /*-----------------------------------------------------------------------------------*/ - -<*>^.*\n { // prepass: look for line continuations - functionLine = FALSE; - - //fprintf(stderr, "---%s", yytext); - - int indexStart = getAmpersandAtTheStart(yytext, yyleng); - int indexEnd = getAmpOrExclAtTheEnd(yytext, yyleng); - if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp - indexEnd=-1; - - if(indexEnd<0){ // ----- no ampersand as line continuation - if(YY_START == Prepass) { // last line in "continuation" - - // Only take input after initial ampersand - inputStringPrepass+=(const char*)(yytext+(indexStart+1)); - - //printf("BUFFER:%s\n", (const char*)inputStringPrepass); - pushBuffer(inputStringPrepass); - yyColNr = 0; - yy_pop_state(); - } else { // simple line - yyColNr = 0; - REJECT; - } - - } else { // ----- line with continuation - if(YY_START != Prepass) { - comments.setAutoDelete(TRUE); - comments.clear(); - yy_push_state(Prepass); - } - - int length = inputStringPrepass.length(); - - // Only take input after initial ampersand - inputStringPrepass+=(const char*)(yytext+(indexStart+1)); - lineCountPrepass ++; - - // cut off & and remove following comment if present - truncatePrepass(length+indexEnd-(indexStart+1)); - } - - } - - - /*------ ignore strings that are not initialization strings */ -<*>"\\\\" { if (yy_top_state() == Initialization - || yy_top_state() == ArrayInitializer) - initializer+=yytext; - } -<*>"\\\""|\\\' { if (yy_top_state() == Initialization - || yy_top_state() == ArrayInitializer) - initializer+=yytext; - } -<String>\"|\' { // string ends with next quote without previous backspace - if (yytext[0]!=stringStartSymbol) { yyColNr -= yyleng; REJECT; } // single vs double quote - if (yy_top_state() == Initialization - || yy_top_state() == ArrayInitializer) - initializer+=yytext; - yy_pop_state(); - } -<String>. { if (yy_top_state() == Initialization - || yy_top_state() == ArrayInitializer) - initializer+=yytext; - } -<*>\"|\' { /* string starts */ - if (YY_START == StrIgnore) { yyColNr -= yyleng; REJECT; }; // ignore in simple comments - yy_push_state(YY_START); - if (yy_top_state() == Initialization - || yy_top_state() == ArrayInitializer) - initializer+=yytext; - stringStartSymbol=yytext[0]; // single or double quote - BEGIN(String); - } - - /*------ ignore simple comment (not documentation comments) */ - -<*>"!"/[^<>\n] { if (YY_START == String) { yyColNr -= yyleng; 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="*!"; - //fprintf(stderr,"start comment %d\n",yyLineNr); - } - } -<StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character - //fprintf(stderr,"end comment %d %s\n",yyLineNr,debugStr.data()); - } // comment line ends -<StrIgnore>. { debugStr+=yytext; } - - - /*------ use handling ------------------------------------------------------------*/ - -<Start,ModuleBody,SubprogBody>"use"{BS_} { - if(YY_START == Start) - { - addModule(NULL); - yy_push_state(ModuleBody); //anon program - } - yy_push_state(Use); - } -<Use>{ID} { - //fprintf(stderr,"using dir %s\n",yytext); - current->name=yytext; - current->fileName = yyFileName; - current->section=Entry::USINGDIR_SEC; - current_root->addSubEntry(current); - current = new Entry; - current->lang = SrcLangExt_Fortran; - 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 ; - current->lang = SrcLangExt_Fortran; - } -<Use,UseOnly>"\n" { - yyColNr -= 1; - unput(*yytext); - yy_pop_state(); - } - - /* INTERFACE definitions */ -<Start,ModuleBody,SubprogBody>{ -^{BS}interface{IDSYM}+ { /* variable with interface prefix */ } -^{BS}interface { ifType = IF_SPECIFIC; - yy_push_state(InterfaceBody); - // do not start a scope here, every - // interface body is a scope of its own - } - -^{BS}abstract{BS_}interface { ifType = IF_ABSTRACT; - yy_push_state(InterfaceBody); - // do not start a scope here, every - // interface body is a scope of its own - } - -^{BS}interface{BS_}{ID}{ARGS}? { ifType = IF_GENERIC; - yy_push_state(InterfaceBody); - - // extract generic name - QCString name = QCString(yytext).stripWhiteSpace(); - name = name.right(name.length() - 9).stripWhiteSpace(); - addInterface(name, ifType); - - startScope(last_entry); - } -} - -<InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? { - // end scope only if GENERIC interface - if (ifType == IF_GENERIC && !endScope(current_root)) - yyterminate(); - - ifType = IF_NONE; - yy_pop_state(); - } -<InterfaceBody>module{BS}procedure { yy_push_state(YY_START); - BEGIN(ModuleProcedure); - } -<ModuleProcedure>{ID} { if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) - { - addInterface(yytext, ifType); - startScope(last_entry); - } - - current->section = Entry::FUNCTION_SEC ; - current->name = yytext; - moduleProcedures.append(current); - addCurrentEntry(); - } -<ModuleProcedure>"\n" { yyColNr -= 1; - unput(*yytext); - yy_pop_state(); - } -<InterfaceBody>. {} - - /*-- Contains handling --*/ -<Start>^{BS}{CONTAINS}/({BS}|\n|!) { - if(YY_START == Start) - { - addModule(NULL); - yy_push_state(ModuleBodyContains); //anon program - } - } -<ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(ModuleBodyContains); } -<SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(SubprogBodyContains); } -<TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(TypedefBodyContains); } - - /*------ module handling ------------------------------------------------------------*/ -<Start>block{BS}data{BS}{ID_} { // - v_type = V_IGNORE; - yy_push_state(BlockData); - defaultProtection = Public; - } -<Start>module|program{BS_} { // - v_type = V_IGNORE; - if(yytext[0]=='m' || yytext[0]=='M') - yy_push_state(Module); - else - yy_push_state(Program); - defaultProtection = Public; - } -<BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!) { // end block data - //if (!endScope(current_root)) - // yyterminate(); - defaultProtection = Public; - yy_pop_state(); - } -<Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module - resolveModuleProcedures(moduleProcedures, current_root); - if (!endScope(current_root)) - yyterminate(); - defaultProtection = Public; - yy_pop_state(); - } -<Module>{ID} { - addModule(yytext, TRUE); - BEGIN(ModuleBody); - } - -<Program>{ID} { - addModule(yytext, FALSE); - BEGIN(ModuleBody); - } - - /*------- access specification --------------------------------------------------------------------------*/ - -<ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private; - current->protection = defaultProtection ; - } -<ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public; - current->protection = defaultProtection ; - } - - /*------- type definition -------------------------------------------------------------------------------*/ - -<Start,ModuleBody>^{BS}type { - if(YY_START == Start) - { - addModule(NULL); - yy_push_state(ModuleBody); //anon program - } - - yy_push_state(Typedef); - current->protection = defaultProtection; - typeProtection = defaultProtection; - typeMode = true; - } -<Typedef>{ -{COMMA} {} - -{BS}"::"{BS} {} - -abstract { - current->spec |= Entry::AbstractClass; - } -extends{ARGS} { - QCString basename = extractFromParens(yytext); - current->extends->append(new BaseInfo(basename, Public, Normal)); - } -public { - current->protection = Public; - typeProtection = Public; - } -private { - current->protection = Private; - typeProtection = Private; - } -{LANGUAGE_BIND_SPEC} { - /* ignored for now */ - } -{ID} { /* type name found */ - current->section = Entry::CLASS_SEC; - current->spec |= Entry::Struct; - current->name = yytext; - current->fileName = yyFileName; - current->bodyLine = yyLineNr; - - /* 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; - } - - addCurrentEntry(); - startScope(last_entry); - BEGIN(TypedefBody); - } -} - -<TypedefBodyContains>{ /* Type Bound Procedures */ -^{BS}PROCEDURE{ARGS}? { - current->type = QCString(yytext).simplifyWhiteSpace(); - } -^{BS}final { - current->spec |= Entry::Final; - current->type = QCString(yytext).simplifyWhiteSpace(); - } -^{BS}generic { - current->type = QCString(yytext).simplifyWhiteSpace(); - } -{COMMA} { - } -{ATTR_SPEC} { - currentModifiers |= QCString(yytext); - } -{BS}"::"{BS} { - } -{ID} { - QCString name = yytext; - modifiers[current_root][name.lower()] |= currentModifiers; - current->section = Entry::FUNCTION_SEC; - current->name = name; - current->fileName = yyFileName; - current->bodyLine = yyLineNr; - addCurrentEntry(); - } -{BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */ - last_entry->args = yytext; - } -"\n" { - currentModifiers = SymbolModifiers(); - newLine(); - docBlock.resize(0); - } -} - - -<TypedefBody,TypedefBodyContains>{ -^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */ - if (!endScope(current_root)) - yyterminate(); - typeMode = false; - yy_pop_state(); - } -} - - /*------- module/global/typedef variable ---------------------------------------------------*/ - -<SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) { - // - // ABSTRACT and specific interfaces are stored - // in a scope of their own, even if multiple - // are group in one INTERFACE/END INTERFACE block. - // - if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) - endScope(current_root); - - if (!endScope(current_root)) - yyterminate(); - subrCurrent.remove(0u); - yy_pop_state() ; - } -<BlockData>{ -{ID} { - } -} -<Start,ModuleBody,TypedefBody,SubprogBody>{ -^{BS}{TYPE_SPEC}/{SEPARATE} { - /* variable declaration starts */ - if(YY_START == Start) - { - addModule(NULL); - yy_push_state(ModuleBody); //anon program - } - argType = QCString(yytext).simplifyWhiteSpace(); - yy_push_state(AttributeList); - } - /* Dimitri: macro expansion should already be done during preprocessing not here! -^{BS}{PP_ID}{KIND}? { // check for preprocessor symbol expand to type - QCString str = yytext; - str = str.stripWhiteSpace(); - //DefineDict* defines = getGlobalDefineDict(); - QCString name; - int index = str.find("("); - if (index != -1) - name = str.left(index).stripWhiteSpace(); - else - name = str; - - Define *define = 0; //(*defines)[name]; - if (define != 0 && isTypeName(define->definition)) - { - argType = str; - yy_push_state(AttributeList); - } - else - { - yyColNr -= yyleng; - REJECT; - } - } - */ -{ATTR_STMT}/{BS_}{ID} | -{ATTR_STMT}/{BS}"::" { - /* attribute statement starts */ - //fprintf(stderr,"5=========> Attribute statement: %s\n", yytext); - QCString tmp = yytext; - currentModifiers |= tmp.stripWhiteSpace(); - argType=""; - yy_push_state(YY_START); - BEGIN( AttributeList ) ; - } -{ID} { - } -^{BS}"type"{BS_}"is" { } -} -<AttributeList>{ -{COMMA} {} -{BS} {} -{ATTR_SPEC}. { /* update current modifierswhen it is an ATTR_SPEC and not a variable name */ - /* bug_625519 */ - QChar chr = yytext[yyleng-1]; - if (chr.isLetter() || chr.isDigit() || (chr == '_')) - { - yyColNr -= yyleng; - REJECT; - } - else - { - QCString tmp = yytext; - tmp = tmp.left(tmp.length() - 1); - yyColNr -= 1; - unput(yytext[yyleng-1]); - currentModifiers |= (tmp); - } - } -"::" { /* end attribute list */ - BEGIN( Variable ); - } -. { /* unknown attribute, consider variable name */ - //cout<<"start variables, unput "<<*yytext<<endl; - yyColNr -= 1; - 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 (QCString works) */ - QCString name=yytext; - /* remember attributes for the symbol */ - modifiers[current_root][name.lower()] |= currentModifiers; - argName= name; - - v_type= V_IGNORE; - if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) - { // 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()) - { // declaration of parameter list: add type for corr. parameter - parameter = getParameter(argName); - if (parameter) - { - v_type= V_PARAMETER; - if (!argType.isNull()) parameter->type=argType.stripWhiteSpace(); - if (!docBlock.isNull()) - { - subrHandleCommentBlock(docBlock,TRUE); - } - } - // save, it may be function return type - if (parameter) - { - modifiers[current_root][name.lower()].type = argType; - } - else - { - if ((current_root->name.lower() == argName.lower()) || - (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower())) - { - int strt = current_root->type.find("function"); - QString lft; - QString rght; - if (strt != -1) - { - lft = ""; - rght = ""; - if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace(); - if ((current_root->type.length() - strt - strlen("function"))!= 0) - { - rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace(); - } - current_root->type = lft; - if (rght.length() > 0) - { - if (current_root->type.length() > 0) current_root->type += " "; - current_root->type += rght; - } - if (argType.stripWhiteSpace().length() > 0) - { - if (current_root->type.length() > 0) current_root->type += " "; - current_root->type += argType.stripWhiteSpace(); - } - if (current_root->type.length() > 0) current_root->type += " "; - current_root->type += "function"; - } - else - { - current_root->type += " " + argType.stripWhiteSpace(); - } - current_root->type = current_root->type.stripWhiteSpace(); - modifiers[current_root][name.lower()].type = current_root->type; - } - else - { - 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. */ - QCString name(argName); - QCString attr("dimension"); - attr += yytext; - modifiers[current_root][name] |= attr; - } -<Variable>{COMMA} { //printf("COMMA: %d<=..<=%d\n", yyColNr-yyleng, yyColNr); - // locate !< comment - updateVariablePrepassComment(yyColNr-yyleng, yyColNr); - } -<Variable>{BS}"=" { yy_push_state(YY_START); - initializer=""; - initializerScope = initializerArrayScope = 0; - BEGIN(Initialization); - } -<Variable>"\n" { currentModifiers = SymbolModifiers(); - yy_pop_state(); // end variable declaration list - newLine(); - docBlock.resize(0); - } -<Variable>";".*"\n" { currentModifiers = SymbolModifiers(); - yy_pop_state(); // end variable declaration list - docBlock.resize(0); - inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data(); - yyLineNr--; - pushBuffer(inputStringSemi); - } -<*>";".*"\n" { - if (YY_START == Variable) REJECT; // Just be on the safe side - if (YY_START == String) REJECT; // ";" ignored in strings - if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments - inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data(); - yyLineNr--; - pushBuffer(inputStringSemi); - } - -<Initialization,ArrayInitializer>"(/" { initializer+=yytext; - initializerArrayScope++; - BEGIN(ArrayInitializer); // initializer may contain comma - } -<ArrayInitializer>"/)" { initializer+=yytext; - initializerArrayScope--; - if(initializerArrayScope<=0) - { - initializerArrayScope = 0; // just in case - BEGIN(Initialization); - } - } -<ArrayInitializer>. { initializer+=yytext; } -<Initialization>"(" { initializerScope++; - initializer+=yytext; - } -<Initialization>")" { initializerScope--; - initializer+=yytext; - } -<Initialization>{COMMA} { if (initializerScope == 0) - { - updateVariablePrepassComment(yyColNr-yyleng, yyColNr); - yy_pop_state(); // end initialization - if (v_type == V_VARIABLE) last_entry->initializer= initializer; - } - else - initializer+=", "; - } -<Initialization>"\n"|"!" { //| - yy_pop_state(); // end initialization - if (v_type == V_VARIABLE) last_entry->initializer= initializer; - yyColNr -= 1; - unput(*yytext); - } -<Initialization>. { initializer+=yytext; } - - /*------ fortran subroutine/function handling ------------------------------------------------------------*/ - /* Start is initial condition */ - -<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { - if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) - { - addInterface("$interface$", ifType); - startScope(last_entry); - } - - // TYPE_SPEC is for old function style function result - result = QCString(yytext).stripWhiteSpace(); - current->type = result; - yy_push_state(SubprogPrefix); - } - -<SubprogPrefix>{BS}{SUBPROG}{BS_} { - // Fortran subroutine or function found - v_type = V_IGNORE; - result=yytext; - result=result.stripWhiteSpace(); - addSubprogram(result); - BEGIN(Subprog); - } - -<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} { - // Fortran subroutine or function found - v_type = V_IGNORE; - if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) - { - addInterface("$interface$", ifType); - startScope(last_entry); - } - - result = QCString(yytext).stripWhiteSpace(); - addSubprogram(result); - yy_push_state(Subprog); - } - -<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; - - if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) - { - current_root->name.replace(QRegExp("\\$interface\\$"), yytext); - } - - BEGIN(Parameterlist); - } -<Parameterlist>"(" { current->args = "("; } -<Parameterlist>")" { - current->args += ")"; - current->args = removeRedundantWhiteSpace(current->args); - addCurrentEntry(); - startScope(last_entry); - BEGIN(SubprogBody); - } -<Parameterlist>{COMMA}|{BS} { current->args += yytext; - CommentInPrepass *c = locatePrepassComment(yyColNr-yyleng, yyColNr); - if (c!=NULL) { - if(current->argList->count()>0) { - current->argList->at(current->argList->count()-1)->docs = c->str; - } - } - } -<Parameterlist>{ID} { - //current->type not yet available - QCString param = yytext; - // std::cout << "3=========> got parameter " << param << std::endl; - current->args += param; - Argument *arg = new Argument; - arg->name = param; - arg->type = ""; - current->argList->append(arg); - } -<Parameterlist>{NOARGS} { - newLine(); - //printf("3=========> without parameterlist \n"); - //current->argList = ; - addCurrentEntry(); - startScope(last_entry); - BEGIN(SubprogBody); -} -<SubprogBody>result{BS}\({BS}{ID} { - if (functionLine) - { - 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; - } - - /*---- documentation comments --------------------------------------------------------------------*/ - -<Variable,SubprogBody,ModuleBody,TypedefBody>"!<" { /* backward docu comment */ - if (v_type != V_IGNORE) { - current->docLine = yyLineNr; - docBlockJavaStyle = FALSE; - docBlock.resize(0); - docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF"); - startCommentBlock(TRUE); - yy_push_state(DocBackLine); - } - } -<DocBackLine>.* { // contents of current comment line - docBlock+=yytext; - } -<DocBackLine>"\n"{BS}"!"("<"|"!"+) { // comment block (next line is also comment line) - docBlock+="\n"; // \n is necessary for lists - newLine(); - } -<DocBackLine>"\n" { // comment block ends at the end of this line - //cout <<"3=========> comment block : "<< docBlock << endl; - yyColNr -= 1; - unput(*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) - { - subrHandleCommentBlock(docBlock,TRUE); - } - yy_pop_state(); - docBlock.resize(0); - } - -<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains>"!>" { - 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 - newLine(); - } -<DocBlock>"\n" { // comment block ends at the end of this line - //cout <<"3=========> comment block : "<< docBlock << endl; - yyColNr -= 1; - unput(*yytext); - handleCommentBlock(docBlock,TRUE); - yy_pop_state(); - } - - /*------------------------------------------------------------------------------------------------*/ - -<*>"\n" { - newLine(); - //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl; - debugStr=""; - } - - - /*---- error: EOF in wrong state --------------------------------------------------------------------*/ - -<*><<EOF>> { - if ( include_stack_ptr <= 0 ) { - if (YY_START!=INITIAL && YY_START!=Start) { - //fprintf(stderr,"==== Error: EOF reached in wrong state (end missing)"); - scanner_abort(); - } - yyterminate(); - } else { - popBuffer(); - } - } -<*>{LOG_OPER} { // Fortran logical comparison keywords - } -<*>. { - //debugStr+=yytext; - //printf("I:%c\n", *yytext); - } // ignore remaining text - - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ -%% -//---------------------------------------------------------------------------- - -#if 0 -static void extractPrefix(QCString &text) -{ - int prefixIndex = 0; - int curIndex = 0; - bool cont = TRUE; - const char* pre[] = {"RECURSIVE","PURE","ELEMENTAL"}; - while(cont) - { - cont = FALSE; - for(unsigned int i=0; i<3; i++) - { - if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0) - { - text.remove(0,strlen(pre[i])); - text.stripWhiteSpace(); - cont = TRUE; - } - } - } -} -#endif - -static void newLine() { - yyLineNr++; - yyLineNr+=lineCountPrepass; - lineCountPrepass=0; - comments.clear(); -} - -static CommentInPrepass* locatePrepassComment(int from, int to) { - //printf("Locate %d-%d\n", from, to); - for(uint i=0; i<comments.count(); i++) { // todo: optimize - int c = comments.at(i)->column; - //printf("Candidate %d\n", c); - if (c>=from && c<=to) { - // comment for previous variable or parameter - return comments.at(i); - } - } - return NULL; -} - -static void updateVariablePrepassComment(int from, int to) { - CommentInPrepass *c = locatePrepassComment(from, to); - if (c!=NULL && v_type == V_VARIABLE) { - last_entry->brief = c->str; - } else if (c!=NULL && v_type == V_PARAMETER) { - Argument *parameter = getParameter(argName); - if (parameter) parameter->docs = c->str; - } -} - -static int getAmpersandAtTheStart(const char *buf, int length) -{ - for(int i=0; i<length; i++) { - switch(buf[i]) { - case ' ': - case '\t': - break; - case '&': - return i; - default: - return -1; - } - } - return -1; -} - -/* Returns ampersand index, comment start index or -1 if neither exist.*/ -static int getAmpOrExclAtTheEnd(const char *buf, int length) -{ - // Avoid ampersands in string and comments - int parseState = Start; - char quoteSymbol = 0; - int ampIndex = -1; - int commentIndex = -1; - - for(int i=0; i<length && parseState!=Comment; i++) - { - // When in string, skip backslashes - // Legacy code, not sure whether this is correct? - if(parseState==String) - { - if(buf[i]=='\\') i++; - } - - switch(buf[i]) - { - case '\'': - case '"': - // Close string, if quote symbol matches. - // Quote symbol is set iff parseState==String - if(buf[i]==quoteSymbol) - { - parseState = Start; - quoteSymbol = 0; - } - // Start new string, if not already in string or comment - else if(parseState==Start) - { - parseState = String; - quoteSymbol = buf[i]; - } - ampIndex = -1; // invalidate prev ampersand - break; - case '!': - // When in string or comment, ignore exclamation mark - if(parseState==Start) - { - parseState = Comment; - commentIndex = i; - } - break; - case ' ': // ignore whitespace - case '\t': - case '\n': // this may be at the end of line - break; - case '&': - ampIndex = i; - break; - default: - ampIndex = -1; // invalidate prev ampersand - } - } - - if (ampIndex>=0) - return ampIndex; - else - return commentIndex; -} - -/* Although comments at the end of continuation line are grabbed by this function, -* we still do not know how to use them later in parsing. -*/ -void truncatePrepass(int index) -{ - int length = inputStringPrepass.length(); - for (int i=index+1; i<length; i++) { - if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment - struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2)); - comments.append(c); - } - } - inputStringPrepass.truncate(index); -} - -// simplified way to know if this is fixed form -// duplicate in fortrancode.l -static bool recognizeFixedForm(const char* contents) -{ - int column=0; - bool skipLine=FALSE; - - for(int i=0;;i++) { - column++; - - switch(contents[i]) { - case '\n': - column=0; - skipLine=FALSE; - break; - case ' ': - break; - case '\000': - return FALSE; - case 'C': - case 'c': - case '*': - if(column==1) return TRUE; - if(skipLine) break; - return FALSE; - case '!': - if(column>1 && column<7) return FALSE; - skipLine=TRUE; - break; - default: - if(skipLine) break; - if(column==7) return TRUE; - return FALSE; - } - } - return FALSE; -} - -/* This function assumes that contents has at least size=length+1 */ -static void insertCharacter(char *contents, int length, int pos, char c) -{ - // shift tail by one character - for(int i=length; i>pos; i--) - contents[i]=contents[i-1]; - // set the character - contents[pos] = c; -} - -/* change comments and bring line continuation character to previous line */ -static const char* prepassFixedForm(const char* contents) -{ - int column=0; - int prevLineLength=0; - int prevLineAmpOrExclIndex=-1; - bool emptyLabel=TRUE; - int newContentsSize = strlen(contents)+2; // \000 and one spare character (to avoid reallocation) - char* newContents = (char*)malloc(newContentsSize); - - for(int i=0, j=0;;i++,j++) { - if(j>=newContentsSize-1) { // check for one spare character, which may be eventually used below (by &) - newContents = (char*)realloc(newContents, newContentsSize+1000); - newContentsSize = newContentsSize+1000; - } - - column++; - char c = contents[i]; - switch(c) { - case '\n': - prevLineLength=column; - prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength); - column=0; - emptyLabel=TRUE; - newContents[j]=c; - break; - case ' ': - newContents[j]=c; - break; - case '\000': - newContents[j]='\000'; - return newContents; - case 'C': - case 'c': - case '*': - if (column!=6) - { - emptyLabel=FALSE; - if(column==1) - newContents[j]='!'; - else - newContents[j]=c; - break; - } - default: - if(column==6 && emptyLabel) { // continuation - if (c != '0') { // 0 not allowed as continuatioin character, see f95 standard paragraph 3.3.2.3 - newContents[j]=' '; - - if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line - insertCharacter(newContents, j+1, (j+1)-6-1, '&'); - j++; - } else { // add & just before end of previous line comment - insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&'); - j++; - } - } else { - newContents[j]=c; // , just handle like space - } - } else { - newContents[j]=c; - emptyLabel=FALSE; - } - break; - } - } - return newContents; -} - -static void pushBuffer(QCString& buffer) -{ - if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) - { - fprintf( stderr, "Stack buffers nested too deeply" ); - exit( 1 ); - } - include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; - yy_switch_to_buffer(yy_scan_string(buffer)); - - //fprintf(stderr, "--PUSH--%s", (const char *)buffer); - buffer = NULL; -} - -static void popBuffer() { - //fprintf(stderr, "--POP--"); - include_stack_ptr --; - yy_delete_buffer( YY_CURRENT_BUFFER ); - yy_switch_to_buffer( include_stack[include_stack_ptr] ); -} - -/** 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); - dest->doc = src->doc; - dest->brief = src->brief; -} - -/** 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(); -} - -#if 0 -static bool isTypeName(QCString name) -{ - name = name.lower(); - return name=="integer" || name == "real" || - name=="complex" || name == "logical"; -} -#endif - -/*! Extracts string which resides within parentheses of provided string. */ -static QCString extractFromParens(const QCString name) -{ - QCString 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; - deferred |= mdfs.deferred; - nonoverridable |= mdfs.nonoverridable; - nopass |= mdfs.nopass; - pass |= mdfs.pass; - passVar = mdfs.passVar; - return *this; -} - -/*! Extracts and adds passed modifier to these modifiers.*/ -SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString) -{ - mdfString = mdfString.lower(); - SymbolModifiers newMdf; - - if (mdfString.find("dimension")==0) - { - newMdf.dimension=mdfString; - } - else if (mdfString.contains("intent")) - { - QCString 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; - } - else if (mdfString=="nopass") - { - newMdf.nopass = TRUE; - } - else if (mdfString=="deferred") - { - newMdf.deferred = TRUE; - } - else if (mdfString=="non_overridable") - { - newMdf.nonoverridable = TRUE; - } - else if (mdfString.contains("pass")) - { - newMdf.pass = TRUE; - if (mdfString.contains("(")) - newMdf.passVar = extractFromParens(mdfString); - else - newMdf.passVar = ""; - } - - (*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, QCString 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 0; -} - -/*! Find function with given name in \a entry. */ -#if 0 -static Entry *findFunction(Entry* entry, QCString 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 0; -} -#endif - -/*! Apply modifiers stored in \a mdfs to the \a typeName string. */ -static QCString applyModifiers(QCString 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"; - } - if (mdfs.deferred) - { - typeName += ", "; - typeName += "deferred"; - } - if (mdfs.nonoverridable) - { - typeName += ", "; - typeName += "non_overridable"; - } - if (mdfs.nopass) - { - typeName += ", "; - typeName += "nopass"; - } - if (mdfs.pass) - { - typeName += ", "; - typeName += "pass"; - if (!mdfs.passVar.isEmpty()) - typeName += "(" + mdfs.passVar + ")"; - } - if (mdfs.protection == SymbolModifiers::PUBLIC) - { - typeName += ", "; - typeName += "public"; - } - else if (mdfs.protection == SymbolModifiers::PRIVATE) - { - typeName += ", "; - typeName += "private"; - } - - return typeName; -} - -/*! Apply modifiers stored in \a mdfs to the \a arg argument. */ -static void applyModifiers(Argument *arg, SymbolModifiers& mdfs) -{ - QCString 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) -{ - QCString 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<QCString,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, bool isGlobalRoot) -{ - //cout<<"end scope: "<<scope->name<<endl; - if (current_root->parent() || isGlobalRoot) - { - 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<QCString,SymbolModifiers>& mdfsMap = modifiers[scope]; - - if (scope->section == Entry::FUNCTION_SEC) - { - // iterate all symbol modifiers of the scope - for (QMap<QCString,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; - QCString 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 - } - - } - 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; - int count = 0; - int found = FALSE; - for (;(ce=eli.current());++eli) - { - count++; - if (ce->section != Entry::FUNCTION_SEC) - continue; - - Argument *arg = findArgument(scope->parent(), ce->name, TRUE); - if (arg != 0) - { - // set type of dummy procedure argument to interface - arg->name = arg->type; - arg->type = scope->name; - } - if (ce->name.lower() == scope->name.lower()) found = TRUE; - } - if ((count == 1) && found) - { - // clear all modifiers of the scope - modifiers.remove(scope); - delete scope->parent()->removeSubEntry(scope); - scope = 0; - return TRUE; - } - } - } - if (scope->section!=Entry::FUNCTION_SEC) - { // not function section - // 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 QCString getFullName(Entry *e) -{ - QCString 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() -{ - if (typeMode) - { - current->protection = typeProtection; - } - else - { - current->protection = defaultProtection; - } - current->mtype = mtype; - current->virt = virt; - current->stat = gstat; - current->lang = SrcLangExt_Fortran; - initGroupInfo(current); -} - -/** - adds current entry to current_root and creates new current -*/ -static void addCurrentEntry() -{ - //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data()); - current_root->addSubEntry(current); - last_entry = current; - current = new Entry ; - initEntry(); -} - -static int max(int a, int b) {return a>b?a:b;} - -static void addModule(const char *name, bool isModule) -{ - //fprintf(stderr, "0=========> got module %s\n", name); - - if (isModule) - current->section = Entry::CLASS_SEC; - else - current->section = Entry::FUNCTION_SEC; - - if (name!=NULL) - { - current->name = name; - } - else - { - QCString fname = yyFileName; - int index = max(fname.findRev('/'), fname.findRev('\\')); - fname = fname.right(fname.length()-index-1); - fname = fname.prepend("__").append("__"); - current->name = fname; - } - current->type = "program"; - current->fileName = yyFileName; - current->bodyLine = yyLineNr; // used for source reference - current->protection = Public ; - addCurrentEntry(); - startScope(last_entry); -} - - -static void addSubprogram(const char *text) -{ - //fprintf(stderr,"1=========> got subprog, type: %s\n",text); - subrCurrent.prepend(current); - current->section = Entry::FUNCTION_SEC ; - QCString subtype = text; subtype=subtype.lower().stripWhiteSpace(); - functionLine = subtype=="function"; - 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->args.resize(0); - current->argList->clear(); - docBlock.resize(0); -} - -/*! 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(QCString name, InterfaceType type) -{ - if (YY_START == Start) - { - addModule(NULL); - yy_push_state(ModuleBody); //anon program - } - - current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC; - current->spec = Entry::Interface; - current->name = name; - - switch (type) - { - case IF_ABSTRACT: - current->type = "abstract"; - break; - - case IF_GENERIC: - current->type = "generic"; - break; - - case IF_SPECIFIC: - case IF_NONE: - default: - current->type = ""; - } - - /* 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; - } - - current->fileName = yyFileName; - current->bodyLine = yyLineNr; - addCurrentEntry(); -} - - -//----------------------------------------------------------------------------- - -/*! Get the argument \a name. - */ -static Argument* getParameter(const QCString &name) -{ - // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl; - Argument *ret = 0; - if (current_root->argList==0) return 0; - ArgumentListIterator ali(*current_root->argList); - Argument *a; - for (ali.toFirst();(a=ali.current());++ali) - { - if (a->name.lower()==name.lower()) - { - ret=a; - //printf("parameter found: %s\n",(const char*)name); - 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()); - int lineNr = brief ? current->briefLine : current->docLine; - while (parseCommentBlock( - g_thisParser, - docBlockInBody ? last_entry : current, - doc, // text - yyFileName, // file - lineNr, - 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 void subrHandleCommentBlock(const QCString &doc,bool brief) -{ - Entry *tmp_entry = current; - current = subrCurrent.first(); // temporarily switch to the entry of the subroutine / function - if (docBlock.stripWhiteSpace().find("\\param") == 0) - { - handleCommentBlock("\n\n"+doc,brief); - } - else if (docBlock.stripWhiteSpace().find("@param") == 0) - { - handleCommentBlock("\n\n"+doc,brief); - } - else - { - int dir1 = modifiers[current_root][argName.lower()].direction; - handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + - argName + " " + doc,brief); - } - current=tmp_entry; -} - -//---------------------------------------------------------------------------- -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; - inputStringPrepass = NULL; - inputPositionPrepass = 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)) - { - isFixedForm = recognizeFixedForm(fileBuf); - - if (isFixedForm) - { - msg("Prepassing fixed form of %s\n", fileName); - //printf("---strlen=%d\n", strlen(fileBuf)); - //clock_t start=clock(); - - inputString = prepassFixedForm(fileBuf); - - //clock_t end=clock(); - //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC); - } - - yyLineNr= 1 ; - yyFileName = fileName; - msg("Parsing file %s...\n",yyFileName.data()); - - startScope(rt); // implies current_root = rt - initParser(); - groupEnterFile(yyFileName,yyLineNr); - - current = new Entry; - current->lang = SrcLangExt_Fortran; - current->name = yyFileName; - current->section = Entry::SOURCE_SEC; - current_root->addSubEntry(current); - file_root = current; - current = new Entry; - current->lang = SrcLangExt_Fortran; - - fscanYYrestart( fscanYYin ); - { - BEGIN( Start ); - } - - fscanYYlex(); - groupLeaveFile(yyFileName,yyLineNr); - - endScope(current_root, TRUE); // TRUE - global root - - //debugCompounds(rt); //debug - - rt->program.resize(0); - delete current; current=0; - moduleProcedures.clear(); - if (isFixedForm) { - free((char*)inputString); - inputString=NULL; - } - - 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, - bool showLineNumbers - ) -{ - ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, - fileDef,startLine,endLine,inlineFragment,memberDef, - showLineNumbers); -} - -bool FortranLanguageScanner::needsPreprocessing(const QCString &extension) -{ - return extension!=extension.lower(); // use preprocessor only for upper case extensions -} -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(); - } - - // dummy call to avoid compiler warning - (void)yy_top_state(); - - 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 - |