Doxygen
Loading...
Searching...
No Matches
fortrancode.l
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Parser for syntax highlighting and references for Fortran90 F subset
4 *
5 * Copyright (C) by Anke Visser
6 * based on the work of Dimitri van Heesch.
7 * Copyright (C) 2020 by Dimitri van Heesch.
8 *
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.
14 *
15 * Documents produced by Doxygen are derivative works derived from the
16 * input used in their production; they are not affected by this license.
17 *
18 */
19
20/**
21 @todo
22 - continuation lines not always recognized
23 - merging of use-statements with same module name and different only-names
24 - rename part of use-statement
25 - links to interface functions
26 - references to variables
27**/
28%option never-interactive
29%option case-insensitive
30%option reentrant
31%option prefix="fortrancodeYY"
32%option extra-type="struct fortrancodeYY_state *"
33%option noyy_top_state
34%top{
35#include <stdint.h>
36// forward declare yyscan_t to improve type safety
37#define YY_TYPEDEF_YY_SCANNER_T
38struct yyguts_t;
39typedef yyguts_t *yyscan_t;
yyguts_t * yyscan_t
Definition code.l:24
40}
41
42%{
43
44/*
45 * includes
46 */
47#include <stdio.h>
48#include <assert.h>
49#include <ctype.h>
50
51#include "doxygen.h"
52#include "message.h"
53#include "outputlist.h"
54#include "util.h"
55#include "membername.h"
56#include "defargs.h"
57#include "config.h"
58#include "groupdef.h"
59#include "classlist.h"
60#include "filedef.h"
61#include "namespacedef.h"
62#include "tooltip.h"
63#include "fortrancode.h"
64#include "fortranscanner.h"
65#include "containers.h"
66#include "debug.h"
67#include "searchindex.h"
68
69// Toggle for some debugging info
70//#define DBG_CTX(x) fprintf x
71#define DBG_CTX(x) do { } while(0)
72
73#define YY_NO_TOP_STATE 1
74#define YY_NO_INPUT 1
75#define YY_NO_UNISTD_H 1
76
77/*
78 * For fixed formatted code position 6 is of importance (continuation character).
79 * The following variables and macros keep track of the column number
80 * YY_USER_ACTION is always called for each scan action
81 * YY_FTN_RESET is used to handle end of lines and reset the column counter
82 * YY_FTN_REJECT resets the column counters when a pattern is rejected and thus rescanned.
83 */
86int yy_end = 1;
87#define YY_USER_ACTION {yy_old_start = yy_my_start; yy_my_start = yy_end; yy_end += static_cast<int>(yyleng);}
88#define YY_FTN_RESET {yy_old_start = 0; yy_my_start = 0; yy_end = 1;}
89#define YY_FTN_REJECT {yy_end = yy_my_start; yy_my_start = yy_old_start; REJECT;}
90
91//--------------------------------------------------------------------------------
92
93/**
94 data of an use-statement
95*/
97{
98 public:
99 QCString module; // just for debug
100 std::vector<QCString> onlyNames; /* entries of the ONLY-part */
101};
102
103/**
104 module name -> list of ONLY/remote entries
105 (module name = name of the module, which can be accessed via use-directive)
106*/
107class UseMap : public std::map<std::string,UseEntry>
108{
109};
110
111/**
112 Contains names of used modules and names of local variables.
113*/
114class Scope
115{
116 public:
117 std::vector<QCString> useNames; //!< contains names of used modules
118 StringUnorderedSet localVars; //!< contains names of local variables
119 StringUnorderedSet externalVars; //!< contains names of external entities
120};
121
122/*===================================================================*/
123/*
124 * statics
125 */
126
128{
129 QCString docBlock; //!< contents of all lines of a documentation block
130 QCString currentModule=QCString(); //!< name of the current enclosing module
131 UseMap useMembers; //!< info about used modules
132 UseEntry useEntry; //!< current use statement info
133 std::vector<Scope> scopeStack;
134 bool isExternal = false;
135 QCString str=QCString(); //!< contents of fortran string
136
137 OutputCodeList * code = nullptr;
138
139 const char * inputString = nullptr; //!< the code fragment as text
140 int inputPosition = 0; //!< read offset during parsing
141 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 = nullptr; //!< signals whether or not a line has a continuation line (fixed source form)
146 bool insideCodeLine = false;
147 const Definition *searchCtx = nullptr;
148 bool collectXRefs = false;
149 bool isFixedForm = false;
150
151 bool insideBody = false; //!< inside subprog/program body? => create links
152 const char * currentFontClass = nullptr;
154
155 bool exampleBlock = false;
158
159 std::unique_ptr<FileDef> exampleFileDef;
160 const FileDef * sourceFileDef = nullptr;
161 const Definition * currentDefinition = nullptr;
162 const MemberDef * currentMemberDef = nullptr;
164
165 char stringStartSymbol = '\0'; // single or double quote
166// count in variable declaration to filter out
167// declared from referenced names
169
170// signal when in type / class /procedure declaration
171 int inTypeDecl = 0;
172
173 bool endComment = false;
175 std::vector<const Definition *> foldStack;
176
178};
179
180[[maybe_unused]] static const char *stateToString(int state);
181
182static bool getFortranNamespaceDefs(const QCString &mname,
183 NamespaceDef *&cd);
184static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
185 ClassDef *&cd, const UseMap &useMap);
186
187//----------------------------------------------------------------------------
188
189static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment=false);
190static void endFontClass(yyscan_t yyscanner,bool specialComment=false);
191static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
192static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
193static void startCodeLine(yyscan_t yyscanner);
194static void endCodeLine(yyscan_t yyscanner);
195static void nextCodeLine(yyscan_t yyscanner);
196static void codifyLines(yyscan_t yyscanner,const QCString &text);
197static void writeMultiLineCodeLink(yyscan_t yyscanner,OutputCodeList &ol,
198 Definition *d,const QCString &text);
199static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd,
200 const QCString &memberText,
201 OutputCodeList &ol);
202static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // map with used modules
203 const QCString &memberText, // exact member text
204 OutputCodeList &ol,
205 const QCString &text);
206static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const QCString &lname);
207static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const char *lname);
208static int countLines(yyscan_t yyscanner);
209static void startScope(yyscan_t yyscanner);
210static void endScope(yyscan_t yyscanner);
211static void addUse(yyscan_t yyscanner,const QCString &moduleName);
212static void addLocalVar(yyscan_t yyscanner,const QCString &varName);
213static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
214 const UseMap &useMap);
215static int yyread(yyscan_t yyscanner,char *buf,int max_size);
216static inline void pop_state(yyscan_t yyscanner);
217
218/* -----------------------------------------------------------------*/
219#undef YY_INPUT
220#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
221
222// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
223static inline const char *getLexerFILE() {return __FILE__;}
224#include "doxygen_lex.h"
225
A abstract class representing of a compound symbol.
Definition classdef.h:104
The common base class of all entity definitions found in the sources.
Definition definition.h:76
A model of a file symbol.
Definition filedef.h:99
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
An abstract interface of a namespace symbol.
Class representing a list of different code generators.
Definition outputlist.h:164
This is an alternative implementation of QCString.
Definition qcstring.h:101
Contains names of used modules and names of local variables.
StringUnorderedSet externalVars
contains names of external entities
StringUnorderedSet localVars
contains names of local variables
std::vector< QCString > useNames
contains names of used modules
Class that manages the tooltips for a source file.
Definition tooltip.h:26
data of an use-statement
Definition fortrancode.l:97
std::vector< QCString > onlyNames
QCString module
Definition fortrancode.l:99
module name -> list of ONLY/remote entries (module name = name of the module, which can be accessed v...
std::unordered_set< std::string > StringUnorderedSet
Definition containers.h:29
static void startScope(yyscan_t yyscanner)
start scope
static bool getGenericProcedureLink(yyscan_t yyscanner, const ClassDef *cd, const QCString &memberText, OutputCodeList &ol)
gets the link to a generic procedure which depends not on the name, but on the parameter list
static void endCodeLine(yyscan_t yyscanner)
static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName, ClassDef *&cd, const UseMap &useMap)
searches for definition of a type
static void endScope(yyscan_t yyscanner)
end scope
static void nextCodeLine(yyscan_t yyscanner)
static void startCodeLine(yyscan_t yyscanner)
static void codifyLines(yyscan_t yyscanner, const QCString &text)
static bool getFortranNamespaceDefs(const QCString &mname, NamespaceDef *&cd)
searches for definition of a module (Namespace)
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
static int countLines(yyscan_t yyscanner)
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
static const char * stateToString(int state)
int yy_my_start
Definition fortrancode.l:85
static void pop_state(yyscan_t yyscanner)
static void addUse(yyscan_t yyscanner, const QCString &moduleName)
static MemberDef * getFortranDefs(yyscan_t yyscanner, const QCString &memberName, const QCString &moduleName, const UseMap &useMap)
searches for definition of function memberName
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
int yy_old_start
Definition fortrancode.l:84
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
static bool getLink(yyscan_t yyscanner, const UseMap &useMap, const QCString &memberText, OutputCodeList &ol, const QCString &text)
static const char * getLexerFILE()
static void addLocalVar(yyscan_t yyscanner, const QCString &varName)
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
int yy_end
Definition fortrancode.l:86
static void generateLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &lname)
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, Definition *d, const QCString &text)
Web server based search engine.
TooltipManager tooltipManager
OutputCodeList * code
int * hasContLine
signals whether or not a line has a continuation line (fixed source form)
bool insideBody
inside subprog/program body? => create links
int contLineNr
current, local, line number for continuation determination
QCString docBlock
contents of all lines of a documentation block
int inputPosition
read offset during parsing
std::vector< Scope > scopeStack
std::unique_ptr< FileDef > exampleFileDef
const FileDef * sourceFileDef
QCString str
contents of fortran string
const MemberDef * currentMemberDef
const Definition * searchCtx
UseEntry useEntry
current use statement info
QCString currentModule
name of the current enclosing module
int yyLineNr
current line number
UseMap useMembers
info about used modules
std::vector< const Definition * > foldStack
const char * inputString
the code fragment as text
int inputLines
number of line in the code fragment
const Definition * currentDefinition
const char * currentFontClass
A bunch of utility functions.
226%}
227
228IDSYM [a-z_A-Z0-9]
229ID [a-z_A-Z]+{IDSYM}*
230SUBPROG (subroutine|function)
231BS [ \t]*
232BS_ [ \t]+
233COMMA {BS},{BS}
234ARGS_L0 ("("[^)]*")")
235ARGS_L1a [^()]*"("[^)]*")"[^)]*
236ARGS_L1 ("("{ARGS_L1a}*")")
237ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
238ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
239
240NUM_TYPE (complex|integer|logical|real)
241LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
242KIND {ARGS}
243CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
244TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE|ENUMERATOR)
245
246INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
247ATTR_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)
248ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC)
249/* Assume that attribute statements are almost the same as attributes. */
250FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE|RANK)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT|GO{BS}TO)
251COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON)
252IGNORE (CALL)
253PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?0
254LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
255
256/* | */
257
258%option noyywrap
259%option stack
260%option caseless
261/*%option debug*/
262
263%x Start
264%x SubCall
265%x ClassName
266%x Subprog
267%x DocBlock
268%x Use
269%x UseOnly
270%x Import
271%x Declaration
272%x DeclarationBinding
273%x DeclContLine
274%x String
275%x Subprogend
276
278 /*==================================================================*/
279
280 /*-------- ignore ------------------------------------------------------------*/
281
282<Start>{IGNORE}/{BS}"(" { // do not search keywords, intrinsics... TODO: complete list
283 codifyLines(yyscanner,yytext);
284 }
static void codifyLines(yyscan_t yyscanner, const QCString &text)
Definition code.l:2514
285 /*-------- inner construct ---------------------------------------------------*/
286
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);
292 }
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
Definition code.l:3504
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition code.l:3489
293<Start>{FLOW}/{BS}[,( \t\n] {
294 if (yyextra->isFixedForm)
295 {
296 if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT;
297 }
298 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
299 {
300 std::lock_guard<std::mutex> lock(Doxygen::countFlowKeywordsMutex);
301 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(yyextra->currentMemberDef));
302 if (mdm)
303 {
305 }
306 }
307 /* font class is defined e.g. in doxygen.css */
308 startFontClass(yyscanner,"keywordflow");
309 codifyLines(yyscanner,yytext);
310 endFontClass(yyscanner);
311 }
static std::mutex countFlowKeywordsMutex
Definition doxygen.h:141
virtual void incrementFlowKeyWordCount()=0
#define YY_FTN_REJECT
Definition fortrancode.l:89
MemberDefMutable * toMemberDefMutable(Definition *d)
312<Start>{BS}(RANK){BS_}(DEFAULT) |
313<Start>{BS}(RANK)/{BS}"("{BS}([0-9]+|"*"){BS}")" |
314<Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) {
315 startFontClass(yyscanner,"keywordflow");
316 codifyLines(yyscanner,yytext);
317 endFontClass(yyscanner);
318 }
319<Start>{BS}"end"({BS}{FLOW})/[ \t\n] { // list is a bit long as not all have possible end
320 startFontClass(yyscanner,"keywordflow");
321 codifyLines(yyscanner,yytext);
322 endFontClass(yyscanner);
323 }
324<Start>"implicit"{BS}("none"|{TYPE_SPEC}) {
325 startFontClass(yyscanner,"keywordtype");
326 codifyLines(yyscanner,yytext);
327 endFontClass(yyscanner);
328 }
329<Start>^{BS}"namelist"/[/] { // Namelist specification
330 startFontClass(yyscanner,"keywordtype");
331 codifyLines(yyscanner,yytext);
332 endFontClass(yyscanner);
333 }
334 /*-------- use statement -------------------------------------------*/
335<Start>"use"{BS_} {
336 startFontClass(yyscanner,"keywordtype");
337 codifyLines(yyscanner,yytext);
338 endFontClass(yyscanner);
339 yy_push_state(YY_START,yyscanner);
340 BEGIN(Use);
341 }
342<Use>"ONLY" { // TODO: rename
343 startFontClass(yyscanner,"keywordtype");
344 codifyLines(yyscanner,yytext);
345 endFontClass(yyscanner);
346 yy_push_state(YY_START,yyscanner);
347 BEGIN(UseOnly);
348 }
349<Use>{ID} {
350 QCString tmp(yytext);
351 tmp = tmp.lower();
352 yyextra->insideBody=TRUE;
353 generateLink(yyscanner,*yyextra->code, yytext);
354 yyextra->insideBody=FALSE;
355
356 /* append module name to use dict */
357 yyextra->useEntry = UseEntry();
358 yyextra->useEntry.module = tmp;
359 yyextra->useMembers.emplace(tmp.str(), yyextra->useEntry);
360 addUse(yyscanner,tmp);
361 }
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
362<Use,UseOnly,Import>{BS},{BS} { codifyLines(yyscanner,yytext); }
363<UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yyscanner,yytext);
364 yyextra->contLineNr++;
#define YY_FTN_RESET
Definition fortrancode.l:88
366<UseOnly>{ID} {
367 QCString tmp(yytext);
368 tmp = tmp.lower();
369 yyextra->useEntry.onlyNames.push_back(tmp);
370 yyextra->insideBody=TRUE;
371 generateLink(yyscanner,*yyextra->code, yytext);
372 yyextra->insideBody=FALSE;
373 }
374<Use,UseOnly,Import>"\n" {
375 unput(*yytext);
376 pop_state(yyscanner);
378 }
379<*>"import"{BS}/"\n" |
380<*>"import"{BS_} {
381 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
382 startFontClass(yyscanner,"keywordtype");
383 codifyLines(yyscanner,yytext);
384 endFontClass(yyscanner);
385 yy_push_state(YY_START,yyscanner);
386 BEGIN(Import);
387 }
388<Import>{ID} {
389 yyextra->insideBody=TRUE;
390 generateLink(yyscanner,*yyextra->code, yytext);
391 yyextra->insideBody=FALSE;
392 }
393<Import>("ONLY"|"NONE"|"ALL") {
394 startFontClass(yyscanner,"keywordtype");
395 codifyLines(yyscanner,yytext);
396 endFontClass(yyscanner);
397 }
398 /*-------- fortran module -----------------------------------------*/
399<Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
400 startScope(yyscanner);
401 startFontClass(yyscanner,"keyword");
402 codifyLines(yyscanner,yytext);
403 endFontClass(yyscanner);
404 yy_push_state(YY_START,yyscanner);
405 BEGIN(ClassName);
406 if (!qstricmp(yytext,"module")) yyextra->currentModule="module";
407 }
int qstricmp(const char *s1, const char *s2)
Definition qcstring.cpp:442
408<Start>("enum")/{BS_}|{BS}{COMMA}{BS}{LANGUAGE_BIND_SPEC}|\n { //
409 startScope(yyscanner);
410 startFontClass(yyscanner,"keyword");
411 codifyLines(yyscanner,yytext);
412 endFontClass(yyscanner);
413 yy_push_state(YY_START,yyscanner);
414 BEGIN(ClassName);
415 }
416<*>{LANGUAGE_BIND_SPEC} { //
417 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
418 startFontClass(yyscanner,"keyword");
419 codifyLines(yyscanner,yytext);
420 endFontClass(yyscanner);
421 }
422<Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { //
423 startScope(yyscanner);
424 startFontClass(yyscanner,"keyword");
425 codifyLines(yyscanner,yytext);
426 endFontClass(yyscanner);
427 yy_push_state(YY_START,yyscanner);
428 BEGIN(ClassName);
429 }
430<ClassName>{ID} {
431 if (yyextra->currentModule == "module")
432 {
433 yyextra->currentModule=yytext;
434 yyextra->currentModule = yyextra->currentModule.lower();
435 }
436 generateLink(yyscanner,*yyextra->code,yytext);
437 pop_state(yyscanner);
438 }
439<ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable declaration
440 startFontClass(yyscanner,"keyword");
441 yyextra->code->codify(QCString(yytext));
442 endFontClass(yyscanner);
443 }
444<ClassName>\n { // interface may be without name
445 pop_state(yyscanner);
447 }
448<Start>^{BS}"end"({BS_}"enum").* {
450 }
451<Start>^{BS}"end"({BS_}"type").* {
453 }
454<Start>^{BS}"end"({BS_}"module").* { // just reset yyextra->currentModule, rest is done in following rule
455 yyextra->currentModule=nullptr;
457 }
458 /*-------- subprog definition -------------------------------------*/
459<Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
460 startFontClass(yyscanner,"keyword");
461 codifyLines(yyscanner,yytext);
462 endFontClass(yyscanner);
463 }
464<Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found
465 startFontClass(yyscanner,"keyword");
466 codifyLines(yyscanner,yytext);
467 endFontClass(yyscanner);
468 yy_push_state(YY_START,yyscanner);
469 BEGIN(Subprog);
470 }
471<Subprog>{ID} { // subroutine/function name
472 DBG_CTX((stderr, "===> start subprogram %s\n", yytext));
473 startScope(yyscanner);
474 generateLink(yyscanner,*yyextra->code,yytext);
475 }
#define DBG_CTX(x)
Definition code.l:73
476<Subprog>"result"/{BS}"("[^)]*")" {
477 startFontClass(yyscanner,"keyword");
478 codifyLines(yyscanner,yytext);
479 endFontClass(yyscanner);
480 }
481<Subprog>"("[^)]*")" { // ignore rest of line
482 codifyLines(yyscanner,yytext);
483 }
484<Subprog,Subprogend>"\n" { codifyLines(yyscanner,yytext);
485 yyextra->contLineNr++;
486 pop_state(yyscanner);
488 }
489<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface")?{BS} { // Fortran subroutine or function ends
490 //cout << "===> end function " << yytext << endl;
491 endScope(yyscanner);
492 startFontClass(yyscanner,"keyword");
493 codifyLines(yyscanner,yytext);
494 endFontClass(yyscanner);
495 yy_push_state(YY_START,yyscanner);
496 BEGIN(Subprogend);
497 }
498<Subprogend>{ID}/{BS}(\n|!|;) {
499 generateLink(yyscanner,*yyextra->code,yytext);
500 pop_state(yyscanner);
501 }
502<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface"){BS}/(\n|!|;) { // Fortran subroutine or function ends
503 //cout << "===> end function " << yytext << endl;
504 endScope(yyscanner);
505 startFontClass(yyscanner,"keyword");
506 codifyLines(yyscanner,yytext);
507 endFontClass(yyscanner);
508 }
509 /*-------- variable declaration ----------------------------------*/
510<Start>^{BS}"real"/[,:( ] { // real is a bit tricky as it is a data type but also a function.
511 yy_push_state(YY_START,yyscanner);
512 BEGIN(Declaration);
513 startFontClass(yyscanner,"keywordtype");
514 yyextra->code->codify(QCString(yytext));
515 endFontClass(yyscanner);
516 }
517<Start>{TYPE_SPEC}/[,:( ] {
518 QCString typ(yytext);
519 typ = removeRedundantWhiteSpace(typ.lower());
520 if (typ.startsWith("real")) YY_FTN_REJECT;
521 if (typ == "type" || typ == "class" || typ == "procedure") yyextra->inTypeDecl = 1;
522 yy_push_state(YY_START,yyscanner);
523 BEGIN(Declaration);
524 startFontClass(yyscanner,"keywordtype");
525 yyextra->code->codify(QCString(yytext));
526 endFontClass(yyscanner);
527 }
QCString removeRedundantWhiteSpace(const QCString &s)
Definition util.cpp:578
528<Start>{ATTR_SPEC} {
529 if (QCString(yytext) == "external")
530 {
531 yy_push_state(YY_START,yyscanner);
532 BEGIN(Declaration);
533 yyextra->isExternal = true;
534 }
535 startFontClass(yyscanner,"keywordtype");
536 yyextra->code->codify(QCString(yytext));
537 endFontClass(yyscanner);
538 }
539<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration
540 if (QCString(yytext) == "external") yyextra->isExternal = true;
541 startFontClass(yyscanner,"keywordtype");
542 yyextra->code->codify(QCString(yytext));
543 endFontClass(yyscanner);
544 }
545<Declaration>{ID} { // local var
546 if (yyextra->isFixedForm && yy_my_start == 1)
547 {
548 startFontClass(yyscanner,"comment");
549 yyextra->code->codify(QCString(yytext));
550 endFontClass(yyscanner);
551 }
552 else if (yyextra->currentMemberDef &&
553 ((yyextra->currentMemberDef->isFunction() && (yyextra->currentMemberDef->typeString()!=QCString("subroutine") || yyextra->inTypeDecl)) ||
554 yyextra->currentMemberDef->isVariable() || yyextra->currentMemberDef->isEnumValue()
555 )
556 )
557 {
558 generateLink(yyscanner,*yyextra->code, yytext);
559 }
560 else
561 {
562 yyextra->code->codify(QCString(yytext));
563 addLocalVar(yyscanner,QCString(yytext));
564 }
565 }
566<Declaration>{BS}("=>"|"="){BS} { // Procedure binding
567 BEGIN(DeclarationBinding);
568 yyextra->code->codify(QCString(yytext));
569 }
570<DeclarationBinding>{ID} { // Type bound procedure link
571 generateLink(yyscanner,*yyextra->code, yytext);
572 pop_state(yyscanner);
573 }
574<Declaration>[(] { // start of array or type / class specification
575 yyextra->bracketCount++;
576 yyextra->code->codify(QCString(yytext));
577 }
578
579<Declaration>[)] { // end array specification
580 yyextra->bracketCount--;
581 if (!yyextra->bracketCount) yyextra->inTypeDecl = 0;
582 yyextra->code->codify(QCString(yytext));
583 }
584
585<Declaration,DeclarationBinding>"&" { // continuation line
586 yyextra->code->codify(QCString(yytext));
587 if (!yyextra->isFixedForm)
588 {
589 yy_push_state(YY_START,yyscanner);
590 BEGIN(DeclContLine);
591 }
592 }
593<DeclContLine>"\n" { // declaration not yet finished
594 yyextra->contLineNr++;
595 codifyLines(yyscanner,yytext);
596 yyextra->bracketCount = 0;
597 pop_state(yyscanner);
599 }
600<Declaration,DeclarationBinding>"\n" { // end declaration line (?)
601 if (yyextra->endComment)
602 {
603 yyextra->endComment=FALSE;
604 }
605 else
606 {
607 codifyLines(yyscanner,yytext);
608 }
609 yyextra->bracketCount = 0;
610 yyextra->contLineNr++;
611 if (!(yyextra->hasContLine && yyextra->hasContLine[yyextra->contLineNr - 1]))
612 {
613 yyextra->isExternal = false;
614 pop_state(yyscanner);
615 }
617 }
618
619 /*-------- subprog calls -----------------------------------------*/
620
621<Start>"call"{BS_} {
622 startFontClass(yyscanner,"keyword");
623 codifyLines(yyscanner,yytext);
624 endFontClass(yyscanner);
625 yy_push_state(YY_START,yyscanner);
626 BEGIN(SubCall);
627 }
628<SubCall>{ID} { // subroutine call
629 yyextra->insideBody=TRUE;
630 generateLink(yyscanner,*yyextra->code, yytext);
631 yyextra->insideBody=FALSE;
632 pop_state(yyscanner);
633 }
634<Start>{ID}{BS}/"(" { // function call
635 if (yyextra->isFixedForm && yy_my_start == 6)
636 {
637 // fixed form continuation line
639 }
640 else if (QCString(yytext).stripWhiteSpace().lower() == "type")
641 {
642 yy_push_state(YY_START,yyscanner);
643 BEGIN(Declaration);
644 startFontClass(yyscanner,"keywordtype");
645 yyextra->code->codify(QCString(yytext).stripWhiteSpace());
646 endFontClass(yyscanner);
647 yyextra->code->codify(QCString(yytext + 4));
648 }
649 else
650 {
651 yyextra->insideBody=TRUE;
652 generateLink(yyscanner,*yyextra->code,yytext);
653 yyextra->insideBody=FALSE;
654 }
655 }
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:72
656
657 /*-------- comments ---------------------------------------------------*/
658<Start,Declaration,DeclarationBinding>\n?{BS}"!>"|"!<" { // start comment line or comment block
659 if (yytext[0] == '\n')
660 {
661 yyextra->contLineNr++;
662 yy_old_start = 0;
663 yy_my_start = 1;
664 yy_end = static_cast<int>(yyleng);
665 }
666 // Actually we should see if ! on position 6, can be continuation
667 // but the chance is very unlikely, so no effort to solve it here
668 yy_push_state(YY_START,yyscanner);
669 BEGIN(DocBlock);
670 yyextra->docBlock=yytext;
671 }
672<Declaration,DeclarationBinding>{BS}"!<" { // start comment line or comment block
673 yy_push_state(YY_START,yyscanner);
674 BEGIN(DocBlock);
675 yyextra->docBlock=yytext;
676 }
677
678<DocBlock>.* { // contents of current comment line
679 yyextra->docBlock+=yytext;
680 }
681<DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line)
682 yyextra->contLineNr++;
683 yy_old_start = 0;
684 yy_my_start = 1;
685 yy_end = static_cast<int>(yyleng);
686 // Actually we should see if ! on position 6, can be continuation
687 // but the chance is very unlikely, so no effort to solve it here
688 yyextra->docBlock+=yytext;
689 }
690<DocBlock>"\n" { // comment block ends at the end of this line
691 // remove special comment (default config)
692 yyextra->contLineNr++;
693 startFontClass(yyscanner,"comment");
694 codifyLines(yyscanner,yyextra->docBlock);
695 endFontClass(yyscanner);
696 unput(*yytext);
697 yyextra->contLineNr--;
698 pop_state(yyscanner);
700 }
701
702<*>"!"[^><\n].*|"!"$ { // normal comment
703 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
704 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
705 startFontClass(yyscanner,"comment");
706 codifyLines(yyscanner,yytext);
707 endFontClass(yyscanner);
708 }
709
710<*>^[Cc*].* { // normal comment
711 if(! yyextra->isFixedForm) YY_FTN_REJECT;
712
713 startFontClass(yyscanner,"comment");
714 codifyLines(yyscanner,yytext);
715 endFontClass(yyscanner);
716 }
717<*>"assignment"/{BS}"("{BS}"="{BS}")" {
718 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
719 startFontClass(yyscanner,"keyword");
720 codifyLines(yyscanner,yytext);
721 endFontClass(yyscanner);
722 }
723<*>"operator"/{BS}"("[^)]*")" {
724 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
725 startFontClass(yyscanner,"keyword");
726 codifyLines(yyscanner,yytext);
727 endFontClass(yyscanner);
728 }
729
730 /*------ preprocessor --------------------------------------------*/
731<Start>"#".*\n {
732 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
733 yyextra->contLineNr++;
734 startFontClass(yyscanner,"preprocessor");
735 codifyLines(yyscanner,yytext);
736 endFontClass(yyscanner);
738 }
739 /*------ variable references? -------------------------------------*/
740
741<Start>"%"{BS}{ID} { // ignore references to elements
742 yyextra->code->codify(QCString(yytext));
743 }
744<Start>{ID} {
745 yyextra->insideBody=TRUE;
746 generateLink(yyscanner,*yyextra->code, yytext);
747 yyextra->insideBody=FALSE;
748 }
749 /*------ strings --------------------------------------------------*/
750<String>\n { // string with \n inside
751 yyextra->contLineNr++;
752 yyextra->str+=yytext;
753 startFontClass(yyscanner,"stringliteral");
754 codifyLines(yyscanner,yyextra->str);
755 endFontClass(yyscanner);
756 yyextra->str = "";
758 }
759<String>\"|\' { // string ends with next quote without previous backspace
760 if(yytext[0]!=yyextra->stringStartSymbol) YY_FTN_REJECT; // single vs double quote
761 yyextra->str+=yytext;
762 startFontClass(yyscanner,"stringliteral");
763 codifyLines(yyscanner,yyextra->str);
764 endFontClass(yyscanner);
765 pop_state(yyscanner);
766 }
767<String>[\x80-\xFF]* |
768<String>. {yyextra->str+=yytext;}
769
770<*>\"|\' { /* string starts */
771 /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */
772 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
773 yy_push_state(YY_START,yyscanner);
774 yyextra->stringStartSymbol=yytext[0]; // single or double quote
775 BEGIN(String);
776 yyextra->str=yytext;
777 }
778 /*-----------------------------------------------------------------------------*/
779
780<*>\n {
781 if (yyextra->endComment)
782 {
783 yyextra->endComment=FALSE;
784 }
785 else
786 {
787 codifyLines(yyscanner,yytext);
788 // comment cannot extend over the end of a line so should always be terminated at the end of the line.
789 if (yyextra->currentFontClass && !strcmp(yyextra->currentFontClass,"comment")) endFontClass(yyscanner);
790 }
791 yyextra->contLineNr++;
793 }
794<*>^{BS}"type"{BS}"=" { yyextra->code->codify(QCString(yytext)); }
795
796<*>[\x80-\xFF]* { // keep utf8 characters together...
797 if (yyextra->isFixedForm && yy_my_start > yyextra->fixedCommentAfter)
798 {
799 startFontClass(yyscanner,"comment");
800 codifyLines(yyscanner,yytext);
801 }
802 else
803 {
804 yyextra->code->codify(QCString(yytext));
805 }
806 }
807<*>. {
808 if (yyextra->isFixedForm && yy_my_start > yyextra->fixedCommentAfter)
809 {
810 //yy_push_state(YY_START,yyscanner);
811 //BEGIN(DocBlock);
812 //yyextra->docBlock=yytext;
813 startFontClass(yyscanner,"comment");
814 codifyLines(yyscanner,yytext);
815 }
816 else
817 {
818 yyextra->code->codify(QCString(yytext));
819 }
820 }
821<*>{LOG_OPER} { // Fortran logical comparison keywords
822 yyextra->code->codify(QCString(yytext));
823 }
824<*><<EOF>> {
825 if (YY_START == DocBlock)
826 {
827 startFontClass(yyscanner,"comment");
828 codifyLines(yyscanner,yyextra->docBlock);
829 endFontClass(yyscanner);
830 }
831 yyterminate();
832 }
#define yyterminate()
833%%
834
835/*@ ----------------------------------------------------------------------------
836 */
837
838static int yyread(yyscan_t yyscanner,char *buf,int max_size)
839{
840 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
841 int inputPosition = yyextra->inputPosition;
842 const char *s = yyextra->inputString + inputPosition;
843 int c=0;
844 while( c < max_size && *s)
845 {
846 *buf++ = *s++;
847 c++;
848 }
849 yyextra->inputPosition += c;
850 return c;
851}
852
853static void endFontClass(yyscan_t yyscanner,bool specialComment)
854{
855 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
856 if (yyextra->currentFontClass)
857 {
858 yyextra->code->endFontClass();
859 yyextra->currentFontClass=nullptr;
860 }
861 if (specialComment && yyextra->insideSpecialComment)
862 {
863 yyextra->code->endSpecialComment();
864 yyextra->insideSpecialComment=false;
865 }
866}
867
868static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment)
869{
870 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
871 if (specialComment)
872 {
873 yyextra->code->startSpecialComment();
874 yyextra->insideSpecialComment = true;
875 }
876 // if font class is already set don't stop and start it.
877 if (qstrcmp(yyextra->currentFontClass,s)!=0)
878 {
879 endFontClass(yyscanner);
880 yyextra->code->startFontClass(QCString(s));
881 yyextra->currentFontClass=s;
882 }
883}
884
885static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
886{
887 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
888 if (Doxygen::searchIndex.enabled())
889 {
890 if (yyextra->searchCtx)
891 {
892 Doxygen::searchIndex.setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
893 }
894 else
895 {
896 Doxygen::searchIndex.setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
897 }
898 }
899}
900
901static void addToSearchIndex(yyscan_t /*yyscanner*/,const QCString &text)
902{
903 if (Doxygen::searchIndex.enabled())
904 {
905 Doxygen::searchIndex.addWord(text,FALSE);
906 }
907}
908
909static void codeFolding(yyscan_t yyscanner,const Definition *d)
910{
911 if (Config_getBool(HTML_CODE_FOLDING))
912 {
913 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
914 while (!yyextra->foldStack.empty())
915 {
916 const Definition *dd = yyextra->foldStack.back();
917 if (dd->getEndBodyLine()+1==yyextra->yyLineNr) // +1 to close the section after the end of the body
918 {
919 yyextra->code->endFold();
920 //printf("%d: end codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(dd->name()),dd->getStartDefLine(),dd->getEndBodyLine());
921 yyextra->foldStack.pop_back();
922 }
923 else
924 {
925 break;
926 }
927 }
928 if (d)
929 {
930 int startLine = d->getStartDefLine();
931 int endLine = d->getEndBodyLine();
932 if (endLine!=-1 && startLine!=endLine &&
933 // since the end of a section is closed after the last line, we need to avoid starting a
934 // new section if the previous section ends at the same line, i.e. something like
935 // struct X {
936 // ...
937 // }; struct S { <- start of S and end of X at the same line
938 // ...
939 // };
940 (yyextra->foldStack.empty() || yyextra->foldStack.back()->getEndBodyLine()!=startLine))
941 {
942 //printf("%d: start codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(d->name()),d->getStartDefLine(),d->getEndBodyLine());
943 yyextra->code->startFold(yyextra->yyLineNr,"","");
944 yyextra->foldStack.push_back(d);
945 }
946 }
947 }
948}
949
950/*! start a new line of code, inserting a line number if yyextra->sourceFileDef
951 * is TRUE. If a definition starts at the current line, then the line
952 * number is linked to the documentation of that definition.
953 */
954static void startCodeLine(yyscan_t yyscanner)
955{
956 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
957 if (yyextra->sourceFileDef)
958 {
959 //QCString lineNumber,lineAnchor;
960 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
961 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
962
963 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
964 //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,d ? qPrint(d->name()) : "<null>");
965 if (!yyextra->includeCodeFragment && d)
966 {
967 yyextra->currentDefinition = d;
968 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
969 yyextra->insideBody = FALSE;
970 yyextra->endComment = FALSE;
971 QCString lineAnchor;
972 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
973 if (yyextra->currentMemberDef)
974 {
975 codeFolding(yyscanner,yyextra->currentMemberDef);
976 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
977 yyextra->currentMemberDef->getOutputFileBase(),
978 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
979 !yyextra->includeCodeFragment);
980 setCurrentDoc(yyscanner,lineAnchor);
981 }
982 else if (d->isLinkableInProject())
983 {
984 codeFolding(yyscanner,d);
985 yyextra->code->writeLineNumber(d->getReference(),
987 QCString(),yyextra->yyLineNr,
988 !yyextra->includeCodeFragment);
989 setCurrentDoc(yyscanner,lineAnchor);
990 }
991 else
992 {
993 codeFolding(yyscanner,nullptr);
994 }
995 }
996 else
997 {
998 codeFolding(yyscanner,nullptr);
999 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
1000 !yyextra->includeCodeFragment);
1001 }
1002 }
1003 yyextra->code->startCodeLine(yyextra->yyLineNr);
1004 yyextra->insideCodeLine=true;
1005 if (yyextra->currentFontClass)
1006 {
1007 yyextra->code->startFontClass(QCString(yyextra->currentFontClass));
1008 }
1009}
1010
1011
1012static void endCodeLine(yyscan_t yyscanner)
1013{
1014 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1015 endFontClass(yyscanner);
1016 yyextra->code->endCodeLine();
1017 yyextra->insideCodeLine=false;
1018}
1019
1020static void nextCodeLine(yyscan_t yyscanner)
1021{
1022 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1023 const char * fc = yyextra->currentFontClass;
1024 endCodeLine(yyscanner);
1025 if (yyextra->yyLineNr<yyextra->inputLines)
1026 {
1027 yyextra->currentFontClass = fc;
1028 startCodeLine(yyscanner);
1029 }
1030}
1031
1032/*! write a code fragment 'text' that may span multiple lines, inserting
1033 * line numbers for each line.
1034 */
1035static void codifyLines(yyscan_t yyscanner,const QCString &text)
1036{
1037 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1038 //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text);
1039 if (text.isEmpty()) return;
1040 const char *p=text.data(),*sp=p;
1041 char c = 0;
1042 bool done=FALSE;
1043 while (!done)
1044 {
1045 sp=p;
1046 while ((c=*p++) && c!='\n') { }
1047 if (c=='\n')
1048 {
1049 yyextra->yyLineNr++;
1050 size_t l = static_cast<size_t>(p-sp-1);
1051 std::string tmp(sp,l);
1052 yyextra->code->codify(tmp.c_str());
1053 nextCodeLine(yyscanner);
1054 }
1055 else
1056 {
1057 yyextra->code->codify(QCString(sp));
1058 done=TRUE;
1059 }
1060 }
1061}
1062
1063/*! writes a link to a fragment \a text that may span multiple lines, inserting
1064 * line numbers for each line. If \a text contains newlines, the link will be
1065 * split into multiple links with the same destination, one for each line.
1066 */
1068 Definition *d,const QCString &text)
1069{
1070 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1071 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1072 yyextra->tooltipManager.addTooltip(d);
1073 QCString ref = d->getReference();
1074 QCString file = d->getOutputFileBase();
1075 QCString anchor = d->anchor();
1076 QCString tooltip;
1077 if (!sourceTooltips) // fall back to simple "title" tooltips
1078 {
1079 tooltip = d->briefDescriptionAsTooltip();
1080 }
1081 bool done=FALSE;
1082 const char *p=text.data();
1083 while (!done)
1084 {
1085 const char *sp=p;
1086 char c = 0;
1087 while ((c=*p++) && c!='\n') { }
1088 if (c=='\n')
1089 {
1090 yyextra->yyLineNr++;
1091 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1092 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1093 nextCodeLine(yyscanner);
1094 }
1095 else
1096 {
1097 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1098 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1099 done=TRUE;
1100 }
1101 }
1102}
1103//-------------------------------------------------------------------------------
1104/**
1105 searches for definition of a module (Namespace)
1106 @param mname the name of the module
1107 @param cd the entry, if found or null
1108 @returns true, if module is found
1109*/
1110static bool getFortranNamespaceDefs(const QCString &mname,
1111 NamespaceDef *&cd)
1112{
1113 if (mname.isEmpty()) return FALSE; /* empty name => nothing to link */
1114
1115 // search for module
1116 if ((cd=Doxygen::namespaceLinkedMap->find(mname))) return TRUE;
1117
1118 return FALSE;
1119}
1120//-------------------------------------------------------------------------------
1121/**
1122 searches for definition of a type
1123 @param tname the name of the type
1124 @param moduleName name of enclosing module or null, if global entry
1125 @param cd the entry, if found or null
1126 @param useMap map of data of USE-statement
1127 @returns true, if type is found
1128*/
1129static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
1130 ClassDef *&cd, const UseMap &useMap)
1131{
1132 if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
1133
1134 //cout << "=== search for type: " << tname << endl;
1135
1136 // search for type
1137 if ((cd=Doxygen::classLinkedMap->find(tname)))
1138 {
1139 //cout << "=== type found in global module" << endl;
1140 return TRUE;
1141 }
1142 else if (!moduleName.isEmpty() && (cd=Doxygen::classLinkedMap->find(moduleName+"::"+tname)))
1143 {
1144 //cout << "=== type found in local module" << endl;
1145 return TRUE;
1146 }
1147 else
1148 {
1149 for (const auto &[name,useEntry] : useMap)
1150 {
1151 if ((cd=Doxygen::classLinkedMap->find(useEntry.module+"::"+tname)))
1152 {
1153 //cout << "=== type found in used module" << endl;
1154 return TRUE;
1155 }
1156 }
1157 }
1158
1159 return FALSE;
1160}
1161
1162/**
1163 searches for definition of function memberName
1164 @param yyscanner the scanner data to be used
1165 @param memberName the name of the function/variable
1166 @param moduleName name of enclosing module or null, if global entry
1167 @param useMap map of data of USE-statement
1168 @returns MemberDef pointer, if found, or nullptr otherwise
1169*/
1170static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
1171 const UseMap &useMap)
1172{
1173 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1174 if (memberName.isEmpty()) return nullptr; /* empty name => nothing to link */
1175
1176 // look in local variables
1177 for (auto it = yyextra->scopeStack.rbegin(); it!=yyextra->scopeStack.rend(); ++it)
1178 {
1179 const Scope &scope = *it;
1180 std::string lowMemName = memberName.lower().str();
1181 if (scope.localVars .find(lowMemName)!=std::end(scope.localVars) && // local var
1182 scope.externalVars.find(lowMemName)==std::end(scope.externalVars)) // and not external
1183 {
1184 return nullptr;
1185 }
1186 }
1187
1188 // search for function
1189 MemberName *mn = Doxygen::functionNameLinkedMap->find(memberName);
1190 if (!mn)
1191 {
1192 mn = Doxygen::memberNameLinkedMap->find(memberName);
1193 }
1194
1195 if (mn) // name is known
1196 {
1197 // all found functions with given name
1198 for (const auto &md : *mn)
1199 {
1200 const FileDef *fd=md->getFileDef();
1201 const GroupDef *gd=md->getGroupDef();
1202 const ClassDef *cd=md->getClassDef();
1203
1204 //cout << "found link with same name: " << fd->fileName() << " " << memberName;
1205 //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
1206
1207 if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
1208 {
1209 const NamespaceDef *nspace= md->getNamespaceDef();
1210
1211 if (nspace == nullptr)
1212 { // found function in global scope
1213 if (cd == nullptr)
1214 { // Skip if bound to type
1215 return md.get();
1216 }
1217 }
1218 else if (moduleName == nspace->name())
1219 { // found in local scope
1220 return md.get();
1221 }
1222 else
1223 { // else search in used modules
1224 QCString usedModuleName= nspace->name();
1225 auto use_it = useMap.find(usedModuleName.str());
1226 if (use_it!=useMap.end())
1227 {
1228 const UseEntry &ue = use_it->second;
1229 // check if only-list exists and if current entry exists is this list
1230 if (ue.onlyNames.empty())
1231 {
1232 //cout << " found in module " << usedModuleName << " entry " << memberName << endl;
1233 return md.get(); // whole module used
1234 }
1235 else
1236 {
1237 for ( const auto &name : ue.onlyNames)
1238 {
1239 //cout << " search in only: " << usedModuleName << ":: " << memberName << "==" << (*it)<< endl;
1240 if (memberName == name)
1241 {
1242 return md.get(); // found in ONLY-part of use list
1243 }
1244 }
1245 }
1246 }
1247 }
1248 } // if linkable
1249 } // for
1250 }
1251 return nullptr;
1252}
1253
1254/**
1255 gets the link to a generic procedure which depends not on the name, but on the parameter list
1256 @todo implementation
1257*/
1259 const QCString &,
1261{
1262 return FALSE;
1263}
1264
1265static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // dictionary with used modules
1266 const QCString &memberText, // exact member text
1267 OutputCodeList &ol,
1268 const QCString &text)
1269{
1270 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1271 MemberDef *md=nullptr;
1272 QCString memberName= removeRedundantWhiteSpace(memberText);
1273
1274 if ((md=getFortranDefs(yyscanner,memberName, yyextra->currentModule, useMap)) && md->isLinkable())
1275 {
1276 if (md->isVariable() && (md->getLanguage()!=SrcLangExt::Fortran)) return FALSE; // Non Fortran variables aren't handled yet,
1277 // see also linkifyText in util.cpp
1278
1280 md->getBodyDef() : md->getOuterScope();
1281 if (md->getGroupDef()) d = md->getGroupDef();
1282 if (d && d->isLinkable())
1283 {
1284 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
1285 yyextra->insideBody && yyextra->collectXRefs)
1286 {
1287 addDocCrossReference(yyextra->currentMemberDef,md);
1288 }
1289 writeMultiLineCodeLink(yyscanner,ol,md,!text.isEmpty() ? text : memberText);
1290 addToSearchIndex(yyscanner, !text.isEmpty() ? text : memberText);
1291 return TRUE;
1292 }
1293 }
1294 return FALSE;
1295}
1296
1297
1298static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const QCString &lname)
1299{
1300 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1301 ClassDef *cd=nullptr;
1302 NamespaceDef *nsd=nullptr;
1303 QCString name = lname;
1304 name = removeRedundantWhiteSpace(name.lower());
1305
1306 // check if lowercase lname is a linkable type or interface
1307 if ( (getFortranTypeDefs(name, yyextra->currentModule, cd, yyextra->useMembers)) && cd->isLinkable() )
1308 {
1309 if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
1310 (getGenericProcedureLink(yyscanner, cd, name, ol)) )
1311 {
1312 //cout << "=== generic procedure resolved" << endl;
1313 }
1314 else
1315 { // write type or interface link
1316 writeMultiLineCodeLink(yyscanner, ol,cd,name);
1317 addToSearchIndex(yyscanner, name);
1318 }
1319 }
1320 // check for module
1321 else if ( (getFortranNamespaceDefs(name, nsd)) && nsd->isLinkable() )
1322 { // write module link
1323 writeMultiLineCodeLink(yyscanner,ol,nsd,name);
1324 addToSearchIndex(yyscanner,name);
1325 }
1326 // check for function/variable
1327 else if (getLink(yyscanner,yyextra->useMembers, name, ol, name))
1328 {
1329 //cout << "=== found link for lowercase " << lname << endl;
1330 }
1331 else
1332 {
1333 // nothing found, just write out the word
1334 //startFontClass("charliteral"); //test
1335 codifyLines(yyscanner,name);
1336 //endFontClass(yyscanner); //test
1337 addToSearchIndex(yyscanner,name);
1338 }
1339}
1340
1341static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const char *lname)
1342{
1343 generateLink(yyscanner,ol,QCString(lname));
1344}
1345
1346/*! counts the number of lines in the input */
1347static int countLines(yyscan_t yyscanner)
1348{
1349 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1350 const char *p=yyextra->inputString;
1351 char c = 0;
1352 int count=1;
1353 while ((c=*p))
1354 {
1355 p++ ;
1356 if (c=='\n') count++;
1357 }
1358 if (p>yyextra->inputString && *(p-1)!='\n')
1359 { // last line does not end with a \n, so we add an extra
1360 // line and explicitly terminate the line after parsing.
1361 count++;
1362 }
1363 return count;
1364}
1365
1366//----------------------------------------------------------------------------
1367/** start scope */
1368static void startScope(yyscan_t yyscanner)
1369{
1370 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1371 DBG_CTX((stderr, "===> startScope %s",yytext));
1372 yyextra->scopeStack.emplace_back();
1373}
1374
1375/** end scope */
1376static void endScope(yyscan_t yyscanner)
1377{
1378 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1379 DBG_CTX((stderr,"===> endScope %s",yytext));
1380 if (yyextra->scopeStack.empty())
1381 {
1382 DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n"));
1383 return;
1384 }
1385
1386 Scope &scope = yyextra->scopeStack.back();
1387 for ( const auto &name : scope.useNames)
1388 {
1389 yyextra->useMembers.erase(name.str());
1390 }
1391 yyextra->scopeStack.pop_back();
1392}
1393
1394static void addUse(yyscan_t yyscanner,const QCString &moduleName)
1395{
1396 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1397 if (!yyextra->scopeStack.empty())
1398 yyextra->scopeStack.back().useNames.push_back(moduleName);
1399}
1400
1401static void addLocalVar(yyscan_t yyscanner,const QCString &varName)
1402{
1403 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1404 if (!yyextra->scopeStack.empty())
1405 {
1406 std::string lowVarName = varName.lower().str();
1407 yyextra->scopeStack.back().localVars.insert(lowVarName);
1408 if (yyextra->isExternal) yyextra->scopeStack.back().externalVars.insert(lowVarName);
1409 }
1410}
1411
1412/*===================================================================*/
1413
1414
1415static void checkContLines(yyscan_t yyscanner,const char *s)
1416{
1417 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1418 int numLines = 0;
1419 int i = 0;
1420 const char *p = s;
1421
1422 numLines = 2; // one for element 0, one in case no \n at end
1423 while (*p)
1424 {
1425 if (*p == '\n') numLines++;
1426 p++;
1427 }
1428
1429 yyextra->hasContLine = (int *) malloc((numLines) * sizeof(int));
1430 for (i = 0; i < numLines; i++)
1431 {
1432 yyextra->hasContLine[i] = 0;
1433 }
1434 p = prepassFixedForm(s, yyextra->hasContLine,yyextra->fixedCommentAfter);
1435 yyextra->hasContLine[0] = 0;
1436}
1437
1438void parseFortranCode(OutputCodeList &,const char *,const QCString &,
1439 bool , const char *,const FileDef *,
1440 int ,int ,bool ,
1441 const MemberDef *,bool,const Definition *,
1442 bool , FortranFormat )
1443{
1444 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1445
1446 return;
1447}
1448
1449//---------------------------------------------------------
1450
1457
1459{
1460 p->format = format;
1461 fortrancodeYYlex_init_extra(&p->state,&p->yyscanner);
1462#ifdef FLEX_DEBUG
1463 fortrancodeYYset_debug(Debug::isFlagSet(Debug::Lex_fortrancode)?1:0,p->yyscanner);
1464#endif
1466}
1467
1469{
1470 fortrancodeYYlex_destroy(p->yyscanner);
1471}
1472
1474{
1475 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1476 yyextra->currentDefinition = nullptr;
1477 yyextra->currentMemberDef = nullptr;
1478 yyextra->currentFontClass = nullptr;
1479 yyextra->insideCodeLine = FALSE;
1480 BEGIN( Start );
1481}
1482
1484 const QCString & /* scopeName */,
1485 const QCString & input,
1486 SrcLangExt /*lang*/,
1487 bool stripCodeComments,
1488 bool isExampleBlock,
1489 const QCString & exampleName,
1490 const FileDef * fileDef,
1491 int startLine,
1492 int endLine,
1493 bool inlineFragment,
1494 const MemberDef * /* memberDef */,
1495 bool /* showLineNumbers */,
1496 const Definition *searchCtx,
1497 bool collectXRefs
1498 )
1499{
1500 yyscan_t yyscanner = p->yyscanner;
1501 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1502 //::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
1503 // fileDef,startLine,endLine,inlineFragment,memberDef,
1504 // showLineNumbers,searchCtx,collectXRefs,m_format);
1505 // parseFortranCode(OutputCodeList &od,const char *,const QCString &s,
1506 // bool exBlock, const char *exName,FileDef *fd,
1507 // int startLine,int endLine,bool inlineFragment,
1508 // const MemberDef *,bool,const Definition *searchCtx,
1509 // bool collectXRefs, FortranFormat format)
1510 if (input.isEmpty()) return;
1511 DebugLex debugLex(Debug::Lex_fortrancode, __FILE__, fileDef ? qPrint(fileDef->fileName()): nullptr);
1512 codeOutIntf.stripCodeComments(stripCodeComments);
1513 yyextra->code = &codeOutIntf;
1514 yyextra->inputString = input.data();
1515 yyextra->inputPosition = 0;
1516 yyextra->fileName = fileDef ? fileDef->fileName():"";
1517 yyextra->isFixedForm = recognizeFixedForm(input,p->format);
1518 yyextra->contLineNr = 1;
1519 yyextra->hasContLine = nullptr;
1520 if (yyextra->isFixedForm)
1521 {
1522 checkContLines(yyscanner,yyextra->inputString);
1523 yyextra->fixedCommentAfter = Config_getInt(FORTRAN_COMMENT_AFTER);
1524 }
1525 yyextra->currentFontClass = nullptr;
1526 yyextra->insideCodeLine = FALSE;
1527 yyextra->searchCtx = searchCtx;
1528 yyextra->collectXRefs = collectXRefs;
1529 if (startLine!=-1)
1530 yyextra->yyLineNr = startLine;
1531 else
1532 yyextra->yyLineNr = 1;
1533
1534 if (endLine!=-1)
1535 yyextra->inputLines = endLine+1;
1536 else
1537 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1538
1539 yyextra->exampleBlock = isExampleBlock;
1540 yyextra->exampleName = exampleName;
1541 yyextra->sourceFileDef = fileDef;
1542 yyextra->foldStack.clear();
1543 yyextra->insideSpecialComment = false;
1544 if (isExampleBlock && fileDef==nullptr)
1545 {
1546 // create a dummy filedef for the example
1547 yyextra->exampleFileDef = createFileDef(QCString(),exampleName);
1548 yyextra->sourceFileDef = yyextra->exampleFileDef.get();
1549 }
1550 if (yyextra->sourceFileDef)
1551 {
1552 setCurrentDoc(yyscanner,QCString("l00001"));
1553 }
1554 yyextra->currentDefinition = nullptr;
1555 yyextra->currentMemberDef = nullptr;
1556 if (!yyextra->exampleName.isEmpty())
1557 {
1558 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example");
1559 }
1560 yyextra->includeCodeFragment = inlineFragment;
1561 startCodeLine(yyscanner);
1562 fortrancodeYYrestart(nullptr, yyscanner);
1563 BEGIN( Start );
1564 fortrancodeYYlex(yyscanner);
1565 if (yyextra->insideCodeLine)
1566 {
1567 endCodeLine(yyscanner);
1568 }
1569 if (Config_getBool(HTML_CODE_FOLDING))
1570 {
1571 while (!yyextra->foldStack.empty())
1572 {
1573 yyextra->code->endFold();
1574 yyextra->foldStack.pop_back();
1575 }
1576 }
1577 if (!fileDef && isExampleBlock && yyextra->sourceFileDef)
1578 {
1579 // delete the temporary file definition used for this example
1580 yyextra->exampleFileDef.reset();
1581 yyextra->sourceFileDef=nullptr;
1582 }
1583 if (yyextra->hasContLine) free(yyextra->hasContLine);
1584 yyextra->hasContLine = nullptr;
1585
1586 // write the tooltips
1587 yyextra->tooltipManager.writeTooltips(codeOutIntf);
1588}
1589
1590static inline void pop_state(yyscan_t yyscanner)
1591{
1592 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1593 if ( yyg->yy_start_stack_ptr <= 0 )
1594 warn(yyextra->fileName,yyextra->yyLineNr,"Unexpected statement '%s'",yytext );
1595 else
1596 yy_pop_state(yyscanner);
1597}
1598//---------------------------------------------------------
1599
1600#include "fortrancode.l.h"
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e.
@ Lex_fortrancode
Definition debug.h:59
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:135
virtual int getEndBodyLine() const =0
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual bool isLinkable() const =0
virtual QCString anchor() const =0
virtual QCString briefDescriptionAsTooltip() const =0
virtual const FileDef * getBodyDef() const =0
virtual bool isLinkableInProject() const =0
virtual int getStartDefLine() const =0
virtual QCString getReference() const =0
virtual CodeSymbolType codeSymbolType() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
virtual const QCString & name() const =0
static NamespaceLinkedMap * namespaceLinkedMap
Definition doxygen.h:115
static ClassLinkedMap * classLinkedMap
Definition doxygen.h:96
static MemberNameLinkedMap * functionNameLinkedMap
Definition doxygen.h:112
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static MemberNameLinkedMap * memberNameLinkedMap
Definition doxygen.h:111
static SearchIndexIntf searchIndex
Definition doxygen.h:124
virtual QCString fileName() const =0
void resetCodeParserState() override
Resets the state of the code parser.
FortranCodeParser(FortranFormat format=FortranFormat::Unknown)
std::unique_ptr< Private > p
Definition fortrancode.h:56
void parseCode(OutputCodeList &codeOutIntf, const QCString &scopeName, const QCString &input, SrcLangExt lang, bool stripCodeComments, bool isExampleBlock, const QCString &exampleName=QCString(), const FileDef *fileDef=nullptr, int startLine=-1, int endLine=-1, bool inlineFragment=FALSE, const MemberDef *memberDef=nullptr, bool showLineNumbers=TRUE, const Definition *searchCtx=nullptr, bool collectXRefs=TRUE) override
Parses a source file or fragment with the goal to produce highlighted and cross-referenced output.
~FortranCodeParser() override
A model of a group of symbols.
Definition groupdef.h:52
virtual GroupDef * getGroupDef()=0
virtual bool isVariable() const =0
void writeCodeLink(CodeSymbolType type, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name, const QCString &tooltip)
Definition outputlist.h:249
void stripCodeComments(bool b)
Definition outputlist.h:237
QCString lower() const
Definition qcstring.h:234
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text)
Definition code.l:2565
static void endCodeLine(yyscan_t yyscanner)
Definition code.l:2487
static void nextCodeLine(yyscan_t yyscanner)
Definition code.l:2496
static void startCodeLine(yyscan_t yyscanner)
Definition code.l:2418
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3980
static int countLines(yyscan_t yyscanner)
Definition code.l:3471
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition code.l:2296
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString(), bool varOnly=FALSE)
Definition code.l:2897
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition code.l:2280
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2360
#define Config_getInt(name)
Definition config.h:34
#define Config_getBool(name)
Definition config.h:33
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:267
static void checkContLines(yyscan_t yyscanner, const char *s)
void parseFortranCode(OutputCodeList &, const char *, const QCString &, bool, const char *, const FileDef *, int, int, bool, const MemberDef *, bool, const Definition *, bool, FortranFormat)
const char * prepassFixedForm(const char *contents, int *hasContLine, int fixedCommentAfter)
void addDocCrossReference(const MemberDef *s, const MemberDef *d)
#define warn(file, line, fmt,...)
Definition message.h:59
const char * qPrint(const char *s)
Definition qcstring.h:672
int qstrcmp(const char *str1, const char *str2)
Definition qcstring.h:69
fortrancodeYY_state state
SrcLangExt
Language as given by extension.
Definition types.h:42
@ Fortran
Definition types.h:53
FortranFormat
Definition types.h:410
bool recognizeFixedForm(const QCString &contents, FortranFormat format)
Definition util.cpp:6671
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3858