Orb/Doxygen/src/fortrancode.l
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 /******************************************************************************
       
     2  *
       
     3  * Parser for syntax hightlighting and references 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 /**
       
    20  @todo - continutation lines not always recognized
       
    21        - merging of use-statements with same module name and different only-names
       
    22        - rename part of use-statement
       
    23        - links to interface functions 
       
    24        - references to variables
       
    25 **/
       
    26 
       
    27 %{
       
    28 
       
    29 /*
       
    30  *	includes
       
    31  */
       
    32 #include "qtbc.h"
       
    33 #include <stdio.h>
       
    34 #include <assert.h>
       
    35 #include <ctype.h>
       
    36 #include <qregexp.h>
       
    37 #include <qdir.h>
       
    38 #include <qstringlist.h>
       
    39 #include "entry.h"
       
    40 #include "doxygen.h"
       
    41 #include "message.h"
       
    42 #include "outputlist.h"
       
    43 #include "util.h"
       
    44 #include "membername.h"
       
    45 #include "searchindex.h"
       
    46 #include "defargs.h"
       
    47 
       
    48 #define YY_NEVER_INTERACTIVE 1
       
    49 #define YY_NO_TOP_STATE 1
       
    50    
       
    51 //--------------------------------------------------------------------------------
       
    52 
       
    53 /**
       
    54   data of an use-statement
       
    55 */
       
    56 class UseEntry 
       
    57 {
       
    58  public: 
       
    59    QCString module; // just for debug
       
    60    QStringList onlyNames;   /* entries of the ONLY-part */
       
    61 };
       
    62 
       
    63 /**
       
    64   module name -> list of ONLY/remote entries
       
    65   (module name = name of the module, which can be accessed via use-directive)
       
    66 */
       
    67 class UseSDict : public SDict<UseEntry> 
       
    68 {
       
    69   public:
       
    70     UseSDict() : SDict<UseEntry>(17) {}
       
    71 };
       
    72 
       
    73 /**
       
    74   Contains names of used modules and names of local variables.
       
    75 */
       
    76 class Scope 
       
    77 {
       
    78   public:
       
    79     QStringList useNames; //!< contains names of used modules
       
    80     QDict<void> localVars; //!< contains names of local variables
       
    81 
       
    82     Scope() : localVars(7, FALSE /*caseSensitive*/) {}
       
    83 };
       
    84 
       
    85 /*===================================================================*/
       
    86 /* 
       
    87  *	statics
       
    88  */
       
    89   
       
    90 static QCString  docBlock;                   //!< contents of all lines of a documentation block
       
    91 static QCString  currentModule=0;            //!< name of the current enclosing module
       
    92 static UseSDict  *useMembers= new UseSDict;  //!< info about used modules
       
    93 static UseEntry  *useEntry = 0;              //!< current use statement info
       
    94 static QList<Scope> scopeStack;
       
    95 // static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
       
    96 static QCString str="";         //!> contents of fortran string
       
    97 
       
    98 static CodeOutputInterface * g_code;
       
    99 
       
   100 // TODO: is this still needed? if so, make it work
       
   101 static QCString      g_parmType;
       
   102 static QCString      g_parmName;
       
   103 
       
   104 static const char *  g_inputString;     //!< the code fragment as text
       
   105 static int	     g_inputPosition;   //!< read offset during parsing 
       
   106 static int           g_inputLines;      //!< number of line in the code fragment
       
   107 static int	     g_yyLineNr;        //!< current line number
       
   108 static bool          g_needsTermination;
       
   109 static bool          g_isFixedForm;
       
   110 
       
   111 static bool          g_insideBody;      //!< inside subprog/program body? => create links
       
   112 static const char *  g_currentFontClass;
       
   113 
       
   114 static bool          g_exampleBlock;
       
   115 static QCString      g_exampleName;
       
   116 static QCString      g_exampleFile;
       
   117 
       
   118 static FileDef *     g_sourceFileDef;
       
   119 static Definition *  g_currentDefinition;
       
   120 static MemberDef *   g_currentMemberDef;
       
   121 static bool          g_includeCodeFragment;
       
   122 
       
   123 static char          stringStartSymbol; // single or double quote
       
   124 // count in variable declaration to filter out
       
   125 //  declared from referenced names
       
   126 static int 	     bracketCount = 0; 
       
   127 
       
   128 // simplified way to know if this is fixed form
       
   129 // duplicate in fortranscanner.l
       
   130 static bool recognizeFixedForm(const char* contents)
       
   131 {
       
   132   int column=0;
       
   133   bool skipLine=FALSE;
       
   134 
       
   135   for (int i=0;;i++) 
       
   136   {
       
   137     column++;
       
   138 
       
   139     switch(contents[i]) 
       
   140     {
       
   141       case '\n':
       
   142         column=0;
       
   143         skipLine=FALSE;
       
   144         break;
       
   145       case ' ':
       
   146         break;
       
   147       case '\000':
       
   148         return FALSE;
       
   149       case 'C':
       
   150       case 'c':
       
   151       case '*':
       
   152         if(column==1) return TRUE;
       
   153         if(skipLine) break;
       
   154         return FALSE;
       
   155       case '!':
       
   156         if(column>1 && column<7) return FALSE;
       
   157         skipLine=TRUE;
       
   158         break;
       
   159       default:
       
   160         if(skipLine) break;
       
   161         if(column==7) return TRUE;
       
   162         return FALSE;
       
   163     }
       
   164   }
       
   165   return FALSE;
       
   166 }
       
   167 
       
   168 static void endFontClass()
       
   169 {
       
   170   if (g_currentFontClass)
       
   171   {
       
   172     g_code->endFontClass();
       
   173     g_currentFontClass=0;
       
   174   }
       
   175 }
       
   176 
       
   177 static void startFontClass(const char *s)
       
   178 {
       
   179   endFontClass();
       
   180   g_code->startFontClass(s);
       
   181   g_currentFontClass=s;
       
   182 }
       
   183 
       
   184 static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
       
   185 {
       
   186   if (Doxygen::searchIndex)
       
   187   {
       
   188     Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
       
   189   }
       
   190 }
       
   191 
       
   192 static void addToSearchIndex(const char *text)
       
   193 {
       
   194   if (Doxygen::searchIndex)
       
   195   {
       
   196     Doxygen::searchIndex->addWord(text,FALSE);
       
   197   }
       
   198 }
       
   199 
       
   200 /*! start a new line of code, inserting a line number if g_sourceFileDef
       
   201  * is TRUE. If a definition starts at the current line, then the line
       
   202  * number is linked to the documentation of that definition.
       
   203  */
       
   204 static void startCodeLine()
       
   205 {
       
   206   if (g_sourceFileDef)
       
   207   {
       
   208     //QCString lineNumber,lineAnchor;
       
   209     //lineNumber.sprintf("%05d",g_yyLineNr);
       
   210     //lineAnchor.sprintf("l%05d",g_yyLineNr);
       
   211    
       
   212     Definition *d   = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
       
   213     //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>");
       
   214     if (!g_includeCodeFragment && d)
       
   215     {
       
   216       g_currentDefinition = d;
       
   217       g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
       
   218       g_insideBody = FALSE;
       
   219       g_parmType.resize(0);
       
   220       g_parmName.resize(0);
       
   221       QCString lineAnchor;
       
   222       lineAnchor.sprintf("l%05d",g_yyLineNr);
       
   223       if (g_currentMemberDef)
       
   224       {
       
   225         g_code->writeLineNumber(g_currentMemberDef->getReference(),
       
   226 	                        g_currentMemberDef->getOutputFileBase(),
       
   227 	                        g_currentMemberDef->anchor(),g_yyLineNr);
       
   228         setCurrentDoc(
       
   229                                 g_currentMemberDef->qualifiedName(),
       
   230 	                        g_sourceFileDef->getSourceFileBase(),
       
   231 	                        lineAnchor);
       
   232       }
       
   233       else if (d->isLinkableInProject())
       
   234       {
       
   235         g_code->writeLineNumber(d->getReference(),
       
   236 	                        d->getOutputFileBase(),
       
   237 	                        0,g_yyLineNr);
       
   238         setCurrentDoc(
       
   239                                 d->qualifiedName(),
       
   240 	                        g_sourceFileDef->getSourceFileBase(),
       
   241 	                        lineAnchor);
       
   242       }
       
   243     }
       
   244     else
       
   245     {
       
   246       g_code->writeLineNumber(0,0,0,g_yyLineNr);
       
   247     }
       
   248   }
       
   249   g_code->startCodeLine(); 
       
   250   if (g_currentFontClass)
       
   251   {
       
   252     g_code->startFontClass(g_currentFontClass);
       
   253   }
       
   254 }
       
   255 
       
   256 
       
   257 static void endFontClass();
       
   258 static void endCodeLine()
       
   259 {
       
   260   endFontClass();
       
   261   g_code->endCodeLine();
       
   262 }
       
   263 
       
   264 /*! write a code fragment `text' that may span multiple lines, inserting
       
   265  * line numbers for each line.
       
   266  */
       
   267 static void codifyLines(char *text)
       
   268 {
       
   269   //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
       
   270   char *p=text,*sp=p;
       
   271   char c;
       
   272   bool done=FALSE;
       
   273   while (!done)
       
   274   {
       
   275     sp=p;
       
   276     while ((c=*p++) && c!='\n') { }
       
   277     if (c=='\n')
       
   278     {
       
   279       g_yyLineNr++;
       
   280       *(p-1)='\0';
       
   281       g_code->codify(sp);
       
   282       endCodeLine();
       
   283       if (g_yyLineNr<g_inputLines) 
       
   284       {
       
   285 	startCodeLine();
       
   286       }
       
   287     }
       
   288     else
       
   289     {
       
   290       g_code->codify(sp);
       
   291       done=TRUE;
       
   292     }
       
   293   }
       
   294 }
       
   295 
       
   296 static void codifyLines(QCString str)
       
   297 {
       
   298   char *tmp= (char *) malloc(str.length()+1);
       
   299   strcpy(tmp, str);
       
   300   codifyLines(tmp);
       
   301   free(tmp);
       
   302 }
       
   303 
       
   304 /*! writes a link to a fragment \a text that may span multiple lines, inserting
       
   305  * line numbers for each line. If \a text contains newlines, the link will be 
       
   306  * split into multiple links with the same destination, one for each line.
       
   307  */
       
   308 static void writeMultiLineCodeLink(CodeOutputInterface &ol,
       
   309                   const char *ref,const char *file,
       
   310                   const char *anchor,const char *text)
       
   311 {
       
   312   bool done=FALSE;
       
   313   char *p=(char *)text;
       
   314   while (!done)
       
   315   {
       
   316     char *sp=p;
       
   317     char c;
       
   318     while ((c=*p++) && c!='\n') { }
       
   319     if (c=='\n')
       
   320     {
       
   321       g_yyLineNr++;
       
   322       *(p-1)='\0';
       
   323       //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
       
   324       ol.writeCodeLink(ref,file,anchor,sp,0);
       
   325       endCodeLine();
       
   326       if (g_yyLineNr<g_inputLines) 
       
   327       {
       
   328 	startCodeLine();
       
   329       }
       
   330     }
       
   331     else
       
   332     {
       
   333       //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
       
   334       ol.writeCodeLink(ref,file,anchor,sp,0);
       
   335       done=TRUE;
       
   336     }
       
   337   }
       
   338 }
       
   339 
       
   340 /**
       
   341   generates dictionay entries that are used if REFERENCED_BY_RELATION ... options are set
       
   342   (e.g. the "referenced by ..." list after the function documentation) 
       
   343 */
       
   344 
       
   345 static void addDocCrossReference(MemberDef *src, MemberDef *dst)
       
   346 {
       
   347   if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
       
   348  //printf("======= addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
       
   349   if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) && 
       
   350       (src->isFunction()))
       
   351   {
       
   352     dst->addSourceReferencedBy(src);
       
   353   }
       
   354   if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && (src->isFunction()))
       
   355   {
       
   356     src->addSourceReferences(dst);
       
   357   }
       
   358 }
       
   359 
       
   360 //-------------------------------------------------------------------------------
       
   361 /**
       
   362   searches for definition of a type
       
   363   @param tname the name of the type
       
   364   @param moduleName name of enclosing module or null, if global entry
       
   365   @param cd the entry, if found or null
       
   366   @param useDict dictionary of data of USE-statement
       
   367   @returns true, if type is found 
       
   368 */
       
   369 static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName, 
       
   370                                ClassDef *&cd, UseSDict *usedict=0)
       
   371 {
       
   372   if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
       
   373 
       
   374   //cout << "=== search for type: " << tname << endl;
       
   375 
       
   376   // search for type  
       
   377   if ((cd=Doxygen::classSDict->find(tname))) 
       
   378   {
       
   379     //cout << "=== type found in global module" << endl;
       
   380     return TRUE;
       
   381   }
       
   382   else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname))) 
       
   383   {
       
   384     //cout << "=== type found in local module" << endl;
       
   385     return TRUE;
       
   386   }
       
   387   else 
       
   388   {
       
   389     UseEntry *use;
       
   390     for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di)
       
   391       if ((cd= Doxygen::classSDict->find(use->module+"::"+tname))) 
       
   392       {
       
   393  	//cout << "===  type found in used module" << endl;
       
   394         return TRUE;
       
   395       }
       
   396   }
       
   397 
       
   398   return FALSE;
       
   399 }
       
   400 
       
   401 /**
       
   402   searches for definition of function memberName
       
   403   @param memberName the name of the function/variable
       
   404   @param moduleName name of enclosing module or null, if global entry
       
   405   @param md the entry, if found or null
       
   406   @param usedict array of data of USE-statement
       
   407   @returns true, if found 
       
   408 */
       
   409 static bool getFortranDefs(const QCString &memberName, const QCString &moduleName, 
       
   410                            MemberDef *&md, UseSDict *usedict=0)
       
   411 {
       
   412   if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */
       
   413 
       
   414   // look in local variables
       
   415   for (Scope *scope=scopeStack.last(); scope!=NULL; scope=scopeStack.prev())
       
   416   {
       
   417     if(scope->localVars.find(memberName))
       
   418       return FALSE;
       
   419   }
       
   420 
       
   421   // search for function
       
   422   MemberName *mn = Doxygen::functionNameSDict->find(memberName);
       
   423 
       
   424   if (mn) // name is known
       
   425   {
       
   426       MemberListIterator mli(*mn);
       
   427       for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name
       
   428       {
       
   429         FileDef  *fd=md->getFileDef();
       
   430         GroupDef *gd=md->getGroupDef();
       
   431 
       
   432  //cout << "found link with same name: " << fd->fileName() << "  " <<  memberName;
       
   433  //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
       
   434 
       
   435         if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
       
   436         {
       
   437            NamespaceDef *nspace= md->getNamespaceDef();
       
   438 
       
   439            if (nspace == 0) 
       
   440 	   { // found function in global scope
       
   441              return TRUE;
       
   442            }
       
   443            else if (moduleName == nspace->name()) 
       
   444 	   { // found in local scope
       
   445              return TRUE;
       
   446            }
       
   447            else 
       
   448 	   { // else search in used modules
       
   449 	     QCString moduleName= nspace->name();
       
   450 	     UseEntry *ue= usedict->find(moduleName);
       
   451 	     if (ue) 
       
   452 	     {
       
   453                // check if only-list exists and if current entry exists is this list
       
   454 	       QStringList &only= ue->onlyNames;
       
   455 	       if (only.isEmpty()) 
       
   456 	       {
       
   457                //cout << " found in module " << moduleName << " entry " << memberName <<  endl;
       
   458                  return TRUE; // whole module used
       
   459                }
       
   460                else
       
   461 	       {
       
   462 	         for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
       
   463                  {
       
   464                    //cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<<  endl;
       
   465 		   if (memberName == (QCString)(*it))
       
   466                      return TRUE; // found in ONLY-part of use list
       
   467 	         }
       
   468 	       }
       
   469              }
       
   470            }
       
   471         } // if linkable
       
   472       } // for
       
   473   }
       
   474   return FALSE;
       
   475 }
       
   476 
       
   477 /**
       
   478  gets the link to a generic procedure which depends not on the name, but on the parameter list
       
   479  @todo implementation
       
   480 */
       
   481 static bool getGenericProcedureLink(const ClassDef *cd, 
       
   482                                     const char *memberText, 
       
   483 				    CodeOutputInterface &ol) 
       
   484 {
       
   485   (void)cd;
       
   486   (void)memberText;
       
   487   (void)ol;
       
   488   return FALSE;
       
   489 }
       
   490 
       
   491 static bool getLink(UseSDict *usedict, // dictonary with used modules
       
   492                     const char *memberText,  // exact member text
       
   493 		    CodeOutputInterface &ol,
       
   494 		    const char *text)
       
   495 {
       
   496   MemberDef *md;
       
   497   QCString memberName= removeRedundantWhiteSpace(memberText);
       
   498 
       
   499   if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable())
       
   500   { 
       
   501     //if (md->isVariable()) return FALSE; // variables aren't handled yet	
       
   502 
       
   503     Definition *d = md->getOuterScope()==Doxygen::globalScope ?
       
   504 	            md->getBodyDef() : md->getOuterScope();
       
   505     if (md->getGroupDef()) d = md->getGroupDef();
       
   506     if (d && d->isLinkable())
       
   507     {
       
   508       if (g_currentDefinition && g_currentMemberDef && md!=g_currentMemberDef && g_insideBody)
       
   509       { 
       
   510 	addDocCrossReference(g_currentMemberDef,md); 
       
   511       }     
       
   512       ol.linkableSymbol(g_yyLineNr,md->name(),md,
       
   513 	                g_currentMemberDef ? g_currentMemberDef : g_currentDefinition);
       
   514       writeMultiLineCodeLink(ol,md->getReference(),
       
   515 	                        md->getOutputFileBase(),
       
   516 	                        md->anchor(),
       
   517 				text ? text : memberText);
       
   518       addToSearchIndex(text ? text : memberText);
       
   519       return TRUE;
       
   520     } 
       
   521   }
       
   522   return FALSE;
       
   523 }
       
   524 
       
   525 
       
   526 static void generateLink(CodeOutputInterface &ol, char *lname)
       
   527 {
       
   528   ClassDef *cd=0;
       
   529  
       
   530   // check if lname is a linkable type or interface
       
   531   if ( (getFortranTypeDefs(lname, currentModule, cd, useMembers)) && cd->isLinkable() )
       
   532   {
       
   533     if ( (cd->compoundType() == ClassDef::Class) && // was  Entry::INTERFACE_SEC) &&
       
   534          (getGenericProcedureLink(cd, lname, ol)) ) 
       
   535     {
       
   536       //cout << "=== generic procedure resolved" << endl; 
       
   537     } 
       
   538     else 
       
   539     { // write type or interface link
       
   540       ol.linkableSymbol(g_yyLineNr, lname, cd, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
       
   541       writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,lname);
       
   542       addToSearchIndex(lname);
       
   543     }
       
   544   }
       
   545   // check for function/variable
       
   546   else if (getLink(useMembers, lname, ol, lname)) 
       
   547   {
       
   548     //cout << "=== found link for " << lname << endl;
       
   549   }
       
   550   else 
       
   551   {
       
   552     // nothing found, just write out the word
       
   553     ol.linkableSymbol(g_yyLineNr, lname, 0, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
       
   554     //startFontClass("charliteral"); //test
       
   555     codifyLines(lname);
       
   556     //endFontClass(); //test
       
   557     addToSearchIndex(lname);
       
   558   }
       
   559 }
       
   560 
       
   561 /*! counts the number of lines in the input */
       
   562 static int countLines()
       
   563 {
       
   564   const char *p=g_inputString;
       
   565   char c;
       
   566   int count=1;
       
   567   while ((c=*p)) 
       
   568   { 
       
   569     p++ ; 
       
   570     if (c=='\n') count++;  
       
   571   }
       
   572   if (p>g_inputString && *(p-1)!='\n') 
       
   573   { // last line does not end with a \n, so we add an extra
       
   574     // line and explicitly terminate the line after parsing.
       
   575     count++, 
       
   576     g_needsTermination=TRUE; 
       
   577   } 
       
   578   return count;
       
   579 }
       
   580 
       
   581 //----------------------------------------------------------------------------
       
   582 /** start scope */
       
   583 void startScope() 
       
   584 {
       
   585   // fprintf(stderr, "===> startScope %s",yytext);
       
   586   Scope *scope = new Scope;
       
   587   scopeStack.append(scope);
       
   588 }
       
   589 
       
   590 /** end scope */
       
   591 void endScope() 
       
   592 {
       
   593   // fprintf(stderr,"===> endScope %s",yytext);
       
   594   if (scopeStack.isEmpty()) 
       
   595   {
       
   596     fprintf(stderr,"WARNING: fortrancode.l: stack empty!"); 
       
   597     return;
       
   598     //exit(-1);
       
   599   }
       
   600 
       
   601   Scope *scope = scopeStack.getLast();
       
   602   scopeStack.removeLast();
       
   603   for ( QStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it) 
       
   604   {
       
   605     useMembers->remove(*it);
       
   606   }
       
   607   delete scope;
       
   608 }
       
   609 
       
   610 void addUse(QString moduleName) 
       
   611 {
       
   612   if (!scopeStack.isEmpty())
       
   613     scopeStack.last()->useNames.append(moduleName);
       
   614 }
       
   615 
       
   616 void addLocalVar(QString varName) 
       
   617 {
       
   618   if (!scopeStack.isEmpty())
       
   619     scopeStack.last()->localVars.insert(varName, (void*)1);
       
   620 }
       
   621 
       
   622 //----------------------------------------------------------------------------
       
   623 
       
   624 /* -----------------------------------------------------------------*/
       
   625 #undef	YY_INPUT
       
   626 #define	YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
       
   627 
       
   628 static int yyread(char *buf,int max_size)
       
   629 {
       
   630     int c=0;
       
   631     while( c < max_size && g_inputString[g_inputPosition] )
       
   632     {
       
   633 	*buf = g_inputString[g_inputPosition++] ;
       
   634 	c++; buf++;
       
   635     }
       
   636     return c;
       
   637 }
       
   638 
       
   639 %}
       
   640 
       
   641 IDSYM	  [a-z_A-Z0-9]
       
   642 ID        [a-z_A-Z]+{IDSYM}*
       
   643 SUBPROG   (subroutine|function)
       
   644 B         [ \t]
       
   645 BS        [ \t]*
       
   646 BS_       [ \t]+
       
   647 COMMA     {BS},{BS}
       
   648 ARGS      {BS}("("[^)]*")"){BS}
       
   649 
       
   650 NUM_TYPE  (complex|integer|logical|real)
       
   651 KIND      {ARGS}
       
   652 CHAR      (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
       
   653 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{B}PRECISION|{CHAR})
       
   654 
       
   655 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
       
   656 ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET|RECURSIVE|PURE|ELEMENTAL)
       
   657 ACCESS_SPEC (PRIVATE|PUBLIC)
       
   658 /* Assume that attribute statements are almost the same as attributes. */
       
   659 ATTR_STMT {ATTR_SPEC}|DIMENSION
       
   660 COMMANDS  (BLOCK{BS}DATA|DO|SELECT|CASE|WHERE|IF|THEN|ELSE|MODULE{BS_}PROCEDURE|CONTAINS|IMPLICIT{BS}NONE|CONTAINS|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|DEALLOCATE|SIZE|END{BS}IF|END{BS}DO|WHILE|INQUIRE|OPEN|CLOSE|DATA)
       
   661 IGNORE (CALL)
       
   662 
       
   663 /* |  */
       
   664 
       
   665 %option noyywrap
       
   666 %option stack
       
   667 %option caseless
       
   668 /*%option debug*/
       
   669 
       
   670 %x Start
       
   671 %x SubCall
       
   672 %x FuncDef
       
   673 %x ClassName
       
   674 %x ClassVar
       
   675 %x Subprog
       
   676 %x DocBlock
       
   677 %x Use
       
   678 %x UseOnly
       
   679 %x TypeDecl
       
   680 %x Declaration
       
   681 %x DeclContLine
       
   682 %x Parameterlist
       
   683 %x String
       
   684 
       
   685 %%
       
   686  /*==================================================================*/
       
   687 
       
   688  /*-------- ignore ------------------------------------------------------------*/
       
   689 
       
   690 <Start>{IGNORE}/{BS}"("?                { // do not search keywords, intrinsics... TODO: complete list
       
   691   					  codifyLines(yytext);
       
   692                                         }
       
   693  /*-------- inner construct ---------------------------------------------------*/
       
   694  
       
   695 <Start>{COMMANDS}/[,( \t\n].*           { // hightlight rest of fortran statements
       
   696    					  /* font class is defined e.g. in doxygen.css */
       
   697   					  startFontClass("keyword");
       
   698   					  codifyLines(yytext);
       
   699 					  endFontClass();
       
   700 					}
       
   701 <Start>"end"({BS_}{COMMANDS})?/[ \t\n]  { 
       
   702   					  startFontClass("keyword");
       
   703   					  codifyLines(yytext);
       
   704 					  endFontClass();
       
   705 					}
       
   706 
       
   707  /*-------- use statement -------------------------------------------*/
       
   708 <Start>"use"{BS_}                       { 
       
   709   					  codifyLines(yytext);
       
   710                                           yy_push_state(YY_START);
       
   711 					  BEGIN(Use);     
       
   712                                         }
       
   713 <Use>{ID}                               {
       
   714   					  startFontClass("keywordflow");
       
   715   					  codifyLines(yytext);
       
   716 					  endFontClass();
       
   717 
       
   718 					  /* append module name to use dict */
       
   719                                           useEntry = new UseEntry();
       
   720 					  useEntry->module = yytext;
       
   721                                           useMembers->append(yytext, useEntry);
       
   722 					  addUse(yytext);
       
   723                                         }           
       
   724 <Use>,{BS}"ONLY"                        { // TODO: rename
       
   725  					  codifyLines(yytext);
       
   726                                           yy_push_state(YY_START);
       
   727 					  BEGIN(UseOnly);     
       
   728                                         }           
       
   729 <UseOnly>{BS},{BS}                      { codifyLines(yytext); }
       
   730 <UseOnly>{ID}                           {
       
   731  					  codifyLines(yytext);
       
   732                                           useEntry->onlyNames.append(yytext);
       
   733                                         }   
       
   734 <Use,UseOnly>"\n"                       {
       
   735                                           unput(*yytext);
       
   736                                           yy_pop_state();
       
   737                                         }
       
   738        
       
   739  /*-------- fortran module  -----------------------------------------*/
       
   740 <Start>("program"|"module"|"type"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n {  //
       
   741 					  startScope();
       
   742   					  startFontClass("keyword"); 
       
   743   					  codifyLines(yytext);
       
   744 					  endFontClass();
       
   745                                           yy_push_state(YY_START);
       
   746 					  BEGIN(ClassName); 
       
   747 	                                  if (!stricmp(yytext,"module")) currentModule="module";
       
   748 					}
       
   749 <ClassName>{ID}               	        {
       
   750 	                                  if (currentModule == "module") currentModule=yytext;
       
   751 					  generateLink(*g_code,yytext);
       
   752                                           yy_pop_state();
       
   753  					}
       
   754 <ClassName>\n				{ // interface may be without name
       
   755                                           yy_pop_state();
       
   756 					  REJECT;
       
   757 					}
       
   758 <Start>"end"({BS_}"module").*          { // just reset currentModule, rest is done in following rule
       
   759                                           currentModule=0;
       
   760 					  REJECT;
       
   761                                         }
       
   762 <Start>^{BS}"end"({BS}("program"|"module"|"type"|"interface")({BS_}{ID})?)?{BS}/(\n|!) {  //
       
   763                                           endScope();
       
   764  					  startFontClass("keyword"); 
       
   765   					  codifyLines(yytext);
       
   766 					  endFontClass();
       
   767                                         }
       
   768 
       
   769  /*-------- subprog definition -------------------------------------*/
       
   770 <Start>{TYPE_SPEC}{BS}/{SUBPROG}{BS_}  {   // TYPE_SPEC is for old function style function result
       
   771    					  startFontClass("keyword");
       
   772   					  codifyLines(yytext);
       
   773 					  endFontClass();
       
   774                                        }              
       
   775 <Start>{SUBPROG}{BS_}                  {  // Fortran subroutine or function found
       
   776    					  startFontClass("keyword");
       
   777   					  codifyLines(yytext);
       
   778 					  endFontClass();
       
   779                                           yy_push_state(YY_START);
       
   780                                           BEGIN(Subprog);
       
   781                                         }
       
   782 <Subprog>{ID}                           { // subroutine/function name
       
   783                                           // fprintf(stderr, "===> start subprogram %s\n", yytext);
       
   784 					  startScope();
       
   785 					  generateLink(*g_code,yytext);
       
   786                                         }
       
   787 <Subprog>"(".*                          { // ignore rest of line 
       
   788  					  codifyLines(yytext);
       
   789                                         }
       
   790 <Subprog>"\n"                           { codifyLines(yytext);
       
   791                                           yy_pop_state();
       
   792                                         }
       
   793 <Start>^{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) {  // Fortran subroutine or function ends
       
   794                                           //cout << "===> end function " << yytext << endl;
       
   795                                           endScope();
       
   796    					  startFontClass("keyword");
       
   797   					  codifyLines(yytext);
       
   798 					  endFontClass();
       
   799                                         }
       
   800  /*-------- variable declaration ----------------------------------*/
       
   801 <Start>"TYPE"{BS}"("                    {
       
   802                                           yy_push_state(YY_START);
       
   803 					  BEGIN(TypeDecl);
       
   804    					  startFontClass("keywordtype");
       
   805 					  g_code->codify(yytext);
       
   806 					  endFontClass();
       
   807                                         }
       
   808 <TypeDecl>{ID}                          { // link type
       
   809 					  g_insideBody=TRUE;
       
   810 					  generateLink(*g_code,yytext);
       
   811 					  g_insideBody=FALSE;
       
   812                                         }
       
   813 <TypeDecl>")"                           { 
       
   814 					  BEGIN(Declaration);
       
   815    					  startFontClass("keywordtype");
       
   816 					  g_code->codify(yytext);
       
   817 					  endFontClass();
       
   818                                         }
       
   819 <Start>{TYPE_SPEC}/[,:( ]               { 
       
   820                                           yy_push_state(YY_START);
       
   821 					  BEGIN(Declaration);
       
   822    					  startFontClass("keywordtype");
       
   823 					  g_code->codify(yytext);
       
   824 					  endFontClass();
       
   825                                        }
       
   826 <Start>{ATTR_SPEC}		       { 
       
   827    					  startFontClass("keywordtype");
       
   828 					  g_code->codify(yytext);
       
   829 					  endFontClass();
       
   830                                        }
       
   831 <Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration
       
   832   					  startFontClass("keywordtype");
       
   833 					  g_code->codify(yytext);
       
   834 					  endFontClass();
       
   835   					}
       
   836 <Declaration>{ID}                       { // local var
       
   837 					  g_code->codify(yytext);
       
   838 					  if (g_currentMemberDef && g_currentMemberDef->isFunction())
       
   839 					    addLocalVar(yytext);
       
   840 					}
       
   841 <Declaration>[(]			{ // start of array specification
       
   842 					  bracketCount++;
       
   843 					  g_code->codify(yytext);
       
   844 					}
       
   845 
       
   846 <Declaration>[)]			{ // end array specification
       
   847 					  bracketCount--;
       
   848 					  g_code->codify(yytext);
       
   849 					}
       
   850 
       
   851 <Declaration>"&"                        { // continuation line
       
   852                                           yy_push_state(YY_START);
       
   853 					  BEGIN(DeclContLine);					  
       
   854  					}
       
   855 <DeclContLine>"\n"                      { // declaration not yet finished
       
   856                                           codifyLines(yytext);
       
   857 					  bracketCount = 0;
       
   858                                           yy_pop_state();
       
   859  				 	}
       
   860 <Declaration>"\n"                       { // end declaration line
       
   861 					  codifyLines(yytext);
       
   862 					  bracketCount = 0;
       
   863                                           yy_pop_state();
       
   864  					}
       
   865 
       
   866  /*-------- subprog calls  -----------------------------------------*/
       
   867 
       
   868 <Start>"call"{BS_}                      {
       
   869   					  codifyLines(yytext);
       
   870                                           yy_push_state(YY_START);
       
   871 					  BEGIN(SubCall);
       
   872                                         }
       
   873 <SubCall>{ID}                           { // subroutine call
       
   874 					  g_insideBody=TRUE;
       
   875                                           generateLink(*g_code, yytext);
       
   876 					  g_insideBody=FALSE;
       
   877 	                                  yy_pop_state();
       
   878                                         }
       
   879 <Start>{ID}{BS}/"("                     { // function call
       
   880 					  g_insideBody=TRUE;
       
   881                                           generateLink(*g_code, yytext);
       
   882 					  g_insideBody=FALSE;
       
   883                                         }
       
   884 
       
   885  /*-------- comments ---------------------------------------------------*/
       
   886 <Start>\n?{BS}"!>"                      { // start comment line or comment block
       
   887                                           yy_push_state(YY_START);
       
   888 					  BEGIN(DocBlock);
       
   889                                           docBlock=yytext;
       
   890 					}
       
   891 
       
   892 <DocBlock>.*    			{ // contents of current comment line
       
   893                                           docBlock+=yytext;
       
   894   					}
       
   895 <DocBlock>"\n"{BS}("!>"|"!"+)		{ //| comment block (next line is also comment line)
       
   896 					  docBlock+=yytext; 
       
   897    					}
       
   898 <DocBlock>"\n"        			{ // comment block ends at the end of this line
       
   899  					  docBlock+=yytext; 
       
   900                                           // remove special comment (default config)
       
   901   					  if (Config_getBool("STRIP_CODE_COMMENTS"))
       
   902 					  {
       
   903 					    g_yyLineNr+=((QCString)docBlock).contains('\n');
       
   904 					    endCodeLine();
       
   905 					    if (g_yyLineNr<g_inputLines) 
       
   906 					    {
       
   907 					      startCodeLine();
       
   908 					    }
       
   909 					  }
       
   910 					  else // do not remove comment
       
   911 					  {
       
   912 					    startFontClass("comment");
       
   913 					    codifyLines(docBlock);
       
   914 					    endFontClass();
       
   915 					  }
       
   916                                          yy_pop_state();
       
   917 					}
       
   918 
       
   919 <*>"!"[^>\n].*|"!"$ 			{ // normal comment
       
   920 					  if(YY_START == String) REJECT; // ignore in strings
       
   921   					  startFontClass("comment");
       
   922   					  codifyLines(yytext);
       
   923 					  endFontClass();
       
   924 					}
       
   925 
       
   926 <*>^[Cc*].*              		{ // normal comment
       
   927                                           if(! g_isFixedForm) REJECT;
       
   928 
       
   929   					  startFontClass("comment");
       
   930   					  codifyLines(yytext);
       
   931 					  endFontClass();
       
   932 					}
       
   933 
       
   934  /*------ preprocessor  --------------------------------------------*/ 
       
   935 <Start>"#".*\n                          { startFontClass("preprocessor");
       
   936   					  codifyLines(yytext);
       
   937 					  endFontClass();
       
   938                                         }
       
   939  /*------ variable references?  -------------------------------------*/ 
       
   940 
       
   941 <Start>"%"{BS}{ID}	 		{ // ignore references to elements 
       
   942 					  g_code->codify(yytext);
       
   943 					}
       
   944 <Start>{ID}                             {   
       
   945   					    g_insideBody=TRUE;
       
   946                                             generateLink(*g_code, yytext);
       
   947 					    g_insideBody=FALSE;
       
   948                                         }
       
   949  /*------ strings --------------------------------------------------*/ 
       
   950 <*>"\\\\"                               { str+=yytext; /* ignore \\  */}
       
   951 <*>"\\\""|\\\'                          { str+=yytext; /* ignore \"  */}
       
   952 
       
   953 <String>\"|\'                           { // string ends with next quote without previous backspace 
       
   954                                           if(yytext[0]!=stringStartSymbol) REJECT; // single vs double quote
       
   955                                           str+=yytext;
       
   956   					  startFontClass("stringliteral");
       
   957   					  codifyLines(str);
       
   958 					  endFontClass();
       
   959                                           yy_pop_state();
       
   960                                         }           
       
   961 <String>.                               {str+=yytext;}
       
   962 
       
   963 <*>\"|\'                                { /* string starts */
       
   964 					  /* if(YY_START == StrIgnore) REJECT; // ignore in simple comments */
       
   965                                           yy_push_state(YY_START);
       
   966                                           stringStartSymbol=yytext[0]; // single or double quote
       
   967                                           BEGIN(String);
       
   968 					  str=yytext;
       
   969                                         }
       
   970  /*-----------------------------------------------------------------------------*/
       
   971 
       
   972 <*>\n					{
       
   973   					  codifyLines(yytext); 
       
   974   					}
       
   975 <*>.					{ 
       
   976   					  g_code->codify(yytext);
       
   977 					}
       
   978 %%
       
   979 
       
   980 /*@ ----------------------------------------------------------------------------
       
   981  */
       
   982 
       
   983 /*===================================================================*/
       
   984 
       
   985 
       
   986 void resetFortranCodeParserState() {}
       
   987 
       
   988 void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s, 
       
   989                   bool exBlock, const char *exName,FileDef *fd,
       
   990 		  int startLine,int endLine,bool inlineFragment,
       
   991 		  MemberDef *memberDef)
       
   992 {
       
   993   //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
       
   994 
       
   995   // used parameters
       
   996   (void)memberDef;
       
   997   (void)className;
       
   998 
       
   999   if (s.isEmpty()) return;
       
  1000   g_code = &od;
       
  1001   g_inputString   = s;
       
  1002   g_inputPosition = 0;
       
  1003   g_isFixedForm = recognizeFixedForm((const char*)s);
       
  1004   g_currentFontClass = 0;
       
  1005   g_needsTermination = FALSE;
       
  1006   if (endLine!=-1)
       
  1007     g_inputLines  = endLine+1;
       
  1008   else
       
  1009     g_inputLines  = countLines();
       
  1010 
       
  1011   if (startLine!=-1)
       
  1012     g_yyLineNr    = startLine;
       
  1013   else
       
  1014     g_yyLineNr    = 1;
       
  1015 
       
  1016   g_exampleBlock  = exBlock; 
       
  1017   g_exampleName   = exName;
       
  1018   g_sourceFileDef = fd;
       
  1019   if (exBlock && fd==0)
       
  1020   {
       
  1021     // create a dummy filedef for the example
       
  1022     g_sourceFileDef = new FileDef("",exName);
       
  1023   }
       
  1024   if (g_sourceFileDef) 
       
  1025   {
       
  1026     setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase());
       
  1027   }
       
  1028   g_currentDefinition = 0;
       
  1029   g_currentMemberDef = 0;
       
  1030   if (!g_exampleName.isEmpty())
       
  1031   {
       
  1032     g_exampleFile = convertNameToFile(g_exampleName+"-example");
       
  1033   }
       
  1034   g_includeCodeFragment = inlineFragment;
       
  1035   startCodeLine();
       
  1036   g_parmName.resize(0);
       
  1037   g_parmType.resize(0);
       
  1038   fcodeYYrestart( fcodeYYin );
       
  1039   BEGIN( Start );
       
  1040   fcodeYYlex();
       
  1041   if (g_needsTermination)
       
  1042   {
       
  1043     endFontClass();
       
  1044     g_code->endCodeLine();
       
  1045   }
       
  1046   if (exBlock && g_sourceFileDef)
       
  1047   {
       
  1048     // delete the temporary file definition used for this example
       
  1049     delete g_sourceFileDef;
       
  1050     g_sourceFileDef=0;
       
  1051   }
       
  1052   return;
       
  1053 }
       
  1054 
       
  1055 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
       
  1056 extern "C" { // some bogus code to keep the compiler happy
       
  1057   void fcodeYYdummy() { yy_flex_realloc(0,0); } 
       
  1058 }
       
  1059 #elif YY_FLEX_SUBMINOR_VERSION<33
       
  1060 #error "You seem to be using a version of flex newer than 2.5.4 but older than 2.5.33. These versions do NOT work with doxygen! Please use version <=2.5.4 or >=2.5.33 or expect things to be parsed wrongly!"
       
  1061 #else
       
  1062 extern "C" { // some bogus code to keep the compiler happy
       
  1063   void fcodeYYdummy() { yy_top_state(); } 
       
  1064 }
       
  1065 #endif
       
  1066