1 /* -*- mode: fundamental; indent-tabs-mode: 1; -*- */
2 /*****************************************************************************
3 * Parser for Fortran90 F subset
5 * Copyright (C) by Anke Visser
6 * based on the work of Dimitri van Heesch.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation under the terms of the GNU General Public License is hereby
10 * granted. No representations are made about the suitability of this software
11 * for any purpose. It is provided "as is" without express or implied warranty.
12 * See the GNU General Public License for more details.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
21 * - Consider using startScope(), endScope() functions with module, program,
22 * subroutine or any other scope in fortran program.
24 * - Symbol modifiers (attributes) are collected using SymbolModifiers |= operator during
25 * substructure parsing. When substructure ends all modifiers are applied to actual
26 * entries in applyModifiers() functions.
28 * - How case insensitiveness should be handled in code?
29 * On one side we have arg->name and entry->name, on another side modifierMap[name].
30 * In entries and arguments case is the same as in code, in modifier map case is lowered and
31 * then it is compared to lowered entry/argument names.
33 * - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space
34 * with separate rule?: It seems it is often necessary, because we may parse something like
35 * "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]'
38 * - Must track yyLineNr when using REJECT, unput() or similar commands.
40 %option never-interactive
41 %option case-insensitive
42 %option prefix="fortranscannerYY"
57 #include "fortranscanner.h"
65 #include "commentscan.h"
66 #include "fortrancode.h"
68 #include "arguments.h"
70 // Toggle for some debugging info
71 //#define DBG_CTX(x) fprintf x
72 #define DBG_CTX(x) do { } while(0)
75 #define YY_NO_UNISTD_H 1
77 enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER, V_RESULT};
78 enum InterfaceType { IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT };
80 // {{{ ----- Helper structs -----
81 //! Holds modifiers (ie attributes) for one symbol (variable, function, etc)
82 struct SymbolModifiers {
83 enum Protection {NONE_P, PUBLIC, PRIVATE};
84 enum Direction {NONE_D, IN, OUT, INOUT};
86 //!< This is only used with function return value.
87 QCString type, returnName;
88 Protection protection;
105 bool volat; /* volatile is a reserved name */
106 bool value; /* volatile is a reserved name */
109 SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D),
110 optional(FALSE), protect(FALSE), dimension(), allocatable(FALSE),
111 external(FALSE), intrinsic(FALSE), parameter(FALSE),
112 pointer(FALSE), target(FALSE), save(FALSE), deferred(FALSE), nonoverridable(FALSE),
113 nopass(FALSE), pass(FALSE), contiguous(FALSE), volat(FALSE), value(FALSE), passVar() {}
115 SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
116 SymbolModifiers& operator|=(QCString mdfrString);
119 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs);
121 static const char *directionStrs[] =
123 "", "intent(in)", "intent(out)", "intent(inout)"
125 static const char *directionParam[] =
127 "", "[in]", "[out]", "[in,out]"
132 /* -----------------------------------------------------------------
136 static ParserInterface *g_thisParser;
137 static const char * inputString;
138 static int inputPosition;
139 static bool isFixedForm;
140 static QCString inputStringPrepass; ///< Input string for prepass of line cont. '&'
141 static QCString inputStringSemi; ///< Input string after command separetor ';'
142 static unsigned int inputPositionPrepass;
143 static int lineCountPrepass = 0;
145 static QList<Entry> subrCurrent;
147 struct CommentInPrepass {
150 CommentInPrepass(int column, QCString str) : column(column), str(str) {}
152 static QList<CommentInPrepass> comments;
154 YY_BUFFER_STATE *include_stack = NULL;
155 int include_stack_ptr = 0;
156 int include_stack_cnt = 0;
158 static QFile inputFile;
159 static QCString yyFileName;
160 static int yyLineNr = 1 ;
161 static int yyColNr = 0 ;
162 static Entry* current_root = 0 ;
163 static Entry* global_root = 0 ;
164 static Entry* file_root = 0 ;
165 static Entry* current = 0 ;
166 static Entry* last_entry = 0 ;
167 static Entry* last_enum = 0 ;
168 static ScanVar v_type = V_IGNORE; // type of parsed variable
169 static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved
171 static QCString docBlock;
172 static bool docBlockInBody = FALSE;
173 static bool docBlockJavaStyle;
175 static MethodTypes mtype;
177 static Specifier virt;
179 static QCString debugStr;
180 static QCString result; // function result
181 static Argument *parameter; // element of parameter list
182 static QCString argType; // fortran type of an argument of a parameter list
183 static QCString argName; // last identifier name in variable list
184 static QCString initializer; // initial value of a variable
185 static int initializerArrayScope; // number if nested array scopes in initializer
186 static int initializerScope; // number if nested function calls in initializer
187 static QCString useModuleName; // name of module in the use statement
188 static Protection defaultProtection;
189 static Protection typeProtection;
190 static int typeMode = false;
191 static InterfaceType ifType = IF_NONE;
192 static bool functionLine = FALSE;
194 static char stringStartSymbol; // single or double quote
195 static bool parsingPrototype = FALSE; // see parsePrototype()
197 //! Accumulated modifiers of current statement, eg variable declaration.
198 static SymbolModifiers currentModifiers;
199 //! Holds program scope->symbol name->symbol modifiers.
200 static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers;
202 static Entry *global_scope = NULL;
203 static int anonCount = 0 ;
204 //-----------------------------------------------------------------------------
206 static int yyread(char *buf,int max_size);
207 static void startCommentBlock(bool);
208 static void handleCommentBlock(const QCString &doc,bool brief);
209 static void subrHandleCommentBlock(const QCString &doc,bool brief);
210 static void subrHandleCommentBlockResult(const QCString &doc,bool brief);
211 static void addCurrentEntry(int case_insens);
212 static void addModule(const char *name, bool isModule=FALSE);
213 static void addSubprogram(const char *text);
214 static void addInterface(QCString name, InterfaceType type);
215 static Argument *getParameter(const QCString &name);
216 static void scanner_abort();
218 static void startScope(Entry *scope);
219 static bool endScope(Entry *scope, bool isGlobalRoot=FALSE);
220 //static bool isTypeName(QCString name);
221 static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
222 static int getAmpersandAtTheStart(const char *buf, int length);
223 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch);
224 static void truncatePrepass(int index);
225 static void pushBuffer(QCString &buffer);
226 static void popBuffer();
227 //static void extractPrefix(QCString& text);
228 static QCString extractFromParens(const QCString name);
229 static CommentInPrepass* locatePrepassComment(int from, int to);
230 static void updateVariablePrepassComment(int from, int to);
231 static void newLine();
232 static void initEntry();
234 static const char *stateToString(int state);
236 //-----------------------------------------------------------------------------
238 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
239 #define YY_USER_ACTION yyColNr+=(int)yyleng;
240 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
245 //-----------------------------------------------------------------------------
247 NOTIDSYM [^a-z_A-Z0-9]
249 ID [a-z_A-Z%]+{IDSYM}*
250 ID_ [a-z_A-Z%]*{IDSYM}*
252 LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]*
253 SUBPROG (subroutine|function)
257 BT_ ([ \t]+|[ \t]*"(")
259 ARGS_L0 ("("[^)]*")")
260 ARGS_L1a [^()]*"("[^)]*")"[^)]*
261 ARGS_L1 ("("{ARGS_L1a}*")")
262 ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
263 ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
266 NUM_TYPE (complex|integer|logical|real)
267 LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
269 CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
270 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|ENUMERATOR|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
272 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
273 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|VALUE)
274 ACCESS_SPEC (PRIVATE|PUBLIC)
275 LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
276 /* Assume that attribute statements are almost the same as attributes. */
277 ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
278 EXTERNAL_STMT (EXTERNAL)
281 PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?
282 SCOPENAME ({ID}{BS}"::"{BS})*
289 //---------------------------------------------------------------------------------
291 /** fortran parsing states */
296 %x SubprogBodyContains
302 %x ModuleBodyContains
310 %x TypedefBodyContains
320 /** comment parsing states */
327 /** prototype parsing */
334 /*-----------------------------------------------------------------------------------*/
336 <Prepass>^{BS}[&]*{BS}!.*\n { /* skip lines with just comment. Note code was in free format or has been converted to it */
339 <Prepass>^{BS}\n { /* skip empty lines */
342 <*>^.*\n { // prepass: look for line continuations
343 functionLine = FALSE;
345 DBG_CTX((stderr, "---%s", yytext));
347 int indexStart = getAmpersandAtTheStart(yytext, (int)yyleng);
348 int indexEnd = getAmpOrExclAtTheEnd(yytext, (int)yyleng, '\0');
349 if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
352 if(indexEnd<0){ // ----- no ampersand as line continuation
353 if(YY_START == Prepass) { // last line in "continuation"
355 // Only take input after initial ampersand
356 inputStringPrepass+=(const char*)(yytext+(indexStart+1));
358 //printf("BUFFER:%s\n", (const char*)inputStringPrepass);
359 pushBuffer(inputStringPrepass);
362 } else { // simple line
367 } else { // ----- line with continuation
368 if(YY_START != Prepass) {
369 comments.setAutoDelete(TRUE);
371 yy_push_state(Prepass);
374 int length = inputStringPrepass.length();
376 // Only take input after initial ampersand
377 inputStringPrepass+=(const char*)(yytext+(indexStart+1));
380 // cut off & and remove following comment if present
381 truncatePrepass(length+indexEnd-(indexStart+1));
387 /*------ ignore strings that are not initialization strings */
388 <String>\"|\' { // string ends with next quote without previous backspace
389 if (yytext[0]!=stringStartSymbol) { yyColNr -= (int)yyleng; REJECT; } // single vs double quote
390 if (yy_top_state() == Initialization
391 || yy_top_state() == ArrayInitializer)
395 <String>. { if (yy_top_state() == Initialization
396 || yy_top_state() == ArrayInitializer)
399 <*>\"|\' { /* string starts */
400 if (YY_START == StrIgnore) { yyColNr -= (int)yyleng; REJECT; }; // ignore in simple comments
401 yy_push_state(YY_START);
402 if (yy_top_state() == Initialization
403 || yy_top_state() == ArrayInitializer)
405 stringStartSymbol=yytext[0]; // single or double quote
409 /*------ ignore simple comment (not documentation comments) */
411 <*>"!"/[^<>\n] { if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
412 // skip comment line (without docu comments "!>" "!<" )
413 /* ignore further "!" and ignore comments in Strings */
414 if ((YY_START != StrIgnore) && (YY_START != String))
416 yy_push_state(YY_START);
419 DBG_CTX((stderr,"start comment %d\n",yyLineNr));
422 <StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character
423 DBG_CTX((stderr,"end comment %d %s\n",yyLineNr,debugStr.data()));
424 } // comment line ends
425 <StrIgnore>. { debugStr+=yytext; }
428 /*------ use handling ------------------------------------------------------------*/
430 <Start,ModuleBody,SubprogBody>"use"{BS_} {
431 if(YY_START == Start)
434 yy_push_state(ModuleBody); //anon program
439 DBG_CTX((stderr,"using dir %s\n",yytext));
440 current->name=yytext;
441 current->fileName = yyFileName;
442 current->section=Entry::USINGDIR_SEC;
443 current_root->addSubEntry(current);
445 current->lang = SrcLangExt_Fortran;
449 useModuleName=yytext;
451 <Use>,{BS}"ONLY" { BEGIN(UseOnly);
453 <UseOnly>{BS},{BS} {}
455 current->name= useModuleName+"::"+yytext;
456 current->fileName = yyFileName;
457 current->section=Entry::USINGDECL_SEC;
458 current_root->addSubEntry(current);
459 current = new Entry ;
460 current->lang = SrcLangExt_Fortran;
468 /* INTERFACE definitions */
469 <Start,ModuleBody,SubprogBody>{
470 ^{BS}interface{IDSYM}+ { /* variable with interface prefix */ }
471 ^{BS}interface { ifType = IF_SPECIFIC;
472 yy_push_state(InterfaceBody);
473 // do not start a scope here, every
474 // interface body is a scope of its own
477 ^{BS}abstract{BS_}interface { ifType = IF_ABSTRACT;
478 yy_push_state(InterfaceBody);
479 // do not start a scope here, every
480 // interface body is a scope of its own
483 ^{BS}interface{BS_}{ID}{ARGS}? { ifType = IF_GENERIC;
484 current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
485 yy_push_state(InterfaceBody);
487 // extract generic name
488 QCString name = QCString(yytext).stripWhiteSpace();
489 name = name.right(name.length() - 9).stripWhiteSpace().lower();
490 addInterface(name, ifType);
491 startScope(last_entry);
495 <InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? {
496 // end scope only if GENERIC interface
497 if (ifType == IF_GENERIC)last_entry->parent()->endBodyLine = yyLineNr - 1;
498 if (ifType == IF_GENERIC && !endScope(current_root))
504 <InterfaceBody>module{BS}procedure { yy_push_state(YY_START);
505 BEGIN(ModuleProcedure);
507 <ModuleProcedure>{ID} { if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
509 addInterface(yytext, ifType);
510 startScope(last_entry);
513 current->section = Entry::FUNCTION_SEC ;
514 current->name = yytext;
515 moduleProcedures.append(current);
518 <ModuleProcedure>"\n" { yyColNr -= 1;
524 /*-- Contains handling --*/
525 <Start>^{BS}{CONTAINS}/({BS}|\n|!) {
526 if(YY_START == Start)
529 yy_push_state(ModuleBodyContains); //anon program
532 <ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(ModuleBodyContains); }
533 <SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(SubprogBodyContains); }
534 <TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(TypedefBodyContains); }
536 /*------ module handling ------------------------------------------------------------*/
537 <Start>block{BS}data{BS}{ID_} { //
539 yy_push_state(BlockData);
540 defaultProtection = Public;
542 <Start>module|program{BS_} { //
544 if(yytext[0]=='m' || yytext[0]=='M')
545 yy_push_state(Module);
547 yy_push_state(Program);
548 defaultProtection = Public;
550 <BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!) { // end block data
551 //if (!endScope(current_root))
553 defaultProtection = Public;
556 <Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module
557 resolveModuleProcedures(moduleProcedures, current_root);
558 if (!endScope(current_root))
560 defaultProtection = Public;
563 if (global_scope != (Entry *) -1)
564 yy_push_state(Start);
566 yy_pop_state(); // cannot pop artrificial entry
570 yy_push_state(Start);
571 global_scope = (Entry *)-1; // signal that the global_scope has already been used.
575 addModule(yytext, TRUE);
580 addModule(yytext, FALSE);
584 /*------- access specification --------------------------------------------------------------------------*/
586 <ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private;
587 current->protection = defaultProtection ;
589 <ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public;
590 current->protection = defaultProtection ;
593 /*------- type definition -------------------------------------------------------------------------------*/
595 <Start,ModuleBody>^{BS}type/[^a-z0-9_] {
596 if(YY_START == Start)
599 yy_push_state(ModuleBody); //anon program
602 yy_push_state(Typedef);
603 current->protection = defaultProtection;
604 typeProtection = defaultProtection;
613 current->spec |= Entry::AbstractClass;
616 QCString basename = extractFromParens(yytext).lower();
617 current->extends->append(new BaseInfo(basename, Public, Normal));
620 current->protection = Public;
621 typeProtection = Public;
624 current->protection = Private;
625 typeProtection = Private;
627 {LANGUAGE_BIND_SPEC} {
628 /* ignored for now */
630 {ID} { /* type name found */
631 current->section = Entry::CLASS_SEC;
632 current->spec |= Entry::Struct;
633 current->name = yytext;
634 current->fileName = yyFileName;
635 current->bodyLine = yyLineNr;
636 current->startLine = yyLineNr;
638 /* if type is part of a module, mod name is necessary for output */
639 if ((current_root) &&
640 (current_root->section == Entry::CLASS_SEC
641 || current_root->section == Entry::NAMESPACE_SEC))
643 current->name = current_root->name + "::" + current->name;
647 startScope(last_entry);
652 <TypedefBodyContains>{ /* Type Bound Procedures */
653 ^{BS}PROCEDURE{ARGS}? {
654 current->type = QCString(yytext).simplifyWhiteSpace();
657 current->spec |= Entry::Final;
658 current->type = QCString(yytext).simplifyWhiteSpace();
661 current->type = QCString(yytext).simplifyWhiteSpace();
666 currentModifiers |= QCString(yytext);
671 QCString name = yytext;
672 modifiers[current_root][name.lower()] |= currentModifiers;
673 current->section = Entry::FUNCTION_SEC;
674 current->name = name;
675 current->fileName = yyFileName;
676 current->bodyLine = yyLineNr;
677 current->startLine = yyLineNr;
680 {BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */
681 QCString args = yytext;
682 last_entry->args = args.lower();
685 currentModifiers = SymbolModifiers();
692 <TypedefBody,TypedefBodyContains>{
693 ^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
694 last_entry->parent()->endBodyLine = yyLineNr;
695 if (!endScope(current_root))
702 /*------- module/global/typedef variable ---------------------------------------------------*/
704 <SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {
706 // ABSTRACT and specific interfaces are stored
707 // in a scope of their own, even if multiple
708 // are group in one INTERFACE/END INTERFACE block.
710 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
712 endScope(current_root);
713 last_entry->endBodyLine = yyLineNr - 1;
715 current_root->endBodyLine = yyLineNr - 1;
717 if (!endScope(current_root))
719 subrCurrent.remove(0u);
726 <Start,ModuleBody,TypedefBody,SubprogBody,Enum>{
727 ^{BS}{TYPE_SPEC}/{SEPARATE} {
729 if (YY_START == Enum)
731 argType = "@"; // enum marker
735 argType = QCString(yytext).simplifyWhiteSpace().lower();
737 current->bodyLine = yyLineNr + 1;
738 current->endBodyLine = yyLineNr + lineCountPrepass;
739 /* variable declaration starts */
740 if(YY_START == Start)
743 yy_push_state(ModuleBody); //anon program
745 yy_push_state(AttributeList);
747 /* Dimitri: macro expansion should already be done during preprocessing not here!
748 ^{BS}{PP_ID}{KIND}? { // check for preprocessor symbol expand to type
749 QCString str = yytext;
750 str = str.stripWhiteSpace();
751 //DefineDict* defines = getGlobalDefineDict();
753 int index = str.find("(");
755 name = str.left(index).stripWhiteSpace();
759 Define *define = 0; //(*defines)[name];
760 if (define != 0 && isTypeName(define->definition))
763 yy_push_state(AttributeList);
767 yyColNr -= (int)yyleng;
772 {EXTERNAL_STMT}/({BS}"::"|{BS_}{ID}) {
773 /* external can be a "type" or an attribute */
774 if(YY_START == Start)
777 yy_push_state(ModuleBody); //anon program
779 QCString tmp = yytext;
780 currentModifiers |= tmp.stripWhiteSpace();
781 argType = QCString(yytext).simplifyWhiteSpace().lower();
782 yy_push_state(AttributeList);
784 {ATTR_STMT}/{BS_}{ID} |
785 {ATTR_STMT}/{BS}"::" {
786 /* attribute statement starts */
787 DBG_CTX((stderr,"5=========> Attribute statement: %s\n", yytext));
788 QCString tmp = yytext;
789 currentModifiers |= tmp.stripWhiteSpace();
791 yy_push_state(YY_START);
792 BEGIN( AttributeList ) ;
796 ^{BS}"type"{BS_}"is"/{BT_} { }
797 ^{BS}"type"{BS}"=" { }
798 ^{BS}"class"{BS_}"is"/{BT_} { }
799 ^{BS}"class"{BS_}"default" { }
804 {ATTR_SPEC}. { /* update current modifiers when it is an ATTR_SPEC and not a variable name */
806 QChar chr = yytext[(int)yyleng-1];
807 if (chr.isLetter() || chr.isDigit() || (chr == '_'))
809 yyColNr -= (int)yyleng;
814 QCString tmp = yytext;
815 tmp = tmp.left(tmp.length() - 1);
817 unput(yytext[(int)yyleng-1]);
818 currentModifiers |= (tmp);
821 "::" { /* end attribute list */
824 . { /* unknown attribute, consider variable name */
825 //cout<<"start variables, unput "<<*yytext<<endl;
833 <Variable>{ID} { /* parse variable declaration */
834 //cout << "5=========> got variable: " << argType << "::" << yytext << endl;
835 /* work around for bug in QCString.replace (QCString works) */
836 QCString name=yytext;
838 /* remember attributes for the symbol */
839 modifiers[current_root][name.lower()] |= currentModifiers;
843 if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC)
844 { // new variable entry
846 current->section = Entry::VARIABLE_SEC;
847 current->name = argName;
848 current->type = argType;
849 current->fileName = yyFileName;
850 current->bodyLine = yyLineNr; // used for source reference
851 current->startLine = yyLineNr;
854 current_root->addSubEntry(current);
855 current = new Entry(*current);
856 // add to the scope surrounding the enum (copy!)
857 current_root->parent()->addSubEntry(current);
859 current = new Entry ;
867 else if (!argType.isEmpty())
868 { // declaration of parameter list: add type for corr. parameter
869 parameter = getParameter(argName);
873 if (!argType.isNull()) parameter->type=argType.stripWhiteSpace();
874 if (!docBlock.isNull())
876 subrHandleCommentBlock(docBlock,TRUE);
879 // save, it may be function return type
882 modifiers[current_root][name.lower()].type = argType;
886 if ((current_root->name.lower() == argName.lower()) ||
887 (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower()))
889 int strt = current_root->type.find("function");
897 if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace();
898 if ((current_root->type.length() - strt - strlen("function"))!= 0)
900 rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace();
902 current_root->type = lft;
903 if (rght.length() > 0)
905 if (current_root->type.length() > 0) current_root->type += " ";
906 current_root->type += rght;
908 if (argType.stripWhiteSpace().length() > 0)
910 if (current_root->type.length() > 0) current_root->type += " ";
911 current_root->type += argType.stripWhiteSpace();
913 if (current_root->type.length() > 0) current_root->type += " ";
914 current_root->type += "function";
915 if (!docBlock.isNull())
917 subrHandleCommentBlockResult(docBlock,TRUE);
922 current_root->type += " " + argType.stripWhiteSpace();
924 current_root->type = current_root->type.stripWhiteSpace();
925 modifiers[current_root][name.lower()].type = current_root->type;
929 modifiers[current_root][name.lower()].type = argType;
932 // any accumulated doc for argument should be emptied,
933 // because it is handled other way and this doc can be
934 // unexpectedly passed to the next member.
935 current->doc.resize(0);
936 current->brief.resize(0);
939 <Variable>{ARGS} { /* dimension of the previous entry. */
940 QCString name(argName);
941 QCString attr("dimension");
943 modifiers[current_root][name.lower()] |= attr;
945 <Variable>{COMMA} { //printf("COMMA: %d<=..<=%d\n", yyColNr-(int)yyleng, yyColNr);
947 updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
950 yy_push_state(YY_START);
952 initializerScope = initializerArrayScope = 0;
953 BEGIN(Initialization);
955 <Variable>"\n" { currentModifiers = SymbolModifiers();
956 yy_pop_state(); // end variable declaration list
960 <Variable>";".*"\n" { currentModifiers = SymbolModifiers();
961 yy_pop_state(); // end variable declaration list
963 inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
965 pushBuffer(inputStringSemi);
968 if (YY_START == Variable) REJECT; // Just be on the safe side
969 if (YY_START == String) REJECT; // ";" ignored in strings
970 if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments
971 inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
973 pushBuffer(inputStringSemi);
976 <Initialization,ArrayInitializer>"[" |
977 <Initialization,ArrayInitializer>"(/" { initializer+=yytext;
978 initializerArrayScope++;
979 BEGIN(ArrayInitializer); // initializer may contain comma
981 <ArrayInitializer>"]" |
982 <ArrayInitializer>"/)" { initializer+=yytext;
983 initializerArrayScope--;
984 if(initializerArrayScope<=0)
986 initializerArrayScope = 0; // just in case
987 BEGIN(Initialization);
990 <ArrayInitializer>. { initializer+=yytext; }
991 <Initialization>"(" { initializerScope++;
994 <Initialization>")" { initializerScope--;
997 <Initialization>{COMMA} { if (initializerScope == 0)
999 updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
1000 yy_pop_state(); // end initialization
1003 last_enum->initializer= initializer;
1007 if (v_type == V_VARIABLE) last_entry->initializer= initializer;
1013 <Initialization>"\n"|"!" { //|
1014 yy_pop_state(); // end initialization
1017 last_enum->initializer= initializer;
1021 if (v_type == V_VARIABLE) last_entry->initializer= initializer;
1026 <Initialization>. { initializer+=yytext; }
1028 <*>{BS}"enum"{BS}","{BS}"bind"{BS}"("{BS}"c"{BS}")"{BS} {
1029 if(YY_START == Start)
1032 yy_push_state(ModuleBody); //anon program
1035 yy_push_state(Enum);
1036 current->protection = defaultProtection;
1037 typeProtection = defaultProtection;
1040 current->spec |= Entry::Struct;
1041 current->name.resize(0);
1042 current->args.resize(0);
1043 current->name.sprintf("@%d",anonCount++);
1045 current->section = Entry::ENUM_SEC;
1046 current->fileName = yyFileName;
1047 current->startLine = yyLineNr;
1048 current->bodyLine = yyLineNr;
1049 if ((current_root) &&
1050 (current_root->section == Entry::CLASS_SEC
1051 || current_root->section == Entry::NAMESPACE_SEC))
1053 current->name = current_root->name + "::" + current->name;
1057 startScope(last_entry);
1060 <Enum>"end"{BS}"enum" {
1061 last_entry->parent()->endBodyLine = yyLineNr;
1062 if (!endScope(current_root))
1067 /*------ fortran subroutine/function handling ------------------------------------------------------------*/
1068 /* Start is initial condition */
1070 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
1071 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1073 addInterface("$interface$", ifType);
1074 startScope(last_entry);
1077 // TYPE_SPEC is for old function style function result
1078 result = QCString(yytext).stripWhiteSpace().lower();
1079 current->type = result;
1080 yy_push_state(SubprogPrefix);
1083 <SubprogPrefix>{BS}{SUBPROG}{BS_} {
1084 // Fortran subroutine or function found
1087 result=result.stripWhiteSpace();
1088 addSubprogram(result);
1090 current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1091 current->startLine = yyLineNr;
1094 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1095 // Fortran subroutine or function found
1097 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1099 addInterface("$interface$", ifType);
1100 startScope(last_entry);
1103 result = QCString(yytext).stripWhiteSpace();
1104 addSubprogram(result);
1105 yy_push_state(Subprog);
1106 current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1107 current->startLine = yyLineNr;
1110 <Subprog>{BS} { /* ignore white space */ }
1111 <Subprog>{ID} { current->name = yytext;
1112 //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
1113 modifiers[current_root][current->name.lower()].returnName = current->name.lower();
1115 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1117 current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
1120 BEGIN(Parameterlist);
1122 <Parameterlist>"(" { current->args = "("; }
1123 <Parameterlist>")" {
1124 current->args += ")";
1125 current->args = removeRedundantWhiteSpace(current->args);
1127 startScope(last_entry);
1130 <Parameterlist>{COMMA}|{BS} { current->args += yytext;
1131 CommentInPrepass *c = locatePrepassComment(yyColNr-(int)yyleng, yyColNr);
1133 if(current->argList->count()>0) {
1134 current->argList->at(current->argList->count()-1)->docs = c->str;
1138 <Parameterlist>{ID} {
1139 //current->type not yet available
1140 QCString param = yytext;
1141 // std::cout << "3=========> got parameter " << param << std::endl;
1142 current->args += param;
1143 Argument *arg = new Argument;
1146 current->argList->append(arg);
1148 <Parameterlist>{NOARGS} {
1150 //printf("3=========> without parameterlist \n");
1151 //current->argList = ;
1153 startScope(last_entry);
1156 <SubprogBody>result{BS}\({BS}{ID} {
1160 result= result.right(result.length()-result.find("(")-1);
1161 result= result.stripWhiteSpace();
1162 modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
1164 //cout << "=====> got result " << result << endl;
1167 /*---- documentation comments --------------------------------------------------------------------*/
1169 <Variable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<" { /* backward docu comment */
1170 if (v_type != V_IGNORE) {
1171 current->docLine = yyLineNr;
1172 docBlockJavaStyle = FALSE;
1174 docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1175 startCommentBlock(TRUE);
1176 yy_push_state(DocBackLine);
1180 /* handle out of place !< comment as a normal comment */
1181 if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
1182 // skip comment line (without docu comments "!>" "!<" )
1183 /* ignore further "!" and ignore comments in Strings */
1184 if ((YY_START != StrIgnore) && (YY_START != String))
1186 yy_push_state(YY_START);
1192 <DocBackLine>.* { // contents of current comment line
1195 <DocBackLine>"\n"{BS}"!"("<"|"!"+) { // comment block (next line is also comment line)
1196 docBlock+="\n"; // \n is necessary for lists
1199 <DocBackLine>"\n" { // comment block ends at the end of this line
1200 //cout <<"3=========> comment block : "<< docBlock << endl;
1203 if (v_type == V_VARIABLE)
1205 Entry *tmp_entry = current;
1206 current = last_entry; // temporarily switch to the previous entry
1207 if (last_enum) current = last_enum;
1208 handleCommentBlock(docBlock,TRUE);
1211 else if (v_type == V_PARAMETER)
1213 subrHandleCommentBlock(docBlock,TRUE);
1215 else if (v_type == V_RESULT)
1217 subrHandleCommentBlockResult(docBlock,TRUE);
1223 <Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,Enum>"!>" {
1224 yy_push_state(YY_START);
1225 current->docLine = yyLineNr;
1226 docBlockJavaStyle = FALSE;
1227 if (YY_START==SubprogBody) docBlockInBody = TRUE;
1229 docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1230 startCommentBlock(TRUE);
1232 //cout << "start DocBlock " << endl;
1235 <DocBlock>.* { // contents of current comment line
1238 <DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line)
1239 docBlock+="\n"; // \n is necessary for lists
1242 <DocBlock>"\n" { // comment block ends at the end of this line
1243 //cout <<"3=========> comment block : "<< docBlock << endl;
1246 handleCommentBlock(docBlock,TRUE);
1250 /*-----Prototype parsing -------------------------------------------------------------------------*/
1251 <Prototype>{BS}{SUBPROG}{BS_} {
1252 BEGIN(PrototypeSubprog);
1254 <Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} {
1255 current->name = QCString(yytext).lower();
1256 current->name.stripWhiteSpace();
1257 BEGIN(PrototypeArgs);
1260 "("|")"|","|{BS_} { current->args += yytext; }
1261 {ID} { current->args += yytext;
1262 Argument *a = new Argument;
1263 a->name = QCString(yytext).lower();
1264 current->argList->append(a);
1268 /*------------------------------------------------------------------------------------------------*/
1272 //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
1277 /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1280 if (parsingPrototype) {
1283 } else if ( include_stack_ptr <= 0 ) {
1284 if (YY_START!=INITIAL && YY_START!=Start) {
1285 DBG_CTX((stderr,"==== Error: EOF reached in wrong state (end missing)"));
1293 <*>{LOG_OPER} { // Fortran logical comparison keywords
1297 //printf("I:%c\n", *yytext);
1298 } // ignore remaining text
1300 /**********************************************************************************/
1301 /**********************************************************************************/
1302 /**********************************************************************************/
1304 //----------------------------------------------------------------------------
1307 static void extractPrefix(QCString &text)
1309 int prefixIndex = 0;
1312 const char* pre[] = {"RECURSIVE","IMPURE","PURE","ELEMENTAL"};
1316 for(unsigned int i=0; i<4; i++)
1318 if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
1320 text.remove(0,strlen(pre[i]));
1321 text.stripWhiteSpace();
1329 static void newLine() {
1331 yyLineNr+=lineCountPrepass;
1336 static CommentInPrepass* locatePrepassComment(int from, int to) {
1337 //printf("Locate %d-%d\n", from, to);
1338 for(uint i=0; i<comments.count(); i++) { // todo: optimize
1339 int c = comments.at(i)->column;
1340 //printf("Candidate %d\n", c);
1341 if (c>=from && c<=to) {
1342 // comment for previous variable or parameter
1343 return comments.at(i);
1349 static void updateVariablePrepassComment(int from, int to) {
1350 CommentInPrepass *c = locatePrepassComment(from, to);
1351 if (c!=NULL && v_type == V_VARIABLE) {
1352 last_entry->brief = c->str;
1353 } else if (c!=NULL && v_type == V_PARAMETER) {
1354 Argument *parameter = getParameter(argName);
1355 if (parameter) parameter->docs = c->str;
1359 static int getAmpersandAtTheStart(const char *buf, int length)
1361 for(int i=0; i<length; i++) {
1375 /* Returns ampersand index, comment start index or -1 if neither exist.*/
1376 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
1378 // Avoid ampersands in string and comments
1379 int parseState = Start;
1380 char quoteSymbol = 0;
1382 int commentIndex = -1;
1384 if (ch != '\0') parseState = String;
1386 for(int i=0; i<length && parseState!=Comment; i++)
1388 // When in string, skip backslashes
1389 // Legacy code, not sure whether this is correct?
1390 if(parseState==String)
1392 if(buf[i]=='\\') i++;
1399 // Close string, if quote symbol matches.
1400 // Quote symbol is set iff parseState==String
1401 if(buf[i]==quoteSymbol)
1406 // Start new string, if not already in string or comment
1407 else if(parseState==Start)
1409 parseState = String;
1410 quoteSymbol = buf[i];
1412 ampIndex = -1; // invalidate prev ampersand
1415 // When in string or comment, ignore exclamation mark
1416 if(parseState==Start)
1418 parseState = Comment;
1422 case ' ': // ignore whitespace
1424 case '\n': // this may be at the end of line
1430 ampIndex = -1; // invalidate prev ampersand
1437 return commentIndex;
1440 /* Although comments at the end of continuation line are grabbed by this function,
1441 * we still do not know how to use them later in parsing.
1443 void truncatePrepass(int index)
1445 int length = inputStringPrepass.length();
1446 for (int i=index+1; i<length; i++) {
1447 if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment
1448 struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2));
1452 inputStringPrepass.truncate(index);
1455 // simplified way to know if this is fixed form
1456 // duplicate in fortrancode.l
1457 bool recognizeFixedForm(const char* contents, FortranFormat format)
1460 bool skipLine=FALSE;
1462 if (format == FortranFormat_Fixed) return TRUE;
1463 if (format == FortranFormat_Free) return FALSE;
1468 switch(contents[i]) {
1483 if(column==1) return TRUE;
1487 if(column>1 && column<7) return FALSE;
1492 if(column==7) return TRUE;
1499 /* This function assumes that contents has at least size=length+1 */
1500 static void insertCharacter(char *contents, int length, int pos, char c)
1502 // shift tail by one character
1503 for(int i=length; i>pos; i--)
1504 contents[i]=contents[i-1];
1505 // set the character
1509 /* change comments and bring line continuation character to previous line */
1510 /* also used to set continuation marks in case of fortran code usage, done here as it is quite complicated code */
1511 const char* prepassFixedForm(const char* contents, int *hasContLine)
1514 int prevLineLength=0;
1515 int prevLineAmpOrExclIndex=-1;
1516 char prevQuote = '\0';
1517 char thisQuote = '\0';
1518 bool emptyLabel=TRUE;
1519 bool commented=FALSE;
1520 bool inSingle=FALSE;
1521 bool inDouble=FALSE;
1522 bool inBackslash=FALSE;
1523 bool fullCommentLine=TRUE;
1524 int newContentsSize = strlen(contents)+3; // \000, \n (when necessary) and one spare character (to avoid reallocation)
1525 char* newContents = (char*)malloc(newContentsSize);
1528 for(int i=0, j=0;;i++,j++) {
1529 if(j>=newContentsSize-3) { // check for spare characters, which may be eventually used below (by & and '! ')
1530 newContents = (char*)realloc(newContents, newContentsSize+1000);
1531 newContentsSize = newContentsSize+1000;
1535 char c = contents[i];
1538 if (!fullCommentLine)
1540 prevLineLength=column;
1541 prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1542 if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1546 prevLineLength+=column;
1547 /* Even though a full comment line is not really a comment line it can be seen as one. An empty line is also seen as a comment line (small bonus) */
1550 hasContLine[curLine - 1] = 1;
1553 fullCommentLine=TRUE;
1558 prevQuote = thisQuote;
1571 newContents[j]='\000';
1572 newContentsSize = strlen(newContents);
1573 if (newContents[newContentsSize - 1] != '\n')
1575 // to be on the safe side
1576 newContents = (char*)realloc(newContents, newContentsSize+2);
1577 newContents[newContentsSize] = '\n';
1578 newContents[newContentsSize + 1] = '\000';
1584 if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1586 // we have some special cases in respect to strings and escaped string characters
1587 fullCommentLine=FALSE;
1591 inBackslash = !inBackslash;
1598 inSingle = !inSingle;
1599 if (inSingle) thisQuote = c;
1600 else thisQuote = '\0';
1608 inDouble = !inDouble;
1609 if (inDouble) thisQuote = c;
1610 else thisQuote = '\0';
1615 inBackslash = FALSE;
1621 if ((column <= fixedCommentAfter) && (column!=6))
1629 else if ((c == '!') && !inDouble && !inSingle)
1636 if (!commented) fullCommentLine=FALSE;
1643 if (!commented && (column < 6) && ((c - '0') >= 0) && ((c - '0') <= 9)) { // remove numbers, i.e. labels from first 5 positions.
1646 else if(column==6 && emptyLabel) { // continuation
1647 if (!commented) fullCommentLine=FALSE;
1648 if (c != '0') { // 0 not allowed as continuation character, see f95 standard paragraph 3.3.2.3
1651 if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line
1652 /* first line is not a continuation line in code, just in snippets etc. */
1653 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-1, '&');
1655 } else { // add & just before end of previous line comment
1656 /* first line is not a continuation line in code, just in snippets etc. */
1657 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&');
1660 if (hasContLine) hasContLine[curLine - 1] = 1;
1662 newContents[j]=c; // , just handle like space
1665 } else if ((column > fixedCommentAfter) && !commented) {
1666 // first non commented non blank character after position fixedCommentAfter
1668 // I'm not a possible start of doxygen comment
1669 newContents[j++]='!';
1670 newContents[j++]=' '; // so that '<' and '>' as first character are not converted to doxygen comment
1675 if (!commented) fullCommentLine=FALSE;
1688 newContentsSize = strlen(newContents);
1689 if (newContents[newContentsSize - 1] != '\n')
1691 // to be on the safe side
1692 newContents = (char*)realloc(newContents, newContentsSize+2);
1693 newContents[newContentsSize] = '\n';
1694 newContents[newContentsSize + 1] = '\000';
1699 static void pushBuffer(QCString& buffer)
1701 if (include_stack_cnt <= include_stack_ptr)
1703 include_stack_cnt++;
1704 include_stack = (YY_BUFFER_STATE *)realloc(include_stack, include_stack_cnt * sizeof(YY_BUFFER_STATE));
1706 include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
1707 yy_switch_to_buffer(yy_scan_string(buffer));
1709 DBG_CTX((stderr, "--PUSH--%s", (const char *)buffer));
1713 static void popBuffer() {
1714 DBG_CTX((stderr, "--POP--"));
1715 include_stack_ptr --;
1716 yy_delete_buffer( YY_CURRENT_BUFFER );
1717 yy_switch_to_buffer( include_stack[include_stack_ptr] );
1720 /** used to copy entry to an interface module procedure */
1721 static void copyEntry(Entry *dest, Entry *src)
1723 dest->type = src->type;
1724 dest->fileName = src->fileName;
1725 dest->startLine = src->startLine;
1726 dest->bodyLine = src->bodyLine;
1727 dest->endBodyLine = src->endBodyLine;
1728 dest->args = src->args;
1729 dest->argList = new ArgumentList(*src->argList);
1730 dest->doc = src->doc;
1731 dest->brief = src->brief;
1734 /** fill empty interface module procedures with info from
1735 corresponding module subprogs
1736 @TODO: handle procedures in used modules
1738 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
1740 if (moduleProcedures.isEmpty()) return;
1742 EntryListIterator eli1(moduleProcedures);
1743 // for all module procedures
1744 for (Entry *ce1; (ce1=eli1.current()); ++eli1)
1746 // check all entries in this module
1747 EntryListIterator eli2(*current_root->children());
1748 for (Entry *ce2; (ce2=eli2.current()); ++eli2)
1750 if (ce1->name == ce2->name)
1752 copyEntry(ce1, ce2);
1754 } // for procedures in current module
1755 } // for all interface module procedures
1756 moduleProcedures.clear();
1760 static bool isTypeName(QCString name)
1762 name = name.lower();
1763 return name=="integer" || name == "real" ||
1764 name=="complex" || name == "logical";
1768 /*! Extracts string which resides within parentheses of provided string. */
1769 static QCString extractFromParens(const QCString name)
1771 QCString extracted = name;
1772 int start = extracted.find("(");
1775 extracted.remove(0, start+1);
1777 int end = extracted.findRev(")");
1780 int length = extracted.length();
1781 extracted.remove(end, length);
1783 extracted = extracted.stripWhiteSpace();
1788 /*! Adds passed modifiers to these modifiers.*/
1789 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
1791 if (mdfs.protection!=NONE_P) protection = mdfs.protection;
1792 if (mdfs.direction!=NONE_D) direction = mdfs.direction;
1793 optional |= mdfs.optional;
1794 if (!mdfs.dimension.isNull()) dimension = mdfs.dimension;
1795 allocatable |= mdfs.allocatable;
1796 external |= mdfs.external;
1797 intrinsic |= mdfs.intrinsic;
1798 protect |= mdfs.protect;
1799 parameter |= mdfs.parameter;
1800 pointer |= mdfs.pointer;
1801 target |= mdfs.target;
1803 deferred |= mdfs.deferred;
1804 nonoverridable |= mdfs.nonoverridable;
1805 nopass |= mdfs.nopass;
1807 passVar = mdfs.passVar;
1808 contiguous |= mdfs.contiguous;
1809 volat |= mdfs.volat;
1810 value |= mdfs.value;
1814 /*! Extracts and adds passed modifier to these modifiers.*/
1815 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
1817 mdfString = mdfString.lower();
1818 SymbolModifiers newMdf;
1820 if (mdfString.find("dimension")==0)
1822 newMdf.dimension=mdfString;
1824 else if (mdfString.contains("intent"))
1826 QCString tmp = extractFromParens(mdfString);
1827 bool isin = tmp.contains("in");
1828 bool isout = tmp.contains("out");
1829 if (isin && isout) newMdf.direction = SymbolModifiers::INOUT;
1830 else if (isin) newMdf.direction = SymbolModifiers::IN;
1831 else if (isout) newMdf.direction = SymbolModifiers::OUT;
1833 else if (mdfString=="public")
1835 newMdf.protection = SymbolModifiers::PUBLIC;
1837 else if (mdfString=="private")
1839 newMdf.protection = SymbolModifiers::PRIVATE;
1841 else if (mdfString=="protected")
1843 newMdf.protect = TRUE;
1845 else if (mdfString=="optional")
1847 newMdf.optional = TRUE;
1849 else if (mdfString=="allocatable")
1851 newMdf.allocatable = TRUE;
1853 else if (mdfString=="external")
1855 newMdf.external = TRUE;
1857 else if (mdfString=="intrinsic")
1859 newMdf.intrinsic = TRUE;
1861 else if (mdfString=="parameter")
1863 newMdf.parameter = TRUE;
1865 else if (mdfString=="pointer")
1867 newMdf.pointer = TRUE;
1869 else if (mdfString=="target")
1871 newMdf.target = TRUE;
1873 else if (mdfString=="save")
1877 else if (mdfString=="nopass")
1879 newMdf.nopass = TRUE;
1881 else if (mdfString=="deferred")
1883 newMdf.deferred = TRUE;
1885 else if (mdfString=="non_overridable")
1887 newMdf.nonoverridable = TRUE;
1889 else if (mdfString=="contiguous")
1891 newMdf.contiguous = TRUE;
1893 else if (mdfString=="volatile")
1895 newMdf.volat = TRUE;
1897 else if (mdfString=="value")
1899 newMdf.value = TRUE;
1901 else if (mdfString.contains("pass"))
1904 if (mdfString.contains("("))
1905 newMdf.passVar = extractFromParens(mdfString);
1907 newMdf.passVar = "";
1914 /*! For debugging purposes. */
1915 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
1917 // out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
1918 // ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
1919 // ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
1924 /*! Find argument with given name in \a subprog entry. */
1925 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
1927 QCString cname(name.lower());
1928 for (unsigned int i=0; i<subprog->argList->count(); i++)
1930 Argument *arg = subprog->argList->at(i);
1931 if ((!byTypeName && arg->name.lower() == cname) ||
1932 (byTypeName && arg->type.lower() == cname)
1941 /*! Find function with given name in \a entry. */
1943 static Entry *findFunction(Entry* entry, QCString name)
1945 QCString cname(name.lower());
1947 EntryListIterator eli(*entry->children());
1949 for (;(ce=eli.current());++eli)
1951 if (ce->section != Entry::FUNCTION_SEC)
1954 if (ce->name.lower() == cname)
1962 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */
1963 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs)
1965 if (!mdfs.dimension.isNull())
1967 if (!typeName.isEmpty()) typeName += ", ";
1968 typeName += mdfs.dimension;
1970 if (mdfs.direction!=SymbolModifiers::NONE_D)
1972 if (!typeName.isEmpty()) typeName += ", ";
1973 typeName += directionStrs[mdfs.direction];
1977 if (!typeName.isEmpty()) typeName += ", ";
1978 typeName += "optional";
1980 if (mdfs.allocatable)
1982 if (!typeName.isEmpty()) typeName += ", ";
1983 typeName += "allocatable";
1987 if (!typeName.contains("external"))
1989 if (!typeName.isEmpty()) typeName += ", ";
1990 typeName += "external";
1995 if (!typeName.isEmpty()) typeName += ", ";
1996 typeName += "intrinsic";
2000 if (!typeName.isEmpty()) typeName += ", ";
2001 typeName += "parameter";
2005 if (!typeName.isEmpty()) typeName += ", ";
2006 typeName += "pointer";
2010 if (!typeName.isEmpty()) typeName += ", ";
2011 typeName += "target";
2015 if (!typeName.isEmpty()) typeName += ", ";
2020 if (!typeName.isEmpty()) typeName += ", ";
2021 typeName += "deferred";
2023 if (mdfs.nonoverridable)
2025 if (!typeName.isEmpty()) typeName += ", ";
2026 typeName += "non_overridable";
2030 if (!typeName.isEmpty()) typeName += ", ";
2031 typeName += "nopass";
2035 if (!typeName.isEmpty()) typeName += ", ";
2037 if (!mdfs.passVar.isEmpty())
2038 typeName += "(" + mdfs.passVar + ")";
2040 if (mdfs.protection == SymbolModifiers::PUBLIC)
2042 if (!typeName.isEmpty()) typeName += ", ";
2043 typeName += "public";
2045 else if (mdfs.protection == SymbolModifiers::PRIVATE)
2047 if (!typeName.isEmpty()) typeName += ", ";
2048 typeName += "private";
2052 if (!typeName.isEmpty()) typeName += ", ";
2053 typeName += "protected";
2055 if (mdfs.contiguous)
2057 if (!typeName.isEmpty()) typeName += ", ";
2058 typeName += "contiguous";
2062 if (!typeName.isEmpty()) typeName += ", ";
2063 typeName += "volatile";
2067 if (!typeName.isEmpty()) typeName += ", ";
2068 typeName += "value";
2074 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */
2075 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
2077 QCString tmp = arg->type;
2078 arg->type = applyModifiers(tmp, mdfs);
2081 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */
2082 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
2084 QCString tmp = ent->type;
2085 ent->type = applyModifiers(tmp, mdfs);
2087 if (mdfs.protection == SymbolModifiers::PUBLIC)
2088 ent->protection = Public;
2089 else if (mdfs.protection == SymbolModifiers::PRIVATE)
2090 ent->protection = Private;
2093 /*! Starts the new scope in fortran program. Consider using this function when
2094 * starting module, interface, function or other program block.
2097 static void startScope(Entry *scope)
2099 //cout<<"start scope: "<<scope->name<<endl;
2100 current_root= scope; /* start substructure */
2102 QMap<QCString,SymbolModifiers> mdfMap;
2103 modifiers.insert(scope, mdfMap);
2106 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
2109 static bool endScope(Entry *scope, bool isGlobalRoot)
2111 if (global_scope == scope)
2113 global_scope = NULL;
2116 if (global_scope == (Entry *) -1)
2120 //cout<<"end scope: "<<scope->name<<endl;
2121 if (current_root->parent() || isGlobalRoot)
2123 current_root= current_root->parent(); /* end substructure */
2125 else // if (current_root != scope)
2127 fprintf(stderr,"parse error in end <scopename>\n");
2132 // update variables or subprogram arguments with modifiers
2133 QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
2135 if (scope->section == Entry::FUNCTION_SEC)
2137 // iterate all symbol modifiers of the scope
2138 for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++)
2140 //cout<<it.key()<<": "<<it.data()<<endl;
2141 Argument *arg = findArgument(scope, it.key());
2144 applyModifiers(arg, it.data());
2147 // find return type for function
2148 //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
2149 QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
2150 if (modifiers[scope].contains(returnName))
2152 scope->type = modifiers[scope][returnName].type; // returning type works
2153 applyModifiers(scope, modifiers[scope][returnName]); // returning array works
2157 if (scope->section == Entry::CLASS_SEC)
2158 { // was INTERFACE_SEC
2159 if (scope->parent()->section == Entry::FUNCTION_SEC)
2160 { // interface within function
2161 // iterate functions of interface and
2162 // try to find types for dummy(ie. argument) procedures.
2163 //cout<<"Search in "<<scope->name<<endl;
2164 EntryListIterator eli(*scope->children());
2168 for (;(ce=eli.current());++eli)
2171 if (ce->section != Entry::FUNCTION_SEC)
2174 Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
2177 // set type of dummy procedure argument to interface
2178 arg->name = arg->type;
2179 arg->type = scope->name;
2181 if (ce->name.lower() == scope->name.lower()) found = TRUE;
2183 if ((count == 1) && found)
2185 // clear all modifiers of the scope
2186 modifiers.remove(scope);
2187 delete scope->parent()->removeSubEntry(scope);
2193 if (scope->section!=Entry::FUNCTION_SEC)
2194 { // not function section
2195 // iterate variables: get and apply modifiers
2196 EntryListIterator eli(*scope->children());
2198 for (;(ce=eli.current());++eli)
2200 if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
2203 //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
2204 if (mdfsMap.contains(ce->name.lower()))
2205 applyModifiers(ce, mdfsMap[ce->name.lower()]);
2209 // clear all modifiers of the scope
2210 modifiers.remove(scope);
2216 //! Return full name of the entry. Sometimes we must combine several names recursively.
2217 static QCString getFullName(Entry *e)
2219 QCString name = e->name;
2220 if (e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC
2221 || !e->parent() || e->parent()->name.isEmpty())
2224 return getFullName(e->parent())+"::"+name;
2228 static int yyread(char *buf,int max_size)
2232 while ( c < max_size && inputString[inputPosition] )
2234 *buf = inputString[inputPosition++] ;
2240 static void initParser()
2245 static void initEntry()
2249 current->protection = typeProtection;
2253 current->protection = defaultProtection;
2255 current->mtype = mtype;
2256 current->virt = virt;
2257 current->stat = gstat;
2258 current->lang = SrcLangExt_Fortran;
2259 initGroupInfo(current);
2263 adds current entry to current_root and creates new current
2265 static void addCurrentEntry(int case_insens)
2267 if (case_insens) current->name = current->name.lower();
2268 //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data());
2269 current_root->addSubEntry(current);
2270 last_entry = current;
2271 current = new Entry ;
2275 static int max(int a, int b) {return a>b?a:b;}
2277 static void addModule(const char *name, bool isModule)
2279 DBG_CTX((stderr, "0=========> got module %s\n", name));
2282 current->section = Entry::NAMESPACE_SEC;
2284 current->section = Entry::FUNCTION_SEC;
2288 current->name = name;
2292 QCString fname = yyFileName;
2293 int index = max(fname.findRev('/'), fname.findRev('\\'));
2294 fname = fname.right(fname.length()-index-1);
2295 fname = fname.prepend("__").append("__");
2296 current->name = fname;
2298 current->type = "program";
2299 current->fileName = yyFileName;
2300 current->bodyLine = yyLineNr; // used for source reference
2301 current->startLine = yyLineNr;
2302 current->protection = Public ;
2304 startScope(last_entry);
2308 static void addSubprogram(const char *text)
2310 DBG_CTX((stderr,"1=========> got subprog, type: %s\n",text));
2311 subrCurrent.prepend(current);
2312 current->section = Entry::FUNCTION_SEC ;
2313 QCString subtype = text; subtype=subtype.lower().stripWhiteSpace();
2314 functionLine = (subtype.find("function") != -1);
2315 current->type += " " + subtype;
2316 current->type = current->type.stripWhiteSpace();
2317 current->fileName = yyFileName;
2318 current->bodyLine = yyLineNr; // used for source reference start of body of routine
2319 current->startLine = yyLineNr; // used for source reference start of definition
2320 current->args.resize(0);
2321 current->argList->clear();
2325 /*! Adds interface to the root entry.
2326 * \note Code was brought to this procedure from the parser,
2327 * because there was/is idea to use it in several parts of the parser.
2329 static void addInterface(QCString name, InterfaceType type)
2331 if (YY_START == Start)
2334 yy_push_state(ModuleBody); //anon program
2337 current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
2338 current->spec = Entry::Interface;
2339 current->name = name;
2344 current->type = "abstract";
2348 current->type = "generic";
2357 /* if type is part of a module, mod name is necessary for output */
2358 if ((current_root) &&
2359 (current_root->section == Entry::CLASS_SEC ||
2360 current_root->section == Entry::NAMESPACE_SEC))
2362 current->name= current_root->name + "::" + current->name;
2365 current->fileName = yyFileName;
2366 current->bodyLine = yyLineNr;
2367 current->startLine = yyLineNr;
2372 //-----------------------------------------------------------------------------
2374 /*! Get the argument \a name.
2376 static Argument* getParameter(const QCString &name)
2378 // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl;
2380 if (current_root->argList==0) return 0;
2381 ArgumentListIterator ali(*current_root->argList);
2383 for (ali.toFirst();(a=ali.current());++ali)
2385 if (a->name.lower()==name.lower())
2388 //printf("parameter found: %s\n",(const char*)name);
2395 //----------------------------------------------------------------------------
2396 static void startCommentBlock(bool brief)
2400 current->briefFile = yyFileName;
2401 current->briefLine = yyLineNr;
2405 current->docFile = yyFileName;
2406 current->docLine = yyLineNr;
2410 //----------------------------------------------------------------------------
2412 static void handleCommentBlock(const QCString &doc,bool brief)
2414 bool needsEntry = FALSE;
2415 static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
2417 if (docBlockInBody && hideInBodyDocs)
2419 docBlockInBody = FALSE;
2422 DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
2423 int lineNr = brief ? current->briefLine : current->docLine;
2424 while (parseCommentBlock(
2426 docBlockInBody ? subrCurrent.getFirst() : current,
2430 docBlockInBody ? FALSE : brief,
2431 docBlockInBody ? FALSE : docBlockJavaStyle,
2438 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
2439 if (needsEntry) addCurrentEntry(0);
2441 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
2443 if (needsEntry) addCurrentEntry(0);
2444 docBlockInBody = FALSE;
2447 //----------------------------------------------------------------------------
2448 /// Handle parameter description as defined after the declaration of the parameter
2449 static void subrHandleCommentBlock(const QCString &doc,bool brief)
2452 loc_doc = doc.stripWhiteSpace();
2454 Entry *tmp_entry = current;
2455 current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2457 // Still in the specification section so no inbodyDocs yet, but parameter documentation
2458 current->inbodyDocs = "";
2460 // strip \\param or @param, so we can do some extra checking. We will add it later on again.
2461 if (!loc_doc.stripPrefix("\\param") &&
2462 !loc_doc.stripPrefix("@param")
2463 ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2464 loc_doc.stripWhiteSpace();
2466 // direction as defined with the declaration of the parameter
2467 int dir1 = modifiers[current_root][argName.lower()].direction;
2468 // in description [in] is specified
2469 if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
2471 // check if with the declaration intent(in) or nothing has been specified
2472 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2473 (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
2476 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN]));
2477 loc_doc.stripWhiteSpace();
2478 // in case of empty documentation or (now) just name, consider it as no documemntation
2479 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2481 // reset current back to the part inside the routine
2485 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " +
2486 argName + " " + loc_doc,brief);
2490 // something different specified, give warning and leave error.
2491 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2492 " inconsistency between intent attribute and documentation for parameter: " + argName);
2493 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2494 argName + " " + loc_doc,brief);
2497 // analogous to the [in] case, here [out] direction specified
2498 else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
2500 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2501 (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
2503 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT]));
2504 loc_doc.stripWhiteSpace();
2505 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2510 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " +
2511 argName + " " + loc_doc,brief);
2515 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2516 " inconsistency between intent attribute and documentation for parameter: " + argName);
2517 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2518 argName + " " + loc_doc,brief);
2521 // analogous to the [in] case, here [in,out] direction specified
2522 else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
2524 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2525 (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
2527 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT]));
2528 loc_doc.stripWhiteSpace();
2529 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2534 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " +
2535 argName + " " + loc_doc,brief);
2539 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2540 " inconsistency between intent attribute and documentation for parameter: " + argName);
2541 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2542 argName + " " + loc_doc,brief);
2545 // analogous to the [in] case; here no direction specified
2548 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2553 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2554 argName + " " + loc_doc,brief);
2557 // reset current back to the part inside the routine
2560 //----------------------------------------------------------------------------
2561 /// Handle result description as defined after the declaration of the parameter
2562 static void subrHandleCommentBlockResult(const QCString &doc,bool brief)
2565 loc_doc = doc.stripWhiteSpace();
2567 Entry *tmp_entry = current;
2568 current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2570 // Still in the specification section so no inbodyDocs yet, but parameter documentation
2571 current->inbodyDocs = "";
2573 // strip \\returns or @returns. We will add it later on again.
2574 if (!loc_doc.stripPrefix("\\returns") &&
2575 !loc_doc.stripPrefix("\\return") &&
2576 !loc_doc.stripPrefix("@returns") &&
2577 !loc_doc.stripPrefix("@return")
2578 ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2579 loc_doc.stripWhiteSpace();
2581 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2586 handleCommentBlock(QCString("\n\n@returns ") + loc_doc,brief);
2588 // reset current back to the part inside the routine
2592 //----------------------------------------------------------------------------
2596 static void debugCompounds(Entry *rt) // print Entry structure (for debugging)
2599 printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
2600 EntryListIterator eli(*rt->children());
2602 for (;(ce=eli.current());++eli)
2611 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, FortranFormat format)
2613 char *tmpBuf = NULL;
2616 defaultProtection = Public;
2617 inputString = fileBuf;
2619 inputStringPrepass = NULL;
2620 inputPositionPrepass = 0;
2622 //anonCount = 0; // don't reset per file
2628 inputFile.setName(fileName);
2629 if (inputFile.open(IO_ReadOnly))
2631 isFixedForm = recognizeFixedForm(fileBuf,format);
2635 msg("Prepassing fixed form of %s\n", fileName);
2636 //printf("---strlen=%d\n", strlen(fileBuf));
2637 //clock_t start=clock();
2639 //printf("Input fixed form string:\n%s\n", fileBuf);
2640 //printf("===========================\n");
2641 inputString = prepassFixedForm(fileBuf, NULL);
2642 //printf("Resulting free form string:\n%s\n", inputString);
2643 //printf("===========================\n");
2645 //clock_t end=clock();
2646 //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
2648 else if (inputString[strlen(fileBuf)-1] != '\n')
2650 tmpBuf = (char *)malloc(strlen(fileBuf)+2);
2651 strcpy(tmpBuf,fileBuf);
2652 tmpBuf[strlen(fileBuf)]= '\n';
2653 tmpBuf[strlen(fileBuf)+1]= '\000';
2654 inputString = tmpBuf;
2658 yyFileName = fileName;
2659 msg("Parsing file %s...\n",yyFileName.data());
2662 startScope(rt); // implies current_root = rt
2664 groupEnterFile(yyFileName,yyLineNr);
2666 current = new Entry;
2667 current->lang = SrcLangExt_Fortran;
2668 current->name = yyFileName;
2669 current->section = Entry::SOURCE_SEC;
2670 current_root->addSubEntry(current);
2671 file_root = current;
2672 current = new Entry;
2673 current->lang = SrcLangExt_Fortran;
2675 fortranscannerYYrestart( fortranscannerYYin );
2680 fortranscannerYYlex();
2681 groupLeaveFile(yyFileName,yyLineNr);
2683 if (global_scope && global_scope != (Entry *) -1) endScope(current_root, TRUE); // TRUE - global root
2685 //debugCompounds(rt); //debug
2687 rt->program.resize(0);
2688 delete current; current=0;
2689 moduleProcedures.clear();
2691 free((char*)tmpBuf);
2695 free((char*)inputString);
2703 //----------------------------------------------------------------------------
2705 void FortranLanguageScanner::parseInput(const char *fileName,
2706 const char *fileBuf,
2708 bool /*sameTranslationUnit*/,
2709 QStrList & /*filesInSameTranslationUnit*/)
2711 g_thisParser = this;
2713 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2715 ::parseMain(fileName,fileBuf,root,m_format);
2717 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2720 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2721 const char * scopeName,
2722 const QCString & input,
2723 SrcLangExt /*lang*/,
2724 bool isExampleBlock,
2725 const char * exampleName,
2729 bool inlineFragment,
2730 MemberDef *memberDef,
2731 bool showLineNumbers,
2732 Definition *searchCtx,
2736 ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
2737 fileDef,startLine,endLine,inlineFragment,memberDef,
2738 showLineNumbers,searchCtx,collectXRefs,m_format);
2741 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
2743 return extension!=extension.lower(); // use preprocessor only for upper case extensions
2745 void FortranLanguageScanner::resetCodeParserState()
2747 ::resetFortranCodeParserState();
2750 void FortranLanguageScanner::parsePrototype(const char *text)
2752 QCString buffer = QCString(text);
2754 parsingPrototype = TRUE;
2756 fortranscannerYYlex();
2757 parsingPrototype = FALSE;
2761 static void scanner_abort()
2763 fprintf(stderr,"********************************************************************\n");
2764 fprintf(stderr,"Error in file %s line: %d, state: %d(%s)\n",yyFileName.data(),yyLineNr,YY_START,stateToString(YY_START));
2765 fprintf(stderr,"********************************************************************\n");
2767 EntryListIterator eli(*global_root->children());
2771 for (;(ce=eli.current());++eli)
2773 if (ce == file_root) start=TRUE;
2774 if (start) ce->reset();
2777 // dummy call to avoid compiler warning
2778 (void)yy_top_state();
2784 //----------------------------------------------------------------------------
2786 #if !defined(YY_FLEX_SUBMINOR_VERSION)
2787 //----------------------------------------------------------------------------
2788 extern "C" { // some bogus code to keep the compiler happy
2789 void fortranscannernerYYdummy() { yy_flex_realloc(0,0); }
2793 #define scanStateToString(x) case x: resultString = #x; break;
2794 static const char *stateToString(int state)
2796 const char *resultString;
2799 scanStateToString(INITIAL)
2800 scanStateToString(Subprog)
2801 scanStateToString(SubprogPrefix)
2802 scanStateToString(Parameterlist)
2803 scanStateToString(SubprogBody)
2804 scanStateToString(SubprogBodyContains)
2805 scanStateToString(Start)
2806 scanStateToString(Comment)
2807 scanStateToString(Module)
2808 scanStateToString(Program)
2809 scanStateToString(ModuleBody)
2810 scanStateToString(ModuleBodyContains)
2811 scanStateToString(AttributeList)
2812 scanStateToString(Variable)
2813 scanStateToString(Initialization)
2814 scanStateToString(ArrayInitializer)
2815 scanStateToString(Enum)
2816 scanStateToString(Typedef)
2817 scanStateToString(TypedefBody)
2818 scanStateToString(TypedefBodyContains)
2819 scanStateToString(InterfaceBody)
2820 scanStateToString(StrIgnore)
2821 scanStateToString(String)
2822 scanStateToString(Use)
2823 scanStateToString(UseOnly)
2824 scanStateToString(ModuleProcedure)
2825 scanStateToString(Prepass)
2826 scanStateToString(DocBlock)
2827 scanStateToString(DocBackLine)
2828 scanStateToString(EndDoc)
2829 scanStateToString(BlockData)
2830 scanStateToString(Prototype)
2831 scanStateToString(PrototypeSubprog)
2832 scanStateToString(PrototypeArgs)
2833 default: resultString = "Unknown"; break;
2835 return resultString;