summaryrefslogtreecommitdiffstats
path: root/src/fortrancode.l
diff options
context:
space:
mode:
authordimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>2007-08-15 18:35:31 (GMT)
committerdimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>2007-08-15 18:35:31 (GMT)
commit115c6c02c3b246c525721aef9b1a43aeeb4666d5 (patch)
tree4d3b01807f8eb1364767b33ddb31bfd49b37ef3a /src/fortrancode.l
parenta56b6170231a051a6ba7e2cb3f93b21c7d854761 (diff)
downloadDoxygen-115c6c02c3b246c525721aef9b1a43aeeb4666d5.zip
Doxygen-115c6c02c3b246c525721aef9b1a43aeeb4666d5.tar.gz
Doxygen-115c6c02c3b246c525721aef9b1a43aeeb4666d5.tar.bz2
Release-1.5.3-20070815
Diffstat (limited to 'src/fortrancode.l')
-rw-r--r--src/fortrancode.l959
1 files changed, 959 insertions, 0 deletions
diff --git a/src/fortrancode.l b/src/fortrancode.l
new file mode 100644
index 0000000..b780052
--- /dev/null
+++ b/src/fortrancode.l
@@ -0,0 +1,959 @@
+/******************************************************************************
+ *
+ * Parser for syntax hightlighting and references for Fortran90 F subset
+ *
+ * Copyright (C) by Anke Visser
+ * based on the work of Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+/**
+ @TODO - continutation lines not always recognized
+ - merging of use-statements with same module name and different only-names
+ - rename part of use-statement
+ - links to interface functions
+ - references to variables
+**/
+
+%{
+
+/*
+ * includes
+ */
+#include "qtbc.h"
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include "entry.h"
+#include "doxygen.h"
+#include "message.h"
+#include "outputlist.h"
+#include "util.h"
+#include "membername.h"
+#include "searchindex.h"
+#include "defargs.h"
+
+#define YY_NEVER_INTERACTIVE 1
+#define YY_NO_TOP_STATE 1
+
+//--------------------------------------------------------------------------------
+
+/**
+ data of an use-statement
+*/
+class UseEntry
+{
+ public:
+ QCString module; // just for debug
+ QStringList onlyNames; /* entries of the ONLY-part */
+};
+
+/**
+ module name -> list of ONLY/remote entries
+ (module name = name of the module, which can be accessed via use-directive)
+*/
+class UseSDict : public SDict<UseEntry>
+{
+ public:
+ UseSDict() : SDict<UseEntry>(17) {}
+};
+
+/*===================================================================*/
+/*
+ * statics
+ */
+
+static QCString docBlock; //!< contents of all lines of a documentation block
+static QCString currentModule=0; //!< name of the current enclosing module
+static UseSDict *useMembers= new UseSDict; //!< info about used modules
+static UseEntry *useEntry = 0; //!< current use statement info
+static QStack<QStringList> useStack; //!< contains names of used modules for current program tree
+static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
+static QCString str=""; //!> contents of fortran string
+
+static CodeOutputInterface * g_code;
+
+// TODO: is this still needed? if so, make it work
+static QCString g_parmType;
+static QCString g_parmName;
+
+static const char * g_inputString; //!< the code fragment as text
+static int g_inputPosition; //!< read offset during parsing
+static int g_inputLines; //!< number of line in the code fragment
+static int g_yyLineNr; //!< current line number
+static bool g_needsTermination;
+
+static bool g_insideBody; //!< inside subprog/program body? => create links
+static const char * g_currentFontClass;
+
+static bool g_exampleBlock;
+static QCString g_exampleName;
+static QCString g_exampleFile;
+
+static FileDef * g_sourceFileDef;
+static Definition * g_currentDefinition;
+static MemberDef * g_currentMemberDef;
+static bool g_includeCodeFragment;
+
+
+static void endFontClass()
+{
+ if (g_currentFontClass)
+ {
+ g_code->endFontClass();
+ g_currentFontClass=0;
+ }
+}
+
+static void startFontClass(const char *s)
+{
+ endFontClass();
+ g_code->startFontClass(s);
+ g_currentFontClass=s;
+}
+
+static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
+{
+ static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
+ if (searchEngineEnabled)
+ {
+ Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
+ }
+}
+
+static void addToSearchIndex(const char *text)
+{
+ static bool searchEngineEnabled=Config_getBool("SEARCHENGINE");
+ if (searchEngineEnabled)
+ {
+ Doxygen::searchIndex->addWord(text,FALSE);
+ }
+}
+
+/*! start a new line of code, inserting a line number if g_sourceFileDef
+ * is TRUE. If a definition starts at the current line, then the line
+ * number is linked to the documentation of that definition.
+ */
+static void startCodeLine()
+{
+ if (g_sourceFileDef)
+ {
+ //QCString lineNumber,lineAnchor;
+ //lineNumber.sprintf("%05d",g_yyLineNr);
+ //lineAnchor.sprintf("l%05d",g_yyLineNr);
+
+ Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
+ //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>");
+ if (!g_includeCodeFragment && d)
+ {
+ g_currentDefinition = d;
+ g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
+ g_insideBody = FALSE;
+ g_parmType.resize(0);
+ g_parmName.resize(0);
+ QCString lineAnchor;
+ lineAnchor.sprintf("l%05d",g_yyLineNr);
+ if (g_currentMemberDef)
+ {
+ g_code->writeLineNumber(g_currentMemberDef->getReference(),
+ g_currentMemberDef->getOutputFileBase(),
+ g_currentMemberDef->anchor(),g_yyLineNr);
+ setCurrentDoc(
+ g_currentMemberDef->qualifiedName(),
+ g_sourceFileDef->getSourceFileBase(),
+ lineAnchor);
+ }
+ else if (d->isLinkableInProject())
+ {
+ g_code->writeLineNumber(d->getReference(),
+ d->getOutputFileBase(),
+ 0,g_yyLineNr);
+ setCurrentDoc(
+ d->qualifiedName(),
+ g_sourceFileDef->getSourceFileBase(),
+ lineAnchor);
+ }
+ }
+ else
+ {
+ g_code->writeLineNumber(0,0,0,g_yyLineNr);
+ }
+ }
+ g_code->startCodeLine();
+ if (g_currentFontClass)
+ {
+ g_code->startFontClass(g_currentFontClass);
+ }
+}
+
+
+static void endFontClass();
+static void endCodeLine()
+{
+ if (g_currentFontClass) { g_code->endFontClass(); }
+ g_code->endCodeLine();
+}
+
+/*! write a code fragment `text' that may span multiple lines, inserting
+ * line numbers for each line.
+ */
+static void codifyLines(char *text)
+{
+ //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
+ char *p=text,*sp=p;
+ char c;
+ bool done=FALSE;
+ while (!done)
+ {
+ sp=p;
+ while ((c=*p++) && c!='\n');
+ if (c=='\n')
+ {
+ g_yyLineNr++;
+ *(p-1)='\0';
+ g_code->codify(sp);
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else
+ {
+ g_code->codify(sp);
+ done=TRUE;
+ }
+ }
+}
+
+static void codifyLines(QCString str)
+{
+ char *tmp= (char *) malloc(str.length()+1);
+ strcpy(tmp, str);
+ codifyLines(tmp);
+ free(tmp);
+}
+
+/*! writes a link to a fragment \a text that may span multiple lines, inserting
+ * line numbers for each line. If \a text contains newlines, the link will be
+ * split into multiple links with the same destination, one for each line.
+ */
+static void writeMultiLineCodeLink(CodeOutputInterface &ol,
+ const char *ref,const char *file,
+ const char *anchor,const char *text)
+{
+ bool done=FALSE;
+ char *p=(char *)text;
+ while (!done)
+ {
+ char *sp=p;
+ char c;
+ while ((c=*p++) && c!='\n');
+ if (c=='\n')
+ {
+ g_yyLineNr++;
+ *(p-1)='\0';
+ //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+ ol.writeCodeLink(ref,file,anchor,sp,0);
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else
+ {
+ //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+ ol.writeCodeLink(ref,file,anchor,sp,0);
+ done=TRUE;
+ }
+ }
+}
+
+/**
+ generates dictionay entries that are used if REFERENCED_BY_RELATION ... options are set
+ (e.g. the "referenced by ..." list after the function documentation)
+*/
+
+static void addDocCrossReference(MemberDef *src, MemberDef *dst)
+{
+ if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
+ //printf("======= addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
+ if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) &&
+ (src->isFunction()))
+ {
+ dst->addSourceReferencedBy(src);
+ }
+ if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && (src->isFunction()))
+ {
+ src->addSourceReferences(dst);
+ }
+}
+
+//-------------------------------------------------------------------------------
+/**
+ searches for definition of a type
+ @param memberName the name of the type
+ @param moduleName name of enclosing module or null, if global entry
+ @param cd the entry, if found or null
+ @param useList array of data of USE-statement
+ @returns true, if type is found
+*/
+static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
+ ClassDef *&cd, UseSDict *usedict=0)
+{
+ if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
+
+ //cout << "=== search for type: " << tname << endl;
+
+ // search for type
+ if ((cd=Doxygen::classSDict->find(tname)))
+ {
+ //cout << "=== type found in global module" << endl;
+ return TRUE;
+ }
+ else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname)))
+ {
+ //cout << "=== type found in local module" << endl;
+ return TRUE;
+ }
+ else
+ {
+ UseEntry *use;
+ for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di)
+ if ((cd= Doxygen::classSDict->find(use->module+"::"+tname)))
+ {
+ //cout << "=== type found in used module" << endl;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ searches for definition of function memberName
+ @param memberName the name of the function/variable
+ @param moduleName name of enclosing module or null, if global entry
+ @param memberDef the entry, if found or null
+ @param useList array of data of USE-statement
+ @returns true, if found
+*/
+static bool getFortranDefs(const QCString &memberName, const QCString &moduleName,
+ MemberDef *&md, UseSDict *usedict=0)
+{
+ if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */
+
+ // search for function
+ MemberName *mn = Doxygen::functionNameSDict->find(memberName);
+
+ if (mn) // name is known
+ {
+ MemberListIterator mli(*mn);
+ for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name
+ {
+ FileDef *fd=md->getFileDef();
+ GroupDef *gd=md->getGroupDef();
+
+ //cout << "found link with same name: " << fd->fileName() << " " << memberName;
+ //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
+
+ if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
+ {
+ NamespaceDef *nspace= md->getNamespaceDef();
+
+ if (nspace == 0)
+ { // found function in global scope
+ return TRUE;
+ }
+ else if (moduleName == nspace->name())
+ { // found in local scope
+ return TRUE;
+ }
+ else
+ { // else search in used modules
+ QCString moduleName= nspace->name();
+ UseEntry *ue= usedict->find(moduleName);
+ if (ue)
+ {
+ // check if only-list exists and if current entry exists is this list
+ QStringList &only= ue->onlyNames;
+ if (only.isEmpty())
+ {
+ //cout << " found in module " << moduleName << " entry " << memberName << endl;
+ return TRUE; // whole module used
+ }
+ else
+ {
+ for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
+ {
+ //cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl;
+ if (memberName == (QCString)(*it))
+ return TRUE; // found in ONLY-part of use list
+ }
+ }
+ }
+ }
+ } // if linkable
+ } // for
+ }
+ return FALSE;
+}
+
+/**
+ gets the link to a generic procedure which depends not on the name, but on the parameter list
+ @TODO implementation
+*/
+static bool getGenericProcedureLink(const ClassDef *cd,
+ const char *memberText,
+ CodeOutputInterface &ol)
+{
+ (void)cd;
+ (void)memberText;
+ (void)ol;
+ return FALSE;
+}
+
+static bool getLink(UseSDict *usedict, // dictonary with used modules
+ const char *memberText, // exact member text
+ CodeOutputInterface &ol,
+ const char *text)
+{
+ MemberDef *md;
+ QCString memberName= removeRedundantWhiteSpace(memberText);
+ //printf("Trying `%s'::`%s'\n",c.data(),m.data());
+
+ if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable())
+ {
+ //if (md->isVariable()) return FALSE; // variables aren't handled yet
+
+ Definition *d = md->getOuterScope()==Doxygen::globalScope ?
+ md->getBodyDef() : md->getOuterScope();
+ if (md->getGroupDef()) d = md->getGroupDef();
+ if (d && d->isLinkable())
+ {
+ if (g_currentDefinition && g_currentMemberDef && md!=g_currentMemberDef && g_insideBody)
+ {
+ addDocCrossReference(g_currentMemberDef,md);
+ }
+ ol.linkableSymbol(g_yyLineNr,md->name(),md,
+ g_currentMemberDef ? g_currentMemberDef : g_currentDefinition);
+ writeMultiLineCodeLink(ol,md->getReference(),
+ md->getOutputFileBase(),
+ md->anchor(),
+ text ? text : memberText);
+ addToSearchIndex(text ? text : memberText);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+static void generateLink(CodeOutputInterface &ol, char *lname)
+{
+ ClassDef *cd=0;
+
+ // check if lname is a linkable type or interface
+ if ( (getFortranTypeDefs(lname, currentModule, cd, useMembers)) && cd->isLinkable() )
+ {
+ if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
+ (getGenericProcedureLink(cd, lname, ol)) )
+ {
+ //cout << "=== generic procedure resolved" << endl;
+ }
+ else
+ { // write type or interface link
+ ol.linkableSymbol(g_yyLineNr, lname, cd, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
+ writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,lname);
+ addToSearchIndex(lname);
+ }
+ }
+ // check for function/variable
+ else if (getLink(useMembers, lname, ol, lname))
+ {
+ //cout << "=== found link for " << lname << endl;
+ }
+ else
+ {
+ // nothing found, just write out the word
+ ol.linkableSymbol(g_yyLineNr, lname, 0, g_currentMemberDef?g_currentMemberDef:g_currentDefinition);
+ //startFontClass("charliteral"); //test
+ codifyLines(lname);
+ //endFontClass(); //test
+ addToSearchIndex(lname);
+ }
+}
+
+/*! counts the number of lines in the input */
+static int countLines()
+{
+ const char *p=g_inputString;
+ char c;
+ int count=1;
+ while ((c=*p))
+ {
+ p++ ;
+ if (c=='\n') count++;
+ }
+ if (p>g_inputString && *(p-1)!='\n')
+ { // last line does not end with a \n, so we add an extra
+ // line and explicitly terminate the line after parsing.
+ count++,
+ g_needsTermination=TRUE;
+ }
+ return count;
+}
+
+//----------------------------------------------------------------------------
+/** start use list */
+void startUseScope()
+{
+ //fprintf("===> startUse %s",yytext);
+ useStack.push(currentUseNames);
+ currentUseNames= new QStringList;
+}
+
+/** end use list */
+void endUseScope()
+{
+ //fprintf(stderr,"===> endUse %s",yytext);
+ //UseSDict::Iterator di(*useMembers); UseEntry *ue;
+ //for (di.toFirst(); ue=di.current(); ++di){cout << ue->module ;} cout << endl;
+
+ for ( QStringList::Iterator it = currentUseNames->begin(); it != currentUseNames->end(); ++it)
+ {
+ useMembers->remove(*it);
+ }
+ delete currentUseNames;
+ currentUseNames= useStack.pop();
+ if (currentUseNames == 0)
+ {
+ fprintf(stderr,"fortrancode.l: stack empty!");
+ //exit(-1);
+ }
+}
+
+void addUse(QString moduleName)
+{
+ currentUseNames->append(moduleName);
+}
+//----------------------------------------------------------------------------
+
+/* -----------------------------------------------------------------*/
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
+
+static int yyread(char *buf,int max_size)
+{
+ int c=0;
+ while( c < max_size && g_inputString[g_inputPosition] )
+ {
+ *buf = g_inputString[g_inputPosition++] ;
+ c++; buf++;
+ }
+ return c;
+}
+
+%}
+
+IDSYM [a-z_A-Z0-9]
+ID [a-z_A-Z]+{IDSYM}*
+SUBPROG (subroutine|function)
+B [ \t]
+BS [ \t]*
+BS_ [ \t]+
+COMMA {BS},{BS}
+ARGS {BS}("("[^)]*")"){BS}
+
+NUM_TYPE (complex|integer|logical|real)
+KIND {ARGS}
+CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"([0-9]+|{ARGS}))
+TYPE_SPEC (({NUM_TYPE}("*"[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}PRECISION|{CHAR})
+
+INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
+ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET)
+ACCESS_SPEC (PRIVATE|PUBLIC)
+/* Assume that attribute statements are almost the same as attributes. */
+ATTR_STMT {ATTR_SPEC}|DIMENSION
+COMMANDS (BLOCK{BS}DATA|DO|SELECT|CASE|WHERE|IF|THEN|ELSE|MODULE{BS_}PROCEDURE)
+IGNORE (IMPLICIT{BS}NONE|CONTAINS|WRITE|READ|ALLOCATE|DEALLOCATE|SIZE)
+
+/* | */
+
+%option noyywrap
+%option stack
+%option caseless
+/*%option debug*/
+
+%x Start
+%x SubCall
+%x FuncDef
+%x ClassName
+%x ClassVar
+%x Subprog
+%x DocBlock
+%x Use
+%x UseOnly
+%x TypeDecl
+%x Declaration
+%x DeclContLine
+%x Parameterlist
+%x String
+
+%%
+ /*==================================================================*/
+
+ /*-------- ignore ------------------------------------------------------------*/
+
+<Start>{IGNORE}/{BS}"("? { // do not search keywords, intrinsics... @TODO: complete list
+ codifyLines(yytext);
+ }
+ /*-------- inner construct ---------------------------------------------------*/
+
+<Start>{COMMANDS}/[,( \t\n].* { // hightlight rest of fortran statements
+ /* font class is defined e.g. in doxygen.css */
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+<Start>"end"{BS}{COMMANDS}/[ \t\n].* {
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+
+ /*-------- use statement -------------------------------------------*/
+<Start>"use"{BS_} {
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(Use);
+ }
+<Use>{ID} {
+ startFontClass("keywordflow");
+ codifyLines(yytext);
+ endFontClass();
+
+ /* append module name to use dict */
+ useEntry = new UseEntry();
+ useEntry->module = yytext;
+ useMembers->append(yytext, useEntry);
+ addUse(yytext);
+ }
+<Use>,{BS}"ONLY" { // TODO: rename
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(UseOnly);
+ }
+<UseOnly>{BS},{BS} { codifyLines(yytext); }
+<UseOnly>{ID} {
+ codifyLines(yytext);
+ useEntry->onlyNames.append(yytext);
+ }
+<Use,UseOnly>"\n" {
+ unput(*yytext);
+ yy_pop_state();
+ }
+
+ /*-------- fortran module -----------------------------------------*/
+<Start>("program"|"module"|"type"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
+ startUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ yy_push_state(YY_START);
+ BEGIN(ClassName);
+ if (!strcmp(yytext,"module")) currentModule="module";
+ }
+<ClassName>{ID} {
+ if (currentModule == "module") currentModule=yytext;
+ generateLink(*g_code,yytext);
+ yy_pop_state();
+ }
+<ClassName>\n { // interface may be without name
+ yy_pop_state();
+ REJECT;
+ }
+<Start>"end"{BS}"module".* { // just reset currentModule, rest is done in following rule
+ currentModule=0;
+ REJECT;
+ }
+<Start>"end"{BS}("program"|"module"|"type"|"interface") { //
+ endUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+
+ /*-------- subprog definition -------------------------------------*/
+<Start>{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+<Start>{SUBPROG}{BS_} { // Fortran subroutine or function found
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ yy_push_state(YY_START);
+ BEGIN(Subprog);
+ }
+<Subprog>{ID} { // subroutine/function name
+ //cout << "===> start procedure " << yytext << endl;
+ startUseScope();
+ generateLink(*g_code,yytext);
+ }
+<Subprog>"(".* { // ignore rest of line
+ codifyLines(yytext);
+ }
+<Subprog>"\n" { codifyLines(yytext);
+ yy_pop_state();
+ }
+<Start>"end"{BS}{SUBPROG}.* { // Fortran subroutine or function ends
+ //cout << "===> end function " << yytext << endl;
+ endUseScope();
+ startFontClass("keyword");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*-------- variable declaration ----------------------------------*/
+<Start>"TYPE"{BS}"(" {
+ yy_push_state(YY_START);
+ BEGIN(TypeDecl);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<TypeDecl>{ID} { // link type
+ g_insideBody=TRUE;
+ generateLink(*g_code,yytext);
+ g_insideBody=FALSE;
+ }
+<TypeDecl>")" {
+ BEGIN(Declaration);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Start>{TYPE_SPEC}/[,:( ] {
+ yy_push_state(YY_START);
+ BEGIN(Declaration);
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Start>{ATTR_SPEC} {
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration
+ startFontClass("keywordtype");
+ g_code->codify(yytext);
+ endFontClass();
+ }
+<Declaration>"&" { // continuation line
+ yy_push_state(YY_START);
+ BEGIN(DeclContLine);
+ }
+<DeclContLine>"\n" { // declaration not yet finished
+ codifyLines(yytext);
+ yy_pop_state();
+ }
+<Declaration>"\n" { // end declaration line
+ codifyLines(yytext);
+ yy_pop_state();
+ }
+
+ /*-------- subprog calls -----------------------------------------*/
+
+<Start>"call"{BS_} {
+ codifyLines(yytext);
+ yy_push_state(YY_START);
+ BEGIN(SubCall);
+ }
+<SubCall>{ID} { // subroutine call
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ yy_pop_state();
+ }
+<Start>{ID}{BS}/"(" { // function call
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ }
+
+ /*-------- comments ---------------------------------------------------*/
+<Start>\n?{BS}"!>" { // start comment line or comment block
+ yy_push_state(YY_START);
+ BEGIN(DocBlock);
+ docBlock=yytext;
+ }
+
+<DocBlock>.* { // contents of current comment line
+ docBlock+=yytext;
+ }
+<DocBlock>"\n"{BS}("!>"|"!"+) { //| comment block (next line is also comment line)
+ docBlock+=yytext;
+ }
+<DocBlock>"\n" { // comment block ends at the end of this line
+ docBlock+=yytext;
+ // remove special comment (default config)
+ if (Config_getBool("STRIP_CODE_COMMENTS"))
+ {
+ g_yyLineNr+=((QCString)docBlock).contains('\n');
+ endCodeLine();
+ if (g_yyLineNr<g_inputLines)
+ {
+ startCodeLine();
+ }
+ }
+ else // do not remove comment
+ {
+ startFontClass("comment");
+ codifyLines(docBlock);
+ endFontClass();
+ }
+ yy_pop_state();
+ }
+
+<*>"!"[^>\n].*|"!"$ { // normal comment
+ startFontClass("comment");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*------ preprocessor --------------------------------------------*/
+<Start>"#".*\n { startFontClass("preprocessor");
+ codifyLines(yytext);
+ endFontClass();
+ }
+ /*------ variable references? -------------------------------------*/
+<Start>{ID} {
+ g_insideBody=TRUE;
+ generateLink(*g_code, yytext);
+ g_insideBody=FALSE;
+ }
+
+ /*------ strings --------------------------------------------------*/
+<*>"\\\\" { str+=yytext; /* ignore \\ */}
+<*>"\\\"" { str+=yytext; /* ignore \" */}
+
+<String>\" { // string ends with next quote without previous backspace
+ str+=yytext;
+ startFontClass("stringliteral");
+ codifyLines(str);
+ endFontClass();
+ yy_pop_state();
+ }
+<*>\" { /* string starts */
+ yy_push_state(YY_START);
+ BEGIN(String);
+ str=yytext;
+ }
+<String>. {str+=yytext;}
+
+
+ /*-----------------------------------------------------------------------------*/
+
+<*>\n {
+ codifyLines(yytext);
+ }
+<*>. {
+ g_code->codify(yytext);
+ }
+%%
+
+/*@ ----------------------------------------------------------------------------
+ */
+
+/*===================================================================*/
+
+void resetFortranCodeParserState() {}
+
+void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s,
+ bool exBlock, const char *exName,FileDef *fd,
+ int startLine,int endLine,bool inlineFragment,
+ MemberDef *memberDef)
+{
+ //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
+
+ // used parameters
+ (void)memberDef;
+ (void)className;
+
+ if (s.isEmpty()) return;
+ g_code = &od;
+ g_inputString = s;
+ g_inputPosition = 0;
+ g_currentFontClass = 0;
+ g_needsTermination = FALSE;
+ if (endLine!=-1)
+ g_inputLines = endLine+1;
+ else
+ g_inputLines = countLines();
+
+ if (startLine!=-1)
+ g_yyLineNr = startLine;
+ else
+ g_yyLineNr = 1;
+
+ g_exampleBlock = exBlock;
+ g_exampleName = exName;
+ g_sourceFileDef = fd;
+ if (exBlock && fd==0)
+ {
+ // create a dummy filedef for the example
+ g_sourceFileDef = new FileDef("",exName);
+ }
+ if (g_sourceFileDef)
+ {
+ setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase());
+ }
+ g_currentDefinition = 0;
+ g_currentMemberDef = 0;
+ if (!g_exampleName.isEmpty())
+ {
+ g_exampleFile = convertNameToFile(g_exampleName+"-example");
+ }
+ g_includeCodeFragment = inlineFragment;
+ startCodeLine();
+ g_parmName.resize(0);
+ g_parmType.resize(0);
+ fcodeYYrestart( fcodeYYin );
+ BEGIN( Start );
+ fcodeYYlex();
+ if (g_needsTermination)
+ {
+ endFontClass();
+ g_code->endCodeLine();
+ }
+ if (exBlock && g_sourceFileDef)
+ {
+ // delete the temporary file definition used for this example
+ delete g_sourceFileDef;
+ g_sourceFileDef=0;
+ }
+ return;
+}
+
+#if !defined(YY_FLEX_SUBMINOR_VERSION)
+extern "C" { // some bogus code to keep the compiler happy
+ void fcodeYYdummy() { yy_flex_realloc(0,0); }
+}
+#elif YY_FLEX_SUBMINOR_VERSION<33
+#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!"
+#endif
+