85b6de90d4f697afdd7e51080d7db800df0ce768
[platform/upstream/doxygen.git] / src / fortranscanner.l
1 /* -*- mode: fundamental; indent-tabs-mode: 1; -*- */
2 /*****************************************************************************
3  * Parser for Fortran90 F subset
4  *
5  * Copyright (C) by Anke Visser
6  * based on the work of Dimitri van Heesch.
7  *
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.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */ 
18
19 /* Developer notes.
20  *
21  * - Consider using startScope(), endScope() functions with  module, program, 
22  * subroutine or any other scope in fortran program.
23  *
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.
27  * 
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.
32  *
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]'
36  * are desired.
37  *
38  * - Must track yyLineNr when using REJECT, unput() or similar commands.
39  */
40 %option never-interactive
41 %option case-insensitive
42 %option prefix="fortranscannerYY"
43
44 %{
45
46 #include <stdio.h> 
47 #include <stdlib.h>
48 #include <assert.h>
49 #include <ctype.h>
50
51 #include <qarray.h>
52 #include <qstack.h>
53 #include <qregexp.h>
54 #include <qfile.h>
55 #include <qmap.h>
56   
57 #include "fortranscanner.h"
58 #include "entry.h"
59 #include "message.h"
60 #include "config.h"
61 #include "doxygen.h"
62 #include "util.h"
63 #include "defargs.h"
64 #include "language.h"
65 #include "commentscan.h" 
66 #include "fortrancode.h"
67 #include "pre.h"
68 #include "arguments.h"
69
70 // Toggle for some debugging info
71 //#define DBG_CTX(x) fprintf x
72 #define DBG_CTX(x) do { } while(0)
73
74 #define YY_NO_INPUT 1
75 #define YY_NO_UNISTD_H 1
76
77 enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER, V_RESULT};
78 enum InterfaceType { IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT };
79
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};
85
86   //!< This is only used with function return value.
87   QCString type, returnName;
88   Protection protection;
89   Direction direction;
90   bool optional;
91   bool protect;
92   QCString dimension;
93   bool allocatable;
94   bool external;
95   bool intrinsic;
96   bool parameter;
97   bool pointer;
98   bool target;
99   bool save;
100   bool deferred;
101   bool nonoverridable;
102   bool nopass;
103   bool pass;
104   bool contiguous;
105   bool volat; /* volatile is a reserved name */
106   bool value; /* volatile is a reserved name */
107   QCString passVar;
108
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() {}
114
115   SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
116   SymbolModifiers& operator|=(QCString mdfrString);
117 };
118
119 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs);
120
121 static const char *directionStrs[] = 
122 {
123    "", "intent(in)", "intent(out)", "intent(inout)"
124 };
125 static const char *directionParam[] = 
126 {
127    "", "[in]", "[out]", "[in,out]"
128 };
129
130 // }}}
131
132 /* -----------------------------------------------------------------
133  *
134  *      statics
135  */
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;
144
145 static QList<Entry>  subrCurrent;
146
147 struct CommentInPrepass {
148   int column;
149   QCString str;
150   CommentInPrepass(int column, QCString str) : column(column), str(str) {}
151 };
152 static QList<CommentInPrepass>  comments;
153
154 YY_BUFFER_STATE *include_stack = NULL;
155 int include_stack_ptr = 0;
156 int include_stack_cnt = 0;
157
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 
169                                           // module procedures
170 static QCString         docBlock;
171 static bool             docBlockInBody = FALSE;
172 static bool             docBlockJavaStyle;
173
174 static MethodTypes      mtype;
175 static bool             gstat;
176 static Specifier        virt;
177
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;
192
193 static char              stringStartSymbol; // single or double quote
194 static bool              parsingPrototype = FALSE; // see parsePrototype()
195
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;
200
201 //-----------------------------------------------------------------------------
202
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();
214
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();
229
230 //-----------------------------------------------------------------------------
231 #undef  YY_INPUT
232 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
233 #define YY_USER_ACTION yyColNr+=(int)yyleng;
234 //-----------------------------------------------------------------------------
235
236 %}
237
238  //-----------------------------------------------------------------------------
239  //-----------------------------------------------------------------------------
240 IDSYM     [a-z_A-Z0-9]
241 NOTIDSYM  [^a-z_A-Z0-9]
242 SEPARATE  [:, \t]
243 ID        [a-z_A-Z%]+{IDSYM}*
244 ID_       [a-z_A-Z%]*{IDSYM}*
245 PP_ID     {ID}
246 LABELID   [a-z_A-Z]+[a-z_A-Z0-9\-]*
247 SUBPROG   (subroutine|function)
248 B         [ \t]
249 BS        [ \t]*
250 BS_       [ \t]+
251 COMMA     {BS},{BS}
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})
257 NOARGS    {BS}"\n"
258
259 NUM_TYPE  (complex|integer|logical|real)
260 LOG_OPER  (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
261 KIND      {ARGS}
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}?)
264
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)
272
273 CONTAINS  CONTAINS
274 PREFIX    (RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,3}(RECURSIVE|IMPURE|PURE|ELEMENTAL)?
275 SCOPENAME ({ID}{BS}"::"{BS})*
276
277 %option noyywrap
278 %option stack
279 %option caseless
280 /*%option debug */
281
282  //---------------------------------------------------------------------------------
283
284  /** fortran parsing states */
285 %x      Subprog
286 %x      SubprogPrefix
287 %x      Parameterlist
288 %x      SubprogBody
289 %x      SubprogBodyContains
290 %x      Start
291 %x      Comment
292 %x      Module
293 %x      Program
294 %x      ModuleBody
295 %x      ModuleBodyContains
296 %x      AttributeList
297 %x      Variable
298 %x      Initialization
299 %x      ArrayInitializer
300 %x      Typedef
301 %x      TypedefBody
302 %x      TypedefBodyContains
303 %x      InterfaceBody
304 %x      StrIgnore
305 %x      String
306 %x      Use
307 %x      UseOnly
308 %x      ModuleProcedure
309
310 %x      Prepass
311
312  /** comment parsing states */
313 %x      DocBlock
314 %x      DocBackLine
315 %x      EndDoc
316
317 %x      BlockData
318
319 /** prototype parsing */
320 %x      Prototype
321 %x      PrototypeSubprog
322 %x      PrototypeArgs
323
324 %%
325
326  /*-----------------------------------------------------------------------------------*/
327
328 <Prepass>^{BS}[&]*{BS}!.*\n             { /* skip lines with just comment. Note code was in free format or has been converted to it */
329                                           lineCountPrepass ++;
330                                         }
331 <Prepass>^{BS}\n                        { /* skip empty lines */
332                                           lineCountPrepass ++;
333                                         }
334 <*>^.*\n                                { // prepass: look for line continuations
335                                           functionLine = FALSE;
336
337                                           DBG_CTX((stderr, "---%s", yytext));
338
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
342                                               indexEnd=-1;
343
344                                             if(indexEnd<0){ // ----- no ampersand as line continuation
345                                                if(YY_START == Prepass) { // last line in "continuation"
346
347                                                  // Only take input after initial ampersand
348                                                  inputStringPrepass+=(const char*)(yytext+(indexStart+1));
349    
350                                                  //printf("BUFFER:%s\n", (const char*)inputStringPrepass);
351                                                  pushBuffer(inputStringPrepass);
352                                                  yyColNr = 0;                                            
353                                                  yy_pop_state();
354                                                } else { // simple line
355                                                  yyColNr = 0;
356                                                  REJECT;
357                                                }
358
359                                             } else { // ----- line with continuation
360                                               if(YY_START != Prepass) {
361                                                 comments.setAutoDelete(TRUE);
362                                                 comments.clear();
363                                                 yy_push_state(Prepass);
364                                               }
365
366                                               int length = inputStringPrepass.length();
367
368                                               // Only take input after initial ampersand
369                                               inputStringPrepass+=(const char*)(yytext+(indexStart+1));
370                                               lineCountPrepass ++;
371
372                                               // cut off & and remove following comment if present
373                                               truncatePrepass(length+indexEnd-(indexStart+1));
374                                             }
375
376                                         }
377
378
379  /*------ ignore strings that are not initialization strings */ 
380 <*>"\\\\"                               { if (yy_top_state() == Initialization
381                                               || yy_top_state() == ArrayInitializer)
382                                             initializer+=yytext;
383                                         }
384 <*>"\\\""|\\\'                          { if (yy_top_state() == Initialization
385                                               || yy_top_state() == ArrayInitializer)
386                                             initializer+=yytext;
387                                         }
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)
392                                             initializer+=yytext;
393                                           yy_pop_state();
394                                         }           
395 <String>.                               { if (yy_top_state() == Initialization
396                                               || yy_top_state() == ArrayInitializer)
397                                             initializer+=yytext;
398                                         } 
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)
404                                             initializer+=yytext;
405                                           stringStartSymbol=yytext[0]; // single or double quote
406                                           BEGIN(String);
407                                         }
408
409  /*------ ignore simple comment (not documentation comments) */
410
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)) 
415                                           {
416                                             yy_push_state(YY_START);
417                                             BEGIN(StrIgnore); 
418                                             debugStr="*!";
419                                             DBG_CTX((stderr,"start comment %d\n",yyLineNr));
420                                            }      
421                                         }
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; } 
426
427
428  /*------ use handling ------------------------------------------------------------*/
429
430 <Start,ModuleBody,SubprogBody>"use"{BS_} {
431                                           if(YY_START == Start)
432                                           {
433                                             addModule(NULL); 
434                                             yy_push_state(ModuleBody); //anon program
435                                           }
436                                           yy_push_state(Use);
437                                         }
438 <Use>{ID}                               { 
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);
444                                           current = new Entry;
445                                           current->lang = SrcLangExt_Fortran; 
446                                           yy_pop_state();
447                                         }
448 <Use>{ID}/,                             { 
449                                           useModuleName=yytext;
450                                         }
451 <Use>,{BS}"ONLY"                        { BEGIN(UseOnly); 
452                                         }           
453 <UseOnly>{BS},{BS}                      {}
454 <UseOnly>{ID}                           {
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; 
461                                         }
462 <Use,UseOnly>"\n"                       {
463                                           yyColNr -= 1;
464                                           unput(*yytext);
465                                           yy_pop_state();
466                                         }
467
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
475                                         }
476
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
481                                         }
482
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);
486
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);
492                                         }
493 }
494
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))
499                                             yyterminate();
500
501                                           ifType = IF_NONE;
502                                           yy_pop_state();
503                                         }
504 <InterfaceBody>module{BS}procedure      { yy_push_state(YY_START);
505                                           BEGIN(ModuleProcedure);
506                                         }
507 <ModuleProcedure>{ID}                   { if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
508                                           {
509                                             addInterface(yytext, ifType);
510                                             startScope(last_entry);
511                                           }
512
513                                           current->section = Entry::FUNCTION_SEC ;
514                                           current->name = yytext; 
515                                           moduleProcedures.append(current);
516                                           addCurrentEntry(1);
517                                         }
518 <ModuleProcedure>"\n"                   { yyColNr -= 1;
519                                           unput(*yytext); 
520                                           yy_pop_state();
521                                         }
522 <InterfaceBody>.                        {}
523
524  /*-- Contains handling --*/
525 <Start>^{BS}{CONTAINS}/({BS}|\n|!)      {
526                                           if(YY_START == Start)
527                                           {
528                                             addModule(NULL); 
529                                             yy_push_state(ModuleBodyContains); //anon program
530                                           }                                            
531                                         }
532 <ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!)   { BEGIN(ModuleBodyContains); }
533 <SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!)  { BEGIN(SubprogBodyContains); }
534 <TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!)  { BEGIN(TypedefBodyContains); }
535
536  /*------ module handling ------------------------------------------------------------*/ 
537 <Start>block{BS}data{BS}{ID_}        {  //
538                                          v_type = V_IGNORE;
539                                             yy_push_state(BlockData);
540                                             defaultProtection = Public;
541                                        }
542 <Start>module|program{BS_}             {  //
543                                          v_type = V_IGNORE;
544                                             if(yytext[0]=='m' || yytext[0]=='M')
545                                               yy_push_state(Module);
546                                             else
547                                               yy_push_state(Program);
548                                             defaultProtection = Public;
549                                        }
550 <BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!) { // end block data
551                                             //if (!endScope(current_root))
552                                             //  yyterminate();
553                                             defaultProtection = Public;
554                                             yy_pop_state();
555                                        }
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))
559                                               yyterminate();
560                                             defaultProtection = Public;
561                                             yy_pop_state();
562                                        }
563 <Module>{ID}                           {  
564                                             addModule(yytext, TRUE);
565                                             BEGIN(ModuleBody);
566                                        }
567
568 <Program>{ID}                           {  
569                                             addModule(yytext, FALSE);
570                                             BEGIN(ModuleBody);
571                                        }
572
573   /*------- access specification --------------------------------------------------------------------------*/
574
575 <ModuleBody>private/{BS}(\n|"!")         { defaultProtection = Private;
576                                            current->protection = defaultProtection ;
577                                          }
578 <ModuleBody>public/{BS}(\n|"!")          { defaultProtection = Public;
579                                            current->protection = defaultProtection ;
580                                          }
581
582  /*------- type definition  -------------------------------------------------------------------------------*/
583
584 <Start,ModuleBody>^{BS}type/[^a-z0-9_]   {
585                                           if(YY_START == Start)
586                                           {
587                                             addModule(NULL); 
588                                             yy_push_state(ModuleBody); //anon program
589                                           }
590
591                                           yy_push_state(Typedef);
592                                           current->protection = defaultProtection;
593                                           typeProtection = defaultProtection;
594                                           typeMode = true;
595                                         }
596 <Typedef>{
597 {COMMA}                                 {}
598
599 {BS}"::"{BS}                            {}
600
601 abstract                                {
602                                           current->spec |= Entry::AbstractClass;
603                                         }
604 extends{ARGS}                           {
605                                           QCString basename = extractFromParens(yytext);
606                                           current->extends->append(new BaseInfo(basename, Public, Normal));
607                                         }
608 public                                  {
609                                           current->protection = Public;
610                                           typeProtection = Public;
611                                         }
612 private                                 {
613                                           current->protection = Private;
614                                           typeProtection = Private;
615                                         }
616 {LANGUAGE_BIND_SPEC}                    {
617                                           /* ignored for now */
618                                         }
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;
626
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))
631                                           {
632                                             current->name = current_root->name + "::" + current->name;
633                                           }
634
635                                           addCurrentEntry(1);
636                                           startScope(last_entry); 
637                                           BEGIN(TypedefBody);
638                                         }
639 }
640
641 <TypedefBodyContains>{                  /* Type Bound Procedures */
642 ^{BS}PROCEDURE{ARGS}?                   {
643                                           current->type = QCString(yytext).simplifyWhiteSpace();
644                                         }
645 ^{BS}final                              {
646                                           current->spec |= Entry::Final;
647                                           current->type = QCString(yytext).simplifyWhiteSpace();
648                                         }
649 ^{BS}generic                            {
650                                           current->type = QCString(yytext).simplifyWhiteSpace();
651                                         }
652 {COMMA}                                 {
653                                         }
654 {ATTR_SPEC}                             {
655                                           currentModifiers |= QCString(yytext);
656                                         }
657 {BS}"::"{BS}                            {
658                                         }
659 {ID}                                    {
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;
667                                           addCurrentEntry(1);
668                                         }
669 {BS}"=>"[^(\n|\!)]*                     { /* Specific bindings come after the ID. */
670                                           last_entry->args = yytext;
671                                         }
672 "\n"                                    {
673                                           currentModifiers = SymbolModifiers();
674                                           newLine();
675                                           docBlock.resize(0);
676                                         }
677 }
678
679
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))
684                                             yyterminate();
685                                           typeMode = false;
686                                           yy_pop_state();
687                                         }
688 }
689
690  /*------- module/global/typedef variable ---------------------------------------------------*/
691
692 <SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {  
693                                            //
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.
697                                            //
698                                            if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
699                                            {
700                                              endScope(current_root);
701                                              last_entry->endBodyLine = yyLineNr - 1;
702                                            }
703                                            current_root->endBodyLine = yyLineNr - 1;
704
705                                            if (!endScope(current_root))
706                                              yyterminate();
707                                            subrCurrent.remove(0u);
708                                            yy_pop_state() ;
709                                         }
710 <BlockData>{
711 {ID}                                    {
712                                         }
713 }
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)
720                                           {
721                                             addModule(NULL); 
722                                             yy_push_state(ModuleBody); //anon program
723                                           }
724                                           argType = QCString(yytext).simplifyWhiteSpace().lower();
725                                           yy_push_state(AttributeList);
726                                         }
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();
732                                           QCString name;
733                                           int index = str.find("(");
734                                           if (index != -1)
735                                             name = str.left(index).stripWhiteSpace();
736                                           else
737                                             name = str;
738
739                                           Define *define = 0; //(*defines)[name];
740                                           if (define != 0 && isTypeName(define->definition)) 
741                                           {
742                                             argType = str;
743                                             yy_push_state(AttributeList);
744                                           } 
745                                           else 
746                                           {
747                                             yyColNr -= (int)yyleng;
748                                             REJECT;
749                                           }
750                                         }
751   */
752 {EXTERNAL_STMT}/({BS}"::"|{BS_}{ID})   { 
753                                           /* external can be a "type" or an attribute */
754                                           if(YY_START == Start)
755                                           {
756                                             addModule(NULL); 
757                                             yy_push_state(ModuleBody); //anon program
758                                           }
759                                           QCString tmp = yytext;
760                                           currentModifiers |= tmp.stripWhiteSpace();
761                                           argType = QCString(yytext).simplifyWhiteSpace().lower();
762                                           yy_push_state(AttributeList);
763                                        }
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();
770                                           argType="";
771                                           yy_push_state(YY_START);
772                                           BEGIN( AttributeList ) ;
773                                        }
774 {ID}                                   {
775                                        }  
776 ^{BS}"type"{BS_}"is"/{BS_}             { }
777 ^{BS}"type"{BS}"="                     { }
778 }
779 <AttributeList>{
780 {COMMA}                                 {}
781 {BS}                                    {}
782 {ATTR_SPEC}.                            { /* update current modifiers when it is an ATTR_SPEC and not a variable name */
783                                           /* bug_625519 */
784                                           QChar chr = yytext[(int)yyleng-1];
785                                           if (chr.isLetter() || chr.isDigit() || (chr == '_'))
786                                           {
787                                             yyColNr -= (int)yyleng;
788                                             REJECT;
789                                           }
790                                           else
791                                           {
792                                             QCString tmp = yytext;
793                                             tmp = tmp.left(tmp.length() - 1);
794                                             yyColNr -= 1;
795                                             unput(yytext[(int)yyleng-1]);
796                                             currentModifiers |= (tmp);
797                                           }
798                                         }
799 "::"                                    { /* end attribute list */
800                                           BEGIN( Variable );
801                                         }
802 .                                       { /* unknown attribute, consider variable name */
803                                           //cout<<"start variables, unput "<<*yytext<<endl;
804                                           yyColNr -= 1;
805                                           unput(*yytext);
806                                           BEGIN( Variable );
807                                         }
808 }
809
810 <Variable>{BS}                          { }
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;
815                                           name = name.lower();
816                                           /* remember attributes for the symbol */
817                                           modifiers[current_root][name.lower()] |= currentModifiers;
818                                           argName= name;
819
820                                           v_type= V_IGNORE;
821                                           if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) 
822                                           { // new variable entry
823                                             v_type = V_VARIABLE;
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;
830                                             addCurrentEntry(1);
831                                           } 
832                                           else if (!argType.isEmpty())
833                                           { // declaration of parameter list: add type for corr. parameter 
834                                             parameter = getParameter(argName);
835                                             if (parameter) 
836                                             {
837                                               v_type= V_PARAMETER;
838                                               if (!argType.isNull()) parameter->type=argType.stripWhiteSpace();
839                                               if (!docBlock.isNull()) 
840                                               {
841                                                 subrHandleCommentBlock(docBlock,TRUE);
842                                               }                                     
843                                             }
844                                             // save, it may be function return type
845                                             if (parameter)
846                                             {
847                                               modifiers[current_root][name.lower()].type = argType;
848                                             }
849                                             else
850                                             {
851                                               if ((current_root->name.lower() == argName.lower()) ||
852                                                   (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower()))
853                                               {
854                                                 int strt = current_root->type.find("function");
855                                                 QCString lft;
856                                                 QCString rght;
857                                                 if (strt != -1)
858                                                 {
859                                                   v_type = V_RESULT;
860                                                   lft = "";
861                                                   rght = "";
862                                                   if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace();
863                                                   if ((current_root->type.length() - strt - strlen("function"))!= 0)
864                                                   {
865                                                     rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace();
866                                                   }
867                                                   current_root->type = lft;
868                                                   if (rght.length() > 0)
869                                                   {
870                                                     if (current_root->type.length() > 0) current_root->type += " ";
871                                                     current_root->type += rght;
872                                                   }
873                                                   if (argType.stripWhiteSpace().length() > 0)
874                                                   {
875                                                     if (current_root->type.length() > 0) current_root->type += " ";
876                                                     current_root->type += argType.stripWhiteSpace();
877                                                   }
878                                                   if (current_root->type.length() > 0) current_root->type += " ";
879                                                   current_root->type += "function";
880                                                   if (!docBlock.isNull()) 
881                                                   {
882                                                     subrHandleCommentBlockResult(docBlock,TRUE);
883                                                   }
884                                                 }
885                                                 else
886                                                 {
887                                                   current_root->type += " " + argType.stripWhiteSpace();
888                                                 }
889                                                 current_root->type = current_root->type.stripWhiteSpace();
890                                                 modifiers[current_root][name.lower()].type = current_root->type;
891                                               }
892                                               else
893                                               {
894                                                 modifiers[current_root][name.lower()].type = argType;
895                                               }
896                                             }
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);
902                                           } 
903                                         }
904 <Variable>{ARGS}                        { /* dimension of the previous entry. */
905                                           QCString name(argName);
906                                           QCString attr("dimension");
907                                           attr += yytext;
908                                           modifiers[current_root][name.lower()] |= attr;
909                                         }
910 <Variable>{COMMA}                       { //printf("COMMA: %d<=..<=%d\n", yyColNr-(int)yyleng, yyColNr);
911                                           // locate !< comment
912                                           updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
913                                         }
914 <Variable>{BS}"="                       {
915                                           yy_push_state(YY_START);
916                                           initializer="=";
917                                           initializerScope = initializerArrayScope = 0;
918                                           BEGIN(Initialization);
919                                         }
920 <Variable>"\n"                          { currentModifiers = SymbolModifiers();
921                                           yy_pop_state(); // end variable declaration list
922                                           newLine();
923                                           docBlock.resize(0);
924                                         }
925 <Variable>";".*"\n"                     { currentModifiers = SymbolModifiers();
926                                           yy_pop_state(); // end variable declaration list
927                                           docBlock.resize(0);
928                                           inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
929                                           yyLineNr--;
930                                           pushBuffer(inputStringSemi);
931                                         }
932 <*>";".*"\n"                            {
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();
937                                           yyLineNr--;
938                                           pushBuffer(inputStringSemi);
939                                         }
940
941 <Initialization,ArrayInitializer>"["    |
942 <Initialization,ArrayInitializer>"(/"   { initializer+=yytext;
943                                            initializerArrayScope++;
944                                            BEGIN(ArrayInitializer); // initializer may contain comma
945                                         }
946 <ArrayInitializer>"]"                   |
947 <ArrayInitializer>"/)"                  { initializer+=yytext;
948                                            initializerArrayScope--;
949                                            if(initializerArrayScope<=0)
950                                            {
951                                               initializerArrayScope = 0; // just in case
952                                               BEGIN(Initialization);
953                                            }
954                                         }
955 <ArrayInitializer>.                     { initializer+=yytext; }
956 <Initialization>"("                     { initializerScope++;
957                                           initializer+=yytext;
958                                         }
959 <Initialization>")"                     { initializerScope--;
960                                           initializer+=yytext;
961                                         }
962 <Initialization>{COMMA}                 { if (initializerScope == 0)
963                                           {
964                                             updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
965                                             yy_pop_state(); // end initialization
966                                             if (v_type == V_VARIABLE) last_entry->initializer= initializer;
967                                           }
968                                           else
969                                             initializer+=", ";
970                                         }
971 <Initialization>"\n"|"!"                { //|
972                                           yy_pop_state(); // end initialization
973                                           if (v_type == V_VARIABLE) last_entry->initializer= initializer;
974                                           yyColNr -= 1;
975                                           unput(*yytext);
976                                         }
977 <Initialization>.                       { initializer+=yytext; }
978  
979  /*------ fortran subroutine/function handling ------------------------------------------------------------*/
980  /*       Start is initial condition                                                                       */
981  
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)
984                                          {
985                                            addInterface("$interface$", ifType);
986                                            startScope(last_entry);
987                                          }
988
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);
993                                        }
994
995 <SubprogPrefix>{BS}{SUBPROG}{BS_}     {
996                                          // Fortran subroutine or function found
997                                          v_type = V_IGNORE;
998                                          result=yytext;
999                                          result=result.stripWhiteSpace();
1000                                          addSubprogram(result);
1001                                          BEGIN(Subprog);
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;
1004                                        }
1005
1006 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1007                                          // Fortran subroutine or function found
1008                                          v_type = V_IGNORE;
1009                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1010                                          {
1011                                            addInterface("$interface$", ifType);
1012                                            startScope(last_entry);
1013                                          }
1014
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;
1020                                        }
1021
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();
1026
1027                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1028                                          {
1029                                            current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
1030                                          }
1031
1032                                          BEGIN(Parameterlist);
1033                                        }
1034 <Parameterlist>"("                     { current->args = "("; }
1035 <Parameterlist>")"                     {
1036                                          current->args += ")";
1037                                          current->args = removeRedundantWhiteSpace(current->args);
1038                                          addCurrentEntry(1);
1039                                          startScope(last_entry);
1040                                          BEGIN(SubprogBody);
1041                                        }
1042 <Parameterlist>{COMMA}|{BS}            { current->args += yytext;
1043                                          CommentInPrepass *c = locatePrepassComment(yyColNr-(int)yyleng, yyColNr);
1044                                          if (c!=NULL) {
1045                                            if(current->argList->count()>0) {
1046                                              current->argList->at(current->argList->count()-1)->docs = c->str;
1047                                            }
1048                                          }                       
1049                                        }
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;
1056                                            arg->name = param;
1057                                            arg->type = "";
1058                                            current->argList->append(arg);
1059                                        } 
1060 <Parameterlist>{NOARGS}                {   
1061                                            newLine();
1062                                            //printf("3=========> without parameterlist \n");
1063                                            //current->argList = ;
1064                                            addCurrentEntry(1);
1065                                            startScope(last_entry);
1066                                            BEGIN(SubprogBody);                                     
1067 }
1068 <SubprogBody>result{BS}\({BS}{ID}      {  
1069                                            if (functionLine)
1070                                            {
1071                                              result= yytext;
1072                                              result= result.right(result.length()-result.find("(")-1);
1073                                              result= result.stripWhiteSpace();
1074                                              modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
1075                                            }
1076                                            //cout << "=====> got result " <<  result << endl;
1077                                        } 
1078
1079  /*---- documentation comments --------------------------------------------------------------------*/
1080
1081 <Variable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<"  { /* backward docu comment */
1082                                           if (v_type != V_IGNORE) {
1083                                            current->docLine  = yyLineNr;
1084                                            docBlockJavaStyle = FALSE;
1085                                            docBlock.resize(0);
1086                                            docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1087                                            startCommentBlock(TRUE);
1088                                            yy_push_state(DocBackLine);
1089                                           }
1090                                           else
1091                                           {
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)) 
1097                                             {
1098                                               yy_push_state(YY_START);
1099                                               BEGIN(StrIgnore); 
1100                                               debugStr="*!";
1101                                               //fprintf(stderr,"start comment %d\n",yyLineNr);
1102                                             }      
1103                                           }
1104                                          }
1105 <DocBackLine>.*                          { // contents of current comment line
1106                                           docBlock+=yytext;
1107                                         }
1108 <DocBackLine>"\n"{BS}"!"("<"|"!"+)              { // comment block (next line is also comment line)
1109                                           docBlock+="\n"; // \n is necessary for lists
1110                                           newLine();
1111                                         }
1112 <DocBackLine>"\n"                               { // comment block ends at the end of this line
1113                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1114                                           yyColNr -= 1;
1115                                           unput(*yytext);                                        
1116                                           if (v_type == V_VARIABLE) 
1117                                           {
1118                                             Entry *tmp_entry = current; 
1119                                             current = last_entry; // temporarily switch to the previous entry
1120                                             handleCommentBlock(docBlock,TRUE);
1121                                             current=tmp_entry;
1122                                           }
1123                                           else if (v_type == V_PARAMETER) 
1124                                           {
1125                                             subrHandleCommentBlock(docBlock,TRUE);
1126                                           }
1127                                           else if (v_type == V_RESULT) 
1128                                           {
1129                                             subrHandleCommentBlockResult(docBlock,TRUE);
1130                                           }
1131                                           yy_pop_state();
1132                                           docBlock.resize(0);
1133                                         }
1134
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;
1140                                           docBlock.resize(0);
1141                                           docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1142                                           startCommentBlock(TRUE);
1143                                           BEGIN(DocBlock);
1144                                           //cout << "start DocBlock " << endl;
1145                                         }
1146
1147 <DocBlock>.*                            { // contents of current comment line
1148                                           docBlock+=yytext;
1149                                         }
1150 <DocBlock>"\n"{BS}"!"(">"|"!"+)         { // comment block (next line is also comment line)
1151                                           docBlock+="\n"; // \n is necessary for lists
1152                                           newLine();
1153                                         }
1154 <DocBlock>"\n"                          { // comment block ends at the end of this line
1155                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1156                                           yyColNr -= 1;
1157                                           unput(*yytext);                                        
1158                                           handleCommentBlock(docBlock,TRUE);
1159                                           yy_pop_state();                                          
1160                                         }
1161
1162  /*-----Prototype parsing -------------------------------------------------------------------------*/
1163 <Prototype>{BS}{SUBPROG}{BS_}           {
1164                                           BEGIN(PrototypeSubprog);
1165                                         }
1166 <Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} { 
1167                                           current->name = QCString(yytext).lower();
1168                                           current->name.stripWhiteSpace();
1169                                           BEGIN(PrototypeArgs);
1170                                         }
1171 <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);
1177                                         }
1178 }
1179
1180  /*------------------------------------------------------------------------------------------------*/
1181
1182 <*>"\n"                                 {
1183                                           newLine();
1184                                           //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
1185                                           debugStr="";
1186                                         }
1187
1188
1189  /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1190
1191 <*><<EOF>>                              {
1192                                           if (parsingPrototype) {
1193                                             yyterminate();
1194
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)"));
1198                                               scanner_abort();
1199                                             }
1200                                             yyterminate();
1201                                           } else {
1202                                             popBuffer();
1203                                           }
1204                                         }
1205 <*>{LOG_OPER}                           { // Fortran logical comparison keywords
1206                                         }
1207 <*>.                                    {
1208                                           //debugStr+=yytext;
1209                                           //printf("I:%c\n", *yytext);
1210                                         } // ignore remaining text 
1211
1212  /**********************************************************************************/
1213  /**********************************************************************************/
1214  /**********************************************************************************/
1215 %%
1216 //----------------------------------------------------------------------------
1217
1218 #if 0
1219 static void extractPrefix(QCString &text) 
1220 {
1221   int prefixIndex = 0;
1222   int curIndex = 0;
1223   bool cont = TRUE;
1224   const char* pre[] = {"RECURSIVE","IMPURE","PURE","ELEMENTAL"};
1225   while(cont)
1226   {
1227     cont = FALSE;
1228     for(unsigned int i=0; i<4; i++)
1229     {
1230       if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
1231       {
1232         text.remove(0,strlen(pre[i]));
1233         text.stripWhiteSpace();
1234         cont = TRUE;
1235       }
1236     }
1237   }
1238 }
1239 #endif
1240
1241 static void newLine() {
1242   yyLineNr++;
1243   yyLineNr+=lineCountPrepass;
1244   lineCountPrepass=0;
1245   comments.clear();
1246 }
1247
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);
1256     }
1257   }
1258   return NULL;
1259 }
1260
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;
1268   }
1269 }
1270
1271 static int getAmpersandAtTheStart(const char *buf, int length)
1272 {
1273   for(int i=0; i<length; i++) {
1274     switch(buf[i]) {
1275       case ' ':
1276       case '\t':
1277         break;
1278       case '&':
1279         return i;
1280       default:
1281         return -1;
1282     }
1283   }
1284   return -1;
1285 }
1286
1287 /* Returns ampersand index, comment start index or -1 if neither exist.*/ 
1288 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
1289 {
1290   // Avoid ampersands in string and comments
1291   int parseState = Start;
1292   char quoteSymbol = 0;
1293   int ampIndex = -1;
1294   int commentIndex = -1;
1295   quoteSymbol = ch;
1296   if (ch != '\0') parseState = String;
1297
1298   for(int i=0; i<length && parseState!=Comment; i++)
1299   {
1300     // When in string, skip backslashes
1301     // Legacy code, not sure whether this is correct?
1302     if(parseState==String)
1303     {
1304       if(buf[i]=='\\') i++;
1305     }
1306
1307     switch(buf[i])
1308     {
1309         case '\'':
1310         case '"':
1311           // Close string, if quote symbol matches.
1312           // Quote symbol is set iff parseState==String
1313           if(buf[i]==quoteSymbol)
1314           {
1315              parseState = Start;
1316              quoteSymbol = 0;
1317           }
1318           // Start new string, if not already in string or comment
1319           else if(parseState==Start)
1320           {
1321             parseState = String;
1322             quoteSymbol = buf[i];
1323           }
1324           ampIndex = -1; // invalidate prev ampersand
1325           break;
1326         case '!':
1327           // When in string or comment, ignore exclamation mark
1328           if(parseState==Start)
1329           {
1330             parseState = Comment;
1331             commentIndex = i;
1332           }
1333           break;
1334         case ' ':  // ignore whitespace
1335         case '\t':
1336         case '\n': // this may be at the end of line
1337           break;
1338         case '&':
1339           ampIndex = i;
1340           break;
1341         default:
1342           ampIndex = -1; // invalidate prev ampersand
1343     }
1344   }
1345
1346   if (ampIndex>=0)
1347     return ampIndex;
1348   else
1349    return commentIndex;
1350 }
1351
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.
1354 */
1355 void truncatePrepass(int index)
1356 {
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));
1361       comments.append(c);
1362     }
1363   }
1364   inputStringPrepass.truncate(index);
1365 }
1366
1367 // simplified way to know if this is fixed form
1368 // duplicate in fortrancode.l
1369 bool recognizeFixedForm(const char* contents, FortranFormat format)
1370 {
1371   int column=0;
1372   bool skipLine=FALSE;
1373
1374   if (format == FortranFormat_Fixed) return TRUE;
1375   if (format == FortranFormat_Free)  return FALSE;
1376
1377   for(int i=0;;i++) {
1378     column++;
1379
1380     switch(contents[i]) {
1381       case '\n':
1382         column=0;
1383         skipLine=FALSE;
1384         break;
1385       case ' ':
1386         break;
1387       case '\000':
1388         return FALSE;
1389       case '#':
1390         skipLine=TRUE;
1391         break;
1392       case 'C':
1393       case 'c':
1394       case '*':
1395         if(column==1) return TRUE;
1396         if(skipLine) break;
1397         return FALSE;
1398       case '!':
1399         if(column>1 && column<7) return FALSE;
1400         skipLine=TRUE;
1401         break;
1402       default:
1403         if(skipLine) break;
1404         if(column==7) return TRUE;
1405         return FALSE;
1406     }
1407   }
1408   return FALSE;
1409 }
1410
1411 /* This function assumes that contents has at least size=length+1 */
1412 static void insertCharacter(char *contents, int length, int pos, char c)
1413 {
1414   // shift tail by one character
1415   for(int i=length; i>pos; i--)
1416     contents[i]=contents[i-1];
1417   // set the character
1418   contents[pos] = c;
1419 }
1420
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)
1424 {
1425   int column=0;
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);
1438   int curLine = 1;
1439
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;
1444     }
1445
1446     column++;
1447     char c = contents[i];
1448     switch(c) {
1449       case '\n':
1450         if (!fullCommentLine)
1451         {
1452           prevLineLength=column;
1453           prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1454           if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1455         }
1456         else
1457         {
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) */
1460           if (hasContLine)
1461           {
1462             hasContLine[curLine - 1] = 1;
1463           }
1464         }
1465         fullCommentLine=TRUE;
1466         column=0;
1467         emptyLabel=TRUE;
1468         commented=FALSE;
1469         newContents[j]=c;
1470         prevQuote = thisQuote;
1471         curLine++;
1472         break;
1473       case ' ':
1474       case '\t':
1475         newContents[j]=c;
1476         break;
1477       case '\000':
1478         if (hasContLine)
1479         {
1480            free(newContents);
1481            return NULL;
1482         }
1483         newContents[j]='\000';
1484         newContentsSize = strlen(newContents);
1485         if (newContents[newContentsSize - 1] != '\n')
1486         {
1487           // to be on the safe side
1488           newContents = (char*)realloc(newContents, newContentsSize+2);
1489           newContents[newContentsSize] = '\n';
1490           newContents[newContentsSize + 1] = '\000';
1491         }
1492         return newContents;
1493       case '"':
1494       case '\'':
1495       case '\\':
1496         if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1497         {
1498           // we have some special cases in respect to strings and escaped string characters
1499           fullCommentLine=FALSE;
1500           newContents[j]=c;
1501           if (c == '\\')
1502           {
1503             inBackslash = !inBackslash;
1504             break;
1505           }
1506           else if (c == '\'')
1507           {
1508             if (!inDouble)
1509             {
1510               inSingle = !inSingle;
1511               if (inSingle) thisQuote = c;
1512               else thisQuote = '\0';
1513             }
1514             break;
1515           }
1516           else if (c == '"')
1517           {
1518             if (!inSingle)
1519             {
1520               inDouble = !inDouble; 
1521               if (inDouble) thisQuote = c; 
1522               else thisQuote = '\0';
1523             }
1524             break;
1525           }
1526         }
1527         inBackslash = FALSE;
1528         // fallthrough
1529       case 'C':
1530       case 'c':
1531       case '*':
1532       case '!':
1533         if ((column <= fixedCommentAfter) && (column!=6))
1534         {
1535           emptyLabel=FALSE;
1536           if(column==1)
1537           {
1538             newContents[j]='!';
1539             commented = TRUE;
1540           }
1541           else if ((c == '!') && !inDouble && !inSingle)
1542           {
1543             newContents[j]=c;
1544             commented = TRUE;
1545           }
1546           else
1547           {
1548             if (!commented) fullCommentLine=FALSE;
1549             newContents[j]=c;
1550           }
1551           break;
1552         }
1553         // fallthrough
1554       default:
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
1558             newContents[j]=' ';
1559
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, '&');
1563               j++;
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, '&');
1567               j++;
1568             }
1569             if (hasContLine) hasContLine[curLine - 1] = 1;
1570           } else {
1571             newContents[j]=c; // , just handle like space
1572           }
1573           prevLineLength=0;
1574         } else if ((column > fixedCommentAfter) && !commented) {
1575           // first non commented non blank character after position fixedCommentAfter
1576           if (c != '!') {
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
1580           }
1581           newContents[j]=c;
1582           commented = TRUE;
1583         } else {
1584           if (!commented) fullCommentLine=FALSE;
1585           newContents[j]=c;
1586           emptyLabel=FALSE;
1587         }
1588         break;
1589     }
1590   }
1591
1592   if (hasContLine)
1593   {
1594     free(newContents);
1595     return NULL;
1596   }
1597   newContentsSize = strlen(newContents);
1598   if (newContents[newContentsSize - 1] != '\n')
1599   {
1600     // to be on the safe side
1601     newContents = (char*)realloc(newContents, newContentsSize+2);
1602     newContents[newContentsSize] = '\n';
1603     newContents[newContentsSize + 1] = '\000';
1604   }
1605   return newContents;
1606 }
1607
1608 static void pushBuffer(QCString& buffer)
1609 {
1610   if (include_stack_cnt <= include_stack_ptr)
1611   {
1612      include_stack_cnt++;
1613      include_stack = (YY_BUFFER_STATE *)realloc(include_stack, include_stack_cnt * sizeof(YY_BUFFER_STATE));
1614   }
1615   include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
1616   yy_switch_to_buffer(yy_scan_string(buffer));
1617
1618   DBG_CTX((stderr, "--PUSH--%s", (const char *)buffer));
1619   buffer = NULL;
1620 }
1621
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] );
1627 }
1628
1629 /** used to copy entry to an interface module procedure */
1630 static void copyEntry(Entry *dest, Entry *src) 
1631 {
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;
1641 }
1642
1643 /** fill empty interface module procedures with info from 
1644     corresponding module subprogs 
1645     @TODO: handle procedures in used modules
1646 */
1647 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
1648 {
1649   if (moduleProcedures.isEmpty()) return;
1650  
1651   EntryListIterator eli1(moduleProcedures);
1652   // for all module procedures
1653   for (Entry *ce1; (ce1=eli1.current()); ++eli1) 
1654   {
1655     // check all entries in this module
1656     EntryListIterator eli2(*current_root->children());
1657     for (Entry *ce2; (ce2=eli2.current()); ++eli2) 
1658     {
1659       if (ce1->name == ce2->name) 
1660       {
1661         copyEntry(ce1, ce2);
1662       }
1663     } // for procedures in current module
1664   } // for all interface module procedures
1665   moduleProcedures.clear();
1666 }
1667
1668 #if 0
1669 static bool isTypeName(QCString name)
1670 {
1671   name = name.lower();
1672   return name=="integer" || name == "real" || 
1673          name=="complex" || name == "logical";
1674 }
1675 #endif
1676
1677 /*! Extracts string which resides within parentheses of provided string. */
1678 static QCString extractFromParens(const QCString name)
1679 {
1680   QCString extracted = name;
1681   int start = extracted.find("(");
1682   if (start != -1) 
1683   {
1684     extracted.remove(0, start+1);
1685   }
1686   int end = extracted.findRev(")");
1687   if (end != -1) 
1688   {
1689     int length = extracted.length();
1690     extracted.remove(end, length);
1691   }
1692   extracted = extracted.stripWhiteSpace();
1693
1694   return extracted;
1695 }
1696
1697 /*! Adds passed modifiers to these modifiers.*/
1698 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
1699 {
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;
1711   save |= mdfs.save;
1712   deferred |= mdfs.deferred;
1713   nonoverridable |= mdfs.nonoverridable;
1714   nopass |= mdfs.nopass;
1715   pass |= mdfs.pass;
1716   passVar = mdfs.passVar;
1717   contiguous |= mdfs.contiguous;
1718   volat |= mdfs.volat;
1719   value |= mdfs.value;
1720   return *this;
1721 }
1722
1723 /*! Extracts and adds passed modifier to these modifiers.*/
1724 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
1725 {
1726   mdfString = mdfString.lower();
1727   SymbolModifiers newMdf;
1728
1729   if (mdfString.find("dimension")==0) 
1730   {
1731     newMdf.dimension=mdfString;
1732   }
1733   else if (mdfString.contains("intent")) 
1734   {
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;
1741   }
1742   else if (mdfString=="public") 
1743   {
1744     newMdf.protection = SymbolModifiers::PUBLIC;
1745   }
1746   else if (mdfString=="private") 
1747   {
1748     newMdf.protection = SymbolModifiers::PRIVATE;
1749   }
1750   else if (mdfString=="protected") 
1751   {
1752     newMdf.protect = TRUE;
1753   }
1754   else if (mdfString=="optional") 
1755   {
1756     newMdf.optional = TRUE;
1757   }
1758   else if (mdfString=="allocatable") 
1759   {
1760     newMdf.allocatable = TRUE;
1761   }
1762   else if (mdfString=="external") 
1763   {
1764     newMdf.external = TRUE;
1765   }
1766   else if (mdfString=="intrinsic") 
1767   {
1768     newMdf.intrinsic = TRUE;
1769   }
1770   else if (mdfString=="parameter") 
1771   {
1772     newMdf.parameter = TRUE;
1773   }
1774   else if (mdfString=="pointer") 
1775   {
1776     newMdf.pointer = TRUE;
1777   }
1778   else if (mdfString=="target") 
1779   {
1780     newMdf.target = TRUE;
1781   }
1782   else if (mdfString=="save") 
1783   {
1784     newMdf.save = TRUE;
1785   }
1786   else if (mdfString=="nopass")
1787   {
1788     newMdf.nopass = TRUE;
1789   }
1790   else if (mdfString=="deferred")
1791   {
1792     newMdf.deferred = TRUE;
1793   }
1794   else if (mdfString=="non_overridable")
1795   {
1796     newMdf.nonoverridable = TRUE;
1797   }
1798   else if (mdfString=="contiguous")
1799   {
1800     newMdf.contiguous = TRUE;
1801   }
1802   else if (mdfString=="volatile")
1803   {
1804     newMdf.volat = TRUE;
1805   }
1806   else if (mdfString=="value")
1807   {
1808     newMdf.value = TRUE;
1809   }
1810   else if (mdfString.contains("pass"))
1811   {
1812     newMdf.pass = TRUE;
1813     if (mdfString.contains("("))
1814       newMdf.passVar = extractFromParens(mdfString);
1815     else
1816       newMdf.passVar = "";
1817   }
1818
1819   (*this) |= newMdf;
1820   return *this;
1821 }
1822
1823 /*! For debugging purposes. */
1824 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
1825 //{
1826 //  out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
1827 //    ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
1828 //    ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
1829 //
1830 //  return out;
1831 //}
1832
1833 /*! Find argument with given name in \a subprog entry. */
1834 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
1835 {
1836   QCString cname(name.lower());
1837   for (unsigned int i=0; i<subprog->argList->count(); i++) 
1838   {
1839     Argument *arg = subprog->argList->at(i);
1840     if ((!byTypeName && arg->name.lower() == cname) ||
1841         (byTypeName && arg->type.lower() == cname)
1842        )
1843     {
1844       return arg;
1845     }
1846   }
1847   return 0;
1848 }
1849
1850 /*! Find function with given name in \a entry. */
1851 #if 0
1852 static Entry *findFunction(Entry* entry, QCString name)
1853 {
1854   QCString cname(name.lower());
1855
1856   EntryListIterator eli(*entry->children());
1857   Entry *ce;
1858   for (;(ce=eli.current());++eli) 
1859   {
1860     if (ce->section != Entry::FUNCTION_SEC)
1861       continue;
1862
1863     if (ce->name.lower() == cname)
1864       return ce;
1865   }
1866
1867   return 0;
1868 }
1869 #endif
1870
1871 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */
1872 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs) 
1873 {
1874   if (!mdfs.dimension.isNull()) 
1875   {
1876     if (!typeName.isEmpty()) typeName += ", ";
1877     typeName += mdfs.dimension;
1878   }
1879   if (mdfs.direction!=SymbolModifiers::NONE_D) 
1880   {
1881     if (!typeName.isEmpty()) typeName += ", ";
1882     typeName += directionStrs[mdfs.direction];
1883   }
1884   if (mdfs.optional) 
1885   {
1886     if (!typeName.isEmpty()) typeName += ", ";
1887     typeName += "optional";
1888   }
1889   if (mdfs.allocatable) 
1890   {
1891     if (!typeName.isEmpty()) typeName += ", ";
1892     typeName += "allocatable";
1893   }
1894   if (mdfs.external) 
1895   {
1896     if (!typeName.contains("external"))
1897     {
1898       if (!typeName.isEmpty()) typeName += ", ";
1899       typeName += "external";
1900     }
1901   }
1902   if (mdfs.intrinsic) 
1903   {
1904     if (!typeName.isEmpty()) typeName += ", ";
1905     typeName += "intrinsic";
1906   }
1907   if (mdfs.parameter) 
1908   {
1909     if (!typeName.isEmpty()) typeName += ", ";
1910     typeName += "parameter";
1911   }
1912   if (mdfs.pointer) 
1913   {
1914     if (!typeName.isEmpty()) typeName += ", ";
1915     typeName += "pointer";
1916   }
1917   if (mdfs.target) 
1918   {
1919     if (!typeName.isEmpty()) typeName += ", ";
1920     typeName += "target";
1921   }
1922   if (mdfs.save) 
1923   {
1924     if (!typeName.isEmpty()) typeName += ", ";
1925     typeName += "save";
1926   }
1927   if (mdfs.deferred) 
1928   {
1929     if (!typeName.isEmpty()) typeName += ", ";
1930     typeName += "deferred";
1931   }
1932   if (mdfs.nonoverridable) 
1933   {
1934     if (!typeName.isEmpty()) typeName += ", ";
1935     typeName += "non_overridable";
1936   }
1937   if (mdfs.nopass) 
1938   {
1939     if (!typeName.isEmpty()) typeName += ", ";
1940     typeName += "nopass";
1941   }
1942   if (mdfs.pass) 
1943   {
1944     if (!typeName.isEmpty()) typeName += ", ";
1945     typeName += "pass";
1946     if (!mdfs.passVar.isEmpty())
1947       typeName += "(" + mdfs.passVar + ")";
1948   }
1949   if (mdfs.protection == SymbolModifiers::PUBLIC)
1950   {
1951     if (!typeName.isEmpty()) typeName += ", ";
1952     typeName += "public";
1953   }
1954   else if (mdfs.protection == SymbolModifiers::PRIVATE)
1955   {
1956     if (!typeName.isEmpty()) typeName += ", ";
1957     typeName += "private";
1958   }
1959   if (mdfs.protect)
1960   {
1961     if (!typeName.isEmpty()) typeName += ", ";
1962     typeName += "protected";
1963   }
1964   if (mdfs.contiguous)
1965   {
1966     if (!typeName.isEmpty()) typeName += ", ";
1967     typeName += "contiguous";
1968   }
1969   if (mdfs.volat)
1970   {
1971     if (!typeName.isEmpty()) typeName += ", ";
1972     typeName += "volatile";
1973   }
1974   if (mdfs.value)
1975   {
1976     if (!typeName.isEmpty()) typeName += ", ";
1977     typeName += "value";
1978   }
1979
1980   return typeName;
1981 }
1982
1983 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */
1984 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
1985 {
1986   QCString tmp = arg->type;
1987   arg->type = applyModifiers(tmp, mdfs);
1988 }
1989
1990 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */
1991 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
1992 {
1993   QCString tmp = ent->type;
1994   ent->type = applyModifiers(tmp, mdfs);
1995
1996   if (mdfs.protection == SymbolModifiers::PUBLIC)
1997     ent->protection = Public;
1998   else if (mdfs.protection == SymbolModifiers::PRIVATE)
1999     ent->protection = Private;
2000 }
2001
2002 /*! Starts the new scope in fortran program. Consider using this function when
2003  * starting module, interface, function or other program block.
2004  * \see endScope()
2005  */
2006 static void startScope(Entry *scope) 
2007 {
2008   //cout<<"start scope: "<<scope->name<<endl;
2009   current_root= scope; /* start substructure */
2010
2011   QMap<QCString,SymbolModifiers> mdfMap;
2012   modifiers.insert(scope, mdfMap);
2013 }
2014
2015 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
2016  * \see startScope()
2017  */
2018 static bool endScope(Entry *scope, bool isGlobalRoot)
2019 {
2020   //cout<<"end scope: "<<scope->name<<endl;
2021   if (current_root->parent() || isGlobalRoot)
2022   {
2023     current_root= current_root->parent(); /* end substructure */
2024   }
2025   else 
2026   {
2027     fprintf(stderr,"parse error in end <scopename>");
2028     scanner_abort();
2029     return FALSE;
2030   }
2031
2032   // update variables or subprogram arguments with modifiers
2033   QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
2034
2035   if (scope->section == Entry::FUNCTION_SEC) 
2036   {
2037     // iterate all symbol modifiers of the scope
2038     for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) 
2039     {
2040       //cout<<it.key()<<": "<<it.data()<<endl;
2041       Argument *arg = findArgument(scope, it.key());
2042
2043       if (arg)
2044         applyModifiers(arg, it.data());
2045     }
2046
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)) 
2051     {
2052       scope->type = modifiers[scope][returnName].type; // returning type works
2053       applyModifiers(scope, modifiers[scope][returnName]); // returning array works
2054     }
2055
2056   } 
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());
2065       Entry *ce;
2066       int count = 0;
2067       int found = FALSE;
2068       for (;(ce=eli.current());++eli) 
2069       {
2070         count++;
2071         if (ce->section != Entry::FUNCTION_SEC)
2072           continue;
2073
2074         Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
2075         if (arg != 0) 
2076         {
2077           // set type of dummy procedure argument to interface
2078           arg->name = arg->type;
2079           arg->type = scope->name;
2080         }
2081         if (ce->name.lower() == scope->name.lower()) found = TRUE;
2082       }
2083       if ((count == 1) && found)
2084       {
2085         // clear all modifiers of the scope
2086         modifiers.remove(scope);
2087         delete scope->parent()->removeSubEntry(scope);
2088         scope = 0;
2089         return TRUE;
2090       }
2091     }
2092   } 
2093   if (scope->section!=Entry::FUNCTION_SEC) 
2094   { // not function section 
2095     // iterate variables: get and apply modifiers
2096     EntryListIterator eli(*scope->children());
2097     Entry *ce;
2098     for (;(ce=eli.current());++eli) 
2099     {
2100       if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
2101         continue;
2102
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()]);
2106     }
2107   }
2108
2109   // clear all modifiers of the scope
2110   modifiers.remove(scope);
2111
2112   return TRUE;
2113 }
2114
2115 #if 0
2116 //! Return full name of the entry. Sometimes we must combine several names recursively.
2117 static QCString getFullName(Entry *e) 
2118 {
2119   QCString name = e->name;
2120   if (e->section == Entry::CLASS_SEC //  || e->section == Entry::INTERFACE_SEC
2121      || !e->parent() || e->parent()->name.isEmpty())
2122     return name;
2123
2124   return getFullName(e->parent())+"::"+name;
2125 }
2126 #endif
2127
2128 static int yyread(char *buf,int max_size)
2129 {
2130   int c=0;
2131
2132   while ( c < max_size && inputString[inputPosition] )
2133   {
2134     *buf = inputString[inputPosition++] ;
2135     c++; buf++;
2136   }
2137   return c;
2138 }
2139
2140 static void initParser()
2141 {
2142   last_entry = 0;
2143 }
2144
2145 static void initEntry()
2146 {
2147   if (typeMode)
2148   {
2149     current->protection = typeProtection;
2150   }
2151   else
2152   {
2153     current->protection = defaultProtection;
2154   }
2155   current->mtype      = mtype;
2156   current->virt       = virt;
2157   current->stat       = gstat;
2158   current->lang       = SrcLangExt_Fortran; 
2159   initGroupInfo(current);
2160 }
2161
2162 /**
2163   adds current entry to current_root and creates new current
2164 */
2165 static void addCurrentEntry(int case_insens)
2166 {
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 ;
2172   initEntry();
2173 }
2174
2175 static int max(int a, int b) {return a>b?a:b;}
2176
2177 static void addModule(const char *name, bool isModule)
2178 {
2179   DBG_CTX((stderr, "0=========> got module %s\n", name));
2180
2181   if (isModule)
2182     current->section = Entry::NAMESPACE_SEC;
2183   else
2184     current->section = Entry::FUNCTION_SEC;
2185
2186   if (name!=NULL)
2187   {
2188     current->name = name;
2189   } 
2190   else
2191   {
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;
2197   }
2198   current->type = "program";
2199   current->fileName  = yyFileName;
2200   current->bodyLine  = yyLineNr; // used for source reference
2201   current->startLine  = yyLineNr;
2202   current->protection = Public ;
2203   addCurrentEntry(1);
2204   startScope(last_entry);
2205 }
2206
2207
2208 static void addSubprogram(const char *text)
2209 {
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();
2222   docBlock.resize(0);
2223 }
2224
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.
2228  */ 
2229 static void addInterface(QCString name, InterfaceType type)
2230 {
2231   if (YY_START == Start)
2232   {
2233     addModule(NULL);
2234     yy_push_state(ModuleBody); //anon program
2235   }
2236
2237   current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
2238   current->spec = Entry::Interface;
2239   current->name = name;
2240
2241   switch (type)
2242   {
2243     case IF_ABSTRACT:
2244       current->type = "abstract";
2245       break;
2246
2247     case IF_GENERIC:
2248       current->type = "generic";
2249       break;
2250
2251     case IF_SPECIFIC:
2252     case IF_NONE:
2253     default:
2254       current->type = "";
2255   }
2256
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)) 
2261   {
2262     current->name= current_root->name + "::" + current->name;
2263   }
2264
2265   current->fileName = yyFileName;
2266   current->bodyLine  = yyLineNr; 
2267   current->startLine  = yyLineNr;
2268   addCurrentEntry(1);
2269 }
2270
2271
2272 //-----------------------------------------------------------------------------
2273
2274 /*! Get the argument \a name.
2275  */
2276 static Argument* getParameter(const QCString &name)
2277 {
2278   // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl;
2279   Argument *ret = 0;
2280   if (current_root->argList==0) return 0;
2281   ArgumentListIterator ali(*current_root->argList);
2282   Argument *a;
2283   for (ali.toFirst();(a=ali.current());++ali)
2284   {
2285     if (a->name.lower()==name.lower())
2286     {
2287       ret=a;
2288       //printf("parameter found: %s\n",(const char*)name);
2289       break;
2290     }
2291   } // for
2292   return ret;
2293 }
2294
2295   //----------------------------------------------------------------------------
2296 static void startCommentBlock(bool brief)
2297 {
2298   if (brief)
2299   {
2300     current->briefFile = yyFileName;
2301     current->briefLine = yyLineNr;
2302   }
2303   else
2304   {
2305     current->docFile = yyFileName;
2306     current->docLine = yyLineNr;
2307   }
2308 }
2309
2310 //----------------------------------------------------------------------------
2311
2312 static void handleCommentBlock(const QCString &doc,bool brief)
2313 {
2314   bool needsEntry = FALSE;
2315   static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
2316   int position=0;
2317   if (docBlockInBody && hideInBodyDocs)
2318   {
2319     docBlockInBody = FALSE;
2320     return;
2321   }
2322   DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
2323   int lineNr = brief ? current->briefLine : current->docLine;
2324   while (parseCommentBlock(
2325         g_thisParser,
2326         docBlockInBody ? subrCurrent.getFirst() : current,
2327         doc,        // text
2328         yyFileName, // file
2329         lineNr,
2330         docBlockInBody ? FALSE : brief, 
2331         docBlockInBody ? FALSE : docBlockJavaStyle,
2332         docBlockInBody,
2333         defaultProtection,
2334         position,
2335         needsEntry
2336         )) 
2337   {
2338            DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2339    if (needsEntry) addCurrentEntry(0);
2340   }
2341   DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2342
2343   if (needsEntry) addCurrentEntry(0);
2344   docBlockInBody = FALSE;
2345 }
2346
2347 //----------------------------------------------------------------------------
2348 /// Handle parameter description as defined after the declaration of the parameter
2349 static void subrHandleCommentBlock(const QCString &doc,bool brief)
2350 {
2351   QCString loc_doc;
2352   loc_doc = doc.stripWhiteSpace();
2353
2354   Entry *tmp_entry = current; 
2355   current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2356
2357   // Still in the specification section so no inbodyDocs yet, but parameter documentation
2358   current->inbodyDocs = "";
2359
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();
2365
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)
2370   {
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]))
2374     {
2375       // strip direction
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()))
2380       {
2381         // reset current back to the part inside the routine
2382         current=tmp_entry;
2383         return;
2384       }
2385       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " + 
2386                          argName + " " + loc_doc,brief);
2387     }
2388     else
2389     {
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);
2395     }
2396   }
2397   // analogous to the [in] case, here [out] direction specified
2398   else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
2399   {
2400     if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2401         (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
2402     {
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()))
2406       {
2407         current=tmp_entry;
2408         return;
2409       }
2410       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " + 
2411                          argName + " " + loc_doc,brief);
2412     }
2413     else
2414     {
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);
2419     }
2420   }
2421   // analogous to the [in] case, here [in,out] direction specified
2422   else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
2423   {
2424     if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2425         (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
2426     {
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()))
2430       {
2431         current=tmp_entry;
2432         return;
2433       }
2434       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " + 
2435                          argName + " " + loc_doc,brief);
2436     }
2437     else
2438     {
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);
2443     }
2444   }
2445   // analogous to the [in] case; here no direction specified
2446   else
2447   {
2448     if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2449     {
2450       current=tmp_entry;
2451       return;
2452     }
2453     handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2454                        argName + " " + loc_doc,brief);
2455   }
2456
2457   // reset current back to the part inside the routine
2458   current=tmp_entry;
2459 }
2460 //----------------------------------------------------------------------------
2461 /// Handle result description as defined after the declaration of the parameter
2462 static void subrHandleCommentBlockResult(const QCString &doc,bool brief)
2463 {
2464   QCString loc_doc;
2465   loc_doc = doc.stripWhiteSpace();
2466
2467   Entry *tmp_entry = current; 
2468   current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2469
2470   // Still in the specification section so no inbodyDocs yet, but parameter documentation
2471   current->inbodyDocs = "";
2472
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();
2480
2481   if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2482   {
2483     current=tmp_entry;
2484     return;
2485   }
2486   handleCommentBlock(QCString("\n\n@returns ") + loc_doc,brief);
2487
2488   // reset current back to the part inside the routine
2489   current=tmp_entry;
2490 }
2491
2492 //----------------------------------------------------------------------------
2493 #if 0
2494 static int level=0;
2495
2496 static void debugCompounds(Entry *rt)  // print Entry structure (for debugging)
2497 {
2498  level++;
2499   printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
2500   EntryListIterator eli(*rt->children());
2501   Entry *ce;
2502   for (;(ce=eli.current());++eli)
2503   {
2504      debugCompounds(ce); 
2505   } 
2506 level--;
2507 }
2508 #endif
2509
2510
2511 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, FortranFormat format)
2512 {
2513   char *tmpBuf = NULL;
2514   initParser();
2515
2516   defaultProtection = Public;
2517   inputString = fileBuf;
2518   inputPosition = 0;
2519   inputStringPrepass = NULL;
2520   inputPositionPrepass = 0;
2521
2522   //anonCount     = 0;  // don't reset per file
2523   mtype         = Method;
2524   gstat         = FALSE;
2525   virt          = Normal;
2526   current_root  = rt;
2527   global_root   = rt;
2528   inputFile.setName(fileName);
2529   if (inputFile.open(IO_ReadOnly))
2530   {
2531     isFixedForm = recognizeFixedForm(fileBuf,format);
2532
2533     if (isFixedForm) 
2534     {
2535       msg("Prepassing fixed form of %s\n", fileName);
2536       //printf("---strlen=%d\n", strlen(fileBuf));
2537       //clock_t start=clock();
2538
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");
2544
2545       //clock_t end=clock();
2546       //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
2547     }
2548     else if (inputString[strlen(fileBuf)-1] != '\n')
2549     {
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;
2555     }
2556
2557     yyLineNr= 1 ; 
2558     yyFileName = fileName;
2559     msg("Parsing file %s...\n",yyFileName.data());
2560
2561     startScope(rt); // implies current_root = rt
2562     initParser();
2563     groupEnterFile(yyFileName,yyLineNr);
2564
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; 
2573
2574     fortranscannerYYrestart( fortranscannerYYin );
2575     {
2576       BEGIN( Start );
2577     }
2578
2579     fortranscannerYYlex();
2580     groupLeaveFile(yyFileName,yyLineNr);
2581
2582     endScope(current_root, TRUE); // TRUE - global root
2583
2584     //debugCompounds(rt); //debug 
2585
2586     rt->program.resize(0);
2587     delete current; current=0;
2588     moduleProcedures.clear();
2589     if (tmpBuf) {
2590       free((char*)tmpBuf);
2591       inputString=NULL;
2592     }
2593     if (isFixedForm) {
2594       free((char*)inputString);
2595       inputString=NULL;
2596     }
2597
2598     inputFile.close();
2599   }
2600 }
2601
2602 //----------------------------------------------------------------------------
2603
2604 void FortranLanguageScanner::parseInput(const char *fileName,
2605                                         const char *fileBuf,
2606                                         Entry *root,
2607                                         bool /*sameTranslationUnit*/,
2608                                         QStrList & /*filesInSameTranslationUnit*/)
2609 {
2610   g_thisParser = this;
2611
2612   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2613
2614   ::parseMain(fileName,fileBuf,root,m_format);
2615
2616   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2617 }
2618
2619 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2620                    const char * scopeName,
2621                    const QCString & input,
2622                    SrcLangExt /*lang*/,
2623                    bool isExampleBlock,
2624                    const char * exampleName,
2625                    FileDef * fileDef,
2626                    int startLine,
2627                    int endLine,
2628                    bool inlineFragment,
2629                    MemberDef *memberDef,
2630                    bool showLineNumbers,
2631                    Definition *searchCtx,
2632                    bool collectXRefs
2633                   )
2634 {
2635   ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
2636                      fileDef,startLine,endLine,inlineFragment,memberDef,
2637                      showLineNumbers,searchCtx,collectXRefs,m_format);
2638 }
2639
2640 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
2641 {
2642   return extension!=extension.lower(); // use preprocessor only for upper case extensions
2643 }
2644 void FortranLanguageScanner::resetCodeParserState()
2645 {
2646   ::resetFortranCodeParserState();
2647 }
2648
2649 void FortranLanguageScanner::parsePrototype(const char *text)
2650 {
2651   QCString buffer = QCString(text);
2652   pushBuffer(buffer);
2653   parsingPrototype = TRUE;
2654   BEGIN(Prototype);
2655   fortranscannerYYlex();
2656   parsingPrototype = FALSE;
2657   popBuffer();
2658 }
2659
2660 static void scanner_abort() 
2661 {
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");
2665    
2666   EntryListIterator eli(*global_root->children());
2667   Entry *ce;
2668   bool start=FALSE;
2669
2670   for (;(ce=eli.current());++eli)
2671   {
2672      if (ce == file_root) start=TRUE;
2673      if (start) ce->reset(); 
2674   } 
2675
2676   // dummy call to avoid compiler warning
2677   (void)yy_top_state();
2678   
2679   return;
2680   //exit(-1);
2681 }
2682
2683 //----------------------------------------------------------------------------
2684
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); } 
2689 }
2690 #endif
2691