1 /******************************************************************************
3 * Parser for syntax highlighting and references for Fortran90 F subset
5 * Copyright (C) by Anke Visser
6 * based on the work of Dimitri van Heesch.
7 * Copyright (C) 2020 by Dimitri van Heesch.
9 * Permission to use, copy, modify, and distribute this software and its
10 * documentation under the terms of the GNU General Public License is hereby
11 * granted. No representations are made about the suitability of this software
12 * for any purpose. It is provided "as is" without express or implied warranty.
13 * See the GNU General Public License for more details.
15 * Documents produced by Doxygen are derivative works derived from the
16 * input used in their production; they are not affected by this license.
21 @todo - continuation lines not always recognized
22 - merging of use-statements with same module name and different only-names
23 - rename part of use-statement
24 - links to interface functions
25 - references to variables
27 %option never-interactive
28 %option case-insensitive
30 %option prefix="fortrancodeYY"
31 %option extra-type="struct fortrancodeYY_state *"
32 %option noyy_top_state
35 // forward declare yyscan_t to improve type safety
36 #define YY_TYPEDEF_YY_SCANNER_T
38 typedef yyguts_t *yyscan_t;
52 #include "outputlist.h"
54 #include "membername.h"
58 #include "classlist.h"
60 #include "namespacedef.h"
62 #include "fortrancode.h"
63 #include "fortranscanner.h"
64 #include "containers.h"
66 const int fixedCommentAfter = 72;
68 // Toggle for some debugging info
69 //#define DBG_CTX(x) fprintf x
70 #define DBG_CTX(x) do { } while(0)
72 #define YY_NO_TOP_STATE 1
74 #define YY_NO_UNISTD_H 1
76 #define USE_STATE2STRING 0
79 * For fixed formatted code position 6 is of importance (continuation character).
80 * The following variables and macros keep track of the column number
81 * YY_USER_ACTION is always called for each scan action
82 * YY_FTN_RESET is used to handle end of lines and reset the column counter
83 * YY_FTN_REJECT resets the column counters when a pattern is rejected and thus rescanned.
88 #define YY_USER_ACTION {yy_old_start = yy_my_start; yy_my_start = yy_end; yy_end += static_cast<int>(yyleng);}
89 #define YY_FTN_RESET {yy_old_start = 0; yy_my_start = 0; yy_end = 1;}
90 #define YY_FTN_REJECT {yy_end = yy_my_start; yy_my_start = yy_old_start; REJECT;}
92 //--------------------------------------------------------------------------------
95 data of an use-statement
100 QCString module; // just for debug
101 std::vector<QCString> onlyNames; /* entries of the ONLY-part */
105 module name -> list of ONLY/remote entries
106 (module name = name of the module, which can be accessed via use-directive)
108 class UseMap : public std::map<std::string,UseEntry>
113 Contains names of used modules and names of local variables.
118 std::vector<QCString> useNames; //!< contains names of used modules
119 StringUnorderedSet localVars; //!< contains names of local variables
120 StringUnorderedSet externalVars; //!< contains names of external entities
123 /*===================================================================*/
128 struct fortrancodeYY_state
130 QCString docBlock; //!< contents of all lines of a documentation block
131 QCString currentModule=QCString(); //!< name of the current enclosing module
132 UseMap useMembers; //!< info about used modules
133 UseEntry useEntry; //!< current use statement info
134 std::vector<Scope> scopeStack;
135 bool isExternal = false;
136 QCString str=QCString(); //!< contents of fortran string
138 CodeOutputInterface * code = 0;
140 const char * inputString = 0; //!< the code fragment as text
141 yy_size_t inputPosition = 0; //!< read offset during parsing
142 int inputLines = 0; //!< number of line in the code fragment
143 int yyLineNr = 0; //!< current line number
144 int contLineNr = 0; //!< current, local, line number for continuation determination
145 int *hasContLine = 0; //!< signals whether or not a line has a continuation line (fixed source form)
146 bool needsTermination = false;
147 const Definition *searchCtx = 0;
148 bool collectXRefs = false;
149 bool isFixedForm = false;
151 bool insideBody = false; //!< inside subprog/program body? => create links
152 const char * currentFontClass = 0;
154 bool exampleBlock = false;
155 QCString exampleName;
156 QCString exampleFile;
158 const FileDef * sourceFileDef = 0;
159 const Definition * currentDefinition = 0;
160 const MemberDef * currentMemberDef = 0;
161 bool includeCodeFragment = false;
163 char stringStartSymbol = '\0'; // single or double quote
164 // count in variable declaration to filter out
165 // declared from referenced names
166 int bracketCount = 0;
168 // signal when in type / class /procedure declaration
171 bool endComment = false;
172 TooltipManager tooltipManager;
176 static const char *stateToString(int state);
179 static bool getFortranNamespaceDefs(const QCString &mname,
181 static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
182 ClassDef *&cd, const UseMap &useMap);
184 //----------------------------------------------------------------------------
186 static void endFontClass(yyscan_t yyscanner);
187 static void startFontClass(yyscan_t yyscanner,const char *s);
188 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
189 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
190 static void startCodeLine(yyscan_t yyscanner);
191 static void endCodeLine(yyscan_t yyscanner);
192 static void nextCodeLine(yyscan_t yyscanner);
193 static void codifyLines(yyscan_t yyscanner,const QCString &text);
194 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
195 Definition *d,const QCString &text);
196 static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd,
197 const QCString &memberText,
198 CodeOutputInterface &ol);
199 static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // map with used modules
200 const QCString &memberText, // exact member text
201 CodeOutputInterface &ol,
202 const QCString &text);
203 static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, const QCString &lname);
204 static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, const char *lname);
205 static int countLines(yyscan_t yyscanner);
206 static void startScope(yyscan_t yyscanner);
207 static void endScope(yyscan_t yyscanner);
208 static void addUse(yyscan_t yyscanner,const QCString &moduleName);
209 static void addLocalVar(yyscan_t yyscanner,const QCString &varName);
210 static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
211 const UseMap &useMap);
212 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
215 //-------------------------------------------------------------------
217 static std::mutex g_docCrossReferenceMutex;
218 static std::mutex g_countFlowKeywordsMutex;
220 /* -----------------------------------------------------------------*/
222 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
227 ID [a-z_A-Z]+{IDSYM}*
228 SUBPROG (subroutine|function)
233 ARGS_L0 ("("[^)]*")")
234 ARGS_L1a [^()]*"("[^)]*")"[^)]*
235 ARGS_L1 ("("{ARGS_L1a}*")")
236 ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
237 ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
239 NUM_TYPE (complex|integer|logical|real)
240 LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
242 CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
243 TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE|ENUMERATOR)
245 INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
246 ATTR_SPEC (IMPLICIT|ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|PRIVATE|PUBLIC|SAVE|TARGET|(NON_)?RECURSIVE|PURE|IMPURE|ELEMENTAL|VALUE|NOPASS|DEFERRED|CONTIGUOUS|VOLATILE)
247 ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC)
248 /* Assume that attribute statements are almost the same as attributes. */
249 ATTR_STMT {ATTR_SPEC}|DIMENSION
250 FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT|GO{BS}TO)
251 COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON)
253 PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?0
254 LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
272 %x DeclarationBinding
278 /*==================================================================*/
280 /*-------- ignore ------------------------------------------------------------*/
282 <Start>{IGNORE}/{BS}"(" { // do not search keywords, intrinsics... TODO: complete list
283 codifyLines(yyscanner,yytext);
285 /*-------- inner construct ---------------------------------------------------*/
287 <Start>{COMMANDS}/{BS}[,( \t\n] { // highlight
288 /* font class is defined e.g. in doxygen.css */
289 startFontClass(yyscanner,"keyword");
290 codifyLines(yyscanner,yytext);
291 endFontClass(yyscanner);
293 <Start>{FLOW}/{BS}[,( \t\n] {
294 if (yyextra->isFixedForm)
296 if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT;
298 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
300 std::lock_guard<std::mutex> lock(g_countFlowKeywordsMutex);
301 MemberDefMutable *mdm = toMemberDefMutable(yyextra->currentMemberDef);
304 mdm->incrementFlowKeyWordCount();
307 /* font class is defined e.g. in doxygen.css */
308 startFontClass(yyscanner,"keywordflow");
309 codifyLines(yyscanner,yytext);
310 endFontClass(yyscanner);
312 <Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) {
313 startFontClass(yyscanner,"keywordflow");
314 codifyLines(yyscanner,yytext);
315 endFontClass(yyscanner);
317 <Start>{BS}"end"({BS}{FLOW})/[ \t\n] { // list is a bit long as not all have possible end
318 startFontClass(yyscanner,"keywordflow");
319 codifyLines(yyscanner,yytext);
320 endFontClass(yyscanner);
322 <Start>"implicit"{BS}("none"|{TYPE_SPEC}) {
323 startFontClass(yyscanner,"keywordtype");
324 codifyLines(yyscanner,yytext);
325 endFontClass(yyscanner);
327 <Start>^{BS}"namelist"/[/] { // Namelist specification
328 startFontClass(yyscanner,"keywordtype");
329 codifyLines(yyscanner,yytext);
330 endFontClass(yyscanner);
332 /*-------- use statement -------------------------------------------*/
334 startFontClass(yyscanner,"keywordtype");
335 codifyLines(yyscanner,yytext);
336 endFontClass(yyscanner);
337 yy_push_state(YY_START,yyscanner);
340 <Use>"ONLY" { // TODO: rename
341 startFontClass(yyscanner,"keywordtype");
342 codifyLines(yyscanner,yytext);
343 endFontClass(yyscanner);
344 yy_push_state(YY_START,yyscanner);
348 QCString tmp(yytext);
350 yyextra->insideBody=TRUE;
351 generateLink(yyscanner,*yyextra->code, yytext);
352 yyextra->insideBody=FALSE;
354 /* append module name to use dict */
355 yyextra->useEntry = UseEntry();
356 yyextra->useEntry.module = tmp;
357 yyextra->useMembers.insert(std::make_pair(tmp.str(), yyextra->useEntry));
358 addUse(yyscanner,tmp);
360 <Use,UseOnly,Import>{BS},{BS} { codifyLines(yyscanner,yytext); }
361 <UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yyscanner,yytext);
362 yyextra->contLineNr++;
365 QCString tmp(yytext);
367 yyextra->useEntry.onlyNames.push_back(tmp);
368 yyextra->insideBody=TRUE;
369 generateLink(yyscanner,*yyextra->code, yytext);
370 yyextra->insideBody=FALSE;
372 <Use,UseOnly,Import>"\n" {
374 yy_pop_state(yyscanner);
377 <*>"import"{BS}/"\n" |
379 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
380 startFontClass(yyscanner,"keywordtype");
381 codifyLines(yyscanner,yytext);
382 endFontClass(yyscanner);
383 yy_push_state(YY_START,yyscanner);
387 yyextra->insideBody=TRUE;
388 generateLink(yyscanner,*yyextra->code, yytext);
389 yyextra->insideBody=FALSE;
391 <Import>("ONLY"|"NONE"|"ALL") {
392 startFontClass(yyscanner,"keywordtype");
393 codifyLines(yyscanner,yytext);
394 endFontClass(yyscanner);
396 /*-------- fortran module -----------------------------------------*/
397 <Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
398 startScope(yyscanner);
399 startFontClass(yyscanner,"keyword");
400 codifyLines(yyscanner,yytext);
401 endFontClass(yyscanner);
402 yy_push_state(YY_START,yyscanner);
404 if (!qstricmp(yytext,"module")) yyextra->currentModule="module";
406 <Start>("enum")/{BS_}|{BS}{COMMA}{BS}{LANGUAGE_BIND_SPEC}|\n { //
407 startScope(yyscanner);
408 startFontClass(yyscanner,"keyword");
409 codifyLines(yyscanner,yytext);
410 endFontClass(yyscanner);
411 yy_push_state(YY_START,yyscanner);
414 <*>{LANGUAGE_BIND_SPEC} { //
415 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
416 startFontClass(yyscanner,"keyword");
417 codifyLines(yyscanner,yytext);
418 endFontClass(yyscanner);
420 <Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { //
421 startScope(yyscanner);
422 startFontClass(yyscanner,"keyword");
423 codifyLines(yyscanner,yytext);
424 endFontClass(yyscanner);
425 yy_push_state(YY_START,yyscanner);
429 if (yyextra->currentModule == "module")
431 yyextra->currentModule=yytext;
432 yyextra->currentModule = yyextra->currentModule.lower();
434 generateLink(yyscanner,*yyextra->code,yytext);
435 yy_pop_state(yyscanner);
437 <ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable declaration
438 startFontClass(yyscanner,"keyword");
439 yyextra->code->codify(QCString(yytext));
440 endFontClass(yyscanner);
442 <ClassName>\n { // interface may be without name
443 yy_pop_state(yyscanner);
446 <Start>^{BS}"end"({BS_}"enum").* {
449 <Start>^{BS}"end"({BS_}"type").* {
452 <Start>^{BS}"end"({BS_}"module").* { // just reset yyextra->currentModule, rest is done in following rule
453 yyextra->currentModule=0;
456 /*-------- subprog definition -------------------------------------*/
457 <Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
458 startFontClass(yyscanner,"keyword");
459 codifyLines(yyscanner,yytext);
460 endFontClass(yyscanner);
462 <Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found
463 startFontClass(yyscanner,"keyword");
464 codifyLines(yyscanner,yytext);
465 endFontClass(yyscanner);
466 yy_push_state(YY_START,yyscanner);
469 <Subprog>{ID} { // subroutine/function name
470 DBG_CTX((stderr, "===> start subprogram %s\n", yytext));
471 startScope(yyscanner);
472 generateLink(yyscanner,*yyextra->code,yytext);
474 <Subprog>"result"/{BS}"("[^)]*")" {
475 startFontClass(yyscanner,"keyword");
476 codifyLines(yyscanner,yytext);
477 endFontClass(yyscanner);
479 <Subprog>"("[^)]*")" { // ignore rest of line
480 codifyLines(yyscanner,yytext);
482 <Subprog,Subprogend>"\n" { codifyLines(yyscanner,yytext);
483 yyextra->contLineNr++;
484 yy_pop_state(yyscanner);
487 <Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface")?{BS} { // Fortran subroutine or function ends
488 //cout << "===> end function " << yytext << endl;
490 startFontClass(yyscanner,"keyword");
491 codifyLines(yyscanner,yytext);
492 endFontClass(yyscanner);
493 yy_push_state(YY_START,yyscanner);
496 <Subprogend>{ID}/{BS}(\n|!|;) {
497 generateLink(yyscanner,*yyextra->code,yytext);
498 yy_pop_state(yyscanner);
500 <Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface"){BS}/(\n|!|;) { // Fortran subroutine or function ends
501 //cout << "===> end function " << yytext << endl;
503 startFontClass(yyscanner,"keyword");
504 codifyLines(yyscanner,yytext);
505 endFontClass(yyscanner);
507 /*-------- variable declaration ----------------------------------*/
508 <Start>^{BS}"real"/[,:( ] { // real is a bit tricky as it is a data type but also a function.
509 yy_push_state(YY_START,yyscanner);
511 startFontClass(yyscanner,"keywordtype");
512 yyextra->code->codify(QCString(yytext));
513 endFontClass(yyscanner);
515 <Start>{TYPE_SPEC}/[,:( ] {
516 QCString typ(yytext);
517 typ = removeRedundantWhiteSpace(typ.lower());
518 if (typ.startsWith("real")) YY_FTN_REJECT;
519 if (typ == "type" || typ == "class" || typ == "procedure") yyextra->inTypeDecl = 1;
520 yy_push_state(YY_START,yyscanner);
522 startFontClass(yyscanner,"keywordtype");
523 yyextra->code->codify(QCString(yytext));
524 endFontClass(yyscanner);
527 if (QCString(yytext) == "external")
529 yy_push_state(YY_START,yyscanner);
531 yyextra->isExternal = true;
533 startFontClass(yyscanner,"keywordtype");
534 yyextra->code->codify(QCString(yytext));
535 endFontClass(yyscanner);
537 <Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration
538 if (QCString(yytext) == "external") yyextra->isExternal = true;
539 startFontClass(yyscanner,"keywordtype");
540 yyextra->code->codify(QCString(yytext));
541 endFontClass(yyscanner);
543 <Declaration>{ID} { // local var
544 if (yyextra->isFixedForm && yy_my_start == 1)
546 startFontClass(yyscanner,"comment");
547 yyextra->code->codify(QCString(yytext));
548 endFontClass(yyscanner);
550 else if (yyextra->currentMemberDef &&
551 ((yyextra->currentMemberDef->isFunction() && (yyextra->currentMemberDef->typeString()!=QCString("subroutine") || yyextra->inTypeDecl)) ||
552 yyextra->currentMemberDef->isVariable() || yyextra->currentMemberDef->isEnumValue()
556 generateLink(yyscanner,*yyextra->code, yytext);
560 yyextra->code->codify(QCString(yytext));
561 addLocalVar(yyscanner,QCString(yytext));
564 <Declaration>{BS}("=>"|"="){BS} { // Procedure binding
565 BEGIN(DeclarationBinding);
566 yyextra->code->codify(QCString(yytext));
568 <DeclarationBinding>{ID} { // Type bound procedure link
569 generateLink(yyscanner,*yyextra->code, yytext);
570 yy_pop_state(yyscanner);
572 <Declaration>[(] { // start of array or type / class specification
573 yyextra->bracketCount++;
574 yyextra->code->codify(QCString(yytext));
577 <Declaration>[)] { // end array specification
578 yyextra->bracketCount--;
579 if (!yyextra->bracketCount) yyextra->inTypeDecl = 0;
580 yyextra->code->codify(QCString(yytext));
583 <Declaration,DeclarationBinding>"&" { // continuation line
584 yyextra->code->codify(QCString(yytext));
585 if (!yyextra->isFixedForm)
587 yy_push_state(YY_START,yyscanner);
591 <DeclContLine>"\n" { // declaration not yet finished
592 yyextra->contLineNr++;
593 codifyLines(yyscanner,yytext);
594 yyextra->bracketCount = 0;
595 yy_pop_state(yyscanner);
598 <Declaration,DeclarationBinding>"\n" { // end declaration line (?)
599 if (yyextra->endComment)
601 yyextra->endComment=FALSE;
605 codifyLines(yyscanner,yytext);
607 yyextra->bracketCount = 0;
608 yyextra->contLineNr++;
609 if (!(yyextra->hasContLine && yyextra->hasContLine[yyextra->contLineNr - 1]))
611 yyextra->isExternal = false;
612 yy_pop_state(yyscanner);
617 /*-------- subprog calls -----------------------------------------*/
620 startFontClass(yyscanner,"keyword");
621 codifyLines(yyscanner,yytext);
622 endFontClass(yyscanner);
623 yy_push_state(YY_START,yyscanner);
626 <SubCall>{ID} { // subroutine call
627 yyextra->insideBody=TRUE;
628 generateLink(yyscanner,*yyextra->code, yytext);
629 yyextra->insideBody=FALSE;
630 yy_pop_state(yyscanner);
632 <Start>{ID}{BS}/"(" { // function call
633 if (yyextra->isFixedForm && yy_my_start == 6)
635 // fixed form continuation line
638 else if (QCString(yytext).stripWhiteSpace().lower() == "type")
640 yy_push_state(YY_START,yyscanner);
642 startFontClass(yyscanner,"keywordtype");
643 yyextra->code->codify(QCString(yytext).stripWhiteSpace());
644 endFontClass(yyscanner);
645 yyextra->code->codify(QCString(yytext + 4));
649 yyextra->insideBody=TRUE;
650 generateLink(yyscanner,*yyextra->code,yytext);
651 yyextra->insideBody=FALSE;
655 /*-------- comments ---------------------------------------------------*/
656 <Start,Declaration,DeclarationBinding>\n?{BS}"!>"|"!<" { // start comment line or comment block
657 if (yytext[0] == '\n')
659 yyextra->contLineNr++;
662 yy_end = static_cast<int>(yyleng);
664 // Actually we should see if ! on position 6, can be continuation
665 // but the chance is very unlikely, so no effort to solve it here
666 yy_push_state(YY_START,yyscanner);
668 yyextra->docBlock=yytext;
670 <Declaration,DeclarationBinding>{BS}"!<" { // start comment line or comment block
671 yy_push_state(YY_START,yyscanner);
673 yyextra->docBlock=yytext;
676 <DocBlock>.* { // contents of current comment line
677 yyextra->docBlock+=yytext;
679 <DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line)
680 yyextra->contLineNr++;
683 yy_end = static_cast<int>(yyleng);
684 // Actually we should see if ! on position 6, can be continuation
685 // but the chance is very unlikely, so no effort to solve it here
686 yyextra->docBlock+=yytext;
688 <DocBlock>"\n" { // comment block ends at the end of this line
689 // remove special comment (default config)
690 yyextra->contLineNr++;
691 if (Config_getBool(STRIP_CODE_COMMENTS))
693 yyextra->yyLineNr+=((QCString)yyextra->docBlock).contains('\n');
694 yyextra->yyLineNr+=1;
695 nextCodeLine(yyscanner);
696 yyextra->endComment=TRUE;
698 else // do not remove comment
700 startFontClass(yyscanner,"comment");
701 codifyLines(yyscanner,yyextra->docBlock);
702 endFontClass(yyscanner);
705 yyextra->contLineNr--;
706 yy_pop_state(yyscanner);
710 <*>"!"[^><\n].*|"!"$ { // normal comment
711 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
712 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
713 startFontClass(yyscanner,"comment");
714 codifyLines(yyscanner,yytext);
715 endFontClass(yyscanner);
718 <*>^[Cc*].* { // normal comment
719 if(! yyextra->isFixedForm) YY_FTN_REJECT;
721 startFontClass(yyscanner,"comment");
722 codifyLines(yyscanner,yytext);
723 endFontClass(yyscanner);
725 <*>"assignment"/{BS}"("{BS}"="{BS}")" {
726 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
727 startFontClass(yyscanner,"keyword");
728 codifyLines(yyscanner,yytext);
729 endFontClass(yyscanner);
731 <*>"operator"/{BS}"("[^)]*")" {
732 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
733 startFontClass(yyscanner,"keyword");
734 codifyLines(yyscanner,yytext);
735 endFontClass(yyscanner);
738 /*------ preprocessor --------------------------------------------*/
740 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
741 yyextra->contLineNr++;
742 startFontClass(yyscanner,"preprocessor");
743 codifyLines(yyscanner,yytext);
744 endFontClass(yyscanner);
747 /*------ variable references? -------------------------------------*/
749 <Start>"%"{BS}{ID} { // ignore references to elements
750 yyextra->code->codify(QCString(yytext));
753 yyextra->insideBody=TRUE;
754 generateLink(yyscanner,*yyextra->code, yytext);
755 yyextra->insideBody=FALSE;
757 /*------ strings --------------------------------------------------*/
758 <String>\n { // string with \n inside
759 yyextra->contLineNr++;
760 yyextra->str+=yytext;
761 startFontClass(yyscanner,"stringliteral");
762 codifyLines(yyscanner,yyextra->str);
763 endFontClass(yyscanner);
767 <String>\"|\' { // string ends with next quote without previous backspace
768 if(yytext[0]!=yyextra->stringStartSymbol) YY_FTN_REJECT; // single vs double quote
769 yyextra->str+=yytext;
770 startFontClass(yyscanner,"stringliteral");
771 codifyLines(yyscanner,yyextra->str);
772 endFontClass(yyscanner);
773 yy_pop_state(yyscanner);
775 <String>. {yyextra->str+=yytext;}
777 <*>\"|\' { /* string starts */
778 /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */
779 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
780 yy_push_state(YY_START,yyscanner);
781 yyextra->stringStartSymbol=yytext[0]; // single or double quote
785 /*-----------------------------------------------------------------------------*/
788 if (yyextra->endComment)
790 yyextra->endComment=FALSE;
794 codifyLines(yyscanner,yytext);
795 // comment cannot extend over the end of a line so should always be terminated at the end of the line.
796 if (yyextra->currentFontClass && !strcmp(yyextra->currentFontClass,"comment")) endFontClass(yyscanner);
798 yyextra->contLineNr++;
801 <*>^{BS}"type"{BS}"=" { yyextra->code->codify(QCString(yytext)); }
803 <*>[\x80-\xFF]* { // keep utf8 characters together...
804 if (yyextra->isFixedForm && yy_my_start > fixedCommentAfter)
806 startFontClass(yyscanner,"comment");
807 codifyLines(yyscanner,yytext);
811 yyextra->code->codify(QCString(yytext));
815 if (yyextra->isFixedForm && yy_my_start > fixedCommentAfter)
817 //yy_push_state(YY_START,yyscanner);
819 //yyextra->docBlock=yytext;
820 startFontClass(yyscanner,"comment");
821 codifyLines(yyscanner,yytext);
825 yyextra->code->codify(QCString(yytext));
828 <*>{LOG_OPER} { // Fortran logical comparison keywords
829 yyextra->code->codify(QCString(yytext));
832 if (YY_START == DocBlock) {
833 if (!Config_getBool(STRIP_CODE_COMMENTS))
835 startFontClass(yyscanner,"comment");
836 codifyLines(yyscanner,yyextra->docBlock);
837 endFontClass(yyscanner);
844 /*@ ----------------------------------------------------------------------------
847 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
849 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
850 yy_size_t inputPosition = yyextra->inputPosition;
851 const char *s = yyextra->inputString + inputPosition;
853 while( c < max_size && *s)
858 yyextra->inputPosition += c;
862 static void endFontClass(yyscan_t yyscanner)
864 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
865 if (yyextra->currentFontClass)
867 yyextra->code->endFontClass();
868 yyextra->currentFontClass=0;
872 static void startFontClass(yyscan_t yyscanner,const char *s)
874 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
875 // if font class is already set don't stop and start it.
876 // strcmp does not like null pointers as input.
877 if (!yyextra->currentFontClass || !s || strcmp(yyextra->currentFontClass,s))
879 endFontClass(yyscanner);
880 yyextra->code->startFontClass(QCString(s));
881 yyextra->currentFontClass=s;
885 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
887 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
888 if (Doxygen::searchIndex)
890 if (yyextra->searchCtx)
892 yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
896 yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
901 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text)
903 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
904 if (Doxygen::searchIndex)
906 yyextra->code->addWord(text,FALSE);
910 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
911 * is TRUE. If a definition starts at the current line, then the line
912 * number is linked to the documentation of that definition.
914 static void startCodeLine(yyscan_t yyscanner)
916 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
917 if (yyextra->sourceFileDef)
919 //QCString lineNumber,lineAnchor;
920 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
921 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
923 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
924 //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,d ? qPrint(d->name()) : "<null>");
925 if (!yyextra->includeCodeFragment && d)
927 yyextra->currentDefinition = d;
928 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
929 yyextra->insideBody = FALSE;
930 yyextra->endComment = FALSE;
932 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
933 if (yyextra->currentMemberDef)
935 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
936 yyextra->currentMemberDef->getOutputFileBase(),
937 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
938 !yyextra->includeCodeFragment);
939 setCurrentDoc(yyscanner,lineAnchor);
941 else if (d->isLinkableInProject())
943 yyextra->code->writeLineNumber(d->getReference(),
944 d->getOutputFileBase(),
945 QCString(),yyextra->yyLineNr,
946 !yyextra->includeCodeFragment);
947 setCurrentDoc(yyscanner,lineAnchor);
952 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
953 !yyextra->includeCodeFragment);
956 yyextra->code->startCodeLine(yyextra->sourceFileDef);
957 if (yyextra->currentFontClass)
959 yyextra->code->startFontClass(QCString(yyextra->currentFontClass));
964 static void endCodeLine(yyscan_t yyscanner)
966 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
967 endFontClass(yyscanner);
968 yyextra->code->endCodeLine();
971 static void nextCodeLine(yyscan_t yyscanner)
973 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
974 const char * fc = yyextra->currentFontClass;
975 endCodeLine(yyscanner);
976 if (yyextra->yyLineNr<yyextra->inputLines)
978 yyextra->currentFontClass = fc;
979 startCodeLine(yyscanner);
983 /*! write a code fragment 'text' that may span multiple lines, inserting
984 * line numbers for each line.
986 static void codifyLines(yyscan_t yyscanner,const QCString &text)
988 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
989 //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text);
990 if (text.isEmpty()) return;
991 const char *p=text.data(),*sp=p;
997 while ((c=*p++) && c!='\n') { }
1000 yyextra->yyLineNr++;
1001 int l = (int)(p-sp-1);
1002 char *tmp = (char*)malloc(l+1);
1005 yyextra->code->codify(QCString(tmp));
1007 nextCodeLine(yyscanner);
1011 yyextra->code->codify(QCString(sp));
1017 /*! writes a link to a fragment \a text that may span multiple lines, inserting
1018 * line numbers for each line. If \a text contains newlines, the link will be
1019 * split into multiple links with the same destination, one for each line.
1021 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
1022 Definition *d,const QCString &text)
1024 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1025 static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1026 yyextra->tooltipManager.addTooltip(ol,d);
1027 QCString ref = d->getReference();
1028 QCString file = d->getOutputFileBase();
1029 QCString anchor = d->anchor();
1031 if (!sourceTooltips) // fall back to simple "title" tooltips
1033 tooltip = d->briefDescriptionAsTooltip();
1036 const char *p=text.data();
1041 while ((c=*p++) && c!='\n') { }
1044 yyextra->yyLineNr++;
1045 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1046 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1047 nextCodeLine(yyscanner);
1051 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1052 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1057 //-------------------------------------------------------------------------------
1059 searches for definition of a module (Namespace)
1060 @param mname the name of the module
1061 @param cd the entry, if found or null
1062 @returns true, if module is found
1064 static bool getFortranNamespaceDefs(const QCString &mname,
1067 if (mname.isEmpty()) return FALSE; /* empty name => nothing to link */
1069 // search for module
1070 if ((cd=Doxygen::namespaceLinkedMap->find(mname))) return TRUE;
1074 //-------------------------------------------------------------------------------
1076 searches for definition of a type
1077 @param tname the name of the type
1078 @param moduleName name of enclosing module or null, if global entry
1079 @param cd the entry, if found or null
1080 @param useMap map of data of USE-statement
1081 @returns true, if type is found
1083 static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
1084 ClassDef *&cd, const UseMap &useMap)
1086 if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
1088 //cout << "=== search for type: " << tname << endl;
1091 if ((cd=Doxygen::classLinkedMap->find(tname)))
1093 //cout << "=== type found in global module" << endl;
1096 else if (!moduleName.isEmpty() && (cd= Doxygen::classLinkedMap->find(moduleName+"::"+tname)))
1098 //cout << "=== type found in local module" << endl;
1103 for (const auto &kv : useMap)
1105 if ((cd= Doxygen::classLinkedMap->find(kv.second.module+"::"+tname)))
1107 //cout << "=== type found in used module" << endl;
1117 searches for definition of function memberName
1118 @param yyscanner the scanner data to be used
1119 @param memberName the name of the function/variable
1120 @param moduleName name of enclosing module or null, if global entry
1121 @param useMap map of data of USE-statement
1122 @returns MemberDef pointer, if found, or nullptr otherwise
1124 static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
1125 const UseMap &useMap)
1127 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1128 if (memberName.isEmpty()) return nullptr; /* empty name => nothing to link */
1130 // look in local variables
1131 for (auto it = yyextra->scopeStack.rbegin(); it!=yyextra->scopeStack.rend(); ++it)
1133 const Scope &scope = *it;
1134 std::string lowMemName = memberName.lower().str();
1135 if (scope.localVars .find(lowMemName)!=std::end(scope.localVars) && // local var
1136 scope.externalVars.find(lowMemName)==std::end(scope.externalVars)) // and not external
1142 // search for function
1143 MemberName *mn = Doxygen::functionNameLinkedMap->find(memberName);
1146 mn = Doxygen::memberNameLinkedMap->find(memberName);
1149 if (mn) // name is known
1151 // all found functions with given name
1152 for (const auto &md : *mn)
1154 const FileDef *fd=md->getFileDef();
1155 const GroupDef *gd=md->getGroupDef();
1156 const ClassDef *cd=md->getClassDef();
1158 //cout << "found link with same name: " << fd->fileName() << " " << memberName;
1159 //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
1161 if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
1163 const NamespaceDef *nspace= md->getNamespaceDef();
1166 { // found function in global scope
1168 { // Skip if bound to type
1172 else if (moduleName == nspace->name())
1173 { // found in local scope
1177 { // else search in used modules
1178 QCString usedModuleName= nspace->name();
1179 auto use_it = useMap.find(usedModuleName.str());
1180 if (use_it!=useMap.end())
1182 const UseEntry &ue = use_it->second;
1183 // check if only-list exists and if current entry exists is this list
1184 if (ue.onlyNames.empty())
1186 //cout << " found in module " << usedModuleName << " entry " << memberName << endl;
1187 return md.get(); // whole module used
1191 for ( const auto &name : ue.onlyNames)
1193 //cout << " search in only: " << usedModuleName << ":: " << memberName << "==" << (*it)<< endl;
1194 if (memberName == name)
1196 return md.get(); // found in ONLY-part of use list
1209 gets the link to a generic procedure which depends not on the name, but on the parameter list
1210 @todo implementation
1212 static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd,
1213 const QCString &memberText,
1214 CodeOutputInterface &ol)
1222 static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // dictionary with used modules
1223 const QCString &memberText, // exact member text
1224 CodeOutputInterface &ol,
1225 const QCString &text)
1227 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1229 QCString memberName= removeRedundantWhiteSpace(memberText);
1231 if ((md=getFortranDefs(yyscanner,memberName, yyextra->currentModule, useMap)) && md->isLinkable())
1233 if (md->isVariable() && (md->getLanguage()!=SrcLangExt_Fortran)) return FALSE; // Non Fortran variables aren't handled yet,
1234 // see also linkifyText in util.cpp
1236 const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
1237 md->getBodyDef() : md->getOuterScope();
1238 if (md->getGroupDef()) d = md->getGroupDef();
1239 if (d && d->isLinkable())
1241 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
1242 yyextra->insideBody && yyextra->collectXRefs)
1244 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
1245 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
1247 writeMultiLineCodeLink(yyscanner,ol,md,!text.isEmpty() ? text : memberText);
1248 addToSearchIndex(yyscanner, !text.isEmpty() ? text : memberText);
1256 static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, const QCString &lname)
1258 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1260 NamespaceDef *nsd=0;
1261 QCString name = lname;
1262 name = removeRedundantWhiteSpace(name.lower());
1264 // check if lowercase lname is a linkable type or interface
1265 if ( (getFortranTypeDefs(name, yyextra->currentModule, cd, yyextra->useMembers)) && cd->isLinkable() )
1267 if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
1268 (getGenericProcedureLink(yyscanner, cd, name, ol)) )
1270 //cout << "=== generic procedure resolved" << endl;
1273 { // write type or interface link
1274 writeMultiLineCodeLink(yyscanner, ol,cd,name);
1275 addToSearchIndex(yyscanner, name);
1279 else if ( (getFortranNamespaceDefs(name, nsd)) && nsd->isLinkable() )
1280 { // write module link
1281 writeMultiLineCodeLink(yyscanner,ol,nsd,name);
1282 addToSearchIndex(yyscanner,name);
1284 // check for function/variable
1285 else if (getLink(yyscanner,yyextra->useMembers, name, ol, name))
1287 //cout << "=== found link for lowercase " << lname << endl;
1291 // nothing found, just write out the word
1292 //startFontClass("charliteral"); //test
1293 codifyLines(yyscanner,name);
1294 //endFontClass(yyscanner); //test
1295 addToSearchIndex(yyscanner,name);
1299 static void generateLink(yyscan_t yyscanner,CodeOutputInterface &ol, const char *lname)
1301 generateLink(yyscanner,ol,QCString(lname));
1304 /*! counts the number of lines in the input */
1305 static int countLines(yyscan_t yyscanner)
1307 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1308 const char *p=yyextra->inputString;
1314 if (c=='\n') count++;
1316 if (p>yyextra->inputString && *(p-1)!='\n')
1317 { // last line does not end with a \n, so we add an extra
1318 // line and explicitly terminate the line after parsing.
1320 yyextra->needsTermination=TRUE;
1325 //----------------------------------------------------------------------------
1327 static void startScope(yyscan_t yyscanner)
1329 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1330 DBG_CTX((stderr, "===> startScope %s",yytext));
1331 yyextra->scopeStack.push_back(Scope());
1335 static void endScope(yyscan_t yyscanner)
1337 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1338 DBG_CTX((stderr,"===> endScope %s",yytext));
1339 if (yyextra->scopeStack.empty())
1341 DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n"));
1345 Scope &scope = yyextra->scopeStack.back();
1346 for ( const auto &name : scope.useNames)
1348 yyextra->useMembers.erase(name.str());
1350 yyextra->scopeStack.pop_back();
1353 static void addUse(yyscan_t yyscanner,const QCString &moduleName)
1355 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1356 if (!yyextra->scopeStack.empty())
1357 yyextra->scopeStack.back().useNames.push_back(moduleName);
1360 static void addLocalVar(yyscan_t yyscanner,const QCString &varName)
1362 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1363 if (!yyextra->scopeStack.empty())
1365 std::string lowVarName = varName.lower().str();
1366 yyextra->scopeStack.back().localVars.insert(lowVarName);
1367 if (yyextra->isExternal) yyextra->scopeStack.back().externalVars.insert(lowVarName);
1371 /*===================================================================*/
1374 static void checkContLines(yyscan_t yyscanner,const char *s)
1376 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1381 numLines = 2; // one for element 0, one in case no \n at end
1384 if (*p == '\n') numLines++;
1388 yyextra->hasContLine = (int *) malloc((numLines) * sizeof(int));
1389 for (i = 0; i < numLines; i++)
1390 yyextra->hasContLine[i] = 0;
1391 p = prepassFixedForm(s, yyextra->hasContLine);
1392 yyextra->hasContLine[0] = 0;
1395 void parseFortranCode(CodeOutputInterface &od,const char *,const QCString &s,
1396 bool exBlock, const char *exName,const FileDef *fd,
1397 int startLine,int endLine,bool inlineFragment,
1398 const MemberDef *,bool,const Definition *searchCtx,
1399 bool collectXRefs, FortranFormat format)
1401 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1406 //---------------------------------------------------------
1408 struct FortranCodeParser::Private
1411 fortrancodeYY_state state;
1412 FortranFormat format;
1415 FortranCodeParser::FortranCodeParser(FortranFormat format) : p(std::make_unique<Private>())
1418 fortrancodeYYlex_init_extra(&p->state,&p->yyscanner);
1420 fortrancodeYYset_debug(1,p->yyscanner);
1422 resetCodeParserState();
1425 FortranCodeParser::~FortranCodeParser()
1427 fortrancodeYYlex_destroy(p->yyscanner);
1430 void FortranCodeParser::resetCodeParserState()
1432 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1433 yyextra->currentDefinition = 0;
1434 yyextra->currentMemberDef = 0;
1435 yyextra->currentFontClass = 0;
1436 yyextra->needsTermination = FALSE;
1440 void FortranCodeParser::parseCode(CodeOutputInterface & codeOutIntf,
1441 const QCString & scopeName,
1442 const QCString & input,
1443 SrcLangExt /*lang*/,
1444 bool isExampleBlock,
1445 const QCString & exampleName,
1446 const FileDef * fileDef,
1449 bool inlineFragment,
1450 const MemberDef *memberDef,
1451 bool showLineNumbers,
1452 const Definition *searchCtx,
1456 yyscan_t yyscanner = p->yyscanner;
1457 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1458 //::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
1459 // fileDef,startLine,endLine,inlineFragment,memberDef,
1460 // showLineNumbers,searchCtx,collectXRefs,m_format);
1461 // parseFortranCode(CodeOutputInterface &od,const char *,const QCString &s,
1462 // bool exBlock, const char *exName,FileDef *fd,
1463 // int startLine,int endLine,bool inlineFragment,
1464 // const MemberDef *,bool,const Definition *searchCtx,
1465 // bool collectXRefs, FortranFormat format)
1466 if (input.isEmpty()) return;
1467 printlex(yy_flex_debug, TRUE, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
1468 yyextra->code = &codeOutIntf;
1469 yyextra->inputString = input.data();
1470 yyextra->inputPosition = 0;
1471 yyextra->isFixedForm = recognizeFixedForm(input,p->format);
1472 yyextra->contLineNr = 1;
1473 yyextra->hasContLine = NULL;
1474 if (yyextra->isFixedForm)
1476 checkContLines(yyscanner,yyextra->inputString);
1478 yyextra->currentFontClass = 0;
1479 yyextra->needsTermination = FALSE;
1480 yyextra->searchCtx = searchCtx;
1481 yyextra->collectXRefs = collectXRefs;
1483 yyextra->yyLineNr = startLine;
1485 yyextra->yyLineNr = 1;
1488 yyextra->inputLines = endLine+1;
1490 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1492 yyextra->exampleBlock = isExampleBlock;
1493 yyextra->exampleName = exampleName;
1494 yyextra->sourceFileDef = fileDef;
1495 if (isExampleBlock && fileDef==0)
1497 // create a dummy filedef for the example
1498 yyextra->sourceFileDef = createFileDef(QCString(),exampleName);
1500 if (yyextra->sourceFileDef)
1502 setCurrentDoc(yyscanner,QCString("l00001"));
1504 yyextra->currentDefinition = 0;
1505 yyextra->currentMemberDef = 0;
1506 if (!yyextra->exampleName.isEmpty())
1508 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example");
1510 yyextra->includeCodeFragment = inlineFragment;
1511 startCodeLine(yyscanner);
1512 fortrancodeYYrestart(0, yyscanner);
1514 fortrancodeYYlex(yyscanner);
1515 if (yyextra->needsTermination)
1517 endFontClass(yyscanner);
1518 yyextra->code->endCodeLine();
1520 if (isExampleBlock && yyextra->sourceFileDef)
1522 // delete the temporary file definition used for this example
1523 delete yyextra->sourceFileDef;
1524 yyextra->sourceFileDef=0;
1526 if (yyextra->hasContLine) free(yyextra->hasContLine);
1527 yyextra->hasContLine = NULL;
1529 // write the tooltips
1530 yyextra->tooltipManager.writeTooltips(codeOutIntf);
1532 printlex(yy_flex_debug, FALSE, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
1535 //---------------------------------------------------------
1537 #if USE_STATE2STRING
1538 #include "fortrancode.l.h"