1 /******************************************************************************
3 * Parser for syntax hightlighting and references for Fortran90 F subset
5 * Copyright (C) by Anke Visser
6 * based on the work of Dimitri van Heesch.
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.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
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
37 #include <qstringlist.h>
41 #include "outputlist.h"
43 #include "membername.h"
44 #include "searchindex.h"
46 #include "memberlist.h"
49 #include "classlist.h"
51 #include "namespacedef.h"
54 // Toggle for some debugging info
55 //#define DBG_CTX(x) fprintf x
56 #define DBG_CTX(x) do { } while(0)
58 #define YY_NEVER_INTERACTIVE 1
59 #define YY_NO_TOP_STATE 1
63 * For fixed formatted code position 6 is of importance (continuation character).
64 * The following variables and macros keep track of the column number
65 * YY_USER_ACTION is always called for each scan action
66 * YY_FTN_REST is used to handle end of lines and reset the column counter
67 * YY_FTN_REJECT resets the column counters when a pattern is rejected and thus rescanned.
72 #define YY_USER_ACTION {yy_old_start = yy_my_start; yy_my_start = yy_end; yy_end += yyleng;}
73 #define YY_FTN_RESET {yy_old_start = 0; yy_my_start = 0; yy_end = 1;}
74 #define YY_FTN_REJECT {yy_end = yy_my_start; yy_my_start = yy_old_start; REJECT;}
76 //--------------------------------------------------------------------------------
79 data of an use-statement
84 QCString module; // just for debug
85 QStringList onlyNames; /* entries of the ONLY-part */
89 module name -> list of ONLY/remote entries
90 (module name = name of the module, which can be accessed via use-directive)
92 class UseSDict : public SDict<UseEntry>
95 UseSDict() : SDict<UseEntry>(17) {}
99 Contains names of used modules and names of local variables.
104 QStringList useNames; //!< contains names of used modules
105 QDict<void> localVars; //!< contains names of local variables
107 Scope() : localVars(7, FALSE /*caseSensitive*/) {}
110 /*===================================================================*/
115 static QCString docBlock; //!< contents of all lines of a documentation block
116 static QCString currentModule=0; //!< name of the current enclosing module
117 static UseSDict *useMembers= new UseSDict; //!< info about used modules
118 static UseEntry *useEntry = 0; //!< current use statement info
119 static QList<Scope> scopeStack;
120 // static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
121 static QCString str=""; //!> contents of fortran string
123 static CodeOutputInterface * g_code;
125 // TODO: is this still needed? if so, make it work
126 static QCString g_parmType;
127 static QCString g_parmName;
129 static const char * g_inputString; //!< the code fragment as text
130 static int g_inputPosition; //!< read offset during parsing
131 static int g_inputLines; //!< number of line in the code fragment
132 static int g_yyLineNr; //!< current line number
133 static bool g_needsTermination;
134 static Definition *g_searchCtx;
135 static bool g_collectXRefs;
136 static bool g_isFixedForm;
138 static bool g_insideBody; //!< inside subprog/program body? => create links
139 static const char * g_currentFontClass;
141 static bool g_exampleBlock;
142 static QCString g_exampleName;
143 static QCString g_exampleFile;
145 static FileDef * g_sourceFileDef;
146 static Definition * g_currentDefinition;
147 static MemberDef * g_currentMemberDef;
148 static bool g_includeCodeFragment;
150 static char stringStartSymbol; // single or double quote
151 // count in variable declaration to filter out
152 // declared from referenced names
153 static int bracketCount = 0;
155 static bool g_endComment;
157 // simplified way to know if this is fixed form
158 // duplicate in fortranscanner.l
159 static bool recognizeFixedForm(const char* contents, FortranFormat format)
164 if (format == FortranFormat_Fixed) return TRUE;
165 if (format == FortranFormat_Free) return FALSE;
186 if(column==1) return TRUE;
190 if(column>1 && column<7) return FALSE;
195 if(column==7) return TRUE;
202 static void endFontClass()
204 if (g_currentFontClass)
206 g_code->endFontClass();
207 g_currentFontClass=0;
211 static void startFontClass(const char *s)
214 g_code->startFontClass(s);
215 g_currentFontClass=s;
218 static void setCurrentDoc(const QCString &anchor)
220 if (Doxygen::searchIndex)
224 Doxygen::searchIndex->setCurrentDoc(g_searchCtx,g_searchCtx->anchor(),FALSE);
228 Doxygen::searchIndex->setCurrentDoc(g_sourceFileDef,anchor,TRUE);
233 static void addToSearchIndex(const char *text)
235 if (Doxygen::searchIndex)
237 Doxygen::searchIndex->addWord(text,FALSE);
241 /*! start a new line of code, inserting a line number if g_sourceFileDef
242 * is TRUE. If a definition starts at the current line, then the line
243 * number is linked to the documentation of that definition.
245 static void startCodeLine()
249 //QCString lineNumber,lineAnchor;
250 //lineNumber.sprintf("%05d",g_yyLineNr);
251 //lineAnchor.sprintf("l%05d",g_yyLineNr);
253 Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
254 //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>");
255 if (!g_includeCodeFragment && d)
257 g_currentDefinition = d;
258 g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
259 g_insideBody = FALSE;
260 g_endComment = FALSE;
261 g_parmType.resize(0);
262 g_parmName.resize(0);
264 lineAnchor.sprintf("l%05d",g_yyLineNr);
265 if (g_currentMemberDef)
267 g_code->writeLineNumber(g_currentMemberDef->getReference(),
268 g_currentMemberDef->getOutputFileBase(),
269 g_currentMemberDef->anchor(),g_yyLineNr);
270 setCurrentDoc(lineAnchor);
272 else if (d->isLinkableInProject())
274 g_code->writeLineNumber(d->getReference(),
275 d->getOutputFileBase(),
277 setCurrentDoc(lineAnchor);
282 g_code->writeLineNumber(0,0,0,g_yyLineNr);
285 g_code->startCodeLine(g_sourceFileDef);
286 if (g_currentFontClass)
288 g_code->startFontClass(g_currentFontClass);
293 static void endFontClass();
294 static void endCodeLine()
297 g_code->endCodeLine();
300 /*! write a code fragment `text' that may span multiple lines, inserting
301 * line numbers for each line.
303 static void codifyLines(char *text)
305 //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
309 const char * tmp_currentFontClass = g_currentFontClass;
313 while ((c=*p++) && c!='\n') { }
320 if (g_yyLineNr<g_inputLines)
324 if (tmp_currentFontClass)
326 startFontClass(tmp_currentFontClass);
337 static void codifyLines(QCString str)
339 char *tmp= (char *) malloc(str.length()+1);
345 /*! writes a link to a fragment \a text that may span multiple lines, inserting
346 * line numbers for each line. If \a text contains newlines, the link will be
347 * split into multiple links with the same destination, one for each line.
349 static void writeMultiLineCodeLink(CodeOutputInterface &ol,
350 Definition *d,const char *text)
352 static bool sourceTooltips = Config_getBool("SOURCE_TOOLTIPS");
353 TooltipManager::instance()->addTooltip(d);
354 QCString ref = d->getReference();
355 QCString file = d->getOutputFileBase();
356 QCString anchor = d->anchor();
358 if (!sourceTooltips) // fall back to simple "title" tooltips
360 tooltip = d->briefDescriptionAsTooltip();
363 char *p=(char *)text;
368 while ((c=*p++) && c!='\n') { }
373 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
374 ol.writeCodeLink(ref,file,anchor,sp,tooltip);
376 if (g_yyLineNr<g_inputLines)
383 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
384 ol.writeCodeLink(ref,file,anchor,sp,tooltip);
391 //-------------------------------------------------------------------------------
393 searches for definition of a type
394 @param tname the name of the type
395 @param moduleName name of enclosing module or null, if global entry
396 @param cd the entry, if found or null
397 @param useDict dictionary of data of USE-statement
398 @returns true, if type is found
400 static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
401 ClassDef *&cd, UseSDict *usedict=0)
403 if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
405 //cout << "=== search for type: " << tname << endl;
408 if ((cd=Doxygen::classSDict->find(tname)))
410 //cout << "=== type found in global module" << endl;
413 else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname)))
415 //cout << "=== type found in local module" << endl;
421 for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di)
423 if ((cd= Doxygen::classSDict->find(use->module+"::"+tname)))
425 //cout << "=== type found in used module" << endl;
435 searches for definition of function memberName
436 @param memberName the name of the function/variable
437 @param moduleName name of enclosing module or null, if global entry
438 @param md the entry, if found or null
439 @param usedict array of data of USE-statement
440 @returns true, if found
442 static bool getFortranDefs(const QCString &memberName, const QCString &moduleName,
443 MemberDef *&md, UseSDict *usedict=0)
445 if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */
447 // look in local variables
448 QListIterator<Scope> it(scopeStack);
450 for (it.toLast();(scope=it.current());--it)
452 if (scope->localVars.find(memberName))
456 // search for function
457 MemberName *mn = Doxygen::functionNameSDict->find(memberName);
460 mn = Doxygen::memberNameSDict->find(memberName);
463 if (mn) // name is known
465 MemberListIterator mli(*mn);
466 for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name
468 FileDef *fd=md->getFileDef();
469 GroupDef *gd=md->getGroupDef();
471 //cout << "found link with same name: " << fd->fileName() << " " << memberName;
472 //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
474 if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
476 NamespaceDef *nspace= md->getNamespaceDef();
479 { // found function in global scope
482 else if (moduleName == nspace->name())
483 { // found in local scope
487 { // else search in used modules
488 QCString moduleName= nspace->name();
489 UseEntry *ue= usedict->find(moduleName);
492 // check if only-list exists and if current entry exists is this list
493 QStringList &only= ue->onlyNames;
496 //cout << " found in module " << moduleName << " entry " << memberName << endl;
497 return TRUE; // whole module used
501 for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
503 //cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl;
504 if (memberName == (*it).utf8())
506 return TRUE; // found in ONLY-part of use list
519 gets the link to a generic procedure which depends not on the name, but on the parameter list
522 static bool getGenericProcedureLink(const ClassDef *cd,
523 const char *memberText,
524 CodeOutputInterface &ol)
532 static bool getLink(UseSDict *usedict, // dictonary with used modules
533 const char *memberText, // exact member text
534 CodeOutputInterface &ol,
538 QCString memberName= removeRedundantWhiteSpace(memberText);
540 if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable())
542 //if (md->isVariable()) return FALSE; // variables aren't handled yet
544 Definition *d = md->getOuterScope()==Doxygen::globalScope ?
545 md->getBodyDef() : md->getOuterScope();
546 if (md->getGroupDef()) d = md->getGroupDef();
547 if (d && d->isLinkable())
549 if (g_currentDefinition && g_currentMemberDef &&
550 md!=g_currentMemberDef && g_insideBody && g_collectXRefs)
552 addDocCrossReference(g_currentMemberDef,md);
554 writeMultiLineCodeLink(ol,md,text ? text : memberText);
555 addToSearchIndex(text ? text : memberText);
563 static void generateLink(CodeOutputInterface &ol, char *lname)
566 QCString tmp = lname;
567 tmp = removeRedundantWhiteSpace(tmp.lower());
569 // check if lowercase lname is a linkable type or interface
570 if ( (getFortranTypeDefs(tmp, currentModule, cd, useMembers)) && cd->isLinkable() )
572 if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
573 (getGenericProcedureLink(cd, tmp, ol)) )
575 //cout << "=== generic procedure resolved" << endl;
578 { // write type or interface link
579 writeMultiLineCodeLink(ol,cd,tmp);
580 addToSearchIndex(tmp.data());
583 // check for function/variable
584 else if (getLink(useMembers, tmp, ol, tmp))
586 //cout << "=== found link for lowercase " << lname << endl;
590 // nothing found, just write out the word
591 //startFontClass("charliteral"); //test
593 //endFontClass(); //test
594 addToSearchIndex(tmp.data());
598 /*! counts the number of lines in the input */
599 static int countLines()
601 const char *p=g_inputString;
607 if (c=='\n') count++;
609 if (p>g_inputString && *(p-1)!='\n')
610 { // last line does not end with a \n, so we add an extra
611 // line and explicitly terminate the line after parsing.
613 g_needsTermination=TRUE;
618 //----------------------------------------------------------------------------
620 static void startScope()
622 DBG_CTX((stderr, "===> startScope %s",yytext));
623 Scope *scope = new Scope;
624 scopeStack.append(scope);
628 static void endScope()
630 DBG_CTX((stderr,"===> endScope %s",yytext));
631 if (scopeStack.isEmpty())
633 DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n"));
637 Scope *scope = scopeStack.getLast();
638 scopeStack.removeLast();
639 for ( QStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it)
641 useMembers->remove((*it).utf8());
646 static void addUse(const QCString &moduleName)
648 if (!scopeStack.isEmpty())
649 scopeStack.getLast()->useNames.append(moduleName);
652 static void addLocalVar(const QCString &varName)
654 if (!scopeStack.isEmpty())
655 scopeStack.getLast()->localVars.insert(varName, (void*)1);
658 //----------------------------------------------------------------------------
660 /* -----------------------------------------------------------------*/
662 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
664 static int yyread(char *buf,int max_size)
667 while( c < max_size && g_inputString[g_inputPosition] )
669 *buf = g_inputString[g_inputPosition++] ;
678 ID [a-z_A-Z]+{IDSYM}*
679 SUBPROG (subroutine|function)
684 ARGS_L0 ("("[^)]*")")
685 ARGS_L1a [^()]*"("[^)]*")"[^)]*
686 ARGS_L1 ("("{ARGS_L1a}*")")
687 ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
688 ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
690 NUM_TYPE (complex|integer|logical|real)
691 LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
693 CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
694 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE)
696 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
697 ATTR_SPEC (IMPLICIT|ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|RECURSIVE|PURE|IMPURE|ELEMENTAL|VALUE|NOPASS|DEFERRED)
698 ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC)
699 /* Assume that attribute statements are almost the same as attributes. */
700 ATTR_STMT {ATTR_SPEC}|DIMENSION
701 FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT)
702 COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON)
704 PREFIX (RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,3}(RECURSIVE|IMPURE|PURE|ELEMENTAL)?
730 /*==================================================================*/
732 /*-------- ignore ------------------------------------------------------------*/
734 <Start>{IGNORE}/{BS}"("? { // do not search keywords, intrinsics... TODO: complete list
737 /*-------- inner construct ---------------------------------------------------*/
739 <Start>{COMMANDS}/{BS}[,( \t\n] { // highlight
740 /* font class is defined e.g. in doxygen.css */
741 startFontClass("keyword");
745 <Start>{FLOW}/{BS}[,( \t\n] {
748 if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT;
750 /* font class is defined e.g. in doxygen.css */
751 startFontClass("keywordflow");
755 <Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) {
756 startFontClass("keywordflow");
760 <Start>"end"({BS}{FLOW})?/[ \t\n] { // list is a bit long as not all have possible end
761 startFontClass("keywordflow");
766 <Start>"implicit"{BS}"none" {
767 startFontClass("keywordtype");
771 <Start>^{BS}"namelist"/[//] { // Namelist specification
772 startFontClass("keywordtype");
776 /*-------- use statement -------------------------------------------*/
778 startFontClass("keywordtype");
781 yy_push_state(YY_START);
785 QCString tmp = yytext;
788 generateLink(*g_code, yytext);
791 /* append module name to use dict */
792 useEntry = new UseEntry();
793 //useEntry->module = yytext;
794 //useMembers->append(yytext, useEntry);
796 useEntry->module = tmp;
797 useMembers->append(tmp, useEntry);
800 <Use>,{BS}"ONLY" { // TODO: rename
801 startFontClass("keywordtype");
804 yy_push_state(YY_START);
807 <UseOnly,Import>{BS},{BS} { codifyLines(yytext); }
808 <UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yytext); YY_FTN_RESET}
811 generateLink(*g_code, yytext);
813 useEntry->onlyNames.append(yytext);
815 <Use,UseOnly,Import>"\n" {
817 yy_pop_state();YY_FTN_RESET
819 <Start>"import"{BS_} {
820 startFontClass("keywordtype");
823 yy_push_state(YY_START);
828 generateLink(*g_code, yytext);
831 /*-------- fortran module -----------------------------------------*/
832 <Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
834 startFontClass("keyword");
837 yy_push_state(YY_START);
839 if (!qstricmp(yytext,"module")) currentModule="module";
841 <Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { //
843 startFontClass("keyword");
846 yy_push_state(YY_START);
850 if (currentModule == "module")
852 currentModule=yytext;
853 currentModule = currentModule.lower();
855 generateLink(*g_code,yytext);
858 <ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable deklaration
859 startFontClass("keyword");
860 g_code->codify(yytext);
863 <ClassName>\n { // interface may be without name
867 <Start>"end"({BS_}"module").* { // just reset currentModule, rest is done in following rule
871 /*-------- subprog definition -------------------------------------*/
872 <Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
873 startFontClass("keyword");
877 <Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found
878 startFontClass("keyword");
881 yy_push_state(YY_START);
884 <Subprog>{ID} { // subroutine/function name
885 DBG_CTX((stderr, "===> start subprogram %s\n", yytext));
887 generateLink(*g_code,yytext);
889 <Subprog>"(".* { // ignore rest of line
892 <Subprog,Subprogend>"\n" { codifyLines(yytext);
896 <Start>^{BS}"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"type"|"interface"){BS} { // Fortran subroutine or function ends
897 //cout << "===> end function " << yytext << endl;
899 startFontClass("keyword");
902 yy_push_state(YY_START);
905 <Subprogend>{ID}/{BS}(\n|!) {
906 generateLink(*g_code,yytext);
909 <Start>^{BS}"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"type"|"interface"){BS}/(\n|!) { // Fortran subroutine or function ends
910 //cout << "===> end function " << yytext << endl;
912 startFontClass("keyword");
916 /*-------- variable declaration ----------------------------------*/
917 <Start>{TYPE_SPEC}/[,:( ] {
918 yy_push_state(YY_START);
920 startFontClass("keywordtype");
921 g_code->codify(yytext);
925 startFontClass("keywordtype");
926 g_code->codify(yytext);
929 <Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration
930 startFontClass("keywordtype");
931 g_code->codify(yytext);
934 <Declaration>{ID} { // local var
935 if (g_currentMemberDef && g_currentMemberDef->isFunction() && bracketCount==0)
937 g_code->codify(yytext);
942 generateLink(*g_code, yytext);
945 <Declaration>[(] { // start of array specification
947 g_code->codify(yytext);
950 <Declaration>[)] { // end array specification
952 g_code->codify(yytext);
955 <Declaration>"&" { // continuation line
956 g_code->codify(yytext);
957 yy_push_state(YY_START);
960 <DeclContLine>"\n" { // declaration not yet finished
966 <Declaration>"\n" { // end declaration line
980 /*-------- subprog calls -----------------------------------------*/
984 yy_push_state(YY_START);
987 <SubCall>{ID} { // subroutine call
989 generateLink(*g_code, yytext);
993 <Start>{ID}{BS}/"(" { // function call
995 generateLink(*g_code, yytext);
999 /*-------- comments ---------------------------------------------------*/
1000 <Start>\n?{BS}"!>"|"!<" { // start comment line or comment block
1001 if (yytext[0] == '\n')
1007 // Actually we should see if ! on position 6, can be continuation
1008 // but the chance is very unlikely, so no effort to solve it here
1009 yy_push_state(YY_START);
1013 <Declaration>{BS}"!<" { // start comment line or comment block
1014 yy_push_state(YY_START);
1019 <DocBlock>.* { // contents of current comment line
1022 <DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line)
1026 // Actually we should see if ! on position 6, can be continuation
1027 // but the chance is very unlikely, so no effort to solve it here
1030 <DocBlock>"\n" { // comment block ends at the end of this line
1031 // remove special comment (default config)
1032 if (Config_getBool("STRIP_CODE_COMMENTS"))
1034 g_yyLineNr+=((QCString)docBlock).contains('\n');
1037 if (g_yyLineNr<g_inputLines)
1043 else // do not remove comment
1045 startFontClass("comment");
1046 codifyLines(docBlock);
1054 <*>"!"[^><\n].*|"!"$ { // normal comment
1055 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
1056 if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
1057 startFontClass("comment");
1058 codifyLines(yytext);
1062 <*>^[Cc*].* { // normal comment
1063 if(! g_isFixedForm) YY_FTN_REJECT;
1065 startFontClass("comment");
1066 codifyLines(yytext);
1070 /*------ preprocessor --------------------------------------------*/
1072 if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
1073 startFontClass("preprocessor");
1074 codifyLines(yytext);
1078 /*------ variable references? -------------------------------------*/
1080 <Start>"%"{BS}{ID} { // ignore references to elements
1081 g_code->codify(yytext);
1085 generateLink(*g_code, yytext);
1088 /*------ strings --------------------------------------------------*/
1089 <*>"\\\\" { str+=yytext; /* ignore \\ */}
1090 <*>"\\\""|\\\' { str+=yytext; /* ignore \" */}
1092 <String>\n { // string with \n inside
1094 startFontClass("stringliteral");
1100 <String>\"|\' { // string ends with next quote without previous backspace
1101 if(yytext[0]!=stringStartSymbol) YY_FTN_REJECT; // single vs double quote
1103 startFontClass("stringliteral");
1108 <String>. {str+=yytext;}
1110 <*>\"|\' { /* string starts */
1111 /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */
1112 if (g_isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
1113 yy_push_state(YY_START);
1114 stringStartSymbol=yytext[0]; // single or double quote
1118 /*-----------------------------------------------------------------------------*/
1127 codifyLines(yytext);
1131 <*>^{BS}"type"{BS}"=" { g_code->codify(yytext); }
1134 g_code->codify(yytext);
1136 <*>{LOG_OPER} { // Fortran logical comparison keywords
1137 g_code->codify(yytext);
1141 /*@ ----------------------------------------------------------------------------
1144 /*===================================================================*/
1147 void resetFortranCodeParserState() {}
1149 void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s,
1150 bool exBlock, const char *exName,FileDef *fd,
1151 int startLine,int endLine,bool inlineFragment,
1152 MemberDef *memberDef,bool,Definition *searchCtx,
1153 bool collectXRefs, FortranFormat format)
1155 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1161 if (s.isEmpty()) return;
1162 printlex(yy_flex_debug, TRUE, __FILE__, fd ? fd->fileName().data(): NULL);
1163 TooltipManager::instance()->clearTooltips();
1166 g_inputPosition = 0;
1167 g_isFixedForm = recognizeFixedForm((const char*)s,format);
1168 g_currentFontClass = 0;
1169 g_needsTermination = FALSE;
1170 g_searchCtx = searchCtx;
1171 g_collectXRefs = collectXRefs;
1173 g_inputLines = endLine+1;
1175 g_inputLines = countLines();
1178 g_yyLineNr = startLine;
1182 g_exampleBlock = exBlock;
1183 g_exampleName = exName;
1184 g_sourceFileDef = fd;
1185 if (exBlock && fd==0)
1187 // create a dummy filedef for the example
1188 g_sourceFileDef = new FileDef("",exName);
1190 if (g_sourceFileDef)
1192 setCurrentDoc("l00001");
1194 g_currentDefinition = 0;
1195 g_currentMemberDef = 0;
1196 if (!g_exampleName.isEmpty())
1198 g_exampleFile = convertNameToFile(g_exampleName+"-example");
1200 g_includeCodeFragment = inlineFragment;
1202 g_parmName.resize(0);
1203 g_parmType.resize(0);
1204 fortrancodeYYrestart( fortrancodeYYin );
1207 if (g_needsTermination)
1210 g_code->endCodeLine();
1214 TooltipManager::instance()->writeTooltips(*g_code);
1216 if (exBlock && g_sourceFileDef)
1218 // delete the temporary file definition used for this example
1219 delete g_sourceFileDef;
1222 printlex(yy_flex_debug, FALSE, __FILE__, fd ? fd->fileName().data(): NULL);
1226 #if !defined(YY_FLEX_SUBMINOR_VERSION)
1227 extern "C" { // some bogus code to keep the compiler happy
1228 void fortrancodeYYdummy() { yy_flex_realloc(0,0); }
1230 #elif YY_FLEX_SUBMINOR_VERSION<33
1231 #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!"
1233 extern "C" { // some bogus code to keep the compiler happy
1234 void fortrancodeYYdummy() { yy_top_state(); }