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 ScanVar v_type = V_IGNORE; // type of parsed variable
168 static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved
170 static QCString docBlock;
171 static bool docBlockInBody = FALSE;
172 static bool docBlockJavaStyle;
174 static MethodTypes mtype;
176 static Specifier virt;
178 static QCString debugStr;
179 static QCString result; // function result
180 static Argument *parameter; // element of parameter list
181 static QCString argType; // fortran type of an argument of a parameter list
182 static QCString argName; // last identifier name in variable list
183 static QCString initializer; // initial value of a variable
184 static int initializerArrayScope; // number if nested array scopes in initializer
185 static int initializerScope; // number if nested function calls in initializer
186 static QCString useModuleName; // name of module in the use statement
187 static Protection defaultProtection;
188 static Protection typeProtection;
189 static int typeMode = false;
190 static InterfaceType ifType = IF_NONE;
191 static bool functionLine = FALSE;
193 static char stringStartSymbol; // single or double quote
194 static bool parsingPrototype = FALSE; // see parsePrototype()
196 //! Accumulated modifiers of current statement, eg variable declaration.
197 static SymbolModifiers currentModifiers;
198 //! Holds program scope->symbol name->symbol modifiers.
199 static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers;
201 //-----------------------------------------------------------------------------
203 static int yyread(char *buf,int max_size);
204 static void startCommentBlock(bool);
205 static void handleCommentBlock(const QCString &doc,bool brief);
206 static void subrHandleCommentBlock(const QCString &doc,bool brief);
207 static void subrHandleCommentBlockResult(const QCString &doc,bool brief);
208 static void addCurrentEntry(int case_insens);
209 static void addModule(const char *name, bool isModule=FALSE);
210 static void addSubprogram(const char *text);
211 static void addInterface(QCString name, InterfaceType type);
212 static Argument *getParameter(const QCString &name);
213 static void scanner_abort();
215 static void startScope(Entry *scope);
216 static bool endScope(Entry *scope, bool isGlobalRoot=FALSE);
217 //static bool isTypeName(QCString name);
218 static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
219 static int getAmpersandAtTheStart(const char *buf, int length);
220 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch);
221 static void truncatePrepass(int index);
222 static void pushBuffer(QCString &buffer);
223 static void popBuffer();
224 //static void extractPrefix(QCString& text);
225 static QCString extractFromParens(const QCString name);
226 static CommentInPrepass* locatePrepassComment(int from, int to);
227 static void updateVariablePrepassComment(int from, int to);
228 static void newLine();
230 //-----------------------------------------------------------------------------
232 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
233 #define YY_USER_ACTION yyColNr+=(int)yyleng;
234 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
239 //-----------------------------------------------------------------------------
241 NOTIDSYM [^a-z_A-Z0-9]
243 ID [a-z_A-Z%]+{IDSYM}*
244 ID_ [a-z_A-Z%]*{IDSYM}*
246 LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]*
247 SUBPROG (subroutine|function)
252 ARGS_L0 ("("[^)]*")")
253 ARGS_L1a [^()]*"("[^)]*")"[^)]*
254 ARGS_L1 ("("{ARGS_L1a}*")")
255 ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
256 ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
259 NUM_TYPE (complex|integer|logical|real)
260 LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
262 CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
263 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
265 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
266 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)
267 ACCESS_SPEC (PRIVATE|PUBLIC)
268 LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
269 /* Assume that attribute statements are almost the same as attributes. */
270 ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
271 EXTERNAL_STMT (EXTERNAL)
274 PREFIX (RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,3}(RECURSIVE|IMPURE|PURE|ELEMENTAL)?
275 SCOPENAME ({ID}{BS}"::"{BS})*
282 //---------------------------------------------------------------------------------
284 /** fortran parsing states */
289 %x SubprogBodyContains
295 %x ModuleBodyContains
302 %x TypedefBodyContains
312 /** comment parsing states */
319 /** prototype parsing */
326 /*-----------------------------------------------------------------------------------*/
328 <Prepass>^{BS}[&]*{BS}!.*\n { /* skip lines with just comment. Note code was in free format or has been converted to it */
331 <Prepass>^{BS}\n { /* skip empty lines */
334 <*>^.*\n { // prepass: look for line continuations
335 functionLine = FALSE;
337 DBG_CTX((stderr, "---%s", yytext));
339 int indexStart = getAmpersandAtTheStart(yytext, (int)yyleng);
340 int indexEnd = getAmpOrExclAtTheEnd(yytext, (int)yyleng, '\0');
341 if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
344 if(indexEnd<0){ // ----- no ampersand as line continuation
345 if(YY_START == Prepass) { // last line in "continuation"
347 // Only take input after initial ampersand
348 inputStringPrepass+=(const char*)(yytext+(indexStart+1));
350 //printf("BUFFER:%s\n", (const char*)inputStringPrepass);
351 pushBuffer(inputStringPrepass);
354 } else { // simple line
359 } else { // ----- line with continuation
360 if(YY_START != Prepass) {
361 comments.setAutoDelete(TRUE);
363 yy_push_state(Prepass);
366 int length = inputStringPrepass.length();
368 // Only take input after initial ampersand
369 inputStringPrepass+=(const char*)(yytext+(indexStart+1));
372 // cut off & and remove following comment if present
373 truncatePrepass(length+indexEnd-(indexStart+1));
379 /*------ ignore strings that are not initialization strings */
380 <*>"\\\\" { if (yy_top_state() == Initialization
381 || yy_top_state() == ArrayInitializer)
384 <*>"\\\""|\\\' { if (yy_top_state() == Initialization
385 || yy_top_state() == ArrayInitializer)
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;
564 addModule(yytext, TRUE);
569 addModule(yytext, FALSE);
573 /*------- access specification --------------------------------------------------------------------------*/
575 <ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private;
576 current->protection = defaultProtection ;
578 <ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public;
579 current->protection = defaultProtection ;
582 /*------- type definition -------------------------------------------------------------------------------*/
584 <Start,ModuleBody>^{BS}type/[^a-z0-9_] {
585 if(YY_START == Start)
588 yy_push_state(ModuleBody); //anon program
591 yy_push_state(Typedef);
592 current->protection = defaultProtection;
593 typeProtection = defaultProtection;
602 current->spec |= Entry::AbstractClass;
605 QCString basename = extractFromParens(yytext);
606 current->extends->append(new BaseInfo(basename, Public, Normal));
609 current->protection = Public;
610 typeProtection = Public;
613 current->protection = Private;
614 typeProtection = Private;
616 {LANGUAGE_BIND_SPEC} {
617 /* ignored for now */
619 {ID} { /* type name found */
620 current->section = Entry::CLASS_SEC;
621 current->spec |= Entry::Struct;
622 current->name = yytext;
623 current->fileName = yyFileName;
624 current->bodyLine = yyLineNr;
625 current->startLine = yyLineNr;
627 /* if type is part of a module, mod name is necessary for output */
628 if ((current_root) &&
629 (current_root->section == Entry::CLASS_SEC
630 || current_root->section == Entry::NAMESPACE_SEC))
632 current->name = current_root->name + "::" + current->name;
636 startScope(last_entry);
641 <TypedefBodyContains>{ /* Type Bound Procedures */
642 ^{BS}PROCEDURE{ARGS}? {
643 current->type = QCString(yytext).simplifyWhiteSpace();
646 current->spec |= Entry::Final;
647 current->type = QCString(yytext).simplifyWhiteSpace();
650 current->type = QCString(yytext).simplifyWhiteSpace();
655 currentModifiers |= QCString(yytext);
660 QCString name = yytext;
661 modifiers[current_root][name.lower()] |= currentModifiers;
662 current->section = Entry::FUNCTION_SEC;
663 current->name = name;
664 current->fileName = yyFileName;
665 current->bodyLine = yyLineNr;
666 current->startLine = yyLineNr;
669 {BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */
670 last_entry->args = yytext;
673 currentModifiers = SymbolModifiers();
680 <TypedefBody,TypedefBodyContains>{
681 ^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
682 last_entry->parent()->endBodyLine = yyLineNr;
683 if (!endScope(current_root))
690 /*------- module/global/typedef variable ---------------------------------------------------*/
692 <SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {
694 // ABSTRACT and specific interfaces are stored
695 // in a scope of their own, even if multiple
696 // are group in one INTERFACE/END INTERFACE block.
698 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
700 endScope(current_root);
701 last_entry->endBodyLine = yyLineNr - 1;
703 current_root->endBodyLine = yyLineNr - 1;
705 if (!endScope(current_root))
707 subrCurrent.remove(0u);
714 <Start,ModuleBody,TypedefBody,SubprogBody>{
715 ^{BS}{TYPE_SPEC}/{SEPARATE} {
716 current->bodyLine = yyLineNr + 1;
717 current->endBodyLine = yyLineNr + lineCountPrepass;
718 /* variable declaration starts */
719 if(YY_START == Start)
722 yy_push_state(ModuleBody); //anon program
724 argType = QCString(yytext).simplifyWhiteSpace().lower();
725 yy_push_state(AttributeList);
727 /* Dimitri: macro expansion should already be done during preprocessing not here!
728 ^{BS}{PP_ID}{KIND}? { // check for preprocessor symbol expand to type
729 QCString str = yytext;
730 str = str.stripWhiteSpace();
731 //DefineDict* defines = getGlobalDefineDict();
733 int index = str.find("(");
735 name = str.left(index).stripWhiteSpace();
739 Define *define = 0; //(*defines)[name];
740 if (define != 0 && isTypeName(define->definition))
743 yy_push_state(AttributeList);
747 yyColNr -= (int)yyleng;
752 {EXTERNAL_STMT}/({BS}"::"|{BS_}{ID}) {
753 /* external can be a "type" or an attribute */
754 if(YY_START == Start)
757 yy_push_state(ModuleBody); //anon program
759 QCString tmp = yytext;
760 currentModifiers |= tmp.stripWhiteSpace();
761 argType = QCString(yytext).simplifyWhiteSpace().lower();
762 yy_push_state(AttributeList);
764 {ATTR_STMT}/{BS_}{ID} |
765 {ATTR_STMT}/{BS}"::" {
766 /* attribute statement starts */
767 DBG_CTX((stderr,"5=========> Attribute statement: %s\n", yytext));
768 QCString tmp = yytext;
769 currentModifiers |= tmp.stripWhiteSpace();
771 yy_push_state(YY_START);
772 BEGIN( AttributeList ) ;
776 ^{BS}"type"{BS_}"is"/{BS_} { }
777 ^{BS}"type"{BS}"=" { }
782 {ATTR_SPEC}. { /* update current modifiers when it is an ATTR_SPEC and not a variable name */
784 QChar chr = yytext[(int)yyleng-1];
785 if (chr.isLetter() || chr.isDigit() || (chr == '_'))
787 yyColNr -= (int)yyleng;
792 QCString tmp = yytext;
793 tmp = tmp.left(tmp.length() - 1);
795 unput(yytext[(int)yyleng-1]);
796 currentModifiers |= (tmp);
799 "::" { /* end attribute list */
802 . { /* unknown attribute, consider variable name */
803 //cout<<"start variables, unput "<<*yytext<<endl;
811 <Variable>{ID} { /* parse variable declaration */
812 //cout << "5=========> got variable: " << argType << "::" << yytext << endl;
813 /* work around for bug in QCString.replace (QCString works) */
814 QCString name=yytext;
816 /* remember attributes for the symbol */
817 modifiers[current_root][name.lower()] |= currentModifiers;
821 if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC)
822 { // new variable entry
824 current->section = Entry::VARIABLE_SEC;
825 current->name = argName;
826 current->type = argType;
827 current->fileName = yyFileName;
828 current->bodyLine = yyLineNr; // used for source reference
829 current->startLine = yyLineNr;
832 else if (!argType.isEmpty())
833 { // declaration of parameter list: add type for corr. parameter
834 parameter = getParameter(argName);
838 if (!argType.isNull()) parameter->type=argType.stripWhiteSpace();
839 if (!docBlock.isNull())
841 subrHandleCommentBlock(docBlock,TRUE);
844 // save, it may be function return type
847 modifiers[current_root][name.lower()].type = argType;
851 if ((current_root->name.lower() == argName.lower()) ||
852 (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower()))
854 int strt = current_root->type.find("function");
862 if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace();
863 if ((current_root->type.length() - strt - strlen("function"))!= 0)
865 rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace();
867 current_root->type = lft;
868 if (rght.length() > 0)
870 if (current_root->type.length() > 0) current_root->type += " ";
871 current_root->type += rght;
873 if (argType.stripWhiteSpace().length() > 0)
875 if (current_root->type.length() > 0) current_root->type += " ";
876 current_root->type += argType.stripWhiteSpace();
878 if (current_root->type.length() > 0) current_root->type += " ";
879 current_root->type += "function";
880 if (!docBlock.isNull())
882 subrHandleCommentBlockResult(docBlock,TRUE);
887 current_root->type += " " + argType.stripWhiteSpace();
889 current_root->type = current_root->type.stripWhiteSpace();
890 modifiers[current_root][name.lower()].type = current_root->type;
894 modifiers[current_root][name.lower()].type = argType;
897 // any accumulated doc for argument should be emptied,
898 // because it is handled other way and this doc can be
899 // unexpectedly passed to the next member.
900 current->doc.resize(0);
901 current->brief.resize(0);
904 <Variable>{ARGS} { /* dimension of the previous entry. */
905 QCString name(argName);
906 QCString attr("dimension");
908 modifiers[current_root][name.lower()] |= attr;
910 <Variable>{COMMA} { //printf("COMMA: %d<=..<=%d\n", yyColNr-(int)yyleng, yyColNr);
912 updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
915 yy_push_state(YY_START);
917 initializerScope = initializerArrayScope = 0;
918 BEGIN(Initialization);
920 <Variable>"\n" { currentModifiers = SymbolModifiers();
921 yy_pop_state(); // end variable declaration list
925 <Variable>";".*"\n" { currentModifiers = SymbolModifiers();
926 yy_pop_state(); // end variable declaration list
928 inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
930 pushBuffer(inputStringSemi);
933 if (YY_START == Variable) REJECT; // Just be on the safe side
934 if (YY_START == String) REJECT; // ";" ignored in strings
935 if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments
936 inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
938 pushBuffer(inputStringSemi);
941 <Initialization,ArrayInitializer>"[" |
942 <Initialization,ArrayInitializer>"(/" { initializer+=yytext;
943 initializerArrayScope++;
944 BEGIN(ArrayInitializer); // initializer may contain comma
946 <ArrayInitializer>"]" |
947 <ArrayInitializer>"/)" { initializer+=yytext;
948 initializerArrayScope--;
949 if(initializerArrayScope<=0)
951 initializerArrayScope = 0; // just in case
952 BEGIN(Initialization);
955 <ArrayInitializer>. { initializer+=yytext; }
956 <Initialization>"(" { initializerScope++;
959 <Initialization>")" { initializerScope--;
962 <Initialization>{COMMA} { if (initializerScope == 0)
964 updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
965 yy_pop_state(); // end initialization
966 if (v_type == V_VARIABLE) last_entry->initializer= initializer;
971 <Initialization>"\n"|"!" { //|
972 yy_pop_state(); // end initialization
973 if (v_type == V_VARIABLE) last_entry->initializer= initializer;
977 <Initialization>. { initializer+=yytext; }
979 /*------ fortran subroutine/function handling ------------------------------------------------------------*/
980 /* Start is initial condition */
982 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
983 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
985 addInterface("$interface$", ifType);
986 startScope(last_entry);
989 // TYPE_SPEC is for old function style function result
990 result = QCString(yytext).stripWhiteSpace().lower();
991 current->type = result;
992 yy_push_state(SubprogPrefix);
995 <SubprogPrefix>{BS}{SUBPROG}{BS_} {
996 // Fortran subroutine or function found
999 result=result.stripWhiteSpace();
1000 addSubprogram(result);
1002 current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1003 current->startLine = yyLineNr;
1006 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1007 // Fortran subroutine or function found
1009 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1011 addInterface("$interface$", ifType);
1012 startScope(last_entry);
1015 result = QCString(yytext).stripWhiteSpace();
1016 addSubprogram(result);
1017 yy_push_state(Subprog);
1018 current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1019 current->startLine = yyLineNr;
1022 <Subprog>{BS} { /* ignore white space */ }
1023 <Subprog>{ID} { current->name = yytext;
1024 //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
1025 modifiers[current_root][current->name.lower()].returnName = current->name.lower();
1027 if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1029 current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
1032 BEGIN(Parameterlist);
1034 <Parameterlist>"(" { current->args = "("; }
1035 <Parameterlist>")" {
1036 current->args += ")";
1037 current->args = removeRedundantWhiteSpace(current->args);
1039 startScope(last_entry);
1042 <Parameterlist>{COMMA}|{BS} { current->args += yytext;
1043 CommentInPrepass *c = locatePrepassComment(yyColNr-(int)yyleng, yyColNr);
1045 if(current->argList->count()>0) {
1046 current->argList->at(current->argList->count()-1)->docs = c->str;
1050 <Parameterlist>{ID} {
1051 //current->type not yet available
1052 QCString param = yytext;
1053 // std::cout << "3=========> got parameter " << param << std::endl;
1054 current->args += param;
1055 Argument *arg = new Argument;
1058 current->argList->append(arg);
1060 <Parameterlist>{NOARGS} {
1062 //printf("3=========> without parameterlist \n");
1063 //current->argList = ;
1065 startScope(last_entry);
1068 <SubprogBody>result{BS}\({BS}{ID} {
1072 result= result.right(result.length()-result.find("(")-1);
1073 result= result.stripWhiteSpace();
1074 modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
1076 //cout << "=====> got result " << result << endl;
1079 /*---- documentation comments --------------------------------------------------------------------*/
1081 <Variable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<" { /* backward docu comment */
1082 if (v_type != V_IGNORE) {
1083 current->docLine = yyLineNr;
1084 docBlockJavaStyle = FALSE;
1086 docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1087 startCommentBlock(TRUE);
1088 yy_push_state(DocBackLine);
1092 /* handle out of place !< comment as a normal comment */
1093 if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
1094 // skip comment line (without docu comments "!>" "!<" )
1095 /* ignore further "!" and ignore comments in Strings */
1096 if ((YY_START != StrIgnore) && (YY_START != String))
1098 yy_push_state(YY_START);
1101 //fprintf(stderr,"start comment %d\n",yyLineNr);
1105 <DocBackLine>.* { // contents of current comment line
1108 <DocBackLine>"\n"{BS}"!"("<"|"!"+) { // comment block (next line is also comment line)
1109 docBlock+="\n"; // \n is necessary for lists
1112 <DocBackLine>"\n" { // comment block ends at the end of this line
1113 //cout <<"3=========> comment block : "<< docBlock << endl;
1116 if (v_type == V_VARIABLE)
1118 Entry *tmp_entry = current;
1119 current = last_entry; // temporarily switch to the previous entry
1120 handleCommentBlock(docBlock,TRUE);
1123 else if (v_type == V_PARAMETER)
1125 subrHandleCommentBlock(docBlock,TRUE);
1127 else if (v_type == V_RESULT)
1129 subrHandleCommentBlockResult(docBlock,TRUE);
1135 <Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains>"!>" {
1136 yy_push_state(YY_START);
1137 current->docLine = yyLineNr;
1138 docBlockJavaStyle = FALSE;
1139 if (YY_START==SubprogBody) docBlockInBody = TRUE;
1141 docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1142 startCommentBlock(TRUE);
1144 //cout << "start DocBlock " << endl;
1147 <DocBlock>.* { // contents of current comment line
1150 <DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line)
1151 docBlock+="\n"; // \n is necessary for lists
1154 <DocBlock>"\n" { // comment block ends at the end of this line
1155 //cout <<"3=========> comment block : "<< docBlock << endl;
1158 handleCommentBlock(docBlock,TRUE);
1162 /*-----Prototype parsing -------------------------------------------------------------------------*/
1163 <Prototype>{BS}{SUBPROG}{BS_} {
1164 BEGIN(PrototypeSubprog);
1166 <Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} {
1167 current->name = QCString(yytext).lower();
1168 current->name.stripWhiteSpace();
1169 BEGIN(PrototypeArgs);
1172 "("|")"|","|{BS_} { current->args += yytext; }
1173 {ID} { current->args += yytext;
1174 Argument *a = new Argument;
1175 a->name = QCString(yytext).lower();
1176 current->argList->append(a);
1180 /*------------------------------------------------------------------------------------------------*/
1184 //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
1189 /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1192 if (parsingPrototype) {
1195 } else if ( include_stack_ptr <= 0 ) {
1196 if (YY_START!=INITIAL && YY_START!=Start) {
1197 DBG_CTX((stderr,"==== Error: EOF reached in wrong state (end missing)"));
1205 <*>{LOG_OPER} { // Fortran logical comparison keywords
1209 //printf("I:%c\n", *yytext);
1210 } // ignore remaining text
1212 /**********************************************************************************/
1213 /**********************************************************************************/
1214 /**********************************************************************************/
1216 //----------------------------------------------------------------------------
1219 static void extractPrefix(QCString &text)
1221 int prefixIndex = 0;
1224 const char* pre[] = {"RECURSIVE","IMPURE","PURE","ELEMENTAL"};
1228 for(unsigned int i=0; i<4; i++)
1230 if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
1232 text.remove(0,strlen(pre[i]));
1233 text.stripWhiteSpace();
1241 static void newLine() {
1243 yyLineNr+=lineCountPrepass;
1248 static CommentInPrepass* locatePrepassComment(int from, int to) {
1249 //printf("Locate %d-%d\n", from, to);
1250 for(uint i=0; i<comments.count(); i++) { // todo: optimize
1251 int c = comments.at(i)->column;
1252 //printf("Candidate %d\n", c);
1253 if (c>=from && c<=to) {
1254 // comment for previous variable or parameter
1255 return comments.at(i);
1261 static void updateVariablePrepassComment(int from, int to) {
1262 CommentInPrepass *c = locatePrepassComment(from, to);
1263 if (c!=NULL && v_type == V_VARIABLE) {
1264 last_entry->brief = c->str;
1265 } else if (c!=NULL && v_type == V_PARAMETER) {
1266 Argument *parameter = getParameter(argName);
1267 if (parameter) parameter->docs = c->str;
1271 static int getAmpersandAtTheStart(const char *buf, int length)
1273 for(int i=0; i<length; i++) {
1287 /* Returns ampersand index, comment start index or -1 if neither exist.*/
1288 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
1290 // Avoid ampersands in string and comments
1291 int parseState = Start;
1292 char quoteSymbol = 0;
1294 int commentIndex = -1;
1296 if (ch != '\0') parseState = String;
1298 for(int i=0; i<length && parseState!=Comment; i++)
1300 // When in string, skip backslashes
1301 // Legacy code, not sure whether this is correct?
1302 if(parseState==String)
1304 if(buf[i]=='\\') i++;
1311 // Close string, if quote symbol matches.
1312 // Quote symbol is set iff parseState==String
1313 if(buf[i]==quoteSymbol)
1318 // Start new string, if not already in string or comment
1319 else if(parseState==Start)
1321 parseState = String;
1322 quoteSymbol = buf[i];
1324 ampIndex = -1; // invalidate prev ampersand
1327 // When in string or comment, ignore exclamation mark
1328 if(parseState==Start)
1330 parseState = Comment;
1334 case ' ': // ignore whitespace
1336 case '\n': // this may be at the end of line
1342 ampIndex = -1; // invalidate prev ampersand
1349 return commentIndex;
1352 /* Although comments at the end of continuation line are grabbed by this function,
1353 * we still do not know how to use them later in parsing.
1355 void truncatePrepass(int index)
1357 int length = inputStringPrepass.length();
1358 for (int i=index+1; i<length; i++) {
1359 if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment
1360 struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2));
1364 inputStringPrepass.truncate(index);
1367 // simplified way to know if this is fixed form
1368 // duplicate in fortrancode.l
1369 bool recognizeFixedForm(const char* contents, FortranFormat format)
1372 bool skipLine=FALSE;
1374 if (format == FortranFormat_Fixed) return TRUE;
1375 if (format == FortranFormat_Free) return FALSE;
1380 switch(contents[i]) {
1395 if(column==1) return TRUE;
1399 if(column>1 && column<7) return FALSE;
1404 if(column==7) return TRUE;
1411 /* This function assumes that contents has at least size=length+1 */
1412 static void insertCharacter(char *contents, int length, int pos, char c)
1414 // shift tail by one character
1415 for(int i=length; i>pos; i--)
1416 contents[i]=contents[i-1];
1417 // set the character
1421 /* change comments and bring line continuation character to previous line */
1422 /* also used to set continuation marks in case of fortran code usage, done here as it is quite complicated code */
1423 const char* prepassFixedForm(const char* contents, int *hasContLine)
1426 int prevLineLength=0;
1427 int prevLineAmpOrExclIndex=-1;
1428 char prevQuote = '\0';
1429 char thisQuote = '\0';
1430 bool emptyLabel=TRUE;
1431 bool commented=FALSE;
1432 bool inSingle=FALSE;
1433 bool inDouble=FALSE;
1434 bool inBackslash=FALSE;
1435 bool fullCommentLine=TRUE;
1436 int newContentsSize = strlen(contents)+3; // \000, \n (when necessary) and one spare character (to avoid reallocation)
1437 char* newContents = (char*)malloc(newContentsSize);
1440 for(int i=0, j=0;;i++,j++) {
1441 if(j>=newContentsSize-3) { // check for spare characters, which may be eventually used below (by & and '! ')
1442 newContents = (char*)realloc(newContents, newContentsSize+1000);
1443 newContentsSize = newContentsSize+1000;
1447 char c = contents[i];
1450 if (!fullCommentLine)
1452 prevLineLength=column;
1453 prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1454 if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1458 prevLineLength+=column;
1459 /* 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) */
1462 hasContLine[curLine - 1] = 1;
1465 fullCommentLine=TRUE;
1470 prevQuote = thisQuote;
1483 newContents[j]='\000';
1484 newContentsSize = strlen(newContents);
1485 if (newContents[newContentsSize - 1] != '\n')
1487 // to be on the safe side
1488 newContents = (char*)realloc(newContents, newContentsSize+2);
1489 newContents[newContentsSize] = '\n';
1490 newContents[newContentsSize + 1] = '\000';
1496 if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1498 // we have some special cases in respect to strings and escaped string characters
1499 fullCommentLine=FALSE;
1503 inBackslash = !inBackslash;
1510 inSingle = !inSingle;
1511 if (inSingle) thisQuote = c;
1512 else thisQuote = '\0';
1520 inDouble = !inDouble;
1521 if (inDouble) thisQuote = c;
1522 else thisQuote = '\0';
1527 inBackslash = FALSE;
1533 if ((column <= fixedCommentAfter) && (column!=6))
1541 else if ((c == '!') && !inDouble && !inSingle)
1548 if (!commented) fullCommentLine=FALSE;
1555 if(column==6 && emptyLabel) { // continuation
1556 if (!commented) fullCommentLine=FALSE;
1557 if (c != '0') { // 0 not allowed as continuation character, see f95 standard paragraph 3.3.2.3
1560 if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line
1561 /* first line is not a continuation line in code, just in snippets etc. */
1562 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-1, '&');
1564 } else { // add & just before end of previous line comment
1565 /* first line is not a continuation line in code, just in snippets etc. */
1566 if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&');
1569 if (hasContLine) hasContLine[curLine - 1] = 1;
1571 newContents[j]=c; // , just handle like space
1574 } else if ((column > fixedCommentAfter) && !commented) {
1575 // first non commented non blank character after position fixedCommentAfter
1577 // I'm not a possible start of doxygen comment
1578 newContents[j++]='!';
1579 newContents[j++]=' '; // so that '<' and '>' as first character are not converted to doxygen comment
1584 if (!commented) fullCommentLine=FALSE;
1597 newContentsSize = strlen(newContents);
1598 if (newContents[newContentsSize - 1] != '\n')
1600 // to be on the safe side
1601 newContents = (char*)realloc(newContents, newContentsSize+2);
1602 newContents[newContentsSize] = '\n';
1603 newContents[newContentsSize + 1] = '\000';
1608 static void pushBuffer(QCString& buffer)
1610 if (include_stack_cnt <= include_stack_ptr)
1612 include_stack_cnt++;
1613 include_stack = (YY_BUFFER_STATE *)realloc(include_stack, include_stack_cnt * sizeof(YY_BUFFER_STATE));
1615 include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
1616 yy_switch_to_buffer(yy_scan_string(buffer));
1618 DBG_CTX((stderr, "--PUSH--%s", (const char *)buffer));
1622 static void popBuffer() {
1623 DBG_CTX((stderr, "--POP--"));
1624 include_stack_ptr --;
1625 yy_delete_buffer( YY_CURRENT_BUFFER );
1626 yy_switch_to_buffer( include_stack[include_stack_ptr] );
1629 /** used to copy entry to an interface module procedure */
1630 static void copyEntry(Entry *dest, Entry *src)
1632 dest->type = src->type;
1633 dest->fileName = src->fileName;
1634 dest->startLine = src->startLine;
1635 dest->bodyLine = src->bodyLine;
1636 dest->endBodyLine = src->endBodyLine;
1637 dest->args = src->args;
1638 dest->argList = new ArgumentList(*src->argList);
1639 dest->doc = src->doc;
1640 dest->brief = src->brief;
1643 /** fill empty interface module procedures with info from
1644 corresponding module subprogs
1645 @TODO: handle procedures in used modules
1647 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
1649 if (moduleProcedures.isEmpty()) return;
1651 EntryListIterator eli1(moduleProcedures);
1652 // for all module procedures
1653 for (Entry *ce1; (ce1=eli1.current()); ++eli1)
1655 // check all entries in this module
1656 EntryListIterator eli2(*current_root->children());
1657 for (Entry *ce2; (ce2=eli2.current()); ++eli2)
1659 if (ce1->name == ce2->name)
1661 copyEntry(ce1, ce2);
1663 } // for procedures in current module
1664 } // for all interface module procedures
1665 moduleProcedures.clear();
1669 static bool isTypeName(QCString name)
1671 name = name.lower();
1672 return name=="integer" || name == "real" ||
1673 name=="complex" || name == "logical";
1677 /*! Extracts string which resides within parentheses of provided string. */
1678 static QCString extractFromParens(const QCString name)
1680 QCString extracted = name;
1681 int start = extracted.find("(");
1684 extracted.remove(0, start+1);
1686 int end = extracted.findRev(")");
1689 int length = extracted.length();
1690 extracted.remove(end, length);
1692 extracted = extracted.stripWhiteSpace();
1697 /*! Adds passed modifiers to these modifiers.*/
1698 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
1700 if (mdfs.protection!=NONE_P) protection = mdfs.protection;
1701 if (mdfs.direction!=NONE_D) direction = mdfs.direction;
1702 optional |= mdfs.optional;
1703 if (!mdfs.dimension.isNull()) dimension = mdfs.dimension;
1704 allocatable |= mdfs.allocatable;
1705 external |= mdfs.external;
1706 intrinsic |= mdfs.intrinsic;
1707 protect |= mdfs.protect;
1708 parameter |= mdfs.parameter;
1709 pointer |= mdfs.pointer;
1710 target |= mdfs.target;
1712 deferred |= mdfs.deferred;
1713 nonoverridable |= mdfs.nonoverridable;
1714 nopass |= mdfs.nopass;
1716 passVar = mdfs.passVar;
1717 contiguous |= mdfs.contiguous;
1718 volat |= mdfs.volat;
1719 value |= mdfs.value;
1723 /*! Extracts and adds passed modifier to these modifiers.*/
1724 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
1726 mdfString = mdfString.lower();
1727 SymbolModifiers newMdf;
1729 if (mdfString.find("dimension")==0)
1731 newMdf.dimension=mdfString;
1733 else if (mdfString.contains("intent"))
1735 QCString tmp = extractFromParens(mdfString);
1736 bool isin = tmp.contains("in");
1737 bool isout = tmp.contains("out");
1738 if (isin && isout) newMdf.direction = SymbolModifiers::INOUT;
1739 else if (isin) newMdf.direction = SymbolModifiers::IN;
1740 else if (isout) newMdf.direction = SymbolModifiers::OUT;
1742 else if (mdfString=="public")
1744 newMdf.protection = SymbolModifiers::PUBLIC;
1746 else if (mdfString=="private")
1748 newMdf.protection = SymbolModifiers::PRIVATE;
1750 else if (mdfString=="protected")
1752 newMdf.protect = TRUE;
1754 else if (mdfString=="optional")
1756 newMdf.optional = TRUE;
1758 else if (mdfString=="allocatable")
1760 newMdf.allocatable = TRUE;
1762 else if (mdfString=="external")
1764 newMdf.external = TRUE;
1766 else if (mdfString=="intrinsic")
1768 newMdf.intrinsic = TRUE;
1770 else if (mdfString=="parameter")
1772 newMdf.parameter = TRUE;
1774 else if (mdfString=="pointer")
1776 newMdf.pointer = TRUE;
1778 else if (mdfString=="target")
1780 newMdf.target = TRUE;
1782 else if (mdfString=="save")
1786 else if (mdfString=="nopass")
1788 newMdf.nopass = TRUE;
1790 else if (mdfString=="deferred")
1792 newMdf.deferred = TRUE;
1794 else if (mdfString=="non_overridable")
1796 newMdf.nonoverridable = TRUE;
1798 else if (mdfString=="contiguous")
1800 newMdf.contiguous = TRUE;
1802 else if (mdfString=="volatile")
1804 newMdf.volat = TRUE;
1806 else if (mdfString=="value")
1808 newMdf.value = TRUE;
1810 else if (mdfString.contains("pass"))
1813 if (mdfString.contains("("))
1814 newMdf.passVar = extractFromParens(mdfString);
1816 newMdf.passVar = "";
1823 /*! For debugging purposes. */
1824 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
1826 // out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
1827 // ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
1828 // ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
1833 /*! Find argument with given name in \a subprog entry. */
1834 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
1836 QCString cname(name.lower());
1837 for (unsigned int i=0; i<subprog->argList->count(); i++)
1839 Argument *arg = subprog->argList->at(i);
1840 if ((!byTypeName && arg->name.lower() == cname) ||
1841 (byTypeName && arg->type.lower() == cname)
1850 /*! Find function with given name in \a entry. */
1852 static Entry *findFunction(Entry* entry, QCString name)
1854 QCString cname(name.lower());
1856 EntryListIterator eli(*entry->children());
1858 for (;(ce=eli.current());++eli)
1860 if (ce->section != Entry::FUNCTION_SEC)
1863 if (ce->name.lower() == cname)
1871 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */
1872 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs)
1874 if (!mdfs.dimension.isNull())
1876 if (!typeName.isEmpty()) typeName += ", ";
1877 typeName += mdfs.dimension;
1879 if (mdfs.direction!=SymbolModifiers::NONE_D)
1881 if (!typeName.isEmpty()) typeName += ", ";
1882 typeName += directionStrs[mdfs.direction];
1886 if (!typeName.isEmpty()) typeName += ", ";
1887 typeName += "optional";
1889 if (mdfs.allocatable)
1891 if (!typeName.isEmpty()) typeName += ", ";
1892 typeName += "allocatable";
1896 if (!typeName.contains("external"))
1898 if (!typeName.isEmpty()) typeName += ", ";
1899 typeName += "external";
1904 if (!typeName.isEmpty()) typeName += ", ";
1905 typeName += "intrinsic";
1909 if (!typeName.isEmpty()) typeName += ", ";
1910 typeName += "parameter";
1914 if (!typeName.isEmpty()) typeName += ", ";
1915 typeName += "pointer";
1919 if (!typeName.isEmpty()) typeName += ", ";
1920 typeName += "target";
1924 if (!typeName.isEmpty()) typeName += ", ";
1929 if (!typeName.isEmpty()) typeName += ", ";
1930 typeName += "deferred";
1932 if (mdfs.nonoverridable)
1934 if (!typeName.isEmpty()) typeName += ", ";
1935 typeName += "non_overridable";
1939 if (!typeName.isEmpty()) typeName += ", ";
1940 typeName += "nopass";
1944 if (!typeName.isEmpty()) typeName += ", ";
1946 if (!mdfs.passVar.isEmpty())
1947 typeName += "(" + mdfs.passVar + ")";
1949 if (mdfs.protection == SymbolModifiers::PUBLIC)
1951 if (!typeName.isEmpty()) typeName += ", ";
1952 typeName += "public";
1954 else if (mdfs.protection == SymbolModifiers::PRIVATE)
1956 if (!typeName.isEmpty()) typeName += ", ";
1957 typeName += "private";
1961 if (!typeName.isEmpty()) typeName += ", ";
1962 typeName += "protected";
1964 if (mdfs.contiguous)
1966 if (!typeName.isEmpty()) typeName += ", ";
1967 typeName += "contiguous";
1971 if (!typeName.isEmpty()) typeName += ", ";
1972 typeName += "volatile";
1976 if (!typeName.isEmpty()) typeName += ", ";
1977 typeName += "value";
1983 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */
1984 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
1986 QCString tmp = arg->type;
1987 arg->type = applyModifiers(tmp, mdfs);
1990 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */
1991 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
1993 QCString tmp = ent->type;
1994 ent->type = applyModifiers(tmp, mdfs);
1996 if (mdfs.protection == SymbolModifiers::PUBLIC)
1997 ent->protection = Public;
1998 else if (mdfs.protection == SymbolModifiers::PRIVATE)
1999 ent->protection = Private;
2002 /*! Starts the new scope in fortran program. Consider using this function when
2003 * starting module, interface, function or other program block.
2006 static void startScope(Entry *scope)
2008 //cout<<"start scope: "<<scope->name<<endl;
2009 current_root= scope; /* start substructure */
2011 QMap<QCString,SymbolModifiers> mdfMap;
2012 modifiers.insert(scope, mdfMap);
2015 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
2018 static bool endScope(Entry *scope, bool isGlobalRoot)
2020 //cout<<"end scope: "<<scope->name<<endl;
2021 if (current_root->parent() || isGlobalRoot)
2023 current_root= current_root->parent(); /* end substructure */
2027 fprintf(stderr,"parse error in end <scopename>");
2032 // update variables or subprogram arguments with modifiers
2033 QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
2035 if (scope->section == Entry::FUNCTION_SEC)
2037 // iterate all symbol modifiers of the scope
2038 for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++)
2040 //cout<<it.key()<<": "<<it.data()<<endl;
2041 Argument *arg = findArgument(scope, it.key());
2044 applyModifiers(arg, it.data());
2047 // find return type for function
2048 //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
2049 QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
2050 if (modifiers[scope].contains(returnName))
2052 scope->type = modifiers[scope][returnName].type; // returning type works
2053 applyModifiers(scope, modifiers[scope][returnName]); // returning array works
2057 if (scope->section == Entry::CLASS_SEC)
2058 { // was INTERFACE_SEC
2059 if (scope->parent()->section == Entry::FUNCTION_SEC)
2060 { // interface within function
2061 // iterate functions of interface and
2062 // try to find types for dummy(ie. argument) procedures.
2063 //cout<<"Search in "<<scope->name<<endl;
2064 EntryListIterator eli(*scope->children());
2068 for (;(ce=eli.current());++eli)
2071 if (ce->section != Entry::FUNCTION_SEC)
2074 Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
2077 // set type of dummy procedure argument to interface
2078 arg->name = arg->type;
2079 arg->type = scope->name;
2081 if (ce->name.lower() == scope->name.lower()) found = TRUE;
2083 if ((count == 1) && found)
2085 // clear all modifiers of the scope
2086 modifiers.remove(scope);
2087 delete scope->parent()->removeSubEntry(scope);
2093 if (scope->section!=Entry::FUNCTION_SEC)
2094 { // not function section
2095 // iterate variables: get and apply modifiers
2096 EntryListIterator eli(*scope->children());
2098 for (;(ce=eli.current());++eli)
2100 if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
2103 //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
2104 if (mdfsMap.contains(ce->name.lower()))
2105 applyModifiers(ce, mdfsMap[ce->name.lower()]);
2109 // clear all modifiers of the scope
2110 modifiers.remove(scope);
2116 //! Return full name of the entry. Sometimes we must combine several names recursively.
2117 static QCString getFullName(Entry *e)
2119 QCString name = e->name;
2120 if (e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC
2121 || !e->parent() || e->parent()->name.isEmpty())
2124 return getFullName(e->parent())+"::"+name;
2128 static int yyread(char *buf,int max_size)
2132 while ( c < max_size && inputString[inputPosition] )
2134 *buf = inputString[inputPosition++] ;
2140 static void initParser()
2145 static void initEntry()
2149 current->protection = typeProtection;
2153 current->protection = defaultProtection;
2155 current->mtype = mtype;
2156 current->virt = virt;
2157 current->stat = gstat;
2158 current->lang = SrcLangExt_Fortran;
2159 initGroupInfo(current);
2163 adds current entry to current_root and creates new current
2165 static void addCurrentEntry(int case_insens)
2167 if (case_insens) current->name = current->name.lower();
2168 //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data());
2169 current_root->addSubEntry(current);
2170 last_entry = current;
2171 current = new Entry ;
2175 static int max(int a, int b) {return a>b?a:b;}
2177 static void addModule(const char *name, bool isModule)
2179 DBG_CTX((stderr, "0=========> got module %s\n", name));
2182 current->section = Entry::NAMESPACE_SEC;
2184 current->section = Entry::FUNCTION_SEC;
2188 current->name = name;
2192 QCString fname = yyFileName;
2193 int index = max(fname.findRev('/'), fname.findRev('\\'));
2194 fname = fname.right(fname.length()-index-1);
2195 fname = fname.prepend("__").append("__");
2196 current->name = fname;
2198 current->type = "program";
2199 current->fileName = yyFileName;
2200 current->bodyLine = yyLineNr; // used for source reference
2201 current->startLine = yyLineNr;
2202 current->protection = Public ;
2204 startScope(last_entry);
2208 static void addSubprogram(const char *text)
2210 DBG_CTX((stderr,"1=========> got subprog, type: %s\n",text));
2211 subrCurrent.prepend(current);
2212 current->section = Entry::FUNCTION_SEC ;
2213 QCString subtype = text; subtype=subtype.lower().stripWhiteSpace();
2214 functionLine = (subtype.find("function") != -1);
2215 current->type += " " + subtype;
2216 current->type = current->type.stripWhiteSpace();
2217 current->fileName = yyFileName;
2218 current->bodyLine = yyLineNr; // used for source reference start of body of routine
2219 current->startLine = yyLineNr; // used for source reference start of definition
2220 current->args.resize(0);
2221 current->argList->clear();
2225 /*! Adds interface to the root entry.
2226 * \note Code was brought to this procedure from the parser,
2227 * because there was/is idea to use it in several parts of the parser.
2229 static void addInterface(QCString name, InterfaceType type)
2231 if (YY_START == Start)
2234 yy_push_state(ModuleBody); //anon program
2237 current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
2238 current->spec = Entry::Interface;
2239 current->name = name;
2244 current->type = "abstract";
2248 current->type = "generic";
2257 /* if type is part of a module, mod name is necessary for output */
2258 if ((current_root) &&
2259 (current_root->section == Entry::CLASS_SEC ||
2260 current_root->section == Entry::NAMESPACE_SEC))
2262 current->name= current_root->name + "::" + current->name;
2265 current->fileName = yyFileName;
2266 current->bodyLine = yyLineNr;
2267 current->startLine = yyLineNr;
2272 //-----------------------------------------------------------------------------
2274 /*! Get the argument \a name.
2276 static Argument* getParameter(const QCString &name)
2278 // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl;
2280 if (current_root->argList==0) return 0;
2281 ArgumentListIterator ali(*current_root->argList);
2283 for (ali.toFirst();(a=ali.current());++ali)
2285 if (a->name.lower()==name.lower())
2288 //printf("parameter found: %s\n",(const char*)name);
2295 //----------------------------------------------------------------------------
2296 static void startCommentBlock(bool brief)
2300 current->briefFile = yyFileName;
2301 current->briefLine = yyLineNr;
2305 current->docFile = yyFileName;
2306 current->docLine = yyLineNr;
2310 //----------------------------------------------------------------------------
2312 static void handleCommentBlock(const QCString &doc,bool brief)
2314 bool needsEntry = FALSE;
2315 static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
2317 if (docBlockInBody && hideInBodyDocs)
2319 docBlockInBody = FALSE;
2322 DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
2323 int lineNr = brief ? current->briefLine : current->docLine;
2324 while (parseCommentBlock(
2326 docBlockInBody ? subrCurrent.getFirst() : current,
2330 docBlockInBody ? FALSE : brief,
2331 docBlockInBody ? FALSE : docBlockJavaStyle,
2338 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
2339 if (needsEntry) addCurrentEntry(0);
2341 DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry));
2343 if (needsEntry) addCurrentEntry(0);
2344 docBlockInBody = FALSE;
2347 //----------------------------------------------------------------------------
2348 /// Handle parameter description as defined after the declaration of the parameter
2349 static void subrHandleCommentBlock(const QCString &doc,bool brief)
2352 loc_doc = doc.stripWhiteSpace();
2354 Entry *tmp_entry = current;
2355 current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2357 // Still in the specification section so no inbodyDocs yet, but parameter documentation
2358 current->inbodyDocs = "";
2360 // strip \\param or @param, so we can do some extra checking. We will add it later on again.
2361 if (!loc_doc.stripPrefix("\\param") &&
2362 !loc_doc.stripPrefix("@param")
2363 ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2364 loc_doc.stripWhiteSpace();
2366 // direction as defined with the declaration of the parameter
2367 int dir1 = modifiers[current_root][argName.lower()].direction;
2368 // in description [in] is specified
2369 if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
2371 // check if with the declaration intent(in) or nothing has been specified
2372 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2373 (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
2376 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN]));
2377 loc_doc.stripWhiteSpace();
2378 // in case of empty documentation or (now) just name, consider it as no documemntation
2379 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2381 // reset current back to the part inside the routine
2385 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " +
2386 argName + " " + loc_doc,brief);
2390 // something different specified, give warning and leave error.
2391 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2392 " inconsistency between intent attribute and documentation for parameter: " + argName);
2393 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2394 argName + " " + loc_doc,brief);
2397 // analogous to the [in] case, here [out] direction specified
2398 else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
2400 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2401 (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
2403 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT]));
2404 loc_doc.stripWhiteSpace();
2405 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2410 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " +
2411 argName + " " + loc_doc,brief);
2415 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2416 " inconsistency between intent attribute and documentation for parameter: " + argName);
2417 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2418 argName + " " + loc_doc,brief);
2421 // analogous to the [in] case, here [in,out] direction specified
2422 else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
2424 if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2425 (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
2427 loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT]));
2428 loc_doc.stripWhiteSpace();
2429 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2434 handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " +
2435 argName + " " + loc_doc,brief);
2439 warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2440 " inconsistency between intent attribute and documentation for parameter: " + argName);
2441 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2442 argName + " " + loc_doc,brief);
2445 // analogous to the [in] case; here no direction specified
2448 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2453 handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " +
2454 argName + " " + loc_doc,brief);
2457 // reset current back to the part inside the routine
2460 //----------------------------------------------------------------------------
2461 /// Handle result description as defined after the declaration of the parameter
2462 static void subrHandleCommentBlockResult(const QCString &doc,bool brief)
2465 loc_doc = doc.stripWhiteSpace();
2467 Entry *tmp_entry = current;
2468 current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2470 // Still in the specification section so no inbodyDocs yet, but parameter documentation
2471 current->inbodyDocs = "";
2473 // strip \\returns or @returns. We will add it later on again.
2474 if (!loc_doc.stripPrefix("\\returns") &&
2475 !loc_doc.stripPrefix("\\return") &&
2476 !loc_doc.stripPrefix("@returns") &&
2477 !loc_doc.stripPrefix("@return")
2478 ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2479 loc_doc.stripWhiteSpace();
2481 if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2486 handleCommentBlock(QCString("\n\n@returns ") + loc_doc,brief);
2488 // reset current back to the part inside the routine
2492 //----------------------------------------------------------------------------
2496 static void debugCompounds(Entry *rt) // print Entry structure (for debugging)
2499 printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
2500 EntryListIterator eli(*rt->children());
2502 for (;(ce=eli.current());++eli)
2511 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, FortranFormat format)
2513 char *tmpBuf = NULL;
2516 defaultProtection = Public;
2517 inputString = fileBuf;
2519 inputStringPrepass = NULL;
2520 inputPositionPrepass = 0;
2522 //anonCount = 0; // don't reset per file
2528 inputFile.setName(fileName);
2529 if (inputFile.open(IO_ReadOnly))
2531 isFixedForm = recognizeFixedForm(fileBuf,format);
2535 msg("Prepassing fixed form of %s\n", fileName);
2536 //printf("---strlen=%d\n", strlen(fileBuf));
2537 //clock_t start=clock();
2539 //printf("Input fixed form string:\n%s\n", fileBuf);
2540 //printf("===========================\n");
2541 inputString = prepassFixedForm(fileBuf, NULL);
2542 //printf("Resulting free form string:\n%s\n", inputString);
2543 //printf("===========================\n");
2545 //clock_t end=clock();
2546 //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
2548 else if (inputString[strlen(fileBuf)-1] != '\n')
2550 tmpBuf = (char *)malloc(strlen(fileBuf)+2);
2551 strcpy(tmpBuf,fileBuf);
2552 tmpBuf[strlen(fileBuf)]= '\n';
2553 tmpBuf[strlen(fileBuf)+1]= '\000';
2554 inputString = tmpBuf;
2558 yyFileName = fileName;
2559 msg("Parsing file %s...\n",yyFileName.data());
2561 startScope(rt); // implies current_root = rt
2563 groupEnterFile(yyFileName,yyLineNr);
2565 current = new Entry;
2566 current->lang = SrcLangExt_Fortran;
2567 current->name = yyFileName;
2568 current->section = Entry::SOURCE_SEC;
2569 current_root->addSubEntry(current);
2570 file_root = current;
2571 current = new Entry;
2572 current->lang = SrcLangExt_Fortran;
2574 fortranscannerYYrestart( fortranscannerYYin );
2579 fortranscannerYYlex();
2580 groupLeaveFile(yyFileName,yyLineNr);
2582 endScope(current_root, TRUE); // TRUE - global root
2584 //debugCompounds(rt); //debug
2586 rt->program.resize(0);
2587 delete current; current=0;
2588 moduleProcedures.clear();
2590 free((char*)tmpBuf);
2594 free((char*)inputString);
2602 //----------------------------------------------------------------------------
2604 void FortranLanguageScanner::parseInput(const char *fileName,
2605 const char *fileBuf,
2607 bool /*sameTranslationUnit*/,
2608 QStrList & /*filesInSameTranslationUnit*/)
2610 g_thisParser = this;
2612 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2614 ::parseMain(fileName,fileBuf,root,m_format);
2616 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2619 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2620 const char * scopeName,
2621 const QCString & input,
2622 SrcLangExt /*lang*/,
2623 bool isExampleBlock,
2624 const char * exampleName,
2628 bool inlineFragment,
2629 MemberDef *memberDef,
2630 bool showLineNumbers,
2631 Definition *searchCtx,
2635 ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
2636 fileDef,startLine,endLine,inlineFragment,memberDef,
2637 showLineNumbers,searchCtx,collectXRefs,m_format);
2640 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
2642 return extension!=extension.lower(); // use preprocessor only for upper case extensions
2644 void FortranLanguageScanner::resetCodeParserState()
2646 ::resetFortranCodeParserState();
2649 void FortranLanguageScanner::parsePrototype(const char *text)
2651 QCString buffer = QCString(text);
2653 parsingPrototype = TRUE;
2655 fortranscannerYYlex();
2656 parsingPrototype = FALSE;
2660 static void scanner_abort()
2662 fprintf(stderr,"********************************************************************\n");
2663 fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START);
2664 fprintf(stderr,"********************************************************************\n");
2666 EntryListIterator eli(*global_root->children());
2670 for (;(ce=eli.current());++eli)
2672 if (ce == file_root) start=TRUE;
2673 if (start) ce->reset();
2676 // dummy call to avoid compiler warning
2677 (void)yy_top_state();
2683 //----------------------------------------------------------------------------
2685 #if !defined(YY_FLEX_SUBMINOR_VERSION)
2686 //----------------------------------------------------------------------------
2687 extern "C" { // some bogus code to keep the compiler happy
2688 void fortranscannernerYYdummy() { yy_flex_realloc(0,0); }