Imported Upstream version 1.8.8
[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
41 %{
42
43 #include <stdio.h> 
44 #include <stdlib.h>
45 #include <assert.h>
46 #include <ctype.h>
47
48 #include <qarray.h>
49 #include <qstack.h>
50 #include <qregexp.h>
51 #include <unistd.h> 
52 #include <qfile.h>
53 #include <qmap.h>
54   
55 #include "fortranscanner.h"
56 #include "entry.h"
57 #include "message.h"
58 #include "config.h"
59 #include "doxygen.h"
60 #include "util.h"
61 #include "defargs.h"
62 #include "language.h"
63 #include "commentscan.h" 
64 #include "fortrancode.h"
65 #include "pre.h"
66 #include "arguments.h"
67
68 // Toggle for some debugging info
69 //#define DBG_CTX(x) fprintf x
70 #define DBG_CTX(x) do { } while(0)
71
72 #define YY_NEVER_INTERACTIVE 1
73 #define YY_NO_INPUT 1
74
75 enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER};
76 enum InterfaceType { IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT };
77
78 // {{{ ----- Helper structs -----
79 //! Holds modifiers (ie attributes) for one symbol (variable, function, etc)
80 struct SymbolModifiers {
81   enum Protection {NONE_P, PUBLIC, PRIVATE};
82   enum Direction {NONE_D, IN, OUT, INOUT};
83
84   //!< This is only used with function return value.
85   QCString type, returnName;
86   Protection protection;
87   Direction direction;
88   bool optional;
89   bool protect;
90   QCString dimension;
91   bool allocatable;
92   bool external;
93   bool intrinsic;
94   bool parameter;
95   bool pointer;
96   bool target;
97   bool save;
98   bool deferred;
99   bool nonoverridable;
100   bool nopass;
101   bool pass;
102   QCString passVar;
103
104   SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D),
105     optional(FALSE), protect(FALSE), dimension(), allocatable(FALSE),
106     external(FALSE), intrinsic(FALSE), parameter(FALSE),
107     pointer(FALSE), target(FALSE), save(FALSE), deferred(FALSE), nonoverridable(FALSE),
108     nopass(FALSE), pass(FALSE), passVar() {}
109
110   SymbolModifiers& operator|=(const SymbolModifiers &mdfs);
111   SymbolModifiers& operator|=(QCString mdfrString);
112 };
113
114 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs);
115
116 static const char *directionStrs[] = 
117 {
118    "", "intent(in)", "intent(out)", "intent(inout)"
119 };
120 static const char *directionParam[] = 
121 {
122    "", "[in]", "[out]", "[in,out]"
123 };
124
125 // }}}
126
127 /* -----------------------------------------------------------------
128  *
129  *      statics
130  */
131 static ParserInterface *g_thisParser; 
132 static const char *     inputString;
133 static int              inputPosition;
134 static bool             isFixedForm;
135 static QCString         inputStringPrepass; ///< Input string for prepass of line cont. '&'
136 static QCString         inputStringSemi; ///< Input string after command separetor ';'
137 static unsigned int     inputPositionPrepass;
138 static int              lineCountPrepass = 0;
139
140 static QList<Entry>  subrCurrent;
141
142 struct CommentInPrepass {
143   int column;
144   QCString str;
145   CommentInPrepass(int column, QCString str) : column(column), str(str) {}
146 };
147 static QList<CommentInPrepass>  comments;
148
149 YY_BUFFER_STATE *include_stack = NULL;
150 int include_stack_ptr = 0;
151 int include_stack_cnt = 0;
152
153 static QFile            inputFile;
154 static QCString         yyFileName;
155 static int              yyLineNr     = 1 ;
156 static int              yyColNr     = 0 ;
157 static Entry*           current_root = 0 ;
158 static Entry*           global_root  = 0 ;
159 static Entry*           file_root    = 0 ;
160 static Entry*           current      = 0 ;
161 static Entry*           last_entry   = 0 ;
162 static ScanVar          v_type       = V_IGNORE; // type of parsed variable
163 static QList<Entry>     moduleProcedures; // list of all interfaces which contain unresolved 
164                                           // module procedures
165 static QCString         docBlock;
166 static QCString         docBlockName;
167 static bool             docBlockInBody = FALSE;
168 static bool             docBlockJavaStyle;
169
170 static MethodTypes      mtype;
171 static bool             gstat;
172 static Specifier        virt;
173
174 static QCString          debugStr;
175 static QCString          result; // function result
176 static Argument          *parameter; // element of parameter list
177 static QCString          argType;  // fortran type of an argument of a parameter list
178 static QCString          argName;  // last identifier name in variable list
179 static QCString          initializer;  // initial value of a variable
180 static int               initializerArrayScope;  // number if nested array scopes in initializer
181 static int               initializerScope;  // number if nested function calls in initializer
182 static QCString          useModuleName;  // name of module in the use statement
183 static Protection        defaultProtection;
184 static Protection        typeProtection;
185 static int               typeMode = false;
186 static InterfaceType     ifType = IF_NONE;
187 static bool              functionLine = FALSE;
188
189 static char              stringStartSymbol; // single or double quote
190 static bool              parsingPrototype = FALSE; // see parsePrototype()
191
192 //! Accumulated modifiers of current statement, eg variable declaration.
193 static SymbolModifiers currentModifiers;
194 //! Holds program scope->symbol name->symbol modifiers.
195 static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers;
196
197 //-----------------------------------------------------------------------------
198
199 static int yyread(char *buf,int max_size);
200 static void startCommentBlock(bool);
201 static void handleCommentBlock(const QCString &doc,bool brief);
202 static void subrHandleCommentBlock(const QCString &doc,bool brief);
203 static void addCurrentEntry(int case_insens);
204 static void addModule(const char *name, bool isModule=FALSE);
205 static void addSubprogram(const char *text);
206 static void addInterface(QCString name, InterfaceType type);
207 static Argument *getParameter(const QCString &name);
208 static void scanner_abort();
209
210 static void startScope(Entry *scope);
211 static bool endScope(Entry *scope, bool isGlobalRoot=FALSE);
212 //static bool isTypeName(QCString name);
213 static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root);
214 static int getAmpersandAtTheStart(const char *buf, int length);
215 static int getAmpOrExclAtTheEnd(const char *buf, int length);
216 static void truncatePrepass(int index);
217 static void pushBuffer(QCString &buffer);
218 static void popBuffer();
219 //static void extractPrefix(QCString& text);
220 static QCString extractFromParens(const QCString name);
221 static CommentInPrepass* locatePrepassComment(int from, int to);
222 static void updateVariablePrepassComment(int from, int to);
223 static void newLine();
224
225 //-----------------------------------------------------------------------------
226 #undef  YY_INPUT
227 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
228 #define YY_USER_ACTION yyColNr+=(int)yyleng;
229 //-----------------------------------------------------------------------------
230
231 %}
232
233  //-----------------------------------------------------------------------------
234  //-----------------------------------------------------------------------------
235 IDSYM     [a-z_A-Z0-9]
236 NOTIDSYM  [^a-z_A-Z0-9]
237 SEPARATE  [:, \t]
238 ID        [a-z_A-Z%]+{IDSYM}*
239 ID_       [a-z_A-Z%]*{IDSYM}*
240 PP_ID     {ID}
241 LABELID   [a-z_A-Z]+[a-z_A-Z0-9\-]*
242 SUBPROG   (subroutine|function)
243 B         [ \t]
244 BS        [ \t]*
245 BS_       [ \t]+
246 COMMA     {BS},{BS}
247 ARGS_L0   ("("[^)]*")")
248 ARGS_L1a  [^()]*"("[^)]*")"[^)]*
249 ARGS_L1   ("("{ARGS_L1a}*")")
250 ARGS_L2   "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
251 ARGS      {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
252 NOARGS    {BS}"\n"
253
254 NUM_TYPE  (complex|integer|logical|real)
255 LOG_OPER  (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
256 KIND      {ARGS}
257 CHAR      (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
258 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?)
259
260 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
261 ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE)
262 ACCESS_SPEC (PRIVATE|PUBLIC)
263 LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
264 /* Assume that attribute statements are almost the same as attributes. */
265 ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC}
266
267 CONTAINS  CONTAINS
268 PREFIX    (RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,3}(RECURSIVE|IMPURE|PURE|ELEMENTAL)?
269 SCOPENAME ({ID}{BS}"::"{BS})*
270
271 %option noyywrap
272 %option stack
273 %option caseless
274 /*%option debug */
275
276  //---------------------------------------------------------------------------------
277
278  /** fortran parsing states */
279 %x      Subprog
280 %x      SubprogPrefix
281 %x      Parameterlist
282 %x      SubprogBody
283 %x      SubprogBodyContains
284 %x      Start
285 %x      Comment
286 %x      Module
287 %x      Program
288 %x      ModuleBody
289 %x      ModuleBodyContains
290 %x      AttributeList
291 %x      Variable
292 %x      Initialization
293 %x      ArrayInitializer
294 %x      Typedef
295 %x      TypedefBody
296 %x      TypedefBodyContains
297 %x      InterfaceBody
298 %x      StrIgnore
299 %x      String
300 %x      Use
301 %x      UseOnly
302 %x      ModuleProcedure
303
304 %x      Prepass
305
306  /** comment parsing states */
307 %x      DocBlock
308 %x      DocBackLine
309 %x      EndDoc
310
311 %x      BlockData
312
313 /** prototype parsing */
314 %x      Prototype
315 %x      PrototypeSubprog
316 %x      PrototypeArgs
317
318 %%
319
320  /*-----------------------------------------------------------------------------------*/
321
322 <*>^.*\n                                { // prepass: look for line continuations
323                                           functionLine = FALSE;
324
325                                           DBG_CTX((stderr, "---%s", yytext));
326
327                                             int indexStart = getAmpersandAtTheStart(yytext, (int)yyleng);
328                                             int indexEnd = getAmpOrExclAtTheEnd(yytext, (int)yyleng);
329                                             if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp
330                                               indexEnd=-1;
331
332                                             if(indexEnd<0){ // ----- no ampersand as line continuation
333                                                if(YY_START == Prepass) { // last line in "continuation"
334
335                                                  // Only take input after initial ampersand
336                                                  inputStringPrepass+=(const char*)(yytext+(indexStart+1));
337    
338                                                  //printf("BUFFER:%s\n", (const char*)inputStringPrepass);
339                                                  pushBuffer(inputStringPrepass);
340                                                  yyColNr = 0;                                            
341                                                  yy_pop_state();
342                                                } else { // simple line
343                                                  yyColNr = 0;
344                                                  REJECT;
345                                                }
346
347                                             } else { // ----- line with continuation
348                                               if(YY_START != Prepass) {
349                                                 comments.setAutoDelete(TRUE);
350                                                 comments.clear();
351                                                 yy_push_state(Prepass);
352                                               }
353
354                                               int length = inputStringPrepass.length();
355
356                                               // Only take input after initial ampersand
357                                               inputStringPrepass+=(const char*)(yytext+(indexStart+1));
358                                               lineCountPrepass ++;
359
360                                               // cut off & and remove following comment if present
361                                               truncatePrepass(length+indexEnd-(indexStart+1));
362                                             }
363
364                                         }
365
366
367  /*------ ignore strings that are not initialization strings */ 
368 <*>"\\\\"                               { if (yy_top_state() == Initialization
369                                               || yy_top_state() == ArrayInitializer)
370                                             initializer+=yytext;
371                                         }
372 <*>"\\\""|\\\'                          { if (yy_top_state() == Initialization
373                                               || yy_top_state() == ArrayInitializer)
374                                             initializer+=yytext;
375                                         }
376 <String>\"|\'                           { // string ends with next quote without previous backspace
377                                           if (yytext[0]!=stringStartSymbol) { yyColNr -= (int)yyleng; REJECT; } // single vs double quote
378                                           if (yy_top_state() == Initialization
379                                               || yy_top_state() == ArrayInitializer)
380                                             initializer+=yytext;
381                                           yy_pop_state();
382                                         }           
383 <String>.                               { if (yy_top_state() == Initialization
384                                               || yy_top_state() == ArrayInitializer)
385                                             initializer+=yytext;
386                                         } 
387 <*>\"|\'                                { /* string starts */
388                                           if (YY_START == StrIgnore) { yyColNr -= (int)yyleng; REJECT; }; // ignore in simple comments
389                                           yy_push_state(YY_START);
390                                           if (yy_top_state() == Initialization
391                                               || yy_top_state() == ArrayInitializer)
392                                             initializer+=yytext;
393                                           stringStartSymbol=yytext[0]; // single or double quote
394                                           BEGIN(String);
395                                         }
396
397  /*------ ignore simple comment (not documentation comments) */
398
399 <*>"!"/[^<>\n]                         {  if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
400                                           // skip comment line (without docu comments "!>" "!<" ) 
401                                           /* ignore further "!" and ignore comments in Strings */
402                                           if ((YY_START != StrIgnore) && (YY_START != String)) 
403                                           {
404                                             yy_push_state(YY_START);
405                                             BEGIN(StrIgnore); 
406                                             debugStr="*!";
407                                             DBG_CTX((stderr,"start comment %d\n",yyLineNr));
408                                            }      
409                                         }
410 <StrIgnore>.?/\n                        { yy_pop_state(); // comment ends with endline character
411                                           DBG_CTX((stderr,"end comment %d %s\n",yyLineNr,debugStr.data()));
412                                         } // comment line ends
413 <StrIgnore>.                            { debugStr+=yytext; } 
414
415
416  /*------ use handling ------------------------------------------------------------*/
417
418 <Start,ModuleBody,SubprogBody>"use"{BS_} {
419                                           if(YY_START == Start)
420                                           {
421                                             addModule(NULL); 
422                                             yy_push_state(ModuleBody); //anon program
423                                           }
424                                           yy_push_state(Use);
425                                         }
426 <Use>{ID}                               { 
427                                           DBG_CTX((stderr,"using dir %s\n",yytext));
428                                           current->name=yytext;
429                                           current->fileName = yyFileName; 
430                                           current->section=Entry::USINGDIR_SEC;
431                                           current_root->addSubEntry(current);
432                                           current = new Entry;
433                                           current->lang = SrcLangExt_Fortran; 
434                                           yy_pop_state();
435                                         }
436 <Use>{ID}/,                             { 
437                                           useModuleName=yytext;
438                                         }
439 <Use>,{BS}"ONLY"                        { BEGIN(UseOnly); 
440                                         }           
441 <UseOnly>{BS},{BS}                      {}
442 <UseOnly>{ID}                           {
443                                           current->name= useModuleName+"::"+yytext;
444                                           current->fileName = yyFileName; 
445                                           current->section=Entry::USINGDECL_SEC;
446                                           current_root->addSubEntry(current);
447                                           current = new Entry ;
448                                           current->lang = SrcLangExt_Fortran; 
449                                         }
450 <Use,UseOnly>"\n"                       {
451                                           yyColNr -= 1;
452                                           unput(*yytext);
453                                           yy_pop_state();
454                                         }
455
456  /* INTERFACE definitions */
457 <Start,ModuleBody,SubprogBody>{
458 ^{BS}interface{IDSYM}+                  { /* variable with interface prefix */ }
459 ^{BS}interface                          { ifType = IF_SPECIFIC;
460                                           yy_push_state(InterfaceBody);
461                                           // do not start a scope here, every
462                                           // interface body is a scope of its own
463                                         }
464
465 ^{BS}abstract{BS_}interface             { ifType = IF_ABSTRACT;
466                                           yy_push_state(InterfaceBody);
467                                           // do not start a scope here, every
468                                           // interface body is a scope of its own
469                                         }
470
471 ^{BS}interface{BS_}{ID}{ARGS}?          { ifType = IF_GENERIC;
472                                           yy_push_state(InterfaceBody);
473
474                                           // extract generic name
475                                           QCString name = QCString(yytext).stripWhiteSpace();
476                                           name = name.right(name.length() - 9).stripWhiteSpace().lower();
477                                           addInterface(name, ifType);
478                                           startScope(last_entry);
479                                         }
480 }
481
482 <InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? {
483                                           // end scope only if GENERIC interface
484                                           if (ifType == IF_GENERIC && !endScope(current_root))
485                                             yyterminate();
486
487                                           ifType = IF_NONE;
488                                           yy_pop_state();
489                                         }
490 <InterfaceBody>module{BS}procedure      { yy_push_state(YY_START);
491                                           BEGIN(ModuleProcedure);
492                                         }
493 <ModuleProcedure>{ID}                   { if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
494                                           {
495                                             addInterface(yytext, ifType);
496                                             startScope(last_entry);
497                                           }
498
499                                           current->section = Entry::FUNCTION_SEC ;
500                                           current->name = yytext; 
501                                           moduleProcedures.append(current);
502                                           addCurrentEntry(1);
503                                         }
504 <ModuleProcedure>"\n"                   { yyColNr -= 1;
505                                           unput(*yytext); 
506                                           yy_pop_state();
507                                         }
508 <InterfaceBody>.                        {}
509
510  /*-- Contains handling --*/
511 <Start>^{BS}{CONTAINS}/({BS}|\n|!)      {
512                                           if(YY_START == Start)
513                                           {
514                                             addModule(NULL); 
515                                             yy_push_state(ModuleBodyContains); //anon program
516                                           }                                            
517                                         }
518 <ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!)   { BEGIN(ModuleBodyContains); }
519 <SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!)  { BEGIN(SubprogBodyContains); }
520 <TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!)  { BEGIN(TypedefBodyContains); }
521
522  /*------ module handling ------------------------------------------------------------*/ 
523 <Start>block{BS}data{BS}{ID_}        {  //
524                                          v_type = V_IGNORE;
525                                             yy_push_state(BlockData);
526                                             defaultProtection = Public;
527                                        }
528 <Start>module|program{BS_}             {  //
529                                          v_type = V_IGNORE;
530                                             if(yytext[0]=='m' || yytext[0]=='M')
531                                               yy_push_state(Module);
532                                             else
533                                               yy_push_state(Program);
534                                             defaultProtection = Public;
535                                        }
536 <BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!) { // end block data
537                                             //if (!endScope(current_root))
538                                             //  yyterminate();
539                                             defaultProtection = Public;
540                                             yy_pop_state();
541                                        }
542 <Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module   
543                                             resolveModuleProcedures(moduleProcedures, current_root);
544                                             if (!endScope(current_root))
545                                               yyterminate();
546                                             defaultProtection = Public;
547                                             yy_pop_state();
548                                        }
549 <Module>{ID}                           {  
550                                             addModule(yytext, TRUE);
551                                             BEGIN(ModuleBody);
552                                        }
553
554 <Program>{ID}                           {  
555                                             addModule(yytext, FALSE);
556                                             BEGIN(ModuleBody);
557                                        }
558
559   /*------- access specification --------------------------------------------------------------------------*/
560
561 <ModuleBody>private/{BS}(\n|"!")         { defaultProtection = Private;
562                                            current->protection = defaultProtection ;
563                                          }
564 <ModuleBody>public/{BS}(\n|"!")          { defaultProtection = Public;
565                                            current->protection = defaultProtection ;
566                                          }
567
568  /*------- type definition  -------------------------------------------------------------------------------*/
569
570 <Start,ModuleBody>^{BS}type/[^a-z0-9_]   {
571                                           if(YY_START == Start)
572                                           {
573                                             addModule(NULL); 
574                                             yy_push_state(ModuleBody); //anon program
575                                           }
576
577                                           yy_push_state(Typedef);
578                                           current->protection = defaultProtection;
579                                           typeProtection = defaultProtection;
580                                           typeMode = true;
581                                         }
582 <Typedef>{
583 {COMMA}                                 {}
584
585 {BS}"::"{BS}                            {}
586
587 abstract                                {
588                                           current->spec |= Entry::AbstractClass;
589                                         }
590 extends{ARGS}                           {
591                                           QCString basename = extractFromParens(yytext);
592                                           current->extends->append(new BaseInfo(basename, Public, Normal));
593                                         }
594 public                                  {
595                                           current->protection = Public;
596                                           typeProtection = Public;
597                                         }
598 private                                 {
599                                           current->protection = Private;
600                                           typeProtection = Private;
601                                         }
602 {LANGUAGE_BIND_SPEC}                    {
603                                           /* ignored for now */
604                                         }
605 {ID}                                    { /* type name found */
606                                           current->section = Entry::CLASS_SEC;
607                                           current->spec |= Entry::Struct;
608                                           current->name = yytext;
609                                           current->fileName = yyFileName;
610                                           current->bodyLine  = yyLineNr; 
611
612                                           /* if type is part of a module, mod name is necessary for output */
613                                           if ((current_root) && 
614                                               (current_root->section == Entry::CLASS_SEC
615                                                || current_root->section == Entry::NAMESPACE_SEC))
616                                           {
617                                             current->name = current_root->name + "::" + current->name;
618                                           }
619
620                                           addCurrentEntry(1);
621                                           startScope(last_entry); 
622                                           BEGIN(TypedefBody);
623                                         }
624 }
625
626 <TypedefBodyContains>{                  /* Type Bound Procedures */
627 ^{BS}PROCEDURE{ARGS}?                   {
628                                           current->type = QCString(yytext).simplifyWhiteSpace();
629                                         }
630 ^{BS}final                              {
631                                           current->spec |= Entry::Final;
632                                           current->type = QCString(yytext).simplifyWhiteSpace();
633                                         }
634 ^{BS}generic                            {
635                                           current->type = QCString(yytext).simplifyWhiteSpace();
636                                         }
637 {COMMA}                                 {
638                                         }
639 {ATTR_SPEC}                             {
640                                           currentModifiers |= QCString(yytext);
641                                         }
642 {BS}"::"{BS}                            {
643                                         }
644 {ID}                                    {
645                                           QCString name = yytext;
646                                           modifiers[current_root][name.lower()] |= currentModifiers;
647                                           current->section  = Entry::FUNCTION_SEC;
648                                           current->name     = name;
649                                           current->fileName = yyFileName;
650                                           current->bodyLine = yyLineNr;
651                                           addCurrentEntry(1);
652                                         }
653 {BS}"=>"[^(\n|\!)]*                     { /* Specific bindings come after the ID. */
654                                           last_entry->args = yytext;
655                                         }
656 "\n"                                    {
657                                           currentModifiers = SymbolModifiers();
658                                           newLine();
659                                           docBlock.resize(0);
660                                         }
661 }
662
663
664 <TypedefBody,TypedefBodyContains>{
665 ^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */
666                                           if (!endScope(current_root))
667                                             yyterminate();
668                                           typeMode = false;
669                                           yy_pop_state();
670                                         }
671 }
672
673  /*------- module/global/typedef variable ---------------------------------------------------*/
674
675 <SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {  
676                                            //
677                                            // ABSTRACT and specific interfaces are stored
678                                            // in a scope of their own, even if multiple
679                                            // are group in one INTERFACE/END INTERFACE block.
680                                            //
681                                            if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
682                                              endScope(current_root);
683
684                                            if (!endScope(current_root))
685                                              yyterminate();
686                                            subrCurrent.remove(0u);
687                                            yy_pop_state() ;
688                                         }
689 <BlockData>{
690 {ID}                                    {
691                                         }
692 }
693 <Start,ModuleBody,TypedefBody,SubprogBody>{
694 ^{BS}{TYPE_SPEC}/{SEPARATE}             {
695                                           /* variable declaration starts */
696                                           if(YY_START == Start)
697                                           {
698                                             addModule(NULL); 
699                                             yy_push_state(ModuleBody); //anon program
700                                           }
701                                           argType = QCString(yytext).simplifyWhiteSpace().lower();
702                                           yy_push_state(AttributeList);
703                                         }
704   /*  Dimitri: macro expansion should already be done during preprocessing not here!
705 ^{BS}{PP_ID}{KIND}?                     { // check for preprocessor symbol expand to type
706                                           QCString str = yytext;
707                                           str = str.stripWhiteSpace();
708                                           //DefineDict* defines = getGlobalDefineDict();
709                                           QCString name;
710                                           int index = str.find("(");
711                                           if (index != -1)
712                                             name = str.left(index).stripWhiteSpace();
713                                           else
714                                             name = str;
715
716                                           Define *define = 0; //(*defines)[name];
717                                           if (define != 0 && isTypeName(define->definition)) 
718                                           {
719                                             argType = str;
720                                             yy_push_state(AttributeList);
721                                           } 
722                                           else 
723                                           {
724                                             yyColNr -= (int)yyleng;
725                                             REJECT;
726                                           }
727                                         }
728   */
729 {ATTR_STMT}/{BS_}{ID}                  |
730 {ATTR_STMT}/{BS}"::"                   { 
731                                           /* attribute statement starts */
732                                           DBG_CTX((stderr,"5=========> Attribute statement: %s\n", yytext)); 
733                                           QCString tmp = yytext;
734                                           currentModifiers |= tmp.stripWhiteSpace();
735                                           argType="";
736                                           yy_push_state(YY_START);
737                                           BEGIN( AttributeList ) ;
738                                        }
739 {ID}                                   {
740                                        }  
741 ^{BS}"type"{BS_}"is"/{BS_}             { }
742 ^{BS}"type"{BS}"="                     { }
743 }
744 <AttributeList>{
745 {COMMA}                                 {}
746 {BS}                                    {}
747 {ATTR_SPEC}.                            { /* update current modifierswhen it is an ATTR_SPEC and not a variable name */
748                                           /* bug_625519 */
749                                           QChar chr = yytext[(int)yyleng-1];
750                                           if (chr.isLetter() || chr.isDigit() || (chr == '_'))
751                                           {
752                                             yyColNr -= (int)yyleng;
753                                             REJECT;
754                                           }
755                                           else
756                                           {
757                                             QCString tmp = yytext;
758                                             tmp = tmp.left(tmp.length() - 1);
759                                             yyColNr -= 1;
760                                             unput(yytext[(int)yyleng-1]);
761                                             currentModifiers |= (tmp);
762                                           }
763                                         }
764 "::"                                    { /* end attribute list */
765                                           BEGIN( Variable );
766                                         }
767 .                                       { /* unknown attribute, consider variable name */
768                                           //cout<<"start variables, unput "<<*yytext<<endl;
769                                           yyColNr -= 1;
770                                           unput(*yytext);
771                                           BEGIN( Variable );
772                                         }
773 }
774
775 <Variable>{BS}                          { }
776 <Variable>{ID}                          { /* parse variable declaration */
777                                           //cout << "5=========> got variable: " << argType << "::" << yytext << endl;
778                                           /* work around for bug in QCString.replace (QCString works) */
779                                           QCString name=yytext;
780                                           name = name.lower();
781                                           /* remember attributes for the symbol */
782                                           modifiers[current_root][name.lower()] |= currentModifiers;
783                                           argName= name;
784
785                                           v_type= V_IGNORE;
786                                           if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) 
787                                           { // new variable entry
788                                             v_type = V_VARIABLE;
789                                             current->section = Entry::VARIABLE_SEC;
790                                             current->name = argName;
791                                             current->type = argType;
792                                             current->fileName = yyFileName;
793                                             current->bodyLine  = yyLineNr; // used for source reference
794                                             addCurrentEntry(1);
795                                           } 
796                                           else if (!argType.isEmpty())
797                                           { // declaration of parameter list: add type for corr. parameter 
798                                             parameter = getParameter(argName);
799                                             if (parameter) 
800                                             {
801                                               v_type= V_PARAMETER;
802                                               if (!argType.isNull()) parameter->type=argType.stripWhiteSpace();
803                                               if (!docBlock.isNull()) 
804                                               {
805                                                 subrHandleCommentBlock(docBlock,TRUE);
806                                               }                                     
807                                             }
808                                             // save, it may be function return type
809                                             if (parameter)
810                                             {
811                                               modifiers[current_root][name.lower()].type = argType;
812                                             }
813                                             else
814                                             {
815                                               if ((current_root->name.lower() == argName.lower()) ||
816                                                   (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower()))
817                                               {
818                                                 int strt = current_root->type.find("function");
819                                                 QCString lft;
820                                                 QCString rght;
821                                                 if (strt != -1)
822                                                 {
823                                                   lft = "";
824                                                   rght = "";
825                                                   if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace();
826                                                   if ((current_root->type.length() - strt - strlen("function"))!= 0)
827                                                   {
828                                                     rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace();
829                                                   }
830                                                   current_root->type = lft;
831                                                   if (rght.length() > 0)
832                                                   {
833                                                     if (current_root->type.length() > 0) current_root->type += " ";
834                                                     current_root->type += rght;
835                                                   }
836                                                   if (argType.stripWhiteSpace().length() > 0)
837                                                   {
838                                                     if (current_root->type.length() > 0) current_root->type += " ";
839                                                     current_root->type += argType.stripWhiteSpace();
840                                                   }
841                                                   if (current_root->type.length() > 0) current_root->type += " ";
842                                                   current_root->type += "function";
843                                                 }
844                                                 else
845                                                 {
846                                                   current_root->type += " " + argType.stripWhiteSpace();
847                                                 }
848                                                 current_root->type = current_root->type.stripWhiteSpace();
849                                                 modifiers[current_root][name.lower()].type = current_root->type;
850                                               }
851                                               else
852                                               {
853                                                 modifiers[current_root][name.lower()].type = argType;
854                                               }
855                                             }
856                                             // any accumulated doc for argument should be emptied,
857                                             // because it is handled other way and this doc can be
858                                             // unexpectedly passed to the next member.
859                                             current->doc.resize(0);
860                                             current->brief.resize(0);
861                                           } 
862                                         }
863 <Variable>{ARGS}                        { /* dimension of the previous entry. */
864                                           QCString name(argName);
865                                           QCString attr("dimension");
866                                           attr += yytext;
867                                           modifiers[current_root][name.lower()] |= attr;
868                                         }
869 <Variable>{COMMA}                       { //printf("COMMA: %d<=..<=%d\n", yyColNr-(int)yyleng, yyColNr);
870                                           // locate !< comment
871                                           updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
872                                         }
873 <Variable>{BS}"="                       { yy_push_state(YY_START);
874                                           initializer="=";
875                                           initializerScope = initializerArrayScope = 0;
876                                           BEGIN(Initialization);
877                                         }
878 <Variable>"\n"                          { currentModifiers = SymbolModifiers();
879                                           yy_pop_state(); // end variable declaration list
880                                           newLine();
881                                           docBlock.resize(0);
882                                         }
883 <Variable>";".*"\n"                     { currentModifiers = SymbolModifiers();
884                                           yy_pop_state(); // end variable declaration list
885                                           docBlock.resize(0);
886                                           inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
887                                           yyLineNr--;
888                                           pushBuffer(inputStringSemi);
889                                         }
890 <*>";".*"\n"                            {
891                                           if (YY_START == Variable) REJECT; // Just be on the safe side
892                                           if (YY_START == String) REJECT; // ";" ignored in strings
893                                           if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments
894                                           inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data();
895                                           yyLineNr--;
896                                           pushBuffer(inputStringSemi);
897                                         }
898
899 <Initialization,ArrayInitializer>"["    |
900 <Initialization,ArrayInitializer>"(/"   { initializer+=yytext;
901                                            initializerArrayScope++;
902                                            BEGIN(ArrayInitializer); // initializer may contain comma
903                                         }
904 <ArrayInitializer>"]"                   |
905 <ArrayInitializer>"/)"                  { initializer+=yytext;
906                                            initializerArrayScope--;
907                                            if(initializerArrayScope<=0)
908                                            {
909                                               initializerArrayScope = 0; // just in case
910                                               BEGIN(Initialization);
911                                            }
912                                         }
913 <ArrayInitializer>.                     { initializer+=yytext; }
914 <Initialization>"("                     { initializerScope++;
915                                           initializer+=yytext;
916                                         }
917 <Initialization>")"                     { initializerScope--;
918                                           initializer+=yytext;
919                                         }
920 <Initialization>{COMMA}                 { if (initializerScope == 0)
921                                           {
922                                             updateVariablePrepassComment(yyColNr-(int)yyleng, yyColNr);
923                                             yy_pop_state(); // end initialization
924                                             if (v_type == V_VARIABLE) last_entry->initializer= initializer;
925                                           }
926                                           else
927                                             initializer+=", ";
928                                         }
929 <Initialization>"\n"|"!"                { //|
930                                           yy_pop_state(); // end initialization
931                                           if (v_type == V_VARIABLE) last_entry->initializer= initializer;
932                                           yyColNr -= 1;
933                                           unput(*yytext);
934                                         }
935 <Initialization>.                       { initializer+=yytext; }
936  
937  /*------ fortran subroutine/function handling ------------------------------------------------------------*/
938  /*       Start is initial condition                                                                       */
939  
940 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}({PREFIX}{BS_})?/{SUBPROG}{BS_} {
941                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
942                                          {
943                                            addInterface("$interface$", ifType);
944                                            startScope(last_entry);
945                                          }
946
947                                          // TYPE_SPEC is for old function style function result
948                                          result = QCString(yytext).stripWhiteSpace().lower();
949                                          current->type = result;
950                                          yy_push_state(SubprogPrefix);
951                                        }
952
953 <SubprogPrefix>{BS}{SUBPROG}{BS_}     {
954                                          // Fortran subroutine or function found
955                                          v_type = V_IGNORE;
956                                          result=yytext;
957                                          result=result.stripWhiteSpace();
958                                          addSubprogram(result);
959                                          BEGIN(Subprog);
960                                        }
961
962 <Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} {
963                                          // Fortran subroutine or function found
964                                          v_type = V_IGNORE;
965                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
966                                          {
967                                            addInterface("$interface$", ifType);
968                                            startScope(last_entry);
969                                          }
970
971                                          result = QCString(yytext).stripWhiteSpace();
972                                          addSubprogram(result);
973                                          yy_push_state(Subprog);
974                                        }
975
976 <Subprog>{BS}                          {   /* ignore white space */   }
977 <Subprog>{ID}                          { current->name = yytext;
978                                          //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl;
979                                          modifiers[current_root][current->name.lower()].returnName = current->name.lower();
980
981                                          if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC)
982                                          {
983                                            current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
984                                          }
985
986                                          BEGIN(Parameterlist);
987                                        }
988 <Parameterlist>"("                     { current->args = "("; }
989 <Parameterlist>")"                     {
990                                          current->args += ")";
991                                          current->args = removeRedundantWhiteSpace(current->args);
992                                          addCurrentEntry(1);
993                                          startScope(last_entry);
994                                          BEGIN(SubprogBody);
995                                        }
996 <Parameterlist>{COMMA}|{BS}            { current->args += yytext;
997                                          CommentInPrepass *c = locatePrepassComment(yyColNr-(int)yyleng, yyColNr);
998                                          if (c!=NULL) {
999                                            if(current->argList->count()>0) {
1000                                              current->argList->at(current->argList->count()-1)->docs = c->str;
1001                                            }
1002                                          }                       
1003                                        }
1004 <Parameterlist>{ID}                    {
1005                                            //current->type not yet available
1006                                            QCString param = yytext;
1007                                            // std::cout << "3=========> got parameter " << param << std::endl;
1008                                            current->args += param;
1009                                            Argument *arg = new Argument;
1010                                            arg->name = param;
1011                                            arg->type = "";
1012                                            current->argList->append(arg);
1013                                        } 
1014 <Parameterlist>{NOARGS}                {   
1015                                            newLine();
1016                                            //printf("3=========> without parameterlist \n");
1017                                            //current->argList = ;
1018                                            addCurrentEntry(1);
1019                                            startScope(last_entry);
1020                                            BEGIN(SubprogBody);                                     
1021 }
1022 <SubprogBody>result{BS}\({BS}{ID}      {  
1023                                            if (functionLine)
1024                                            {
1025                                              result= yytext;
1026                                              result= result.right(result.length()-result.find("(")-1);
1027                                              result= result.stripWhiteSpace();
1028                                              modifiers[current_root->parent()][current_root->name.lower()].returnName = result;
1029                                            }
1030                                            //cout << "=====> got result " <<  result << endl;
1031                                        } 
1032
1033  /*---- documentation comments --------------------------------------------------------------------*/
1034
1035 <Variable,SubprogBody,ModuleBody,TypedefBody,TypedefBodyContains>"!<"  { /* backward docu comment */
1036                                           if (v_type != V_IGNORE) {
1037                                            current->docLine  = yyLineNr;
1038                                            docBlockJavaStyle = FALSE;
1039                                            docBlock.resize(0);
1040                                            docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
1041                                            startCommentBlock(TRUE);
1042                                            yy_push_state(DocBackLine);
1043                                           }
1044                                           else
1045                                           {
1046                                             /* handle out of place !< comment as a normal comment */
1047                                             if (YY_START == String) { yyColNr -= (int)yyleng; REJECT; } // "!" is ignored in strings
1048                                             // skip comment line (without docu comments "!>" "!<" ) 
1049                                             /* ignore further "!" and ignore comments in Strings */
1050                                             if ((YY_START != StrIgnore) && (YY_START != String)) 
1051                                             {
1052                                               yy_push_state(YY_START);
1053                                               BEGIN(StrIgnore); 
1054                                               debugStr="*!";
1055                                               //fprintf(stderr,"start comment %d\n",yyLineNr);
1056                                             }      
1057                                           }
1058                                          }
1059 <DocBackLine>.*                          { // contents of current comment line
1060                                           docBlock+=yytext;
1061                                         }
1062 <DocBackLine>"\n"{BS}"!"("<"|"!"+)              { // comment block (next line is also comment line)
1063                                           docBlock+="\n"; // \n is necessary for lists
1064                                           newLine();
1065                                         }
1066 <DocBackLine>"\n"                               { // comment block ends at the end of this line
1067                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1068                                           yyColNr -= 1;
1069                                           unput(*yytext);                                        
1070                                           if (v_type == V_VARIABLE) 
1071                                           {
1072                                             Entry *tmp_entry = current; 
1073                                             current = last_entry; // temporarily switch to the previous entry
1074                                             handleCommentBlock(docBlock,TRUE);
1075                                             current=tmp_entry;
1076                                           }
1077                                           else if (v_type == V_PARAMETER) 
1078                                           {
1079                                             subrHandleCommentBlock(docBlock,TRUE);
1080                                           }
1081                                           yy_pop_state();
1082                                           docBlock.resize(0);
1083                                         }
1084
1085 <Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains>"!>"  {
1086                                           yy_push_state(YY_START);
1087                                           current->docLine  = yyLineNr;
1088                                           docBlockJavaStyle = FALSE;
1089                                           if (YY_START==SubprogBody) docBlockInBody = TRUE;
1090                                           docBlock.resize(0);
1091                                           docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF");
1092                                           startCommentBlock(TRUE);
1093                                           BEGIN(DocBlock);
1094                                           //cout << "start DocBlock " << endl;
1095                                         }
1096
1097 <DocBlock>.*                            { // contents of current comment line
1098                                           docBlock+=yytext;
1099                                         }
1100 <DocBlock>"\n"{BS}"!"(">"|"!"+)         { // comment block (next line is also comment line)
1101                                           docBlock+="\n"; // \n is necessary for lists
1102                                           newLine();
1103                                         }
1104 <DocBlock>"\n"                          { // comment block ends at the end of this line
1105                                           //cout <<"3=========> comment block : "<< docBlock << endl;
1106                                           yyColNr -= 1;
1107                                           unput(*yytext);                                        
1108                                           handleCommentBlock(docBlock,TRUE);
1109                                           yy_pop_state();                                          
1110                                         }
1111
1112  /*-----Prototype parsing -------------------------------------------------------------------------*/
1113 <Prototype>{BS}{SUBPROG}{BS_}           {
1114                                           BEGIN(PrototypeSubprog);
1115                                         }
1116 <Prototype,PrototypeSubprog>{BS}{SCOPENAME}?{BS}{ID} { 
1117                                           current->name = QCString(yytext).lower();
1118                                           current->name.stripWhiteSpace();
1119                                           BEGIN(PrototypeArgs);
1120                                         }
1121 <PrototypeArgs>{
1122 "("|")"|","|{BS_}                       { current->args += yytext; }
1123 {ID}                                    { current->args += yytext; 
1124                                           Argument *a = new Argument;
1125                                           a->name = QCString(yytext).lower();
1126                                           current->argList->append(a);
1127                                         }
1128 }
1129
1130  /*------------------------------------------------------------------------------------------------*/
1131
1132 <*>"\n"                                 {
1133                                           newLine();
1134                                           //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl;
1135                                           debugStr="";
1136                                         }
1137
1138
1139  /*---- error: EOF in wrong state --------------------------------------------------------------------*/
1140
1141 <*><<EOF>>                              {
1142                                           if (parsingPrototype) {
1143                                             yyterminate();
1144
1145                                           } else if ( include_stack_ptr <= 0 ) {
1146                                             if (YY_START!=INITIAL && YY_START!=Start) {
1147                                               DBG_CTX((stderr,"==== Error: EOF reached in wrong state (end missing)"));
1148                                               scanner_abort();
1149                                             }
1150                                             yyterminate();
1151                                           } else {
1152                                             popBuffer();
1153                                           }
1154                                         }
1155 <*>{LOG_OPER}                           { // Fortran logical comparison keywords
1156                                         }
1157 <*>.                                    {
1158                                           //debugStr+=yytext;
1159                                           //printf("I:%c\n", *yytext);
1160                                         } // ignore remaining text 
1161
1162  /**********************************************************************************/
1163  /**********************************************************************************/
1164  /**********************************************************************************/
1165 %%
1166 //----------------------------------------------------------------------------
1167
1168 #if 0
1169 static void extractPrefix(QCString &text) 
1170 {
1171   int prefixIndex = 0;
1172   int curIndex = 0;
1173   bool cont = TRUE;
1174   const char* pre[] = {"RECURSIVE","IMPURE","PURE","ELEMENTAL"};
1175   while(cont)
1176   {
1177     cont = FALSE;
1178     for(unsigned int i=0; i<4; i++)
1179     {
1180       if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0)
1181       {
1182         text.remove(0,strlen(pre[i]));
1183         text.stripWhiteSpace();
1184         cont = TRUE;
1185       }
1186     }
1187   }
1188 }
1189 #endif
1190
1191 static void newLine() {
1192   yyLineNr++;
1193   yyLineNr+=lineCountPrepass;
1194   lineCountPrepass=0;
1195   comments.clear();
1196 }
1197
1198 static CommentInPrepass* locatePrepassComment(int from, int to) {
1199   //printf("Locate %d-%d\n", from, to);
1200   for(uint i=0; i<comments.count(); i++) { // todo: optimize
1201     int c = comments.at(i)->column;
1202     //printf("Candidate %d\n", c);
1203     if (c>=from && c<=to) {
1204       // comment for previous variable or parameter
1205       return comments.at(i);
1206     }
1207   }
1208   return NULL;
1209 }
1210
1211 static void updateVariablePrepassComment(int from, int to) {
1212   CommentInPrepass *c = locatePrepassComment(from, to);
1213   if (c!=NULL && v_type == V_VARIABLE) {
1214     last_entry->brief = c->str;
1215   } else if (c!=NULL && v_type == V_PARAMETER) {
1216     Argument *parameter = getParameter(argName);
1217     if (parameter) parameter->docs = c->str;
1218   }
1219 }
1220
1221 static int getAmpersandAtTheStart(const char *buf, int length)
1222 {
1223   for(int i=0; i<length; i++) {
1224     switch(buf[i]) {
1225       case ' ':
1226       case '\t':
1227         break;
1228       case '&':
1229         return i;
1230       default:
1231         return -1;
1232     }
1233   }
1234   return -1;
1235 }
1236
1237 /* Returns ampersand index, comment start index or -1 if neither exist.*/ 
1238 static int getAmpOrExclAtTheEnd(const char *buf, int length)
1239 {
1240   // Avoid ampersands in string and comments
1241   int parseState = Start;
1242   char quoteSymbol = 0;
1243   int ampIndex = -1;
1244   int commentIndex = -1;
1245
1246   for(int i=0; i<length && parseState!=Comment; i++)
1247   {
1248     // When in string, skip backslashes
1249     // Legacy code, not sure whether this is correct?
1250     if(parseState==String)
1251     {
1252       if(buf[i]=='\\') i++;
1253     }
1254
1255     switch(buf[i])
1256     {
1257         case '\'':
1258         case '"':
1259           // Close string, if quote symbol matches.
1260           // Quote symbol is set iff parseState==String
1261           if(buf[i]==quoteSymbol)
1262           {
1263              parseState = Start;
1264              quoteSymbol = 0;
1265           }
1266           // Start new string, if not already in string or comment
1267           else if(parseState==Start)
1268           {
1269             parseState = String;
1270             quoteSymbol = buf[i];
1271           }
1272           ampIndex = -1; // invalidate prev ampersand
1273           break;
1274         case '!':
1275           // When in string or comment, ignore exclamation mark
1276           if(parseState==Start)
1277           {
1278             parseState = Comment;
1279             commentIndex = i;
1280           }
1281           break;
1282         case ' ':  // ignore whitespace
1283         case '\t':
1284         case '\n': // this may be at the end of line
1285           break;
1286         case '&':
1287           ampIndex = i;
1288           break;
1289         default:
1290           ampIndex = -1; // invalidate prev ampersand
1291     }
1292   }
1293
1294   if (ampIndex>=0)
1295     return ampIndex;
1296   else
1297    return commentIndex;
1298 }
1299
1300 /* Although comments at the end of continuation line are grabbed by this function,
1301 * we still do not know how to use them later in parsing.
1302 */
1303 void truncatePrepass(int index)
1304 {
1305   int length = inputStringPrepass.length();
1306   for (int i=index+1; i<length; i++) {
1307     if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment 
1308       struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2));
1309       comments.append(c);
1310     }
1311   }
1312   inputStringPrepass.truncate(index);
1313 }
1314
1315 // simplified way to know if this is fixed form
1316 // duplicate in fortrancode.l
1317 static bool recognizeFixedForm(const char* contents, FortranFormat format)
1318 {
1319   int column=0;
1320   bool skipLine=FALSE;
1321
1322   if (format == FortranFormat_Fixed) return TRUE;
1323   if (format == FortranFormat_Free)  return FALSE;
1324
1325   for(int i=0;;i++) {
1326     column++;
1327
1328     switch(contents[i]) {
1329       case '\n':
1330         column=0;
1331         skipLine=FALSE;
1332         break;
1333       case ' ':
1334         break;
1335       case '\000':
1336         return FALSE;
1337       case '#':
1338         skipLine=TRUE;
1339         break;
1340       case 'C':
1341       case 'c':
1342       case '*':
1343         if(column==1) return TRUE;
1344         if(skipLine) break;
1345         return FALSE;
1346       case '!':
1347         if(column>1 && column<7) return FALSE;
1348         skipLine=TRUE;
1349         break;
1350       default:
1351         if(skipLine) break;
1352         if(column==7) return TRUE;
1353         return FALSE;
1354     }
1355   }
1356   return FALSE;
1357 }
1358
1359 /* This function assumes that contents has at least size=length+1 */
1360 static void insertCharacter(char *contents, int length, int pos, char c)
1361 {
1362   // shift tail by one character
1363   for(int i=length; i>pos; i--)
1364     contents[i]=contents[i-1];
1365   // set the character
1366   contents[pos] = c;
1367 }
1368
1369 /* change comments and bring line continuation character to previous line */
1370 static const char* prepassFixedForm(const char* contents)
1371 {
1372   int column=0;
1373   int prevLineLength=0;
1374   int prevLineAmpOrExclIndex=-1;
1375   bool emptyLabel=TRUE;
1376   int newContentsSize = strlen(contents)+3; // \000, \n (when necessary) and one spare character (to avoid reallocation)
1377   char* newContents = (char*)malloc(newContentsSize);
1378
1379   for(int i=0, j=0;;i++,j++) {
1380     if(j>=newContentsSize-1) { // check for one spare character, which may be eventually used below (by &)
1381       newContents = (char*)realloc(newContents, newContentsSize+1000);
1382       newContentsSize = newContentsSize+1000;
1383     }
1384
1385     column++;
1386     char c = contents[i];
1387     switch(c) {
1388       case '\n':
1389         prevLineLength=column;
1390         prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength);
1391         column=0;
1392         emptyLabel=TRUE;
1393         newContents[j]=c;
1394         break;
1395       case ' ':
1396         newContents[j]=c;
1397         break;
1398       case '\000':
1399         newContents[j]='\000';
1400         newContentsSize = strlen(newContents);
1401         if (newContents[newContentsSize - 1] != '\n')
1402         {
1403           // to be on the safe side
1404           newContents = (char*)realloc(newContents, newContentsSize+2);
1405           newContents[newContentsSize] = '\n';
1406           newContents[newContentsSize + 1] = '\000';
1407         }
1408         return newContents;
1409       case 'C':
1410       case 'c':
1411       case '*':
1412         if (column!=6)
1413         {
1414           emptyLabel=FALSE;
1415           if(column==1)
1416             newContents[j]='!';
1417           else
1418             newContents[j]=c;
1419           break;
1420         }
1421       default:
1422         if(column==6 && emptyLabel) { // continuation
1423           if (c != '0') { // 0 not allowed as continuatioin character, see f95 standard paragraph 3.3.2.3
1424             newContents[j]=' ';
1425
1426             if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line
1427               insertCharacter(newContents, j+1, (j+1)-6-1, '&');
1428               j++;
1429             } else { // add & just before end of previous line comment
1430               insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&');
1431               j++;
1432             }
1433           } else {
1434             newContents[j]=c; // , just handle like space
1435           }
1436         } else {
1437           newContents[j]=c;
1438           emptyLabel=FALSE;
1439         }
1440         break;
1441     }
1442   }
1443
1444   newContentsSize = strlen(newContents);
1445   if (newContents[newContentsSize - 1] != '\n')
1446   {
1447     // to be on the safe side
1448     newContents = (char*)realloc(newContents, newContentsSize+2);
1449     newContents[newContentsSize] = '\n';
1450     newContents[newContentsSize + 1] = '\000';
1451   }
1452   return newContents;
1453 }
1454
1455 static void pushBuffer(QCString& buffer)
1456 {
1457   if (include_stack_cnt <= include_stack_ptr)
1458   {
1459      include_stack_cnt++;
1460      include_stack = (YY_BUFFER_STATE *)realloc(include_stack, include_stack_cnt * sizeof(YY_BUFFER_STATE));
1461   }
1462   include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
1463   yy_switch_to_buffer(yy_scan_string(buffer));
1464
1465   DBG_CTX((stderr, "--PUSH--%s", (const char *)buffer));
1466   buffer = NULL;
1467 }
1468
1469 static void popBuffer() {
1470   DBG_CTX((stderr, "--POP--"));
1471   include_stack_ptr --;
1472   yy_delete_buffer( YY_CURRENT_BUFFER );
1473   yy_switch_to_buffer( include_stack[include_stack_ptr] );
1474 }
1475
1476 /** used to copy entry to an interface module procedure */
1477 static void copyEntry(Entry *dest, Entry *src) 
1478 {
1479    dest->type     = src->type;
1480    dest->fileName = src->fileName;
1481    dest->bodyLine = src->bodyLine;
1482    dest->args     = src->args;
1483    dest->argList  = new ArgumentList(*src->argList);
1484    dest->doc      = src->doc;
1485    dest->brief    = src->brief;
1486 }
1487
1488 /** fill empty interface module procedures with info from 
1489     corresponding module subprogs 
1490     @TODO: handle procedures in used modules
1491 */
1492 void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root)
1493 {
1494   if (moduleProcedures.isEmpty()) return;
1495  
1496   EntryListIterator eli1(moduleProcedures);
1497   // for all module procedures
1498   for (Entry *ce1; (ce1=eli1.current()); ++eli1) 
1499   {
1500     // check all entries in this module
1501     EntryListIterator eli2(*current_root->children());
1502     for (Entry *ce2; (ce2=eli2.current()); ++eli2) 
1503     {
1504       if (ce1->name == ce2->name) 
1505       {
1506         copyEntry(ce1, ce2);
1507       }
1508     } // for procedures in current module
1509   } // for all interface module procedures
1510   moduleProcedures.clear();
1511 }
1512
1513 #if 0
1514 static bool isTypeName(QCString name)
1515 {
1516   name = name.lower();
1517   return name=="integer" || name == "real" || 
1518          name=="complex" || name == "logical";
1519 }
1520 #endif
1521
1522 /*! Extracts string which resides within parentheses of provided string. */
1523 static QCString extractFromParens(const QCString name)
1524 {
1525   QCString extracted = name;
1526   int start = extracted.find("(");
1527   if (start != -1) 
1528   {
1529     extracted.remove(0, start+1);
1530   }
1531   int end = extracted.findRev(")");
1532   if (end != -1) 
1533   {
1534     int length = extracted.length();
1535     extracted.remove(end, length);
1536   }
1537   extracted = extracted.stripWhiteSpace();
1538
1539   return extracted;
1540 }
1541
1542 /*! Adds passed modifiers to these modifiers.*/
1543 SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs)
1544 {
1545   if (mdfs.protection!=NONE_P) protection = mdfs.protection;
1546   if (mdfs.direction!=NONE_D) direction = mdfs.direction;
1547   optional |= mdfs.optional;
1548   if (!mdfs.dimension.isNull()) dimension = mdfs.dimension;
1549   allocatable |= mdfs.allocatable;
1550   external |= mdfs.external;
1551   intrinsic |= mdfs.intrinsic;
1552   protect |= mdfs.protect;
1553   parameter |= mdfs.parameter;
1554   pointer |= mdfs.pointer;
1555   target |= mdfs.target;
1556   save |= mdfs.save;
1557   deferred |= mdfs.deferred;
1558   nonoverridable |= mdfs.nonoverridable;
1559   nopass |= mdfs.nopass;
1560   pass |= mdfs.pass;
1561   passVar = mdfs.passVar;
1562   return *this;
1563 }
1564
1565 /*! Extracts  and adds passed modifier to these modifiers.*/
1566 SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString)
1567 {
1568   mdfString = mdfString.lower();
1569   SymbolModifiers newMdf;
1570
1571   if (mdfString.find("dimension")==0) 
1572   {
1573     newMdf.dimension=mdfString;
1574   }
1575   else if (mdfString.contains("intent")) 
1576   {
1577     QCString tmp = extractFromParens(mdfString);
1578     bool isin = tmp.contains("in");
1579     bool isout = tmp.contains("out");
1580     if (isin && isout) newMdf.direction = SymbolModifiers::INOUT;
1581     else if (isin) newMdf.direction = SymbolModifiers::IN;
1582     else if (isout) newMdf.direction = SymbolModifiers::OUT;
1583   }
1584   else if (mdfString=="public") 
1585   {
1586     newMdf.protection = SymbolModifiers::PUBLIC;
1587   }
1588   else if (mdfString=="private") 
1589   {
1590     newMdf.protection = SymbolModifiers::PRIVATE;
1591   }
1592   else if (mdfString=="protected") 
1593   {
1594     newMdf.protect = TRUE;
1595   }
1596   else if (mdfString=="optional") 
1597   {
1598     newMdf.optional = TRUE;
1599   }
1600   else if (mdfString=="allocatable") 
1601   {
1602     newMdf.allocatable = TRUE;
1603   }
1604   else if (mdfString=="external") 
1605   {
1606     newMdf.external = TRUE;
1607   }
1608   else if (mdfString=="intrinsic") 
1609   {
1610     newMdf.intrinsic = TRUE;
1611   }
1612   else if (mdfString=="parameter") 
1613   {
1614     newMdf.parameter = TRUE;
1615   }
1616   else if (mdfString=="pointer") 
1617   {
1618     newMdf.pointer = TRUE;
1619   }
1620   else if (mdfString=="target") 
1621   {
1622     newMdf.target = TRUE;
1623   }
1624   else if (mdfString=="save") 
1625   {
1626     newMdf.save = TRUE;
1627   }
1628   else if (mdfString=="nopass")
1629   {
1630     newMdf.nopass = TRUE;
1631   }
1632   else if (mdfString=="deferred")
1633   {
1634     newMdf.deferred = TRUE;
1635   }
1636   else if (mdfString=="non_overridable")
1637   {
1638     newMdf.nonoverridable = TRUE;
1639   }
1640   else if (mdfString.contains("pass"))
1641   {
1642     newMdf.pass = TRUE;
1643     if (mdfString.contains("("))
1644       newMdf.passVar = extractFromParens(mdfString);
1645     else
1646       newMdf.passVar = "";
1647   }
1648
1649   (*this) |= newMdf;
1650   return *this;
1651 }
1652
1653 /*! For debugging purposes. */
1654 //ostream& operator<<(ostream& out, const SymbolModifiers& mdfs)
1655 //{
1656 //  out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<<
1657 //    ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<<
1658 //    ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic;
1659 //
1660 //  return out;
1661 //}
1662
1663 /*! Find argument with given name in \a subprog entry. */
1664 static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE)
1665 {
1666   QCString cname(name.lower());
1667   for (unsigned int i=0; i<subprog->argList->count(); i++) 
1668   {
1669     Argument *arg = subprog->argList->at(i);
1670     if ((!byTypeName && arg->name.lower() == cname) ||
1671         (byTypeName && arg->type.lower() == cname)
1672        )
1673     {
1674       return arg;
1675     }
1676   }
1677   return 0;
1678 }
1679
1680 /*! Find function with given name in \a entry. */
1681 #if 0
1682 static Entry *findFunction(Entry* entry, QCString name)
1683 {
1684   QCString cname(name.lower());
1685
1686   EntryListIterator eli(*entry->children());
1687   Entry *ce;
1688   for (;(ce=eli.current());++eli) 
1689   {
1690     if (ce->section != Entry::FUNCTION_SEC)
1691       continue;
1692
1693     if (ce->name.lower() == cname)
1694       return ce;
1695   }
1696
1697   return 0;
1698 }
1699 #endif
1700
1701 /*! Apply modifiers stored in \a mdfs to the \a typeName string. */
1702 static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs) 
1703 {
1704   if (!mdfs.dimension.isNull()) 
1705   {
1706     if (!typeName.isEmpty()) typeName += ", ";
1707     typeName += mdfs.dimension;
1708   }
1709   if (mdfs.direction!=SymbolModifiers::NONE_D) 
1710   {
1711     if (!typeName.isEmpty()) typeName += ", ";
1712     typeName += directionStrs[mdfs.direction];
1713   }
1714   if (mdfs.optional) 
1715   {
1716     if (!typeName.isEmpty()) typeName += ", ";
1717     typeName += "optional";
1718   }
1719   if (mdfs.allocatable) 
1720   {
1721     if (!typeName.isEmpty()) typeName += ", ";
1722     typeName += "allocatable";
1723   }
1724   if (mdfs.external) 
1725   {
1726     if (!typeName.isEmpty()) typeName += ", ";
1727     typeName += "external";
1728   }
1729   if (mdfs.intrinsic) 
1730   {
1731     if (!typeName.isEmpty()) typeName += ", ";
1732     typeName += "intrinsic";
1733   }
1734   if (mdfs.parameter) 
1735   {
1736     if (!typeName.isEmpty()) typeName += ", ";
1737     typeName += "parameter";
1738   }
1739   if (mdfs.pointer) 
1740   {
1741     if (!typeName.isEmpty()) typeName += ", ";
1742     typeName += "pointer";
1743   }
1744   if (mdfs.target) 
1745   {
1746     if (!typeName.isEmpty()) typeName += ", ";
1747     typeName += "target";
1748   }
1749   if (mdfs.save) 
1750   {
1751     if (!typeName.isEmpty()) typeName += ", ";
1752     typeName += "save";
1753   }
1754   if (mdfs.deferred) 
1755   {
1756     if (!typeName.isEmpty()) typeName += ", ";
1757     typeName += "deferred";
1758   }
1759   if (mdfs.nonoverridable) 
1760   {
1761     if (!typeName.isEmpty()) typeName += ", ";
1762     typeName += "non_overridable";
1763   }
1764   if (mdfs.nopass) 
1765   {
1766     if (!typeName.isEmpty()) typeName += ", ";
1767     typeName += "nopass";
1768   }
1769   if (mdfs.pass) 
1770   {
1771     if (!typeName.isEmpty()) typeName += ", ";
1772     typeName += "pass";
1773     if (!mdfs.passVar.isEmpty())
1774       typeName += "(" + mdfs.passVar + ")";
1775   }
1776   if (mdfs.protection == SymbolModifiers::PUBLIC)
1777   {
1778     if (!typeName.isEmpty()) typeName += ", ";
1779     typeName += "public";
1780   }
1781   else if (mdfs.protection == SymbolModifiers::PRIVATE)
1782   {
1783     if (!typeName.isEmpty()) typeName += ", ";
1784     typeName += "private";
1785   }
1786   if (mdfs.protect)
1787   {
1788     if (!typeName.isEmpty()) typeName += ", ";
1789     typeName += "protected";
1790   }
1791
1792   return typeName;
1793 }
1794
1795 /*! Apply modifiers stored in \a mdfs to the \a arg argument. */
1796 static void applyModifiers(Argument *arg, SymbolModifiers& mdfs)
1797 {
1798   QCString tmp = arg->type;
1799   arg->type = applyModifiers(tmp, mdfs);
1800 }
1801
1802 /*! Apply modifiers stored in \a mdfs to the \a ent entry. */
1803 static void applyModifiers(Entry *ent, SymbolModifiers& mdfs)
1804 {
1805   QCString tmp = ent->type;
1806   ent->type = applyModifiers(tmp, mdfs);
1807
1808   if (mdfs.protection == SymbolModifiers::PUBLIC)
1809     ent->protection = Public;
1810   else if (mdfs.protection == SymbolModifiers::PRIVATE)
1811     ent->protection = Private;
1812 }
1813
1814 /*! Starts the new scope in fortran program. Consider using this function when
1815  * starting module, interface, function or other program block.
1816  * \see endScope()
1817  */
1818 static void startScope(Entry *scope) 
1819 {
1820   //cout<<"start scope: "<<scope->name<<endl;
1821   current_root= scope; /* start substructure */
1822
1823   QMap<QCString,SymbolModifiers> mdfMap;
1824   modifiers.insert(scope, mdfMap);
1825 }
1826
1827 /*! Ends scope in fortran program: may update subprogram arguments or module variable attributes.
1828  * \see startScope()
1829  */
1830 static bool endScope(Entry *scope, bool isGlobalRoot)
1831 {
1832   //cout<<"end scope: "<<scope->name<<endl;
1833   if (current_root->parent() || isGlobalRoot)
1834   {
1835     current_root= current_root->parent(); /* end substructure */
1836   }
1837   else 
1838   {
1839     fprintf(stderr,"parse error in end <scopename>");
1840     scanner_abort();
1841     return FALSE;
1842   }
1843
1844   // update variables or subprogram arguments with modifiers
1845   QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope];
1846
1847   if (scope->section == Entry::FUNCTION_SEC) 
1848   {
1849     // iterate all symbol modifiers of the scope
1850     for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) 
1851     {
1852       //cout<<it.key()<<": "<<it.data()<<endl;
1853       Argument *arg = findArgument(scope, it.key());
1854
1855       if (arg)
1856         applyModifiers(arg, it.data());
1857     }
1858
1859     // find return type for function
1860     //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl;
1861     QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower();
1862     if (modifiers[scope].contains(returnName)) 
1863     {
1864       scope->type = modifiers[scope][returnName].type; // returning type works
1865       applyModifiers(scope, modifiers[scope][returnName]); // returning array works
1866     }
1867
1868   } 
1869   if (scope->section == Entry::CLASS_SEC) 
1870   { // was INTERFACE_SEC
1871     if (scope->parent()->section == Entry::FUNCTION_SEC) 
1872     { // interface within function
1873       // iterate functions of interface and 
1874       // try to find types for dummy(ie. argument) procedures.
1875       //cout<<"Search in "<<scope->name<<endl;
1876       EntryListIterator eli(*scope->children());
1877       Entry *ce;
1878       int count = 0;
1879       int found = FALSE;
1880       for (;(ce=eli.current());++eli) 
1881       {
1882         count++;
1883         if (ce->section != Entry::FUNCTION_SEC)
1884           continue;
1885
1886         Argument *arg = findArgument(scope->parent(), ce->name, TRUE);
1887         if (arg != 0) 
1888         {
1889           // set type of dummy procedure argument to interface
1890           arg->name = arg->type;
1891           arg->type = scope->name;
1892         }
1893         if (ce->name.lower() == scope->name.lower()) found = TRUE;
1894       }
1895       if ((count == 1) && found)
1896       {
1897         // clear all modifiers of the scope
1898         modifiers.remove(scope);
1899         delete scope->parent()->removeSubEntry(scope);
1900         scope = 0;
1901         return TRUE;
1902       }
1903     }
1904   } 
1905   if (scope->section!=Entry::FUNCTION_SEC) 
1906   { // not function section 
1907     // iterate variables: get and apply modifiers
1908     EntryListIterator eli(*scope->children());
1909     Entry *ce;
1910     for (;(ce=eli.current());++eli) 
1911     {
1912       if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC)
1913         continue;
1914
1915       //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
1916       if (mdfsMap.contains(ce->name.lower()))
1917         applyModifiers(ce, mdfsMap[ce->name.lower()]);
1918     }
1919   }
1920
1921   // clear all modifiers of the scope
1922   modifiers.remove(scope);
1923
1924   return TRUE;
1925 }
1926
1927 #if 0
1928 //! Return full name of the entry. Sometimes we must combine several names recursively.
1929 static QCString getFullName(Entry *e) 
1930 {
1931   QCString name = e->name;
1932   if (e->section == Entry::CLASS_SEC //  || e->section == Entry::INTERFACE_SEC
1933      || !e->parent() || e->parent()->name.isEmpty())
1934     return name;
1935
1936   return getFullName(e->parent())+"::"+name;
1937 }
1938 #endif
1939
1940 static int yyread(char *buf,int max_size)
1941 {
1942   int c=0;
1943
1944   while ( c < max_size && inputString[inputPosition] )
1945   {
1946     *buf = inputString[inputPosition++] ;
1947     c++; buf++;
1948   }
1949   return c;
1950 }
1951
1952 static void initParser()
1953 {
1954   last_entry = 0;
1955 }
1956
1957 static void initEntry()
1958 {
1959   if (typeMode)
1960   {
1961     current->protection = typeProtection;
1962   }
1963   else
1964   {
1965     current->protection = defaultProtection;
1966   }
1967   current->mtype      = mtype;
1968   current->virt       = virt;
1969   current->stat       = gstat;
1970   current->lang       = SrcLangExt_Fortran; 
1971   initGroupInfo(current);
1972 }
1973
1974 /**
1975   adds current entry to current_root and creates new current
1976 */
1977 static void addCurrentEntry(int case_insens)
1978 {
1979   if (case_insens) current->name = current->name.lower();
1980   //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data());
1981   current_root->addSubEntry(current);
1982   last_entry = current;
1983   current = new Entry ;
1984   initEntry();
1985 }
1986
1987 static int max(int a, int b) {return a>b?a:b;}
1988
1989 static void addModule(const char *name, bool isModule)
1990 {
1991   DBG_CTX((stderr, "0=========> got module %s\n", name));
1992
1993   if (isModule)
1994     current->section = Entry::CLASS_SEC;
1995   else
1996     current->section = Entry::FUNCTION_SEC;
1997
1998   if (name!=NULL)
1999   {
2000     current->name = name;
2001   } 
2002   else
2003   {
2004     QCString fname = yyFileName;
2005     int index = max(fname.findRev('/'), fname.findRev('\\'));
2006     fname = fname.right(fname.length()-index-1);
2007     fname = fname.prepend("__").append("__");
2008     current->name = fname;
2009   }
2010   current->type = "program";
2011   current->fileName  = yyFileName;
2012   current->bodyLine  = yyLineNr; // used for source reference
2013   current->protection = Public ;
2014   addCurrentEntry(1);
2015   startScope(last_entry);
2016 }
2017
2018
2019 static void addSubprogram(const char *text)
2020 {
2021   DBG_CTX((stderr,"1=========> got subprog, type: %s\n",text)); 
2022   subrCurrent.prepend(current);
2023   current->section = Entry::FUNCTION_SEC ;
2024   QCString subtype = text; subtype=subtype.lower().stripWhiteSpace();
2025   functionLine = (subtype.find("function") != -1);
2026   current->type += " " + subtype;
2027   current->type = current->type.stripWhiteSpace();
2028   current->fileName  = yyFileName;
2029   current->bodyLine  = yyLineNr; // used for source reference
2030   current->startLine = -1; // ??? what is startLine for?
2031   current->args.resize(0);
2032   current->argList->clear();
2033   docBlock.resize(0);
2034 }
2035
2036 /*! Adds interface to the root entry.
2037  * \note Code was brought to this procedure from the parser,
2038  * because there was/is idea to use it in several parts of the parser.
2039  */ 
2040 static void addInterface(QCString name, InterfaceType type)
2041 {
2042   if (YY_START == Start)
2043   {
2044     addModule(NULL);
2045     yy_push_state(ModuleBody); //anon program
2046   }
2047
2048   current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC;
2049   current->spec = Entry::Interface;
2050   current->name = name;
2051
2052   switch (type)
2053   {
2054     case IF_ABSTRACT:
2055       current->type = "abstract";
2056       break;
2057
2058     case IF_GENERIC:
2059       current->type = "generic";
2060       break;
2061
2062     case IF_SPECIFIC:
2063     case IF_NONE:
2064     default:
2065       current->type = "";
2066   }
2067
2068   /* if type is part of a module, mod name is necessary for output */
2069   if ((current_root) && 
2070       (current_root->section ==  Entry::CLASS_SEC ||
2071        current_root->section ==  Entry::NAMESPACE_SEC)) 
2072   {
2073     current->name= current_root->name + "::" + current->name;
2074   }
2075
2076   current->fileName = yyFileName;
2077   current->bodyLine  = yyLineNr; 
2078   addCurrentEntry(1);
2079 }
2080
2081
2082 //-----------------------------------------------------------------------------
2083
2084 /*! Get the argument \a name.
2085  */
2086 static Argument* getParameter(const QCString &name)
2087 {
2088   // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl;
2089   Argument *ret = 0;
2090   if (current_root->argList==0) return 0;
2091   ArgumentListIterator ali(*current_root->argList);
2092   Argument *a;
2093   for (ali.toFirst();(a=ali.current());++ali)
2094   {
2095     if (a->name.lower()==name.lower())
2096     {
2097       ret=a;
2098       //printf("parameter found: %s\n",(const char*)name);
2099       break;
2100     }
2101   } // for
2102   return ret;
2103 }
2104
2105   //----------------------------------------------------------------------------
2106 static void startCommentBlock(bool brief)
2107 {
2108   if (brief)
2109   {
2110     current->briefFile = yyFileName;
2111     current->briefLine = yyLineNr;
2112   }
2113   else
2114   {
2115     current->docFile = yyFileName;
2116     current->docLine = yyLineNr;
2117   }
2118 }
2119
2120 //----------------------------------------------------------------------------
2121
2122 static void handleCommentBlock(const QCString &doc,bool brief)
2123 {
2124   bool needsEntry = FALSE;
2125   static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS");
2126   int position=0;
2127   if (docBlockInBody && hideInBodyDocs)
2128   {
2129     docBlockInBody = FALSE;
2130     return;
2131   }
2132   DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
2133   int lineNr = brief ? current->briefLine : current->docLine;
2134   while (parseCommentBlock(
2135         g_thisParser,
2136         docBlockInBody ? subrCurrent.getFirst() : current,
2137         doc,        // text
2138         yyFileName, // file
2139         lineNr,
2140         docBlockInBody ? FALSE : brief, 
2141         docBlockInBody ? FALSE : docBlockJavaStyle,
2142         docBlockInBody,
2143         defaultProtection,
2144         position,
2145         needsEntry
2146         )) 
2147   {
2148            DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2149    if (needsEntry) addCurrentEntry(0);
2150   }
2151   DBG_CTX((stderr,"parseCommentBlock position=%d [%s]  needsEntry=%d\n",position,doc.data()+position,needsEntry));
2152
2153   if (needsEntry) addCurrentEntry(0);
2154   docBlockInBody = FALSE;
2155 }
2156
2157 //----------------------------------------------------------------------------
2158
2159 static void subrHandleCommentBlock(const QCString &doc,bool brief)
2160 {
2161   QCString loc_doc;
2162   Entry *tmp_entry = current; 
2163   current = subrCurrent.getFirst(); // temporarily switch to the entry of the subroutine / function
2164
2165   // Still in the specification section so no inbodyDocs yet, but parameter documentation
2166   current->inbodyDocs = "";
2167
2168   if (docBlock.stripWhiteSpace().find("\\param") == 0)
2169   {
2170     handleCommentBlock("\n\n"+doc,brief);
2171   }
2172   else if (docBlock.stripWhiteSpace().find("@param") == 0)
2173   {
2174     handleCommentBlock("\n\n"+doc,brief);
2175   }
2176   else 
2177   {
2178     int dir1 = modifiers[current_root][argName.lower()].direction;
2179     loc_doc = doc.stripWhiteSpace();
2180     if (loc_doc.lower().find(directionParam[SymbolModifiers::IN]) == 0)
2181     {
2182       if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2183           (directionParam[dir1] == directionParam[SymbolModifiers::IN]))
2184       {
2185         handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::IN] + " " + 
2186                            argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::IN])),brief);
2187       }
2188       else
2189       {
2190         warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
2191         handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2192                            argName + " " + doc,brief);
2193       }
2194     }
2195     else if (loc_doc.lower().find(directionParam[SymbolModifiers::OUT]) == 0)
2196     {
2197       if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2198           (directionParam[dir1] == directionParam[SymbolModifiers::OUT]))
2199       {
2200         handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::OUT] + " " + 
2201                            argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::OUT])),brief);
2202       }
2203       else
2204       {
2205         warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
2206         handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2207                            argName + " " + doc,brief);
2208       }
2209     }
2210     else if (loc_doc.lower().find(directionParam[SymbolModifiers::INOUT]) == 0)
2211     {
2212       if ((directionParam[dir1] == directionParam[SymbolModifiers::NONE_D]) ||
2213           (directionParam[dir1] == directionParam[SymbolModifiers::INOUT]))
2214       {
2215         handleCommentBlock(QCString("\n\n@param ") + directionParam[SymbolModifiers::INOUT] + " " + 
2216                            argName + " " + loc_doc.right(loc_doc.length()-strlen(directionParam[SymbolModifiers::INOUT])),brief);
2217       }
2218       else
2219       {
2220         warn(yyFileName,yyLineNr, "inconsistency between intent attribute and documentation for variable: "+argName);
2221         handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2222                            argName + " " + doc,brief);
2223       }
2224     }
2225     else
2226     {
2227       handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + 
2228                          argName + " " + doc,brief);
2229     }
2230   }
2231   current=tmp_entry;
2232 }
2233
2234 //----------------------------------------------------------------------------
2235 #if 0
2236 static int level=0;
2237
2238 static void debugCompounds(Entry *rt)  // print Entry structure (for debugging)
2239 {
2240  level++;
2241   printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine);
2242   EntryListIterator eli(*rt->children());
2243   Entry *ce;
2244   for (;(ce=eli.current());++eli)
2245   {
2246      debugCompounds(ce); 
2247   } 
2248 level--;
2249 }
2250 #endif
2251
2252
2253 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, FortranFormat format)
2254 {
2255   char *tmpBuf = NULL;
2256   initParser();
2257
2258   defaultProtection = Public;
2259   inputString = fileBuf;
2260   inputPosition = 0;
2261   inputStringPrepass = NULL;
2262   inputPositionPrepass = 0;
2263
2264   //anonCount     = 0;  // don't reset per file
2265   mtype         = Method;
2266   gstat         = FALSE;
2267   virt          = Normal;
2268   current_root  = rt;
2269   global_root   = rt;
2270   inputFile.setName(fileName);
2271   if (inputFile.open(IO_ReadOnly))
2272   {
2273     isFixedForm = recognizeFixedForm(fileBuf,format);
2274
2275     if (isFixedForm) 
2276     {
2277       msg("Prepassing fixed form of %s\n", fileName);
2278       //printf("---strlen=%d\n", strlen(fileBuf));
2279       //clock_t start=clock();
2280
2281       inputString = prepassFixedForm(fileBuf);
2282
2283       //clock_t end=clock();
2284       //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC);
2285     }
2286     else if (inputString[strlen(fileBuf)-1] != '\n')
2287     {
2288       tmpBuf = (char *)malloc(strlen(fileBuf)+2);
2289       strcpy(tmpBuf,fileBuf);
2290       tmpBuf[strlen(fileBuf)]= '\n';
2291       tmpBuf[strlen(fileBuf)+1]= '\000';
2292       inputString = tmpBuf;
2293     }
2294
2295     yyLineNr= 1 ; 
2296     yyFileName = fileName;
2297     msg("Parsing file %s...\n",yyFileName.data());
2298
2299     startScope(rt); // implies current_root = rt
2300     initParser();
2301     groupEnterFile(yyFileName,yyLineNr);
2302
2303     current          = new Entry;
2304     current->lang    = SrcLangExt_Fortran; 
2305     current->name    = yyFileName;
2306     current->section = Entry::SOURCE_SEC;
2307     current_root->addSubEntry(current);
2308     file_root        = current;
2309     current          = new Entry;
2310     current->lang    = SrcLangExt_Fortran; 
2311
2312     fortranscannerYYrestart( fortranscannerYYin );
2313     {
2314       BEGIN( Start );
2315     }
2316
2317     fortranscannerYYlex();
2318     groupLeaveFile(yyFileName,yyLineNr);
2319
2320     endScope(current_root, TRUE); // TRUE - global root
2321
2322     //debugCompounds(rt); //debug 
2323
2324     rt->program.resize(0);
2325     delete current; current=0;
2326     moduleProcedures.clear();
2327     if (tmpBuf) {
2328       free((char*)tmpBuf);
2329       inputString=NULL;
2330     }
2331     if (isFixedForm) {
2332       free((char*)inputString);
2333       inputString=NULL;
2334     }
2335
2336     inputFile.close();
2337   }
2338 }
2339
2340 //----------------------------------------------------------------------------
2341
2342 void FortranLanguageScanner::parseInput(const char *fileName,
2343                                         const char *fileBuf,
2344                                         Entry *root,
2345                                         bool /*sameTranslationUnit*/,
2346                                         QStrList & /*filesInSameTranslationUnit*/)
2347 {
2348   g_thisParser = this;
2349
2350   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2351
2352   ::parseMain(fileName,fileBuf,root,m_format);
2353
2354   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
2355 }
2356
2357 void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
2358                    const char * scopeName,
2359                    const QCString & input,
2360                    SrcLangExt /*lang*/,
2361                    bool isExampleBlock,
2362                    const char * exampleName,
2363                    FileDef * fileDef,
2364                    int startLine,
2365                    int endLine,
2366                    bool inlineFragment,
2367                    MemberDef *memberDef,
2368                    bool showLineNumbers,
2369                    Definition *searchCtx,
2370                    bool collectXRefs
2371                   )
2372 {
2373   ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
2374                      fileDef,startLine,endLine,inlineFragment,memberDef,
2375                      showLineNumbers,searchCtx,collectXRefs,m_format);
2376 }
2377
2378 bool FortranLanguageScanner::needsPreprocessing(const QCString &extension)
2379 {
2380   return extension!=extension.lower(); // use preprocessor only for upper case extensions
2381 }
2382 void FortranLanguageScanner::resetCodeParserState()
2383 {
2384   ::resetFortranCodeParserState();
2385 }
2386
2387 void FortranLanguageScanner::parsePrototype(const char *text)
2388 {
2389   QCString buffer = QCString(text);
2390   pushBuffer(buffer);
2391   parsingPrototype = TRUE;
2392   BEGIN(Prototype);
2393   fortranscannerYYlex();
2394   parsingPrototype = FALSE;
2395   popBuffer();
2396 }
2397
2398 static void scanner_abort() 
2399 {
2400   fprintf(stderr,"********************************************************************\n");
2401   fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START);
2402   fprintf(stderr,"********************************************************************\n");
2403    
2404   EntryListIterator eli(*global_root->children());
2405   Entry *ce;
2406   bool start=FALSE;
2407
2408   for (;(ce=eli.current());++eli)
2409   {
2410      if (ce == file_root) start=TRUE;
2411      if (start) ce->reset(); 
2412   } 
2413
2414   // dummy call to avoid compiler warning
2415   (void)yy_top_state();
2416   
2417   return;
2418   //exit(-1);
2419 }
2420
2421 //----------------------------------------------------------------------------
2422
2423 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
2424 //----------------------------------------------------------------------------
2425 extern "C" { // some bogus code to keep the compiler happy
2426   void fortranscannernerYYdummy() { yy_flex_realloc(0,0); } 
2427 }
2428 #endif
2429