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;
162 const Definition * currentDefinition = nullptr;
163 const MemberDef * currentMemberDef = nullptr;
165
166 char stringStartSymbol = '\0'; // single or double quote
167// count in variable declaration to filter out
168// declared from referenced names
170
171// signal when in type / class /procedure declaration
172 int inTypeDecl = 0;
173
174 bool endComment = false;
176 std::vector<const Definition *> foldStack;
177
179};
180
181[[maybe_unused]] static const char *stateToString(int state);
182
183static bool getFortranNamespaceDefs(const QCString &mname,
184 NamespaceDef *&cd);
185static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
186 ClassDef *&cd, const UseMap &useMap);
187
188//----------------------------------------------------------------------------
189
190static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment=false);
191static void endFontClass(yyscan_t yyscanner,bool specialComment=false);
192static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
193static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
194static void startCodeLine(yyscan_t yyscanner);
195static void endCodeLine(yyscan_t yyscanner);
196static void nextCodeLine(yyscan_t yyscanner);
197static void codifyLines(yyscan_t yyscanner,const QCString &text);
198static void writeMultiLineCodeLink(yyscan_t yyscanner,OutputCodeList &ol,
199 Definition *d,const QCString &text);
200static bool getGenericProcedureLink(yyscan_t yyscanner,const ClassDef *cd,
201 const QCString &memberText,
202 OutputCodeList &ol);
203static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // map with used modules
204 const QCString &memberText, // exact member text
205 OutputCodeList &ol,
206 const QCString &text);
207static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const QCString &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:77
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:165
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)
#define FALSE
Definition qcstring.h:34
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:2516
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:3506
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition code.l:3491
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:139
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
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:530
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(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(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(yytext);
526 endFontClass(yyscanner);
527 }
QCString removeRedundantWhiteSpace(const QCString &s)
Definition util.cpp:567
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(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(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(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(yytext);
563 addLocalVar(yyscanner,yytext);
564 }
565 }
566<Declaration>{BS}("=>"|"="){BS} { // Procedure binding
567 BEGIN(DeclarationBinding);
568 yyextra->code->codify(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(yytext);
577 }
578
579<Declaration>[)] { // end array specification
580 yyextra->bracketCount--;
581 if (!yyextra->bracketCount) yyextra->inTypeDecl = 0;
582 yyextra->code->codify(yytext);
583 }
584
585<Declaration,DeclarationBinding>"&" { // continuation line
586 yyextra->code->codify(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(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(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(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(yytext);
819 }
820 }
821<*>{LOG_OPER} { // Fortran logical comparison keywords
822 yyextra->code->codify(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(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 && yyextra->lineNumbers)
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(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 yyextra->code->codify(QCString(sp,l));
1052 nextCodeLine(yyscanner);
1053 }
1054 else
1055 {
1056 yyextra->code->codify(sp);
1057 done=TRUE;
1058 }
1059 }
1060}
1061
1062/*! writes a link to a fragment \a text that may span multiple lines, inserting
1063 * line numbers for each line. If \a text contains newlines, the link will be
1064 * split into multiple links with the same destination, one for each line.
1065 */
1067 Definition *d,const QCString &text)
1068{
1069 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1070 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1071 yyextra->tooltipManager.addTooltip(d);
1072 QCString ref = d->getReference();
1073 QCString file = d->getOutputFileBase();
1074 QCString anchor = d->anchor();
1075 QCString tooltip;
1076 if (!sourceTooltips) // fall back to simple "title" tooltips
1077 {
1078 tooltip = d->briefDescriptionAsTooltip();
1079 }
1080 bool done=FALSE;
1081 const char *p=text.data();
1082 while (!done)
1083 {
1084 const char *sp=p;
1085 char c = 0;
1086 while ((c=*p++) && c!='\n') { }
1087 if (c=='\n')
1088 {
1089 yyextra->yyLineNr++;
1090 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1091 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1092 nextCodeLine(yyscanner);
1093 }
1094 else
1095 {
1096 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1097 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1098 done=TRUE;
1099 }
1100 }
1101}
1102//-------------------------------------------------------------------------------
1103/**
1104 searches for definition of a module (Namespace)
1105 @param mname the name of the module
1106 @param cd the entry, if found or null
1107 @returns true, if module is found
1108*/
1109static bool getFortranNamespaceDefs(const QCString &mname,
1110 NamespaceDef *&cd)
1111{
1112 if (mname.isEmpty()) return FALSE; /* empty name => nothing to link */
1113
1114 // search for module
1115 if ((cd=Doxygen::namespaceLinkedMap->find(mname))) return TRUE;
1116
1117 return FALSE;
1118}
1119//-------------------------------------------------------------------------------
1120/**
1121 searches for definition of a type
1122 @param tname the name of the type
1123 @param moduleName name of enclosing module or null, if global entry
1124 @param cd the entry, if found or null
1125 @param useMap map of data of USE-statement
1126 @returns true, if type is found
1127*/
1128static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
1129 ClassDef *&cd, const UseMap &useMap)
1130{
1131 if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
1132
1133 //cout << "=== search for type: " << tname << endl;
1134
1135 // search for type
1136 if ((cd=Doxygen::classLinkedMap->find(tname)))
1137 {
1138 //cout << "=== type found in global module" << endl;
1139 return TRUE;
1140 }
1141 else if (!moduleName.isEmpty() && (cd=Doxygen::classLinkedMap->find(moduleName+"::"+tname)))
1142 {
1143 //cout << "=== type found in local module" << endl;
1144 return TRUE;
1145 }
1146 else
1147 {
1148 for (const auto &[name,useEntry] : useMap)
1149 {
1150 if ((cd=Doxygen::classLinkedMap->find(useEntry.module+"::"+tname)))
1151 {
1152 //cout << "=== type found in used module" << endl;
1153 return TRUE;
1154 }
1155 }
1156 }
1157
1158 return FALSE;
1159}
1160
1161/**
1162 searches for definition of function memberName
1163 @param yyscanner the scanner data to be used
1164 @param memberName the name of the function/variable
1165 @param moduleName name of enclosing module or null, if global entry
1166 @param useMap map of data of USE-statement
1167 @returns MemberDef pointer, if found, or nullptr otherwise
1168*/
1169static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
1170 const UseMap &useMap)
1171{
1172 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1173 MemberDef *potentialMd = nullptr;
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 if (md.get()->getFileDef() == yyextra->sourceFileDef) return md.get();
1216 else if (!potentialMd) potentialMd = md.get();
1217 }
1218 }
1219 else if (moduleName == nspace->name())
1220 { // found in local scope
1221 return md.get();
1222 }
1223 else
1224 { // else search in used modules
1225 QCString usedModuleName= nspace->name();
1226 auto use_it = useMap.find(usedModuleName.str());
1227 if (use_it!=useMap.end())
1228 {
1229 const UseEntry &ue = use_it->second;
1230 // check if only-list exists and if current entry exists is this list
1231 if (ue.onlyNames.empty())
1232 {
1233 //cout << " found in module " << usedModuleName << " entry " << memberName << endl;
1234 return md.get(); // whole module used
1235 }
1236 else
1237 {
1238 for ( const auto &name : ue.onlyNames)
1239 {
1240 //cout << " search in only: " << usedModuleName << ":: " << memberName << "==" << (*it)<< endl;
1241 if (memberName == name)
1242 {
1243 return md.get(); // found in ONLY-part of use list
1244 }
1245 }
1246 }
1247 }
1248 }
1249 } // if linkable
1250 } // for
1251 }
1252 return potentialMd;
1253}
1254
1255/**
1256 gets the link to a generic procedure which depends not on the name, but on the parameter list
1257 @todo implementation
1258*/
1260 const QCString &,
1262{
1263 return FALSE;
1264}
1265
1266static bool getLink(yyscan_t yyscanner,const UseMap &useMap, // dictionary with used modules
1267 const QCString &memberText, // exact member text
1268 OutputCodeList &ol,
1269 const QCString &text)
1270{
1271 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1272 MemberDef *md=nullptr;
1273 QCString memberName= removeRedundantWhiteSpace(memberText);
1274
1275 if ((md=getFortranDefs(yyscanner,memberName, yyextra->currentModule, useMap)) && md->isLinkable())
1276 {
1277 if (md->isVariable() && (md->getLanguage()!=SrcLangExt::Fortran)) return FALSE; // Non Fortran variables aren't handled yet,
1278 // see also linkifyText in util.cpp
1279
1281 md->getBodyDef() : md->getOuterScope();
1282 if (md->getGroupDef()) d = md->getGroupDef();
1283 if (d && d->isLinkable())
1284 {
1285 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
1286 yyextra->insideBody && yyextra->collectXRefs)
1287 {
1288 addDocCrossReference(yyextra->currentMemberDef,md);
1289 }
1290 writeMultiLineCodeLink(yyscanner,ol,md,!text.isEmpty() ? text : memberText);
1291 addToSearchIndex(yyscanner, !text.isEmpty() ? text : memberText);
1292 return TRUE;
1293 }
1294 }
1295 return FALSE;
1296}
1297
1298
1299static void generateLink(yyscan_t yyscanner,OutputCodeList &ol, const QCString &lname)
1300{
1301 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1302 ClassDef *cd=nullptr;
1303 NamespaceDef *nsd=nullptr;
1304 QCString name = lname;
1305 name = removeRedundantWhiteSpace(name.lower());
1306
1307 // check if lowercase lname is a linkable type or interface
1308 if ( (getFortranTypeDefs(name, yyextra->currentModule, cd, yyextra->useMembers)) && cd->isLinkable() )
1309 {
1310 if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) &&
1311 (getGenericProcedureLink(yyscanner, cd, name, ol)) )
1312 {
1313 //cout << "=== generic procedure resolved" << endl;
1314 }
1315 else
1316 { // write type or interface link
1317 writeMultiLineCodeLink(yyscanner, ol,cd,name);
1318 addToSearchIndex(yyscanner, name);
1319 }
1320 }
1321 // check for module
1322 else if ( (getFortranNamespaceDefs(name, nsd)) && nsd->isLinkable() )
1323 { // write module link
1324 writeMultiLineCodeLink(yyscanner,ol,nsd,name);
1325 addToSearchIndex(yyscanner,name);
1326 }
1327 // check for function/variable
1328 else if (getLink(yyscanner,yyextra->useMembers, name, ol, name))
1329 {
1330 //cout << "=== found link for lowercase " << lname << endl;
1331 }
1332 else
1333 {
1334 // nothing found, just write out the word
1335 //startFontClass("charliteral"); //test
1336 codifyLines(yyscanner,name);
1337 //endFontClass(yyscanner); //test
1338 addToSearchIndex(yyscanner,name);
1339 }
1340}
1341
1342/*! counts the number of lines in the input */
1343static int countLines(yyscan_t yyscanner)
1344{
1345 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1346 const char *p=yyextra->inputString;
1347 char c = 0;
1348 int count=1;
1349 while ((c=*p))
1350 {
1351 p++ ;
1352 if (c=='\n') count++;
1353 }
1354 if (p>yyextra->inputString && *(p-1)!='\n')
1355 { // last line does not end with a \n, so we add an extra
1356 // line and explicitly terminate the line after parsing.
1357 count++;
1358 }
1359 return count;
1360}
1361
1362//----------------------------------------------------------------------------
1363/** start scope */
1364static void startScope(yyscan_t yyscanner)
1365{
1366 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1367 DBG_CTX((stderr, "===> startScope %s",yytext));
1368 yyextra->scopeStack.emplace_back();
1369}
1370
1371/** end scope */
1372static void endScope(yyscan_t yyscanner)
1373{
1374 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1375 DBG_CTX((stderr,"===> endScope %s",yytext));
1376 if (yyextra->scopeStack.empty())
1377 {
1378 DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n"));
1379 return;
1380 }
1381
1382 Scope &scope = yyextra->scopeStack.back();
1383 for ( const auto &name : scope.useNames)
1384 {
1385 yyextra->useMembers.erase(name.str());
1386 }
1387 yyextra->scopeStack.pop_back();
1388}
1389
1390static void addUse(yyscan_t yyscanner,const QCString &moduleName)
1391{
1392 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1393 if (!yyextra->scopeStack.empty())
1394 yyextra->scopeStack.back().useNames.push_back(moduleName);
1395}
1396
1397static void addLocalVar(yyscan_t yyscanner,const QCString &varName)
1398{
1399 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1400 if (!yyextra->scopeStack.empty())
1401 {
1402 std::string lowVarName = varName.lower().str();
1403 yyextra->scopeStack.back().localVars.insert(lowVarName);
1404 if (yyextra->isExternal) yyextra->scopeStack.back().externalVars.insert(lowVarName);
1405 }
1406}
1407
1408/*===================================================================*/
1409
1410
1411static void checkContLines(yyscan_t yyscanner,const char *s)
1412{
1413 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1414 int numLines = 0;
1415 int i = 0;
1416 const char *p = s;
1417
1418 numLines = 2; // one for element 0, one in case no \n at end
1419 while (*p)
1420 {
1421 if (*p == '\n') numLines++;
1422 p++;
1423 }
1424
1425 yyextra->hasContLine = (int *) malloc((numLines) * sizeof(int));
1426 for (i = 0; i < numLines; i++)
1427 {
1428 yyextra->hasContLine[i] = 0;
1429 }
1430 p = prepassFixedForm(s, yyextra->hasContLine,yyextra->fixedCommentAfter);
1431 yyextra->hasContLine[0] = 0;
1432}
1433
1434void parseFortranCode(OutputCodeList &,const char *,const QCString &,
1435 bool , const char *,const FileDef *,
1436 int ,int ,bool ,
1437 const MemberDef *,bool,const Definition *,
1438 bool , FortranFormat )
1439{
1440 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1441
1442 return;
1443}
1444
1445//---------------------------------------------------------
1446
1453
1455{
1456 p->format = format;
1457 fortrancodeYYlex_init_extra(&p->state,&p->yyscanner);
1458#ifdef FLEX_DEBUG
1459 fortrancodeYYset_debug(Debug::isFlagSet(Debug::Lex_fortrancode)?1:0,p->yyscanner);
1460#endif
1462}
1463
1465{
1466 fortrancodeYYlex_destroy(p->yyscanner);
1467}
1468
1470{
1471 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1472 yyextra->currentDefinition = nullptr;
1473 yyextra->currentMemberDef = nullptr;
1474 yyextra->currentFontClass = nullptr;
1475 yyextra->insideCodeLine = FALSE;
1476 BEGIN( Start );
1477}
1478
1480 const QCString & /* scopeName */,
1481 const QCString & input,
1482 SrcLangExt /*lang*/,
1483 bool stripCodeComments,
1484 const CodeParserOptions &options
1485 )
1486{
1487 yyscan_t yyscanner = p->yyscanner;
1488 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1489 if (input.isEmpty()) return;
1490 DebugLex debugLex(Debug::Lex_fortrancode, __FILE__, options.fileDef() ? qPrint(options.fileDef()->fileName()): nullptr);
1491 codeOutIntf.stripCodeComments(stripCodeComments);
1492 yyextra->code = &codeOutIntf;
1493 yyextra->inputString = input.data();
1494 yyextra->inputPosition = 0;
1495 yyextra->fileName = options.fileDef() ? options.fileDef()->fileName():"";
1496 yyextra->isFixedForm = recognizeFixedForm(input,p->format);
1497 yyextra->contLineNr = 1;
1498 yyextra->hasContLine = nullptr;
1499 if (yyextra->isFixedForm)
1500 {
1501 checkContLines(yyscanner,yyextra->inputString);
1502 yyextra->fixedCommentAfter = Config_getInt(FORTRAN_COMMENT_AFTER);
1503 }
1504 yyextra->currentFontClass = nullptr;
1505 yyextra->insideCodeLine = FALSE;
1506 yyextra->searchCtx = options.searchCtx();
1507 yyextra->collectXRefs = options.collectXRefs();
1508 yyextra->yyLineNr = options.startLine()!=-1 ? options.startLine() : 1;
1509 yyextra->inputLines = options.endLine()!=-1 ? options.endLine()+1 : yyextra->yyLineNr + countLines(yyscanner) - 1;
1510 yyextra->exampleBlock = options.isExample();
1511 yyextra->exampleName = options.exampleName();
1512 yyextra->sourceFileDef = options.fileDef();
1513 yyextra->lineNumbers = options.fileDef() && options.showLineNumbers();
1514 yyextra->foldStack.clear();
1515 yyextra->insideSpecialComment = false;
1516 if (options.isExample() && options.fileDef()==nullptr)
1517 {
1518 // create a dummy filedef for the example
1519 yyextra->exampleFileDef = createFileDef(QCString(),options.exampleName());
1520 yyextra->sourceFileDef = yyextra->exampleFileDef.get();
1521 }
1522 if (yyextra->sourceFileDef)
1523 {
1524 setCurrentDoc(yyscanner,QCString("l00001"));
1525 }
1526 yyextra->currentDefinition = nullptr;
1527 yyextra->currentMemberDef = nullptr;
1528 if (!yyextra->exampleName.isEmpty())
1529 {
1530 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example");
1531 }
1532 yyextra->includeCodeFragment = options.inlineFragment();
1533 startCodeLine(yyscanner);
1534 fortrancodeYYrestart(nullptr, yyscanner);
1535 BEGIN( Start );
1536 fortrancodeYYlex(yyscanner);
1537 if (yyextra->insideCodeLine)
1538 {
1539 endCodeLine(yyscanner);
1540 }
1541 if (Config_getBool(HTML_CODE_FOLDING))
1542 {
1543 while (!yyextra->foldStack.empty())
1544 {
1545 yyextra->code->endFold();
1546 yyextra->foldStack.pop_back();
1547 }
1548 }
1549 if (yyextra->exampleFileDef)
1550 {
1551 // delete the temporary file definition used for this example
1552 yyextra->exampleFileDef.reset();
1553 yyextra->sourceFileDef=nullptr;
1554 }
1555 if (yyextra->hasContLine) free(yyextra->hasContLine);
1556 yyextra->hasContLine = nullptr;
1557
1558 // write the tooltips
1559 yyextra->tooltipManager.writeTooltips(codeOutIntf);
1560}
1561
1562static inline void pop_state(yyscan_t yyscanner)
1563{
1564 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1565 if ( yyg->yy_start_stack_ptr <= 0 )
1566 warn(yyextra->fileName,yyextra->yyLineNr,"Unexpected statement '{}'",yytext );
1567 else
1568 yy_pop_state(yyscanner);
1569}
1570//---------------------------------------------------------
1571
1572#include "fortrancode.l.h"
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e.
@ Lex_fortrancode
Definition debug.h:61
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:133
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:95
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)
void parseCode(OutputCodeList &codeOutIntf, const QCString &scopeName, const QCString &input, SrcLangExt lang, bool stripCodeComments, const CodeParserOptions &options) override
Parses a source file or fragment with the goal to produce highlighted and cross-referenced output.
std::unique_ptr< Private > p
Definition fortrancode.h:47
~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:250
void stripCodeComments(bool b)
Definition outputlist.h:238
QCString lower() const
Definition qcstring.h:249
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
const std::string & str() const
Definition qcstring.h:552
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:172
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text)
Definition code.l:2561
static void endCodeLine(yyscan_t yyscanner)
Definition code.l:2489
static void nextCodeLine(yyscan_t yyscanner)
Definition code.l:2498
static void startCodeLine(yyscan_t yyscanner)
Definition code.l:2420
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3982
static int countLines(yyscan_t yyscanner)
Definition code.l:3473
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition code.l:2304
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString(), bool varOnly=FALSE)
Definition code.l:2893
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition code.l:2288
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2362
#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:268
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:97
const char * qPrint(const char *s)
Definition qcstring.h:687
int qstrcmp(const char *str1, const char *str2)
Definition qcstring.h:69
Options to configure the code parser.
Definition parserintf.h:78
bool isExample() const
Definition parserintf.h:81
const Definition * searchCtx() const
Definition parserintf.h:89
const FileDef * fileDef() const
Definition parserintf.h:83
int endLine() const
Definition parserintf.h:85
bool showLineNumbers() const
Definition parserintf.h:88
bool inlineFragment() const
Definition parserintf.h:86
QCString exampleName() const
Definition parserintf.h:82
int startLine() const
Definition parserintf.h:84
bool collectXRefs() const
Definition parserintf.h:90
fortrancodeYY_state state
SrcLangExt
Definition types.h:207
FortranFormat
Definition types.h:572
bool recognizeFixedForm(const QCString &contents, FortranFormat format)
Definition util.cpp:6366
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3508