Imported Upstream version 1.8.15
[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 Entry*           last_enum    = 0 ;
168 static ScanVar          v_type       = V_IGNORE; // type of parsed variable
169 static QList<Entry>     moduleProcedures; // list of all interfaces which contain unresolved 
170                                           // module procedures
171 static QCString         docBlock;
172 static bool             docBlockInBody = FALSE;
173 static bool             docBlockJavaStyle;
174
175 static MethodTypes      mtype;
176 static bool             gstat;
177 static Specifier        virt;
178
179 static QCString          debugStr;
180 static QCString          result; // function result
181 static Argument          *parameter; // element of parameter list
182 static QCString          argType;  // fortran type of an argument of a parameter list
183 static QCString          argName;  // last identifier name in variable list
184 static QCString          initializer;  // initial value of a variable
185 static int               initializerArrayScope;  // number if nested array scopes in initializer
186 static int               initializerScope;  // number if nested function calls in initializer
187 static QCString          useModuleName;  // name of module in the use statement
188 static Protection        defaultProtection;
189 static Protection        typeProtection;
190 static int               typeMode = false;
191 static InterfaceType     ifType = IF_NONE;
192 static bool              functionLine = FALSE;
193
194 static char              stringStartSymbol; // single or double quote
195 static bool              parsingPrototype = FALSE; // see parsePrototype()
196
197 //! Accumulated modifiers of current statement, eg variable declaration.
198 static SymbolModifiers currentModifiers;
199 //! Holds program scope->symbol name->symbol modifiers.
200 static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers;
201
202 static Entry           *global_scope = NULL;
203 static int              anonCount    = 0 ;
204 //-----------------------------------------------------------------------------
205
206 static int yyread(char *buf,int max_size);
207 static void startCommentBlock(bool);
208 static void handleCommentBlock(const QCString &doc,bool brief);
209 static void subrHandleCommentBlock(const QCString &doc,bool brief);
210 static void subrHandleCommentBlockResult(const QCString &doc,bool brief);
211 static void addCurrentEntry(int case_insens);
212 static void addModule(const char *name, bool isModule=FALSE);
213 static void addSubprogram(const char *text);
214 static void addInterface(QCString name, InterfaceType type);
215 static Argument *getParameter(const QCString &name);
216 static void scanner_abort();
217
218 static void startScope(Entry *scope);
219 static bool endScope(Entry *scope, bool isGlobalRoot=FALSE);
220 //static bool isTypeName(QCString name);
221 static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
222 static int getAmpersandAtTheStart(const char *buf, int length);
223 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch);
224 static void truncatePrepass(int index);
225 static void pushBuffer(QCString &buffer);
226 static void popBuffer();
227 //static void extractPrefix(QCString& text);
228 static QCString extractFromParens(const QCString name);
229 static CommentInPrepass* locatePrepassComment(int from, int to);
230 static void updateVariablePrepassComment(int from, int to);
231 static void newLine();
232 static void initEntry();
233
234 static const char *stateToString(int state);
235
236 //-----------------------------------------------------------------------------
237 #undef  YY_INPUT
238 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
239 #define YY_USER_ACTION yyColNr+=(int)yyleng;
240 //-----------------------------------------------------------------------------
241
242 %}
243
244  //-----------------------------------------------------------------------------
245  //-----------------------------------------------------------------------------
246 IDSYM     [a-z_A-Z0-9]
247 NOTIDSYM  [^a-z_A-Z0-9]
248 SEPARATE  [:, \t]
249 ID        [a-z_A-Z%]+{IDSYM}*
250 ID_       [a-z_A-Z%]*{IDSYM}*
251 PP_ID     {ID}
252 LABELID   [a-z_A-Z]+[a-z_A-Z0-9\-]*
253 SUBPROG   (subroutine|function)
254 B         [ \t]
255 BS        [ \t]*
256 BS_       [ \t]+
257 BT_       ([ \t]+|[ \t]*"(")
258 COMMA     {BS},{BS}
259 ARGS_L0   ("("[^)]*")")
260 ARGS_L1a  [^()]*"("[^)]*")"[^)]*
261 ARGS_L1   ("("{ARGS_L1a}*")")
262 ARGS_L2   "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
263 ARGS      {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
264 NOARGS    {BS}"\n"
265
266 NUM_TYPE  (complex|integer|logical|real)
267 LOG_OPER  (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
268 KIND      {ARGS}
269 CHAR      (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
270 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|ENUMERATOR|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
271
272 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
273 ATTR_SPEC (EXTERNAL|ALLOCATABLE|DIMENSION{ARGS}|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE|CONTIGUOUS|VOLATILE|VALUE)
274 ACCESS_SPEC (PRIVATE|PUBLIC)
275 LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
276 /* Assume that attribute statements are almost the same as attributes. */
277 ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
278 EXTERNAL_STMT (EXTERNAL)
279
280 CONTAINS  CONTAINS
281 PREFIX    ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?
282 SCOPENAME ({ID}{BS}"::"{BS})*
283
284 %option noyywrap
285 %option stack
286 %option caseless
287 /*%option debug */
288
289  //---------------------------------------------------------------------------------
290
291  /** fortran parsing states */
292 %x      Subprog
293 %x      SubprogPrefix
294 %x      Parameterlist
295 %x      SubprogBody
296 %x      SubprogBodyContains
297 %x      Start
298 %x      Comment
299 %x      Module
300 %x      Program
301 %x      ModuleBody
302 %x      ModuleBodyContains
303 %x      AttributeList
304 %x      Variable
305 %x      Initialization
306 %x      ArrayInitializer
307 %x      Enum
308 %x      Typedef
309 %x      TypedefBody
310 %x      TypedefBodyContains
311 %x      InterfaceBody
312 %x      StrIgnore
313 %x      String
314 %x      Use
315 %x      UseOnly
316 %x      ModuleProcedure
317
318 %x      Prepass
319
320  /** comment parsing states */
321 %x      DocBlock
322 %x      DocBackLine
323 %x      EndDoc
324
325 %x      BlockData
326
327 /** prototype parsing */
328 %x      Prototype
329 %x      PrototypeSubprog
330 %x      PrototypeArgs
331
332 %%
333
334  /*-----------------------------------------------------------------------------------*/
335
336 <Prepass>^{BS}[&]*{BS}!.*\n             { /* skip lines with just comment. Note code was in free format or has been converted to it */
337                                           lineCountPrepass ++;
338                                         }
339 <Prepass>^{BS}\n                        { /* skip empty lines */
340                                           lineCountPrepass ++;
341                                         }
342 <*>^.*\n                                { // prepass: look for line continuations
343                                           functionLine = FALSE;
344
345                                           DBG_CTX((stderr, "---%s", yytext));
346
347                                             int indexStart = getAmpersandAtTheStart(yytext, (int)yyleng);
348                                             int indexEnd = getAmpOrExclAtTheEnd(yytext, (int)yyleng, '\0');
349                                             if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
350                                               indexEnd=-1;
351
352                                             if(indexEnd<0){ // ----- no ampersand as line continuation
353                                                if(YY_START == Prepass) { // last line in "continuation"
354
355                                                  // Only take input after initial ampersand
356                                                  inputStringPrepass+=(const char*)(yytext+(indexStart+1));
357    
358                                                  //printf("BUFFER:%s\n", (const char*)inputStringPrepass);
359                                                  pushBuffer(inputStringPrepass);
360                                                  yyColNr = 0;                                            
361                                                  yy_pop_state();
362                                                } else { // simple line
363                                                  yyColNr = 0;
364                                                  REJECT;
365                                                }
366
367                                             } else { // ----- line with continuation
368                                               if(YY_START != Prepass) {
369                                                 comments.setAutoDelete(TRUE);
370                                                 comments.clear();
371                                                 yy_push_state(Prepass);
372                                               }
373
374                                               int length = inputStringPrepass.length();
375
376                                               // Only take input after initial ampersand
377                                               inputStringPrepass+=(const char*)(yytext+(indexStart+1));
378                                               lineCountPrepass ++;
379
380                                               // cut off & and remove following comment if present
381                                               truncatePrepass(length+indexEnd-(indexStart+1));
382                                             }
383
384                                         }
385
386
387  /*------ ignore strings that are not initialization strings */ 
388 <String>\"|\'                           { // string ends with next quote without previous backspace
389                                           if (yytext[0]!=stringStartSymbol) { yyColNr -= (int)yyleng; REJECT; } // single vs double quote
390                                           if (yy_top_state() == Initialization
391                                               || yy_top_state() == ArrayInitializer)
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                                             if (global_scope)
562                                             {
563                                               if (global_scope != (Entry *) -1)
564                                                 yy_push_state(Start);
565                                               else
566                                                 yy_pop_state(); // cannot pop artrificial entry
567                                             }
568                                             else
569                                             {
570                                               yy_push_state(Start);
571                                               global_scope = (Entry *)-1; // signal that the global_scope has already been used.
572                                             }
573                                        }
574 <Module>{ID}                           {  
575                                             addModule(yytext, TRUE);
576                                             BEGIN(ModuleBody);
577                                        }
578
579 <Program>{ID}                           {  
580                                             addModule(yytext, FALSE);
581                                             BEGIN(ModuleBody);
582                                        }
583
584   /*------- access specification --------------------------------------------------------------------------*/
585
586 <ModuleBody>private/{BS}(\n|"!")         { defaultProtection = Private;
587                                            current->protection = defaultProtection ;
588                                          }
589 <ModuleBody>public/{BS}(\n|"!")          { defaultProtection = Public;
590                                            current->protection = defaultProtection ;
591                                          }
592
593  /*------- type definition  -------------------------------------------------------------------------------*/
594
595 <Start,ModuleBody>^{BS}type/[^a-z0-9_]   {
596                                           if(YY_START == Start)
597                                           {
598                                             addModule(NULL); 
599                                             yy_push_state(ModuleBody); //anon program
600                                           }
601
602                                           yy_push_state(Typedef);
603                                           current->protection = defaultProtection;
604                                           typeProtection = defaultProtection;
605                                           typeMode = true;
606                                         }
607 <Typedef>{
608 {COMMA}                                 {}
609
610 {BS}"::"{BS}                            {}
611
612 abstract                                {
613                                           current->spec |= Entry::AbstractClass;
614                                         }
615 extends{ARGS}                           {
616                                           QCString basename = extractFromParens(yytext).lower();
617                                           current->extends->append(new BaseInfo(basename, Public, Normal));
618                                         }
619 public                                  {
620                                           current->protection = Public;
621                                           typeProtection = Public;
622                                         }
623 private                                 {
624                                           current->protection = Private;
625                                           typeProtection = Private;
626                                         }
627 {LANGUAGE_BIND_SPEC}                    {
628                                           /* ignored for now */
629                                         }
630 {ID}                                    { /* type name found */
631                                           current->section = Entry::CLASS_SEC;
632                                           current->spec |= Entry::Struct;
633                                           current->name = yytext;
634                                           current->fileName = yyFileName;
635                                           current->bodyLine  = yyLineNr; 
636                                           current->startLine  = yyLineNr;
637
638                                           /* if type is part of a module, mod name is necessary for output */
639                                           if ((current_root) && 
640                                               (current_root->section == Entry::CLASS_SEC
641                                                || current_root->section == Entry::NAMESPACE_SEC))
642                                           {
643                                             current->name = current_root->name + "::" + current->name;
644                                           }
645
646                                           addCurrentEntry(1);
647                                           startScope(last_entry); 
648                                           BEGIN(TypedefBody);
649                                         }
650 }
651
652 <TypedefBodyContains>{                  /* Type Bound Procedures */
653 ^{BS}PROCEDURE{ARGS}?                   {
654                                           current->type = QCString(yytext).simplifyWhiteSpace();
655                                         }
656 ^{BS}final                              {
657                                           current->spec |= Entry::Final;
658                                           current->type = QCString(yytext).simplifyWhiteSpace();
659                                         }
660 ^{BS}generic                            {
661                                           current->type = QCString(yytext).simplifyWhiteSpace();
662                                         }
663 {COMMA}                                 {
664                                         }
665 {ATTR_SPEC}                             {
666                                           currentModifiers |= QCString(yytext);
667                                         }
668 {BS}"::"{BS}                            {
669                                         }
670 {ID}                                    {
671                                           QCString name = yytext;
672                                           modifiers[current_root][name.lower()] |= currentModifiers;
673                                           current->section  = Entry::FUNCTION_SEC;
674                                           current->name     = name;
675                                           current->fileName = yyFileName;
676                                           current->bodyLine = yyLineNr;
677                                           current->startLine  = yyLineNr;
678                                           addCurrentEntry(1);
679                                         }
680 {BS}"=>"[^(\n|\!)]*                     { /* Specific bindings come after the ID. */
681                                           QCString args = yytext;
682                                           last_entry->args = args.lower();
683                                         }
684 "\n"                                    {
685                                           currentModifiers = SymbolModifiers();
686                                           newLine();
687                                           docBlock.resize(0);
688                                         }
689 }
690
691
692 <TypedefBody,TypedefBodyContains>{
693 ^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
694                                           last_entry->parent()->endBodyLine = yyLineNr;
695                                           if (!endScope(current_root))
696                                             yyterminate();
697                                           typeMode = false;
698                                           yy_pop_state();
699                                         }
700 }
701
702  /*------- module/global/typedef variable ---------------------------------------------------*/
703
704 <SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {  
705                                            //
706                                            // ABSTRACT and specific interfaces are stored
707                                            // in a scope of their own, even if multiple
708                                            // are group in one INTERFACE/END INTERFACE block.
709                                            //
710                                            if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
711                                            {
712                                              endScope(current_root);
713                                              last_entry->endBodyLine = yyLineNr - 1;
714                                            }
715                                            current_root->endBodyLine = yyLineNr - 1;
716
717                                            if (!endScope(current_root))
718                                              yyterminate();
719                                            subrCurrent.remove(0u);
720                                            yy_pop_state() ;
721                                         }
722 <BlockData>{
723 {ID}                                    {
724                                         }
725 }
726 <Start,ModuleBody,TypedefBody,SubprogBody,Enum>{
727 ^{BS}{TYPE_SPEC}/{SEPARATE}             {
728                                           last_enum = 0;
729                                           if (YY_START == Enum)
730                                           {
731                                             argType = "@"; // enum marker
732                                           }
733                                           else
734                                           {
735                                             argType = QCString(yytext).simplifyWhiteSpace().lower();
736                                           }
737                                           current->bodyLine = yyLineNr + 1;
738                                           current->endBodyLine = yyLineNr + lineCountPrepass;
739                                           /* variable declaration starts */
740                                           if(YY_START == Start)
741                                           {
742                                             addModule(NULL); 
743                                             yy_push_state(ModuleBody); //anon program
744                                           }
745                                           yy_push_state(AttributeList);
746                                         }
747   /*  Dimitri: macro expansion should already be done during preprocessing not here!
748 ^{BS}{PP_ID}{KIND}?                     { // check for preprocessor symbol expand to type
749                                           QCString str = yytext;
750                                           str = str.stripWhiteSpace();
751                                           //DefineDict* defines = getGlobalDefineDict();
752                                           QCString name;
753                                           int index = str.find("(");
754                                           if (index != -1)
755                                             name = str.left(index).stripWhiteSpace();
756                                           else
757                                             name = str;
758
759                                           Define *define = 0; //(*defines)[name];
760                                           if (define != 0 && isTypeName(define->definition)) 
761                                           {
762                                             argType = str;
763                                             yy_push_state(AttributeList);
764                                           } 
765                                           else 
766                                           {
767                                             yyColNr -= (int)yyleng;
768                                             REJECT;
769                                           }
770                                         }
771   */
772 {EXTERNAL_STMT}/({BS}"::"|{BS_}{ID})   { 
773                                           /* external can be a "type" or an attribute */
774                                           if(YY_START == Start)
775                                           {
776                                             addModule(NULL); 
777                                             yy_push_state(ModuleBody); //anon program
778                                           }
779                                           QCString tmp = yytext;
780                                           currentModifiers |= tmp.stripWhiteSpace();
781                                           argType = QCString(yytext).simplifyWhiteSpace().lower();
782                                           yy_push_state(AttributeList);
783                                        }
784 {ATTR_STMT}/{BS_}{ID}                  |
785 {ATTR_STMT}/{BS}"::"                   { 
786                                           /* attribute statement starts */
787                                           DBG_CTX((stderr,"5=========> Attribute statement: %s\n", yytext)); 
788                                           QCString tmp = yytext;
789                                           currentModifiers |= tmp.stripWhiteSpace();
790                                           argType="";
791                                           yy_push_state(YY_START);
792                                           BEGIN( AttributeList ) ;
793                                        }
794 {ID}                                   {
795                                        }  
796 ^{BS}"type"{BS_}"is"/{BT_}             { } 
797 ^{BS}"type"{BS}"="                     { }
798 ^{BS}"class"{BS_}"is"/{BT_}            { } 
799 ^{BS}"class"{BS_}"default"             { } 
800 }
801 <AttributeList>{
802 {COMMA}                                 {}
803 {BS}                                    {}
804 {ATTR_SPEC}.                            { /* update current modifiers when it is an ATTR_SPEC and not a variable name */
805                                           /* bug_625519 */
806                                           QChar chr = yytext[(int)yyleng-1];
807                                           if (chr.isLetter() || chr.isDigit() || (chr == '_'))
808                                           {
809                                             yyColNr -= (int)yyleng;
810                                             REJECT;
811                                           }
812                                           else
813                                           {
814                                             QCString tmp = yytext;
815                                             tmp = tmp.left(tmp.length() - 1);
816                                             yyColNr -= 1;
817                                             unput(yytext[(int)yyleng-1]);
818                                             currentModifiers |= (tmp);
819                                           }
820                                         }
821 "::"                                    { /* end attribute list */
822                                           BEGIN( Variable );
823                                         }
824 .                                       { /* unknown attribute, consider variable name */
825                                           //cout<<"start variables, unput "<<*yytext<<endl;
826                                           yyColNr -= 1;
827                                           unput(*yytext);
828                                           BEGIN( Variable );
829                                         }
830 }
831
832 <Variable>{BS}                          { }
833 <Variable>{ID}                          { /* parse variable declaration */
834                                           //cout << "5=========> got variable: " << argType << "::" << yytext << endl;
835                                           /* work around for bug in QCString.replace (QCString works) */
836                                           QCString name=yytext;
837                                           name = name.lower();
838                                           /* remember attributes for the symbol */
839                                           modifiers[current_root][name.lower()] |= currentModifiers;
840                                           argName= name;
841
842                                           v_type= V_IGNORE;
843                                           if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) 
844                                           { // new variable entry
845                                             v_type = V_VARIABLE;
846                                             current->section = Entry::VARIABLE_SEC;
847                                             current->name = argName;
848                                             current->type = argType;
849                                             current->fileName = yyFileName;
850                                             current->bodyLine  = yyLineNr; // used for source reference
851                                             current->startLine  = yyLineNr;
852                                             if (argType == "@")
853                                             {
854                                               current_root->addSubEntry(current);
855                                               current = new Entry(*current);
856                                               // add to the scope surrounding the enum (copy!)
857                                               current_root->parent()->addSubEntry(current);
858                                               last_enum = current;
859                                               current = new Entry ;
860                                               initEntry();
861                                             }
862                                             else
863                                             {
864                                               addCurrentEntry(1);
865                                             }
866                                           } 
867                                           else if (!argType.isEmpty())
868                                           { // declaration of parameter list: add type for corr. parameter 
869                                             parameter = getParameter(argName);
870                                             if (parameter) 
871                                             {
872                                               v_type= V_PARAMETER;
873                                               if (!argType.isNull()) parameter->type=argType.stripWhiteSpace();
874                                               if (!docBlock.isNull()) 
875                                               {
876                                                 subrHandleCommentBlock(docBlock,TRUE);
877                                               }                                     
878                                             }
879                                             // save, it may be function return type
880                                             if (parameter)
881                                             {
882                                               modifiers[current_root][name.lower()].type = argType;
883                                             }
884                                             else
885                                             {
886                                               if ((current_root->name.lower() == argName.lower()) ||
887                                                   (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower()))
888                                               {
889                                                 int strt = current_root->type.find("function");
890                                                 QCString lft;
891                                                 QCString rght;
892                                                 if (strt != -1)
893                                                 {
894                                                   v_type = V_RESULT;
895                                                   lft = "";
896                                                   rght = "";
897                                                   if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace();
898                                                   if ((current_root->type.length() - strt - strlen("function"))!= 0)
899                                                   {
900                                                     rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace();
901                                                   }
902                                                   current_root->type = lft;
903                                                   if (rght.length() > 0)
904                                                   {
905                                                     if (current_root->type.length() > 0) current_root->type += " ";
906                                                     current_root->type += rght;
907                                                   }
908                                                   if (argType.stripWhiteSpace().length() > 0)
909                                                   {
910                                                     if (current_root->type.length() > 0) current_root->type += " ";
911                                                     current_root->type += argType.stripWhiteSpace();
912                                                   }
913                                                   if (current_root->type.length() > 0) current_root->type += " ";
914                                                   current_root->type += "function";
915                                                   if (!docBlock.isNull()) 
916                                                   {
917                                                     subrHandleCommentBlockResult(docBlock,TRUE);
918                                                   }
919                                                 }
920                                                 else
921                                                 {
922                                                   current_root->type += " " + argType.stripWhiteSpace();
923                                                 }
924                                                 current_root->type = current_root->type.stripWhiteSpace();
925                                                 modifiers[current_root][name.lower()].type = current_root->type;
926                                               }
927                                               else
928                                               {
929                                                 modifiers[current_root][name.lower()].type = argType;
930                                               }
931                                             }
932                                             // any accumulated doc for argument should be emptied,
933                                             // because it is handled other way and this doc can be
934                                             // unexpectedly passed to the next member.
935                                             current->doc.resize(0);
936                                             current->brief.resize(0);
937                                           } 
938                                         }
939 <Variable>{ARGS}                        { /* dimension of the previous entry. */
940                                           QCString name(argName);
941                                           QCString attr("dimension");
942                                           attr += yytext;
943                                           modifiers[current_root][name.lower()] |= attr;
944                                         }
945 <Variable>{COMMA}                       { //printf("COMMA: %d<=..<=%d\n", yyColNr-(int)yyleng, yyColNr);
946                                           // locate !< comment
947                                           updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
948                                         }
949 <Variable>{BS}"="                       {
950                                           yy_push_state(YY_START);
951                                           initializer="=";
952                                           initializerScope = initializerArrayScope = 0;
953                                           BEGIN(Initialization);
954                                         }
955 <Variable>"\n"                          { currentModifiers = SymbolModifiers();
956                                           yy_pop_state(); // end variable declaration list
957                                           newLine();
958                                           docBlock.resize(0);
959                                         }
960 <Variable>";".*"\n"                     { currentModifiers = SymbolModifiers();
961                                           yy_pop_state(); // end variable declaration list
962                                           docBlock.resize(0);
963                                           inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
964                                           yyLineNr--;
965                                           pushBuffer(inputStringSemi);
966                                         }
967 <*>";".*"\n"                            {
968                                           if (YY_START == Variable) REJECT; // Just be on the safe side
969                                           if (YY_START == String) REJECT; // ";" ignored in strings
970                                           if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments
971                                           inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
972                                           yyLineNr--;
973                                           pushBuffer(inputStringSemi);
974                                         }
975
976 <Initialization,ArrayInitializer>"["    |
977 <Initialization,ArrayInitializer>"(/"   { initializer+=yytext;
978                                            initializerArrayScope++;
979                                            BEGIN(ArrayInitializer); // initializer may contain comma
980                                         }
981 <ArrayInitializer>"]"                   |
982 <ArrayInitializer>"/)"                  { initializer+=yytext;
983                                            initializerArrayScope--;
984                                            if(initializerArrayScope<=0)
985                                            {
986                                               initializerArrayScope = 0; // just in case
987                                               BEGIN(Initialization);
988                                            }
989                                         }
990 <ArrayInitializer>.                     { initializer+=yytext; }
991 <Initialization>"("                     { initializerScope++;
992                                           initializer+=yytext;
993                                         }
994 <Initialization>")"                     { initializerScope--;
995                                           initializer+=yytext;
996                                         }
997 <Initialization>{COMMA}                 { if (initializerScope == 0)
998                                           {
999                                             updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
1000                                             yy_pop_state(); // end initialization
1001                                             if (last_enum)
1002                                             {
1003                                               last_enum->initializer= initializer;
1004                                             }
1005                                             else
1006                                             {
1007                                               if (v_type == V_VARIABLE) last_entry->initializer= initializer;
1008                                             }
1009                                           }
1010                                           else
1011                                             initializer+=", ";
1012                                         }
1013 <Initialization>"\n"|"!"                { //|
1014                                           yy_pop_state(); // end initialization
1015                                           if (last_enum)
1016                                           {
1017                                             last_enum->initializer= initializer;
1018                                           }
1019                                           else
1020                                           {
1021                                             if (v_type == V_VARIABLE) last_entry->initializer= initializer;
1022                                           }
1023                                           yyColNr -= 1;
1024                                           unput(*yytext);
1025                                         }
1026 <Initialization>.                       { initializer+=yytext; }
1027  
1028 <*>{BS}"enum"{BS}","{BS}"bind"{BS}"("{BS}"c"{BS}")"{BS} {
1029                                           if(YY_START == Start)
1030                                           {
1031                                             addModule(NULL); 
1032                                             yy_push_state(ModuleBody); //anon program
1033                                           }
1034
1035                                           yy_push_state(Enum);
1036                                           current->protection = defaultProtection;
1037                                           typeProtection = defaultProtection;
1038                                           typeMode = true;
1039
1040                                           current->spec |= Entry::Struct;
1041                                           current->name.resize(0);
1042                                           current->args.resize(0);
1043                                           current->name.sprintf("@%d",anonCount++);
1044
1045                                           current->section = Entry::ENUM_SEC;
1046                                           current->fileName  = yyFileName;
1047                                           current->startLine = yyLineNr;
1048                                           current->bodyLine  = yyLineNr;
1049                                           if ((current_root) && 
1050                                               (current_root->section == Entry::CLASS_SEC
1051                                                || current_root->section == Entry::NAMESPACE_SEC))
1052                                           {
1053                                             current->name = current_root->name + "::" + current->name;
1054                                           }
1055
1056                                           addCurrentEntry(1);
1057                                           startScope(last_entry); 
1058                                           BEGIN( Enum ) ;
1059                                         }
1060 <Enum>"end"{BS}"enum"                   {
1061                                           last_entry->parent()->endBodyLine = yyLineNr;
1062                                           if (!endScope(current_root))
1063                                             yyterminate();
1064                                           typeMode = false;
1065                                           yy_pop_state();
1066                                         }
1067  /*------ fortran subroutine/function handling ------------------------------------------------------------*/
1068  /*       Start is initial condition                                                                       */
1069  
1070 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
1071                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1072                                          {
1073                                            addInterface("$interface$", ifType);
1074                                            startScope(last_entry);
1075                                          }
1076
1077                                          // TYPE_SPEC is for old function style function result
1078                                          result = QCString(yytext).stripWhiteSpace().lower();
1079                                          current->type = result;
1080                                          yy_push_state(SubprogPrefix);
1081                                        }
1082
1083 <SubprogPrefix>{BS}{SUBPROG}{BS_}     {
1084                                          // Fortran subroutine or function found
1085                                          v_type = V_IGNORE;
1086                                          result=yytext;
1087                                          result=result.stripWhiteSpace();
1088                                          addSubprogram(result);
1089                                          BEGIN(Subprog);
1090                                          current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1091                                          current->startLine = yyLineNr;
1092                                        }
1093
1094 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
1095                                          // Fortran subroutine or function found
1096                                          v_type = V_IGNORE;
1097                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1098                                          {
1099                                            addInterface("$interface$", ifType);
1100                                            startScope(last_entry);
1101                                          }
1102
1103                                          result = QCString(yytext).stripWhiteSpace();
1104                                          addSubprogram(result);
1105                                          yy_push_state(Subprog);
1106                                          current->bodyLine = yyLineNr + lineCountPrepass + 1; // we have to be at the line after the definition and we have to take continuation lines into account.
1107                                          current->startLine = yyLineNr;
1108                                        }
1109
1110 <Subprog>{BS}                          {   /* ignore white space */   }
1111 <Subprog>{ID}                          { current->name = yytext;
1112                                          //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
1113                                          modifiers[current_root][current->name.lower()].returnName = current->name.lower();
1114
1115                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
1116                                          {
1117                                            current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
1118                                          }
1119
1120                                          BEGIN(Parameterlist);
1121                                        }
1122 <Parameterlist>"("                     { current->args = "("; }
1123 <Parameterlist>")"                     {
1124                                          current->args += ")";
1125                                          current->args = removeRedundantWhiteSpace(current->args);
1126                                          addCurrentEntry(1);
1127                                          startScope(last_entry);
1128                                          BEGIN(SubprogBody);
1129                                        }
1130 <Parameterlist>{COMMA}|{BS}            { current->args += yytext;
1131                                          CommentInPrepass *c = locatePrepassComment(yyColNr-(int)yyleng, yyColNr);
1132                                          if (c!=NULL) {
1133                                            if(current->argList->count()>0) {
1134                                              current->argList->at(current->argList->count()-1)->docs = c->str;
1135                                            }
1136                                          }                       
1137                                        }
1138 <Parameterlist>{ID}                    {
1139                                            //current->type not yet available
1140                                            QCString param = yytext;
1141                                            // std::cout << "3=========> got parameter " << param << std::endl;
1142                                            current->args += param;
1143                                            Argument *arg = new Argument;
1144                                            arg->name = param;
1145                                            arg->type = "";
1146                                            current->argList->append(arg);
1147                                        } 
1148 <Parameterlist>{NOARGS}                {   
1149                                            newLine();
1150                                            //printf("3=========> without parameterlist \n");
1151                                            //current->argList = ;
1152                                            addCurrentEntry(1);
1153                                            startScope(last_entry);
1154                                            BEGIN(SubprogBody);                                     
1155 }
1156 <SubprogBody>result{BS}\({BS}{ID}      {  
1157                                            if (functionLine)
1158                                            {
1159                                              result= yytext;
1160                                              result= result.right(result.length()-result.find("(")-1);
1161                                              result= result.stripWhiteSpace();
1162                                              modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
1163                                            }
1164                                            //cout << "=====> got result " <<  result << endl;
1165                                        } 
1166
1167  /*---- documentation comments --------------------------------------------------------------------*/
1168
1169 <Variable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<"  { /* backward docu comment */
1170                                           if (v_type != V_IGNORE) {
1171                                            current->docLine  = yyLineNr;
1172                                            docBlockJavaStyle = FALSE;
1173                                            docBlock.resize(0);
1174                                            docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1175                                            startCommentBlock(TRUE);
1176                                            yy_push_state(DocBackLine);
1177                                           }
1178                                           else
1179                                           {
1180                                             /* handle out of place !< comment as a normal comment */
1181                                             if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
1182                                             // skip comment line (without docu comments "!>" "!<" ) 
1183                                             /* ignore further "!" and ignore comments in Strings */
1184                                             if ((YY_START != StrIgnore) && (YY_START != String)) 
1185                                             {
1186                                               yy_push_state(YY_START);
1187                                               BEGIN(StrIgnore); 
1188                                               debugStr="*!";
1189                                             }      
1190                                           }
1191                                          }
1192 <DocBackLine>.*                          { // contents of current comment line
1193                                           docBlock+=yytext;
1194                                         }
1195 <DocBackLine>"\n"{BS}"!"("<"|"!"+)              { // comment block (next line is also comment line)
1196                                           docBlock+="\n"; // \n is necessary for lists
1197                                           newLine();
1198                                         }
1199 <DocBackLine>"\n"                               { // comment block ends at the end of this line
1200                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1201                                           yyColNr -= 1;
1202                                           unput(*yytext);                                        
1203                                           if (v_type == V_VARIABLE) 
1204                                           {
1205                                             Entry *tmp_entry = current; 
1206                                             current = last_entry; // temporarily switch to the previous entry
1207                                             if (last_enum) current = last_enum;
1208                                             handleCommentBlock(docBlock,TRUE);
1209                                             current=tmp_entry;
1210                                           }
1211                                           else if (v_type == V_PARAMETER) 
1212                                           {
1213                                             subrHandleCommentBlock(docBlock,TRUE);
1214                                           }
1215                                           else if (v_type == V_RESULT) 
1216                                           {
1217                                             subrHandleCommentBlockResult(docBlock,TRUE);
1218                                           }
1219                                           yy_pop_state();
1220                                           docBlock.resize(0);
1221                                         }
1222
1223 <Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains,Enum>"!>"  {
1224                                           yy_push_state(YY_START);
1225                                           current->docLine  = yyLineNr;
1226                                           docBlockJavaStyle = FALSE;
1227                                           if (YY_START==SubprogBody) docBlockInBody = TRUE;
1228                                           docBlock.resize(0);
1229                                           docBlockJavaStyle = Config_getBool(JAVADOC_AUTOBRIEF);
1230                                           startCommentBlock(TRUE);
1231                                           BEGIN(DocBlock);
1232                                           //cout << "start DocBlock " << endl;
1233                                         }
1234
1235 <DocBlock>.*                            { // contents of current comment line
1236                                           docBlock+=yytext;
1237                                         }
1238 <DocBlock>"\n"{BS}"!"(">"|"!"+)         { // comment block (next line is also comment line)
1239                                           docBlock+="\n"; // \n is necessary for lists
1240                                           newLine();
1241                                         }
1242 <DocBlock>"\n"                          { // comment block ends at the end of this line
1243                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1244                                           yyColNr -= 1;
1245                                           unput(*yytext);                                        
1246                                           handleCommentBlock(docBlock,TRUE);
1247                                           yy_pop_state();                                          
1248                                         }
1249
1250  /*-----Prototype parsing -------------------------------------------------------------------------*/
1251 <Prototype>{BS}{SUBPROG}{BS_}           {
1252                                           BEGIN(PrototypeSubprog);
1253                                         }
1254 <Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} { 
1255                                           current->name = QCString(yytext).lower();
1256                                           current->name.stripWhiteSpace();
1257                                           BEGIN(PrototypeArgs);
1258                                         }
1259 <PrototypeArgs>{
1260 "("|")"|","|{BS_}                       { current->args += yytext; }
1261 {ID}                                    { current->args += yytext; 
1262                                           Argument *a = new Argument;
1263                                           a->name = QCString(yytext).lower();
1264                                           current->argList->append(a);
1265                                         }
1266 }
1267
1268  /*------------------------------------------------------------------------------------------------*/
1269
1270 <*>"\n"                                 {
1271                                           newLine();
1272                                           //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
1273                                           debugStr="";
1274                                         }
1275
1276
1277  /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1278
1279 <*><<EOF>>                              {
1280                                           if (parsingPrototype) {
1281                                             yyterminate();
1282
1283                                           } else if ( include_stack_ptr <= 0 ) {
1284                                             if (YY_START!=INITIAL && YY_START!=Start) {
1285                                               DBG_CTX((stderr,"==== Error: EOF reached in wrong state (end missing)"));
1286                                               scanner_abort();
1287                                             }
1288                                             yyterminate();
1289                                           } else {
1290                                             popBuffer();
1291                                           }
1292                                         }
1293 <*>{LOG_OPER}                           { // Fortran logical comparison keywords
1294                                         }
1295 <*>.                                    {
1296                                           //debugStr+=yytext;
1297                                           //printf("I:%c\n", *yytext);
1298                                         } // ignore remaining text 
1299
1300  /**********************************************************************************/
1301  /**********************************************************************************/
1302  /**********************************************************************************/
1303 %%
1304 //----------------------------------------------------------------------------
1305
1306 #if 0
1307 static void extractPrefix(QCString &text) 
1308 {
1309   int prefixIndex = 0;
1310   int curIndex = 0;
1311   bool cont = TRUE;
1312   const char* pre[] = {"RECURSIVE","IMPURE","PURE","ELEMENTAL"};
1313   while(cont)
1314   {
1315     cont = FALSE;
1316     for(unsigned int i=0; i<4; i++)
1317     {
1318       if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
1319       {
1320         text.remove(0,strlen(pre[i]));
1321         text.stripWhiteSpace();
1322         cont = TRUE;
1323       }
1324     }
1325   }
1326 }
1327 #endif
1328
1329 static void newLine() {
1330   yyLineNr++;
1331   yyLineNr+=lineCountPrepass;
1332   lineCountPrepass=0;
1333   comments.clear();
1334 }
1335
1336 static CommentInPrepass* locatePrepassComment(int from, int to) {
1337   //printf("Locate %d-%d\n", from, to);
1338   for(uint i=0; i<comments.count(); i++) { // todo: optimize
1339     int c = comments.at(i)->column;
1340     //printf("Candidate %d\n", c);
1341     if (c>=from && c<=to) {
1342       // comment for previous variable or parameter
1343       return comments.at(i);
1344     }
1345   }
1346   return NULL;
1347 }
1348
1349 static void updateVariablePrepassComment(int from, int to) {
1350   CommentInPrepass *c = locatePrepassComment(from, to);
1351   if (c!=NULL && v_type == V_VARIABLE) {
1352     last_entry->brief = c->str;
1353   } else if (c!=NULL && v_type == V_PARAMETER) {
1354     Argument *parameter = getParameter(argName);
1355     if (parameter) parameter->docs = c->str;
1356   }
1357 }
1358
1359 static int getAmpersandAtTheStart(const char *buf, int length)
1360 {
1361   for(int i=0; i<length; i++) {
1362     switch(buf[i]) {
1363       case ' ':
1364       case '\t':
1365         break;
1366       case '&':
1367         return i;
1368       default:
1369         return -1;
1370     }
1371   }
1372   return -1;
1373 }
1374
1375 /* Returns ampersand index, comment start index or -1 if neither exist.*/ 
1376 static int getAmpOrExclAtTheEnd(const char *buf, int length, char ch)
1377 {
1378   // Avoid ampersands in string and comments
1379   int parseState = Start;
1380   char quoteSymbol = 0;
1381   int ampIndex = -1;
1382   int commentIndex = -1;
1383   quoteSymbol = ch;
1384   if (ch != '\0') parseState = String;
1385
1386   for(int i=0; i<length && parseState!=Comment; i++)
1387   {
1388     // When in string, skip backslashes
1389     // Legacy code, not sure whether this is correct?
1390     if(parseState==String)
1391     {
1392       if(buf[i]=='\\') i++;
1393     }
1394
1395     switch(buf[i])
1396     {
1397         case '\'':
1398         case '"':
1399           // Close string, if quote symbol matches.
1400           // Quote symbol is set iff parseState==String
1401           if(buf[i]==quoteSymbol)
1402           {
1403              parseState = Start;
1404              quoteSymbol = 0;
1405           }
1406           // Start new string, if not already in string or comment
1407           else if(parseState==Start)
1408           {
1409             parseState = String;
1410             quoteSymbol = buf[i];
1411           }
1412           ampIndex = -1; // invalidate prev ampersand
1413           break;
1414         case '!':
1415           // When in string or comment, ignore exclamation mark
1416           if(parseState==Start)
1417           {
1418             parseState = Comment;
1419             commentIndex = i;
1420           }
1421           break;
1422         case ' ':  // ignore whitespace
1423         case '\t':
1424         case '\n': // this may be at the end of line
1425           break;
1426         case '&':
1427           ampIndex = i;
1428           break;
1429         default:
1430           ampIndex = -1; // invalidate prev ampersand
1431     }
1432   }
1433
1434   if (ampIndex>=0)
1435     return ampIndex;
1436   else
1437    return commentIndex;
1438 }
1439
1440 /* Although comments at the end of continuation line are grabbed by this function,
1441 * we still do not know how to use them later in parsing.
1442 */
1443 void truncatePrepass(int index)
1444 {
1445   int length = inputStringPrepass.length();
1446   for (int i=index+1; i<length; i++) {
1447     if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment 
1448       struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2));
1449       comments.append(c);
1450     }
1451   }
1452   inputStringPrepass.truncate(index);
1453 }
1454
1455 // simplified way to know if this is fixed form
1456 // duplicate in fortrancode.l
1457 bool recognizeFixedForm(const char* contents, FortranFormat format)
1458 {
1459   int column=0;
1460   bool skipLine=FALSE;
1461
1462   if (format == FortranFormat_Fixed) return TRUE;
1463   if (format == FortranFormat_Free)  return FALSE;
1464
1465   for(int i=0;;i++) {
1466     column++;
1467
1468     switch(contents[i]) {
1469       case '\n':
1470         column=0;
1471         skipLine=FALSE;
1472         break;
1473       case ' ':
1474         break;
1475       case '\000':
1476         return FALSE;
1477       case '#':
1478         skipLine=TRUE;
1479         break;
1480       case 'C':
1481       case 'c':
1482       case '*':
1483         if(column==1) return TRUE;
1484         if(skipLine) break;
1485         return FALSE;
1486       case '!':
1487         if(column>1 && column<7) return FALSE;
1488         skipLine=TRUE;
1489         break;
1490       default:
1491         if(skipLine) break;
1492         if(column==7) return TRUE;
1493         return FALSE;
1494     }
1495   }
1496   return FALSE;
1497 }
1498
1499 /* This function assumes that contents has at least size=length+1 */
1500 static void insertCharacter(char *contents, int length, int pos, char c)
1501 {
1502   // shift tail by one character
1503   for(int i=length; i>pos; i--)
1504     contents[i]=contents[i-1];
1505   // set the character
1506   contents[pos] = c;
1507 }
1508
1509 /* change comments and bring line continuation character to previous line */
1510 /* also used to set continuation marks in case of fortran code usage, done here as it is quite complicated code */
1511 const char* prepassFixedForm(const char* contents, int *hasContLine)
1512 {
1513   int column=0;
1514   int prevLineLength=0;
1515   int prevLineAmpOrExclIndex=-1;
1516   char prevQuote = '\0';
1517   char thisQuote = '\0';
1518   bool emptyLabel=TRUE;
1519   bool commented=FALSE;
1520   bool inSingle=FALSE;
1521   bool inDouble=FALSE;
1522   bool inBackslash=FALSE;
1523   bool fullCommentLine=TRUE;
1524   int newContentsSize = strlen(contents)+3; // \000, \n (when necessary) and one spare character (to avoid reallocation)
1525   char* newContents = (char*)malloc(newContentsSize);
1526   int curLine = 1;
1527
1528   for(int i=0, j=0;;i++,j++) {
1529     if(j>=newContentsSize-3) { // check for spare characters, which may be eventually used below (by & and '! ')
1530       newContents = (char*)realloc(newContents, newContentsSize+1000);
1531       newContentsSize = newContentsSize+1000;
1532     }
1533
1534     column++;
1535     char c = contents[i];
1536     switch(c) {
1537       case '\n':
1538         if (!fullCommentLine)
1539         {
1540           prevLineLength=column;
1541           prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength,prevQuote);
1542           if (prevLineAmpOrExclIndex == -1) prevLineAmpOrExclIndex = column - 1;
1543         }
1544         else
1545         {
1546           prevLineLength+=column;
1547           /* Even though a full comment line is not really a comment line it can be seen as one. An empty line is also seen as a comment line (small bonus) */
1548           if (hasContLine)
1549           {
1550             hasContLine[curLine - 1] = 1;
1551           }
1552         }
1553         fullCommentLine=TRUE;
1554         column=0;
1555         emptyLabel=TRUE;
1556         commented=FALSE;
1557         newContents[j]=c;
1558         prevQuote = thisQuote;
1559         curLine++;
1560         break;
1561       case ' ':
1562       case '\t':
1563         newContents[j]=c;
1564         break;
1565       case '\000':
1566         if (hasContLine)
1567         {
1568            free(newContents);
1569            return NULL;
1570         }
1571         newContents[j]='\000';
1572         newContentsSize = strlen(newContents);
1573         if (newContents[newContentsSize - 1] != '\n')
1574         {
1575           // to be on the safe side
1576           newContents = (char*)realloc(newContents, newContentsSize+2);
1577           newContents[newContentsSize] = '\n';
1578           newContents[newContentsSize + 1] = '\000';
1579         }
1580         return newContents;
1581       case '"':
1582       case '\'':
1583       case '\\':
1584         if ((column <= fixedCommentAfter) && (column!=6) && !commented)
1585         {
1586           // we have some special cases in respect to strings and escaped string characters
1587           fullCommentLine=FALSE;
1588           newContents[j]=c;
1589           if (c == '\\')
1590           {
1591             inBackslash = !inBackslash;
1592             break;
1593           }
1594           else if (c == '\'')
1595           {
1596             if (!inDouble)
1597             {
1598               inSingle = !inSingle;
1599               if (inSingle) thisQuote = c;
1600               else thisQuote = '\0';
1601             }
1602             break;
1603           }
1604           else if (c == '"')
1605           {
1606             if (!inSingle)
1607             {
1608               inDouble = !inDouble; 
1609               if (inDouble) thisQuote = c; 
1610               else thisQuote = '\0';
1611             }
1612             break;
1613           }
1614         }
1615         inBackslash = FALSE;
1616         // fallthrough
1617       case 'C':
1618       case 'c':
1619       case '*':
1620       case '!':
1621         if ((column <= fixedCommentAfter) && (column!=6))
1622         {
1623           emptyLabel=FALSE;
1624           if(column==1)
1625           {
1626             newContents[j]='!';
1627             commented = TRUE;
1628           }
1629           else if ((c == '!') && !inDouble && !inSingle)
1630           {
1631             newContents[j]=c;
1632             commented = TRUE;
1633           }
1634           else
1635           {
1636             if (!commented) fullCommentLine=FALSE;
1637             newContents[j]=c;
1638           }
1639           break;
1640         }
1641         // fallthrough
1642       default:
1643         if (!commented && (column < 6) && ((c - '0') >= 0) && ((c - '0') <= 9)) { // remove numbers, i.e. labels from first 5 positions.
1644             newContents[j]=' ';
1645         }
1646         else if(column==6 && emptyLabel) { // continuation
1647           if (!commented) fullCommentLine=FALSE;
1648           if (c != '0') { // 0 not allowed as continuation character, see f95 standard paragraph 3.3.2.3
1649             newContents[j]=' ';
1650
1651             if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line
1652               /* first line is not a continuation line in code, just in snippets etc. */
1653               if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-1, '&');
1654               j++;
1655             } else { // add & just before end of previous line comment
1656               /* first line is not a continuation line in code, just in snippets etc. */
1657               if (curLine != 1) insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&');
1658               j++;
1659             }
1660             if (hasContLine) hasContLine[curLine - 1] = 1;
1661           } else {
1662             newContents[j]=c; // , just handle like space
1663           }
1664           prevLineLength=0;
1665         } else if ((column > fixedCommentAfter) && !commented) {
1666           // first non commented non blank character after position fixedCommentAfter
1667           if (c != '!') {
1668             // I'm not a possible start of doxygen comment
1669             newContents[j++]='!';
1670             newContents[j++]=' '; // so that '<' and '>' as first character are not converted to doxygen comment
1671           }
1672           newContents[j]=c;
1673           commented = TRUE;
1674         } else {
1675           if (!commented) fullCommentLine=FALSE;
1676           newContents[j]=c;
1677           emptyLabel=FALSE;
1678         }
1679         break;
1680     }
1681   }
1682
1683   if (hasContLine)
1684   {
1685     free(newContents);
1686     return NULL;
1687   }
1688   newContentsSize = strlen(newContents);
1689   if (newContents[newContentsSize - 1] != '\n')
1690   {
1691     // to be on the safe side
1692     newContents = (char*)realloc(newContents, newContentsSize+2);
1693     newContents[newContentsSize] = '\n';
1694     newContents[newContentsSize + 1] = '\000';
1695   }
1696   return newContents;
1697 }
1698
1699 static void pushBuffer(QCString& buffer)
1700 {
1701   if (include_stack_cnt <= include_stack_ptr)
1702   {
1703      include_stack_cnt++;
1704      include_stack = (YY_BUFFER_STATE *)realloc(include_stack, include_stack_cnt * sizeof(YY_BUFFER_STATE));
1705   }
1706   include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
1707   yy_switch_to_buffer(yy_scan_string(buffer));
1708
1709   DBG_CTX((stderr, "--PUSH--%s", (const char *)buffer));
1710   buffer = NULL;
1711 }
1712
1713 static void popBuffer() {
1714   DBG_CTX((stderr, "--POP--"));
1715   include_stack_ptr --;
1716   yy_delete_buffer( YY_CURRENT_BUFFER );
1717   yy_switch_to_buffer( include_stack[include_stack_ptr] );
1718 }
1719
1720 /** used to copy entry to an interface module procedure */
1721 static void copyEntry(Entry *dest, Entry *src) 
1722 {
1723    dest->type     = src->type;
1724    dest->fileName = src->fileName;
1725    dest->startLine = src->startLine;
1726    dest->bodyLine = src->bodyLine;
1727    dest->endBodyLine = src->endBodyLine;
1728    dest->args     = src->args;
1729    dest->argList  = new ArgumentList(*src->argList);
1730    dest->doc      = src->doc;
1731    dest->brief    = src->brief;
1732 }
1733
1734 /** fill empty interface module procedures with info from 
1735     corresponding module subprogs 
1736     @TODO: handle procedures in used modules
1737 */
1738 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
1739 {
1740   if (moduleProcedures.isEmpty()) return;
1741  
1742   EntryListIterator eli1(moduleProcedures);
1743   // for all module procedures
1744   for (Entry *ce1; (ce1=eli1.current()); ++eli1) 
1745   {
1746     // check all entries in this module
1747     EntryListIterator eli2(*current_root->children());
1748     for (Entry *ce2; (ce2=eli2.current()); ++eli2) 
1749     {
1750       if (ce1->name == ce2->name) 
1751       {
1752         copyEntry(ce1, ce2);
1753       }
1754     } // for procedures in current module
1755   } // for all interface module procedures
1756   moduleProcedures.clear();
1757 }
1758
1759 #if 0
1760 static bool isTypeName(QCString name)
1761 {
1762   name = name.lower();
1763   return name=="integer" || name == "real" || 
1764          name=="complex" || name == "logical";
1765 }
1766 #endif
1767
1768 /*! Extracts string which resides within parentheses of provided string. */
1769 static QCString extractFromParens(const QCString name)
1770 {
1771   QCString extracted = name;
1772   int start = extracted.find("(");
1773   if (start != -1) 
1774   {
1775     extracted.remove(0, start+1);
1776   }
1777   int end = extracted.findRev(")");
1778   if (end != -1) 
1779   {
1780     int length = extracted.length();
1781     extracted.remove(end, length);
1782   }
1783   extracted = extracted.stripWhiteSpace();
1784
1785   return extracted;
1786 }
1787
1788 /*! Adds passed modifiers to these modifiers.*/
1789 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
1790 {
1791   if (mdfs.protection!=NONE_P) protection = mdfs.protection;
1792   if (mdfs.direction!=NONE_D) direction = mdfs.direction;
1793   optional |= mdfs.optional;
1794   if (!mdfs.dimension.isNull()) dimension = mdfs.dimension;
1795   allocatable |= mdfs.allocatable;
1796   external |= mdfs.external;
1797   intrinsic |= mdfs.intrinsic;
1798   protect |= mdfs.protect;
1799   parameter |= mdfs.parameter;
1800   pointer |= mdfs.pointer;
1801   target |= mdfs.target;
1802   save |= mdfs.save;
1803   deferred |= mdfs.deferred;
1804   nonoverridable |= mdfs.nonoverridable;
1805   nopass |= mdfs.nopass;
1806   pass |= mdfs.pass;
1807   passVar = mdfs.passVar;
1808   contiguous |= mdfs.contiguous;
1809   volat |= mdfs.volat;
1810   value |= mdfs.value;
1811   return *this;
1812 }
1813
1814 /*! Extracts and adds passed modifier to these modifiers.*/
1815 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
1816 {
1817   mdfString = mdfString.lower();
1818   SymbolModifiers newMdf;
1819
1820   if (mdfString.find("dimension")==0) 
1821   {
1822     newMdf.dimension=mdfString;
1823   }
1824   else if (mdfString.contains("intent")) 
1825   {
1826     QCString tmp = extractFromParens(mdfString);
1827     bool isin = tmp.contains("in");
1828     bool isout = tmp.contains("out");
1829     if (isin && isout) newMdf.direction = SymbolModifiers::INOUT;
1830     else if (isin) newMdf.direction = SymbolModifiers::IN;
1831     else if (isout) newMdf.direction = SymbolModifiers::OUT;
1832   }
1833   else if (mdfString=="public") 
1834   {
1835     newMdf.protection = SymbolModifiers::PUBLIC;
1836   }
1837   else if (mdfString=="private") 
1838   {
1839     newMdf.protection = SymbolModifiers::PRIVATE;
1840   }
1841   else if (mdfString=="protected") 
1842   {
1843     newMdf.protect = TRUE;
1844   }
1845   else if (mdfString=="optional") 
1846   {
1847     newMdf.optional = TRUE;
1848   }
1849   else if (mdfString=="allocatable") 
1850   {
1851     newMdf.allocatable = TRUE;
1852   }
1853   else if (mdfString=="external") 
1854   {
1855     newMdf.external = TRUE;
1856   }
1857   else if (mdfString=="intrinsic") 
1858   {
1859     newMdf.intrinsic = TRUE;
1860   }
1861   else if (mdfString=="parameter") 
1862   {
1863     newMdf.parameter = TRUE;
1864   }
1865   else if (mdfString=="pointer") 
1866   {
1867     newMdf.pointer = TRUE;
1868   }
1869   else if (mdfString=="target") 
1870   {
1871     newMdf.target = TRUE;
1872   }
1873   else if (mdfString=="save") 
1874   {
1875     newMdf.save = TRUE;
1876   }
1877   else if (mdfString=="nopass")
1878   {
1879     newMdf.nopass = TRUE;
1880   }
1881   else if (mdfString=="deferred")
1882   {
1883     newMdf.deferred = TRUE;
1884   }
1885   else if (mdfString=="non_overridable")
1886   {
1887     newMdf.nonoverridable = TRUE;
1888   }
1889   else if (mdfString=="contiguous")
1890   {
1891     newMdf.contiguous = TRUE;
1892   }
1893   else if (mdfString=="volatile")
1894   {
1895     newMdf.volat = TRUE;
1896   }
1897   else if (mdfString=="value")
1898   {
1899     newMdf.value = TRUE;
1900   }
1901   else if (mdfString.contains("pass"))
1902   {
1903     newMdf.pass = TRUE;
1904     if (mdfString.contains("("))
1905       newMdf.passVar = extractFromParens(mdfString);
1906     else
1907       newMdf.passVar = "";
1908   }
1909
1910   (*this) |= newMdf;
1911   return *this;
1912 }
1913
1914 /*! For debugging purposes. */
1915 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
1916 //{
1917 //  out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
1918 //    ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
1919 //    ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
1920 //
1921 //  return out;
1922 //}
1923
1924 /*! Find argument with given name in \a subprog entry. */
1925 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
1926 {
1927   QCString cname(name.lower());
1928   for (unsigned int i=0; i<subprog->argList->count(); i++) 
1929   {
1930     Argument *arg = subprog->argList->at(i);
1931     if ((!byTypeName && arg->name.lower() == cname) ||
1932         (byTypeName && arg->type.lower() == cname)
1933        )
1934     {
1935       return arg;
1936     }
1937   }
1938   return 0;
1939 }
1940
1941 /*! Find function with given name in \a entry. */
1942 #if 0
1943 static Entry *findFunction(Entry* entry, QCString name)
1944 {
1945   QCString cname(name.lower());
1946
1947   EntryListIterator eli(*entry->children());
1948   Entry *ce;
1949   for (;(ce=eli.current());++eli) 
1950   {
1951     if (ce->section != Entry::FUNCTION_SEC)
1952       continue;
1953
1954     if (ce->name.lower() == cname)
1955       return ce;
1956   }
1957
1958   return 0;
1959 }
1960 #endif
1961
1962 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */
1963 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs) 
1964 {
1965   if (!mdfs.dimension.isNull()) 
1966   {
1967     if (!typeName.isEmpty()) typeName += ", ";
1968     typeName += mdfs.dimension;
1969   }
1970   if (mdfs.direction!=SymbolModifiers::NONE_D) 
1971   {
1972     if (!typeName.isEmpty()) typeName += ", ";
1973     typeName += directionStrs[mdfs.direction];
1974   }
1975   if (mdfs.optional) 
1976   {
1977     if (!typeName.isEmpty()) typeName += ", ";
1978     typeName += "optional";
1979   }
1980   if (mdfs.allocatable) 
1981   {
1982     if (!typeName.isEmpty()) typeName += ", ";
1983     typeName += "allocatable";
1984   }
1985   if (mdfs.external) 
1986   {
1987     if (!typeName.contains("external"))
1988     {
1989       if (!typeName.isEmpty()) typeName += ", ";
1990       typeName += "external";
1991     }
1992   }
1993   if (mdfs.intrinsic) 
1994   {
1995     if (!typeName.isEmpty()) typeName += ", ";
1996     typeName += "intrinsic";
1997   }
1998   if (mdfs.parameter) 
1999   {
2000     if (!typeName.isEmpty()) typeName += ", ";
2001     typeName += "parameter";
2002   }
2003   if (mdfs.pointer) 
2004   {
2005     if (!typeName.isEmpty()) typeName += ", ";
2006     typeName += "pointer";
2007   }
2008   if (mdfs.target) 
2009   {
2010     if (!typeName.isEmpty()) typeName += ", ";
2011     typeName += "target";
2012   }
2013   if (mdfs.save) 
2014   {
2015     if (!typeName.isEmpty()) typeName += ", ";
2016     typeName += "save";
2017   }
2018   if (mdfs.deferred) 
2019   {
2020     if (!typeName.isEmpty()) typeName += ", ";
2021     typeName += "deferred";
2022   }
2023   if (mdfs.nonoverridable) 
2024   {
2025     if (!typeName.isEmpty()) typeName += ", ";
2026     typeName += "non_overridable";
2027   }
2028   if (mdfs.nopass) 
2029   {
2030     if (!typeName.isEmpty()) typeName += ", ";
2031     typeName += "nopass";
2032   }
2033   if (mdfs.pass) 
2034   {
2035     if (!typeName.isEmpty()) typeName += ", ";
2036     typeName += "pass";
2037     if (!mdfs.passVar.isEmpty())
2038       typeName += "(" + mdfs.passVar + ")";
2039   }
2040   if (mdfs.protection == SymbolModifiers::PUBLIC)
2041   {
2042     if (!typeName.isEmpty()) typeName += ", ";
2043     typeName += "public";
2044   }
2045   else if (mdfs.protection == SymbolModifiers::PRIVATE)
2046   {
2047     if (!typeName.isEmpty()) typeName += ", ";
2048     typeName += "private";
2049   }
2050   if (mdfs.protect)
2051   {
2052     if (!typeName.isEmpty()) typeName += ", ";
2053     typeName += "protected";
2054   }
2055   if (mdfs.contiguous)
2056   {
2057     if (!typeName.isEmpty()) typeName += ", ";
2058     typeName += "contiguous";
2059   }
2060   if (mdfs.volat)
2061   {
2062     if (!typeName.isEmpty()) typeName += ", ";
2063     typeName += "volatile";
2064   }
2065   if (mdfs.value)
2066   {
2067     if (!typeName.isEmpty()) typeName += ", ";
2068     typeName += "value";
2069   }
2070
2071   return typeName;
2072 }
2073
2074 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */
2075 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
2076 {
2077   QCString tmp = arg->type;
2078   arg->type = applyModifiers(tmp, mdfs);
2079 }
2080
2081 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */
2082 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
2083 {
2084   QCString tmp = ent->type;
2085   ent->type = applyModifiers(tmp, mdfs);
2086
2087   if (mdfs.protection == SymbolModifiers::PUBLIC)
2088     ent->protection = Public;
2089   else if (mdfs.protection == SymbolModifiers::PRIVATE)
2090     ent->protection = Private;
2091 }
2092
2093 /*! Starts the new scope in fortran program. Consider using this function when
2094  * starting module, interface, function or other program block.
2095  * \see endScope()
2096  */
2097 static void startScope(Entry *scope) 
2098 {
2099   //cout<<"start scope: "<<scope->name<<endl;
2100   current_root= scope; /* start substructure */
2101
2102   QMap<QCString,SymbolModifiers> mdfMap;
2103   modifiers.insert(scope, mdfMap);
2104 }
2105
2106 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
2107  * \see startScope()
2108  */
2109 static bool endScope(Entry *scope, bool isGlobalRoot)
2110 {
2111   if (global_scope == scope)
2112   {
2113     global_scope = NULL;
2114     return TRUE;
2115   }
2116   if (global_scope == (Entry *) -1)
2117   {
2118     return TRUE;
2119   }
2120   //cout<<"end scope: "<<scope->name<<endl;
2121   if (current_root->parent() || isGlobalRoot)
2122   {
2123     current_root= current_root->parent(); /* end substructure */
2124   }
2125   else // if (current_root != scope)
2126   {
2127     fprintf(stderr,"parse error in end <scopename>\n");
2128     scanner_abort();
2129     return FALSE;
2130   }
2131
2132   // update variables or subprogram arguments with modifiers
2133   QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
2134
2135   if (scope->section == Entry::FUNCTION_SEC) 
2136   {
2137     // iterate all symbol modifiers of the scope
2138     for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) 
2139     {
2140       //cout<<it.key()<<": "<<it.data()<<endl;
2141       Argument *arg = findArgument(scope, it.key());
2142
2143       if (arg)
2144         applyModifiers(arg, it.data());
2145     }
2146
2147     // find return type for function
2148     //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
2149     QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
2150     if (modifiers[scope].contains(returnName)) 
2151     {
2152       scope->type = modifiers[scope][returnName].type; // returning type works
2153       applyModifiers(scope, modifiers[scope][returnName]); // returning array works
2154     }
2155
2156   } 
2157   if (scope->section == Entry::CLASS_SEC) 
2158   { // was INTERFACE_SEC
2159     if (scope->parent()->section == Entry::FUNCTION_SEC) 
2160     { // interface within function
2161       // iterate functions of interface and 
2162       // try to find types for dummy(ie. argument) procedures.
2163       //cout<<"Search in "<<scope->name<<endl;
2164       EntryListIterator eli(*scope->children());
2165       Entry *ce;
2166       int count = 0;
2167       int found = FALSE;
2168       for (;(ce=eli.current());++eli) 
2169       {
2170         count++;
2171         if (ce->section != Entry::FUNCTION_SEC)
2172           continue;
2173
2174         Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
2175         if (arg != 0) 
2176         {
2177           // set type of dummy procedure argument to interface
2178           arg->name = arg->type;
2179           arg->type = scope->name;
2180         }
2181         if (ce->name.lower() == scope->name.lower()) found = TRUE;
2182       }
2183       if ((count == 1) && found)
2184       {
2185         // clear all modifiers of the scope
2186         modifiers.remove(scope);
2187         delete scope->parent()->removeSubEntry(scope);
2188         scope = 0;
2189         return TRUE;
2190       }
2191     }
2192   } 
2193   if (scope->section!=Entry::FUNCTION_SEC) 
2194   { // not function section 
2195     // iterate variables: get and apply modifiers
2196     EntryListIterator eli(*scope->children());
2197     Entry *ce;
2198     for (;(ce=eli.current());++eli) 
2199     {
2200       if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
2201         continue;
2202
2203       //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
2204       if (mdfsMap.contains(ce->name.lower()))
2205         applyModifiers(ce, mdfsMap[ce->name.lower()]);
2206     }
2207   }
2208
2209   // clear all modifiers of the scope
2210   modifiers.remove(scope);
2211
2212   return TRUE;
2213 }
2214
2215 #if 0
2216 //! Return full name of the entry. Sometimes we must combine several names recursively.
2217 static QCString getFullName(Entry *e) 
2218 {
2219   QCString name = e->name;
2220   if (e->section == Entry::CLASS_SEC //  || e->section == Entry::INTERFACE_SEC
2221      || !e->parent() || e->parent()->name.isEmpty())
2222     return name;
2223
2224   return getFullName(e->parent())+"::"+name;
2225 }
2226 #endif
2227
2228 static int yyread(char *buf,int max_size)
2229 {
2230   int c=0;
2231
2232   while ( c < max_size && inputString[inputPosition] )
2233   {
2234     *buf = inputString[inputPosition++] ;
2235     c++; buf++;
2236   }
2237   return c;
2238 }
2239
2240 static void initParser()
2241 {
2242   last_entry = 0;
2243 }
2244
2245 static void initEntry()
2246 {
2247   if (typeMode)
2248   {
2249     current->protection = typeProtection;
2250   }
2251   else
2252   {
2253     current->protection = defaultProtection;
2254   }
2255   current->mtype      = mtype;
2256   current->virt       = virt;
2257   current->stat       = gstat;
2258   current->lang       = SrcLangExt_Fortran; 
2259   initGroupInfo(current);
2260 }
2261
2262 /**
2263   adds current entry to current_root and creates new current
2264 */
2265 static void addCurrentEntry(int case_insens)
2266 {
2267   if (case_insens) current->name = current->name.lower();
2268   //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data());
2269   current_root->addSubEntry(current);
2270   last_entry = current;
2271   current = new Entry ;
2272   initEntry();
2273 }
2274
2275 static int max(int a, int b) {return a>b?a:b;}
2276
2277 static void addModule(const char *name, bool isModule)
2278 {
2279   DBG_CTX((stderr, "0=========> got module %s\n", name));
2280
2281   if (isModule)
2282     current->section = Entry::NAMESPACE_SEC;
2283   else
2284     current->section = Entry::FUNCTION_SEC;
2285
2286   if (name!=NULL)
2287   {
2288     current->name = name;
2289   } 
2290   else
2291   {
2292     QCString fname = yyFileName;
2293     int index = max(fname.findRev('/'), fname.findRev('\\'));
2294     fname = fname.right(fname.length()-index-1);
2295     fname = fname.prepend("__").append("__");
2296     current->name = fname;
2297   }
2298   current->type = "program";
2299   current->fileName  = yyFileName;
2300   current->bodyLine  = yyLineNr; // used for source reference
2301   current->startLine  = yyLineNr;
2302   current->protection = Public ;
2303   addCurrentEntry(1);
2304   startScope(last_entry);
2305 }
2306
2307
2308 static void addSubprogram(const char *text)
2309 {
2310   DBG_CTX((stderr,"1=========> got subprog, type: %s\n",text)); 
2311   subrCurrent.prepend(current);
2312   current->section = Entry::FUNCTION_SEC ;
2313   QCString subtype = text; subtype=subtype.lower().stripWhiteSpace();
2314   functionLine = (subtype.find("function") != -1);
2315   current->type += " " + subtype;
2316   current->type = current->type.stripWhiteSpace();
2317   current->fileName  = yyFileName;
2318   current->bodyLine  = yyLineNr; // used for source reference start of body of routine
2319   current->startLine  = yyLineNr; // used for source reference start of definition
2320   current->args.resize(0);
2321   current->argList->clear();
2322   docBlock.resize(0);
2323 }
2324
2325 /*! Adds interface to the root entry.
2326  * \note Code was brought to this procedure from the parser,
2327  * because there was/is idea to use it in several parts of the parser.
2328  */ 
2329 static void addInterface(QCString name, InterfaceType type)
2330 {
2331   if (YY_START == Start)
2332   {
2333     addModule(NULL);
2334     yy_push_state(ModuleBody); //anon program
2335   }
2336
2337   current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
2338   current->spec = Entry::Interface;
2339   current->name = name;
2340
2341   switch (type)
2342   {
2343     case IF_ABSTRACT:
2344       current->type = "abstract";
2345       break;
2346
2347     case IF_GENERIC:
2348       current->type = "generic";
2349       break;
2350
2351     case IF_SPECIFIC:
2352     case IF_NONE:
2353     default:
2354       current->type = "";
2355   }
2356
2357   /* if type is part of a module, mod name is necessary for output */
2358   if ((current_root) && 
2359       (current_root->section ==  Entry::CLASS_SEC ||
2360        current_root->section ==  Entry::NAMESPACE_SEC)) 
2361   {
2362     current->name= current_root->name + "::" + current->name;
2363   }
2364
2365   current->fileName = yyFileName;
2366   current->bodyLine  = yyLineNr; 
2367   current->startLine  = yyLineNr;
2368   addCurrentEntry(1);
2369 }
2370
2371
2372 //-----------------------------------------------------------------------------
2373
2374 /*! Get the argument \a name.
2375  */
2376 static Argument* getParameter(const QCString &name)
2377 {
2378   // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl;
2379   Argument *ret = 0;
2380   if (current_root->argList==0) return 0;
2381   ArgumentListIterator ali(*current_root->argList);
2382   Argument *a;
2383   for (ali.toFirst();(a=ali.current());++ali)
2384   {
2385     if (a->name.lower()==name.lower())
2386     {
2387       ret=a;
2388       //printf("parameter found: %s\n",(const char*)name);
2389       break;
2390     }
2391   } // for
2392   return ret;
2393 }
2394
2395   //----------------------------------------------------------------------------
2396 static void startCommentBlock(bool brief)
2397 {
2398   if (brief)
2399   {
2400     current->briefFile = yyFileName;
2401     current->briefLine = yyLineNr;
2402   }
2403   else
2404   {
2405     current->docFile = yyFileName;
2406     current->docLine = yyLineNr;
2407   }
2408 }
2409
2410 //----------------------------------------------------------------------------
2411
2412 static void handleCommentBlock(const QCString &doc,bool brief)
2413 {
2414   bool needsEntry = FALSE;
2415   static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
2416   int position=0;
2417   if (docBlockInBody && hideInBodyDocs)
2418   {
2419     docBlockInBody = FALSE;
2420     return;
2421   }
2422   DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
2423   int lineNr = brief ? current->briefLine : current->docLine;
2424   while (parseCommentBlock(
2425         g_thisParser,
2426         docBlockInBody ? subrCurrent.getFirst() : current,
2427         doc,        // text
2428         yyFileName, // file
2429         lineNr,
2430         docBlockInBody ? FALSE : brief, 
2431         docBlockInBody ? FALSE : docBlockJavaStyle,
2432         docBlockInBody,
2433         defaultProtection,
2434         position,
2435         needsEntry
2436         )) 
2437   {
2438            DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2439    if (needsEntry) addCurrentEntry(0);
2440   }
2441   DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2442
2443   if (needsEntry) addCurrentEntry(0);
2444   docBlockInBody = FALSE;
2445 }
2446
2447 //----------------------------------------------------------------------------
2448 /// Handle parameter description as defined after the declaration of the parameter
2449 static void subrHandleCommentBlock(const QCString &doc,bool brief)
2450 {
2451   QCString loc_doc;
2452   loc_doc = doc.stripWhiteSpace();
2453
2454   Entry *tmp_entry = current; 
2455   current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2456
2457   // Still in the specification section so no inbodyDocs yet, but parameter documentation
2458   current->inbodyDocs = "";
2459
2460   // strip \\param or @param, so we can do some extra checking. We will add it later on again.
2461   if (!loc_doc.stripPrefix("\\param") &&
2462       !loc_doc.stripPrefix("@param")
2463      ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2464   loc_doc.stripWhiteSpace();
2465
2466   // direction as defined with the declaration of the parameter
2467   int dir1 = modifiers[current_root][argName.lower()].direction;
2468   // in description [in] is specified
2469   if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
2470   {
2471     // check if with the declaration intent(in) or nothing has been specified
2472     if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2473         (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
2474     {
2475       // strip direction
2476       loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN]));
2477       loc_doc.stripWhiteSpace();
2478       // in case of empty documentation or (now) just name, consider it as no documemntation
2479       if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2480       {
2481         // reset current back to the part inside the routine
2482         current=tmp_entry;
2483         return;
2484       }
2485       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " + 
2486                          argName + " " + loc_doc,brief);
2487     }
2488     else
2489     {
2490       // something different specified, give warning and leave error.
2491       warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2492            " inconsistency between intent attribute and documentation for parameter: " + argName);
2493       handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2494                          argName + " " + loc_doc,brief);
2495     }
2496   }
2497   // analogous to the [in] case, here [out] direction specified
2498   else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
2499   {
2500     if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2501         (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
2502     {
2503       loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT]));
2504       loc_doc.stripWhiteSpace();
2505       if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2506       {
2507         current=tmp_entry;
2508         return;
2509       }
2510       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " + 
2511                          argName + " " + loc_doc,brief);
2512     }
2513     else
2514     {
2515       warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2516            " inconsistency between intent attribute and documentation for parameter: " + argName);
2517       handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2518                          argName + " " + loc_doc,brief);
2519     }
2520   }
2521   // analogous to the [in] case, here [in,out] direction specified
2522   else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
2523   {
2524     if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2525         (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
2526     {
2527       loc_doc = loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT]));
2528       loc_doc.stripWhiteSpace();
2529       if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2530       {
2531         current=tmp_entry;
2532         return;
2533       }
2534       handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " + 
2535                          argName + " " + loc_doc,brief);
2536     }
2537     else
2538     {
2539       warn(yyFileName,yyLineNr, "Routine: " + current->name + current->args +
2540            " inconsistency between intent attribute and documentation for parameter: " + argName);
2541       handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2542                          argName + " " + loc_doc,brief);
2543     }
2544   }
2545   // analogous to the [in] case; here no direction specified
2546   else
2547   {
2548     if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2549     {
2550       current=tmp_entry;
2551       return;
2552     }
2553     handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2554                        argName + " " + loc_doc,brief);
2555   }
2556
2557   // reset current back to the part inside the routine
2558   current=tmp_entry;
2559 }
2560 //----------------------------------------------------------------------------
2561 /// Handle result description as defined after the declaration of the parameter
2562 static void subrHandleCommentBlockResult(const QCString &doc,bool brief)
2563 {
2564   QCString loc_doc;
2565   loc_doc = doc.stripWhiteSpace();
2566
2567   Entry *tmp_entry = current; 
2568   current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2569
2570   // Still in the specification section so no inbodyDocs yet, but parameter documentation
2571   current->inbodyDocs = "";
2572
2573   // strip \\returns or @returns. We will add it later on again.
2574   if (!loc_doc.stripPrefix("\\returns") &&
2575       !loc_doc.stripPrefix("\\return") &&
2576       !loc_doc.stripPrefix("@returns") &&
2577       !loc_doc.stripPrefix("@return")
2578      ) (void)loc_doc; // Do nothing work has been done by stripPrefix; (void)loc_doc: to overcome 'empty controlled statement' warning
2579   loc_doc.stripWhiteSpace();
2580
2581   if (loc_doc.isEmpty() || (loc_doc.lower() == argName.lower()))
2582   {
2583     current=tmp_entry;
2584     return;
2585   }
2586   handleCommentBlock(QCString("\n\n@returns ") + loc_doc,brief);
2587
2588   // reset current back to the part inside the routine
2589   current=tmp_entry;
2590 }
2591
2592 //----------------------------------------------------------------------------
2593 #if 0
2594 static int level=0;
2595
2596 static void debugCompounds(Entry *rt)  // print Entry structure (for debugging)
2597 {
2598  level++;
2599   printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
2600   EntryListIterator eli(*rt->children());
2601   Entry *ce;
2602   for (;(ce=eli.current());++eli)
2603   {
2604      debugCompounds(ce); 
2605   } 
2606 level--;
2607 }
2608 #endif
2609
2610
2611 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, FortranFormat format)
2612 {
2613   char *tmpBuf = NULL;
2614   initParser();
2615
2616   defaultProtection = Public;
2617   inputString = fileBuf;
2618   inputPosition = 0;
2619   inputStringPrepass = NULL;
2620   inputPositionPrepass = 0;
2621
2622   //anonCount     = 0;  // don't reset per file
2623   mtype         = Method;
2624   gstat         = FALSE;
2625   virt          = Normal;
2626   current_root  = rt;
2627   global_root   = rt;
2628   inputFile.setName(fileName);
2629   if (inputFile.open(IO_ReadOnly))
2630   {
2631     isFixedForm = recognizeFixedForm(fileBuf,format);
2632
2633     if (isFixedForm) 
2634     {
2635       msg("Prepassing fixed form of %s\n", fileName);
2636       //printf("---strlen=%d\n", strlen(fileBuf));
2637       //clock_t start=clock();
2638
2639       //printf("Input fixed form string:\n%s\n", fileBuf);
2640       //printf("===========================\n");
2641       inputString = prepassFixedForm(fileBuf, NULL);
2642       //printf("Resulting free form string:\n%s\n", inputString);
2643       //printf("===========================\n");
2644
2645       //clock_t end=clock();
2646       //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
2647     }
2648     else if (inputString[strlen(fileBuf)-1] != '\n')
2649     {
2650       tmpBuf = (char *)malloc(strlen(fileBuf)+2);
2651       strcpy(tmpBuf,fileBuf);
2652       tmpBuf[strlen(fileBuf)]= '\n';
2653       tmpBuf[strlen(fileBuf)+1]= '\000';
2654       inputString = tmpBuf;
2655     }
2656
2657     yyLineNr= 1 ; 
2658     yyFileName = fileName;
2659     msg("Parsing file %s...\n",yyFileName.data());
2660
2661     global_scope = rt;
2662     startScope(rt); // implies current_root = rt
2663     initParser();
2664     groupEnterFile(yyFileName,yyLineNr);
2665
2666     current          = new Entry;
2667     current->lang    = SrcLangExt_Fortran; 
2668     current->name    = yyFileName;
2669     current->section = Entry::SOURCE_SEC;
2670     current_root->addSubEntry(current);
2671     file_root        = current;
2672     current          = new Entry;
2673     current->lang    = SrcLangExt_Fortran; 
2674
2675     fortranscannerYYrestart( fortranscannerYYin );
2676     {
2677       BEGIN( Start );
2678     }
2679
2680     fortranscannerYYlex();
2681     groupLeaveFile(yyFileName,yyLineNr);
2682
2683     if (global_scope && global_scope != (Entry *) -1) endScope(current_root, TRUE); // TRUE - global root
2684
2685     //debugCompounds(rt); //debug 
2686
2687     rt->program.resize(0);
2688     delete current; current=0;
2689     moduleProcedures.clear();
2690     if (tmpBuf) {
2691       free((char*)tmpBuf);
2692       inputString=NULL;
2693     }
2694     if (isFixedForm) {
2695       free((char*)inputString);
2696       inputString=NULL;
2697     }
2698
2699     inputFile.close();
2700   }
2701 }
2702
2703 //----------------------------------------------------------------------------
2704
2705 void FortranLanguageScanner::parseInput(const char *fileName,
2706                                         const char *fileBuf,
2707                                         Entry *root,
2708                                         bool /*sameTranslationUnit*/,
2709                                         QStrList & /*filesInSameTranslationUnit*/)
2710 {
2711   g_thisParser = this;
2712
2713   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2714
2715   ::parseMain(fileName,fileBuf,root,m_format);
2716
2717   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2718 }
2719
2720 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2721                    const char * scopeName,
2722                    const QCString & input,
2723                    SrcLangExt /*lang*/,
2724                    bool isExampleBlock,
2725                    const char * exampleName,
2726                    FileDef * fileDef,
2727                    int startLine,
2728                    int endLine,
2729                    bool inlineFragment,
2730                    MemberDef *memberDef,
2731                    bool showLineNumbers,
2732                    Definition *searchCtx,
2733                    bool collectXRefs
2734                   )
2735 {
2736   ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
2737                      fileDef,startLine,endLine,inlineFragment,memberDef,
2738                      showLineNumbers,searchCtx,collectXRefs,m_format);
2739 }
2740
2741 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
2742 {
2743   return extension!=extension.lower(); // use preprocessor only for upper case extensions
2744 }
2745 void FortranLanguageScanner::resetCodeParserState()
2746 {
2747   ::resetFortranCodeParserState();
2748 }
2749
2750 void FortranLanguageScanner::parsePrototype(const char *text)
2751 {
2752   QCString buffer = QCString(text);
2753   pushBuffer(buffer);
2754   parsingPrototype = TRUE;
2755   BEGIN(Prototype);
2756   fortranscannerYYlex();
2757   parsingPrototype = FALSE;
2758   popBuffer();
2759 }
2760
2761 static void scanner_abort() 
2762 {
2763   fprintf(stderr,"********************************************************************\n");
2764   fprintf(stderr,"Error in file %s line: %d, state: %d(%s)\n",yyFileName.data(),yyLineNr,YY_START,stateToString(YY_START));
2765   fprintf(stderr,"********************************************************************\n");
2766    
2767   EntryListIterator eli(*global_root->children());
2768   Entry *ce;
2769   bool start=FALSE;
2770
2771   for (;(ce=eli.current());++eli)
2772   {
2773      if (ce == file_root) start=TRUE;
2774      if (start) ce->reset(); 
2775   } 
2776
2777   // dummy call to avoid compiler warning
2778   (void)yy_top_state();
2779   
2780   return;
2781   //exit(-1);
2782 }
2783
2784 //----------------------------------------------------------------------------
2785
2786 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
2787 //----------------------------------------------------------------------------
2788 extern "C" { // some bogus code to keep the compiler happy
2789   void fortranscannernerYYdummy() { yy_flex_realloc(0,0); } 
2790 }
2791 #endif
2792
2793 #define scanStateToString(x) case x: resultString = #x; break;
2794 static const char *stateToString(int state)
2795 {
2796   const char *resultString;
2797   switch(state)
2798   {
2799     scanStateToString(INITIAL)
2800     scanStateToString(Subprog)
2801     scanStateToString(SubprogPrefix)
2802     scanStateToString(Parameterlist)
2803     scanStateToString(SubprogBody)
2804     scanStateToString(SubprogBodyContains)
2805     scanStateToString(Start)
2806     scanStateToString(Comment)
2807     scanStateToString(Module)
2808     scanStateToString(Program)
2809     scanStateToString(ModuleBody)
2810     scanStateToString(ModuleBodyContains)
2811     scanStateToString(AttributeList)
2812     scanStateToString(Variable)
2813     scanStateToString(Initialization)
2814     scanStateToString(ArrayInitializer)
2815     scanStateToString(Enum)
2816     scanStateToString(Typedef)
2817     scanStateToString(TypedefBody)
2818     scanStateToString(TypedefBodyContains)
2819     scanStateToString(InterfaceBody)
2820     scanStateToString(StrIgnore)
2821     scanStateToString(String)
2822     scanStateToString(Use)
2823     scanStateToString(UseOnly)
2824     scanStateToString(ModuleProcedure)
2825     scanStateToString(Prepass)
2826     scanStateToString(DocBlock)
2827     scanStateToString(DocBackLine)
2828     scanStateToString(EndDoc)
2829     scanStateToString(BlockData)
2830     scanStateToString(Prototype)
2831     scanStateToString(PrototypeSubprog)
2832     scanStateToString(PrototypeArgs)
2833     default: resultString = "Unknown"; break;
2834   }
2835   return resultString;
2836 }