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 int countLines(yyscan_t yyscanner);
208static void startScope(yyscan_t yyscanner);
209static void endScope(yyscan_t yyscanner);
210static void addUse(yyscan_t yyscanner,const QCString &moduleName);
211static void addLocalVar(yyscan_t yyscanner,const QCString &varName);
212static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
213 const UseMap &useMap);
214static int yyread(yyscan_t yyscanner,char *buf,int max_size);
215static inline void pop_state(yyscan_t yyscanner);
216
217/* -----------------------------------------------------------------*/
218#undef YY_INPUT
219#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
220
221// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
222static inline const char *getLexerFILE() {return __FILE__;}
223#include "doxygen_lex.h"
224
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.
225%}
226
227IDSYM [a-z_A-Z0-9]
228ID [a-z_A-Z]+{IDSYM}*
229SUBPROG (subroutine|function)
230BS [ \t]*
231BS_ [ \t]+
232COMMA {BS},{BS}
233ARGS_L0 ("("[^)]*")")
234ARGS_L1a [^()]*"("[^)]*")"[^)]*
235ARGS_L1 ("("{ARGS_L1a}*")")
236ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")"
237ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2})
238
239NUM_TYPE (complex|integer|logical|real)
240LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.)
241KIND {ARGS}
242CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS}))
243TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS}COMPLEX|DOUBLE{BS}PRECISION|{CHAR}|TYPE|CLASS|PROCEDURE|ENUMERATOR)
244
245INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")"
246ATTR_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)
247ACCESS_SPEC (PROTECTED|PRIVATE|PUBLIC)
248/* Assume that attribute statements are almost the same as attributes. */
249FLOW (DO|SELECT|CASE|SELECT{BS}(CASE|TYPE|RANK)|WHERE|IF|THEN|ELSE|WHILE|FORALL|ELSEWHERE|ELSEIF|RETURN|CONTINUE|EXIT|GO{BS}TO)
250COMMANDS (FORMAT|CONTAINS|MODULE{BS_}PROCEDURE|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|PRESENT|DEALLOCATE|NULLIFY|SIZE|INQUIRE|OPEN|CLOSE|FLUSH|DATA|COMMON)
251IGNORE (CALL)
252PREFIX ((NON_)?RECURSIVE{BS_}|IMPURE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,4}((NON_)?RECURSIVE|IMPURE|PURE|ELEMENTAL)?0
253LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")"
254
255/* | */
256
257%option noyywrap
258%option stack
259%option caseless
260/*%option debug*/
261
262%x Start
263%x SubCall
264%x ClassName
265%x Subprog
266%x DocBlock
267%x Use
268%x UseOnly
269%x Import
270%x Declaration
271%x DeclarationBinding
272%x DeclContLine
273%x String
274%x Subprogend
275
277 /*==================================================================*/
278
279 /*-------- ignore ------------------------------------------------------------*/
280
281<Start>{IGNORE}/{BS}"(" { // do not search keywords, intrinsics... TODO: complete list
282 codifyLines(yyscanner,yytext);
283 }
static void codifyLines(yyscan_t yyscanner, const QCString &text)
Definition code.l:2505
284 /*-------- inner construct ---------------------------------------------------*/
285
286<Start>{COMMANDS}/{BS}[,( \t\n] { // highlight
287 /* font class is defined e.g. in doxygen.css */
288 startFontClass(yyscanner,"keyword");
289 codifyLines(yyscanner,yytext);
290 endFontClass(yyscanner);
291 }
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
Definition code.l:3487
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition code.l:3472
292<Start>{FLOW}/{BS}[,( \t\n] {
293 if (yyextra->isFixedForm)
294 {
295 if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT;
296 }
297 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
298 {
299 std::lock_guard<std::mutex> lock(Doxygen::countFlowKeywordsMutex);
300 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(yyextra->currentMemberDef));
301 if (mdm)
302 {
304 }
305 }
306 /* font class is defined e.g. in doxygen.css */
307 startFontClass(yyscanner,"keywordflow");
308 codifyLines(yyscanner,yytext);
309 endFontClass(yyscanner);
310 }
static std::mutex countFlowKeywordsMutex
Definition doxygen.h:141
virtual void incrementFlowKeyWordCount()=0
#define YY_FTN_REJECT
Definition fortrancode.l:89
MemberDefMutable * toMemberDefMutable(Definition *d)
311<Start>{BS}(RANK){BS_}(DEFAULT) |
312<Start>{BS}(RANK)/{BS}"("{BS}([0-9]+|"*"){BS}")" |
313<Start>{BS}(CASE|CLASS|TYPE){BS_}(IS|DEFAULT) {
314 startFontClass(yyscanner,"keywordflow");
315 codifyLines(yyscanner,yytext);
316 endFontClass(yyscanner);
317 }
318<Start>{BS}"end"({BS}{FLOW})/[ \t\n] { // list is a bit long as not all have possible end
319 startFontClass(yyscanner,"keywordflow");
320 codifyLines(yyscanner,yytext);
321 endFontClass(yyscanner);
322 }
323<Start>"implicit"{BS}("none"|{TYPE_SPEC}) {
324 startFontClass(yyscanner,"keywordtype");
325 codifyLines(yyscanner,yytext);
326 endFontClass(yyscanner);
327 }
328<Start>^{BS}"namelist"/[/] { // Namelist specification
329 startFontClass(yyscanner,"keywordtype");
330 codifyLines(yyscanner,yytext);
331 endFontClass(yyscanner);
332 }
333 /*-------- use statement -------------------------------------------*/
334<Start>"use"{BS_} {
335 startFontClass(yyscanner,"keywordtype");
336 codifyLines(yyscanner,yytext);
337 endFontClass(yyscanner);
338 yy_push_state(YY_START,yyscanner);
339 BEGIN(Use);
340 }
341<Use>"ONLY" { // TODO: rename
342 startFontClass(yyscanner,"keywordtype");
343 codifyLines(yyscanner,yytext);
344 endFontClass(yyscanner);
345 yy_push_state(YY_START,yyscanner);
346 BEGIN(UseOnly);
347 }
348<Use>{ID} {
349 QCString tmp(yytext);
350 tmp = tmp.lower();
351 yyextra->insideBody=TRUE;
352 generateLink(yyscanner,*yyextra->code, yytext);
353 yyextra->insideBody=FALSE;
354
355 /* append module name to use dict */
356 yyextra->useEntry = UseEntry();
357 yyextra->useEntry.module = tmp;
358 yyextra->useMembers.emplace(tmp.str(), yyextra->useEntry);
359 addUse(yyscanner,tmp);
360 }
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
361<Use,UseOnly,Import>{BS},{BS} { codifyLines(yyscanner,yytext); }
362<UseOnly,Import>{BS}&{BS}"\n" { codifyLines(yyscanner,yytext);
363 yyextra->contLineNr++;
#define YY_FTN_RESET
Definition fortrancode.l:88
365<UseOnly>{ID} {
366 QCString tmp(yytext);
367 tmp = tmp.lower();
368 yyextra->useEntry.onlyNames.push_back(tmp);
369 yyextra->insideBody=TRUE;
370 generateLink(yyscanner,*yyextra->code, yytext);
371 yyextra->insideBody=FALSE;
372 }
373<Use,UseOnly,Import>"\n" {
374 unput(*yytext);
375 pop_state(yyscanner);
377 }
378<*>"import"{BS}/"\n" |
379<*>"import"{BS_} {
380 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
381 startFontClass(yyscanner,"keywordtype");
382 codifyLines(yyscanner,yytext);
383 endFontClass(yyscanner);
384 yy_push_state(YY_START,yyscanner);
385 BEGIN(Import);
386 }
387<Import>{ID} {
388 yyextra->insideBody=TRUE;
389 generateLink(yyscanner,*yyextra->code, yytext);
390 yyextra->insideBody=FALSE;
391 }
392<Import>("ONLY"|"NONE"|"ALL") {
393 startFontClass(yyscanner,"keywordtype");
394 codifyLines(yyscanner,yytext);
395 endFontClass(yyscanner);
396 }
397 /*-------- fortran module -----------------------------------------*/
398<Start>("block"{BS}"data"|"program"|"module"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { //
399 startScope(yyscanner);
400 startFontClass(yyscanner,"keyword");
401 codifyLines(yyscanner,yytext);
402 endFontClass(yyscanner);
403 yy_push_state(YY_START,yyscanner);
404 BEGIN(ClassName);
405 if (!qstricmp(yytext,"module")) yyextra->currentModule="module";
406 }
int qstricmp(const char *s1, const char *s2)
Definition qcstring.cpp:447
407<Start>("enum")/{BS_}|{BS}{COMMA}{BS}{LANGUAGE_BIND_SPEC}|\n { //
408 startScope(yyscanner);
409 startFontClass(yyscanner,"keyword");
410 codifyLines(yyscanner,yytext);
411 endFontClass(yyscanner);
412 yy_push_state(YY_START,yyscanner);
413 BEGIN(ClassName);
414 }
415<*>{LANGUAGE_BIND_SPEC} { //
416 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
417 startFontClass(yyscanner,"keyword");
418 codifyLines(yyscanner,yytext);
419 endFontClass(yyscanner);
420 }
421<Start>("type")/{BS_}|({COMMA}({ACCESS_SPEC}|ABSTRACT|EXTENDS))|\n { //
422 startScope(yyscanner);
423 startFontClass(yyscanner,"keyword");
424 codifyLines(yyscanner,yytext);
425 endFontClass(yyscanner);
426 yy_push_state(YY_START,yyscanner);
427 BEGIN(ClassName);
428 }
429<ClassName>{ID} {
430 if (yyextra->currentModule == "module")
431 {
432 yyextra->currentModule=yytext;
433 yyextra->currentModule = yyextra->currentModule.lower();
434 }
435 generateLink(yyscanner,*yyextra->code,yytext);
436 pop_state(yyscanner);
437 }
438<ClassName>({ACCESS_SPEC}|ABSTRACT|EXTENDS)/[,:( ] { //| variable declaration
439 startFontClass(yyscanner,"keyword");
440 yyextra->code->codify(yytext);
441 endFontClass(yyscanner);
442 }
443<ClassName>\n { // interface may be without name
444 pop_state(yyscanner);
446 }
447<Start>^{BS}"end"({BS_}"enum").* {
449 }
450<Start>^{BS}"end"({BS_}"type").* {
452 }
453<Start>^{BS}"end"({BS_}"module").* { // just reset yyextra->currentModule, rest is done in following rule
454 yyextra->currentModule=nullptr;
456 }
457 /*-------- subprog definition -------------------------------------*/
458<Start>({PREFIX}{BS_})?{TYPE_SPEC}{BS_}({PREFIX}{BS_})?{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result
459 startFontClass(yyscanner,"keyword");
460 codifyLines(yyscanner,yytext);
461 endFontClass(yyscanner);
462 }
463<Start>({PREFIX}{BS_})?{SUBPROG}{BS_} { // Fortran subroutine or function found
464 startFontClass(yyscanner,"keyword");
465 codifyLines(yyscanner,yytext);
466 endFontClass(yyscanner);
467 yy_push_state(YY_START,yyscanner);
468 BEGIN(Subprog);
469 }
470<Subprog>{ID} { // subroutine/function name
471 DBG_CTX((stderr, "===> start subprogram %s\n", yytext));
472 startScope(yyscanner);
473 generateLink(yyscanner,*yyextra->code,yytext);
474 }
#define DBG_CTX(x)
Definition code.l:73
475<Subprog>"result"/{BS}"("[^)]*")" {
476 startFontClass(yyscanner,"keyword");
477 codifyLines(yyscanner,yytext);
478 endFontClass(yyscanner);
479 }
480<Subprog>"("[^)]*")" { // ignore rest of line
481 codifyLines(yyscanner,yytext);
482 }
483<Subprog,Subprogend>"\n" { codifyLines(yyscanner,yytext);
484 yyextra->contLineNr++;
485 pop_state(yyscanner);
487 }
488<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface")?{BS} { // Fortran subroutine or function ends
489 //cout << "===> end function " << yytext << endl;
490 endScope(yyscanner);
491 startFontClass(yyscanner,"keyword");
492 codifyLines(yyscanner,yytext);
493 endFontClass(yyscanner);
494 yy_push_state(YY_START,yyscanner);
495 BEGIN(Subprogend);
496 }
497<Subprogend>{ID}/{BS}(\n|!|;) {
498 generateLink(yyscanner,*yyextra->code,yytext);
499 pop_state(yyscanner);
500 }
501<Start>"end"{BS}("block"{BS}"data"|{SUBPROG}|"module"|"program"|"enum"|"type"|"interface"){BS}/(\n|!|;) { // Fortran subroutine or function ends
502 //cout << "===> end function " << yytext << endl;
503 endScope(yyscanner);
504 startFontClass(yyscanner,"keyword");
505 codifyLines(yyscanner,yytext);
506 endFontClass(yyscanner);
507 }
508 /*-------- variable declaration ----------------------------------*/
509<Start>^{BS}"real"/[,:( ] { // real is a bit tricky as it is a data type but also a function.
510 yy_push_state(YY_START,yyscanner);
511 BEGIN(Declaration);
512 startFontClass(yyscanner,"keywordtype");
513 yyextra->code->codify(yytext);
514 endFontClass(yyscanner);
515 }
516<Start>{TYPE_SPEC}/[,:( ] {
517 QCString typ(yytext);
518 typ = removeRedundantWhiteSpace(typ.lower());
519 if (typ.startsWith("real")) YY_FTN_REJECT;
520 if (typ == "type" || typ == "class" || typ == "procedure") yyextra->inTypeDecl = 1;
521 yy_push_state(YY_START,yyscanner);
522 BEGIN(Declaration);
523 startFontClass(yyscanner,"keywordtype");
524 yyextra->code->codify(yytext);
525 endFontClass(yyscanner);
526 }
QCString removeRedundantWhiteSpace(const QCString &s)
Definition util.cpp:579
527<Start>{ATTR_SPEC} {
528 if (QCString(yytext) == "external")
529 {
530 yy_push_state(YY_START,yyscanner);
531 BEGIN(Declaration);
532 yyextra->isExternal = true;
533 }
534 startFontClass(yyscanner,"keywordtype");
535 yyextra->code->codify(yytext);
536 endFontClass(yyscanner);
537 }
538<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration
539 if (QCString(yytext) == "external") yyextra->isExternal = true;
540 startFontClass(yyscanner,"keywordtype");
541 yyextra->code->codify(yytext);
542 endFontClass(yyscanner);
543 }
544<Declaration>{ID} { // local var
545 if (yyextra->isFixedForm && yy_my_start == 1)
546 {
547 startFontClass(yyscanner,"comment");
548 yyextra->code->codify(yytext);
549 endFontClass(yyscanner);
550 }
551 else if (yyextra->currentMemberDef &&
552 ((yyextra->currentMemberDef->isFunction() && (yyextra->currentMemberDef->typeString()!=QCString("subroutine") || yyextra->inTypeDecl)) ||
553 yyextra->currentMemberDef->isVariable() || yyextra->currentMemberDef->isEnumValue()
554 )
555 )
556 {
557 generateLink(yyscanner,*yyextra->code, yytext);
558 }
559 else
560 {
561 yyextra->code->codify(yytext);
562 addLocalVar(yyscanner,yytext);
563 }
564 }
565<Declaration>{BS}("=>"|"="){BS} { // Procedure binding
566 BEGIN(DeclarationBinding);
567 yyextra->code->codify(yytext);
568 }
569<DeclarationBinding>{ID} { // Type bound procedure link
570 generateLink(yyscanner,*yyextra->code, yytext);
571 pop_state(yyscanner);
572 }
573<Declaration>[(] { // start of array or type / class specification
574 yyextra->bracketCount++;
575 yyextra->code->codify(yytext);
576 }
577
578<Declaration>[)] { // end array specification
579 yyextra->bracketCount--;
580 if (!yyextra->bracketCount) yyextra->inTypeDecl = 0;
581 yyextra->code->codify(yytext);
582 }
583
584<Declaration,DeclarationBinding>"&" { // continuation line
585 yyextra->code->codify(yytext);
586 if (!yyextra->isFixedForm)
587 {
588 yy_push_state(YY_START,yyscanner);
589 BEGIN(DeclContLine);
590 }
591 }
592<DeclContLine>"\n" { // declaration not yet finished
593 yyextra->contLineNr++;
594 codifyLines(yyscanner,yytext);
595 yyextra->bracketCount = 0;
596 pop_state(yyscanner);
598 }
599<Declaration,DeclarationBinding>"\n" { // end declaration line (?)
600 if (yyextra->endComment)
601 {
602 yyextra->endComment=FALSE;
603 }
604 else
605 {
606 codifyLines(yyscanner,yytext);
607 }
608 yyextra->bracketCount = 0;
609 yyextra->contLineNr++;
610 if (!(yyextra->hasContLine && yyextra->hasContLine[yyextra->contLineNr - 1]))
611 {
612 yyextra->isExternal = false;
613 pop_state(yyscanner);
614 }
616 }
617
618 /*-------- subprog calls -----------------------------------------*/
619
620<Start>"call"{BS_} {
621 startFontClass(yyscanner,"keyword");
622 codifyLines(yyscanner,yytext);
623 endFontClass(yyscanner);
624 yy_push_state(YY_START,yyscanner);
625 BEGIN(SubCall);
626 }
627<SubCall>{ID} { // subroutine call
628 yyextra->insideBody=TRUE;
629 generateLink(yyscanner,*yyextra->code, yytext);
630 yyextra->insideBody=FALSE;
631 pop_state(yyscanner);
632 }
633<Start>{ID}{BS}/"(" { // function call
634 if (yyextra->isFixedForm && yy_my_start == 6)
635 {
636 // fixed form continuation line
638 }
639 else if (QCString(yytext).stripWhiteSpace().lower() == "type")
640 {
641 yy_push_state(YY_START,yyscanner);
642 BEGIN(Declaration);
643 startFontClass(yyscanner,"keywordtype");
644 yyextra->code->codify(QCString(yytext).stripWhiteSpace());
645 endFontClass(yyscanner);
646 yyextra->code->codify(QCString(yytext + 4));
647 }
648 else
649 {
650 yyextra->insideBody=TRUE;
651 generateLink(yyscanner,*yyextra->code,yytext);
652 yyextra->insideBody=FALSE;
653 }
654 }
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
655
656 /*-------- comments ---------------------------------------------------*/
657<Start,Declaration,DeclarationBinding>\n?{BS}"!>"|"!<" { // start comment line or comment block
658 if (yytext[0] == '\n')
659 {
660 yyextra->contLineNr++;
661 yy_old_start = 0;
662 yy_my_start = 1;
663 yy_end = static_cast<int>(yyleng);
664 }
665 // Actually we should see if ! on position 6, can be continuation
666 // but the chance is very unlikely, so no effort to solve it here
667 yy_push_state(YY_START,yyscanner);
668 BEGIN(DocBlock);
669 yyextra->docBlock=yytext;
670 }
671<Declaration,DeclarationBinding>{BS}"!<" { // start comment line or comment block
672 yy_push_state(YY_START,yyscanner);
673 BEGIN(DocBlock);
674 yyextra->docBlock=yytext;
675 }
676
677<DocBlock>.* { // contents of current comment line
678 yyextra->docBlock+=yytext;
679 }
680<DocBlock>"\n"{BS}("!>"|"!<"|"!!") { // comment block (next line is also comment line)
681 yyextra->contLineNr++;
682 yy_old_start = 0;
683 yy_my_start = 1;
684 yy_end = static_cast<int>(yyleng);
685 // Actually we should see if ! on position 6, can be continuation
686 // but the chance is very unlikely, so no effort to solve it here
687 yyextra->docBlock+=yytext;
688 }
689<DocBlock>"\n" { // comment block ends at the end of this line
690 // remove special comment (default config)
691 yyextra->contLineNr++;
692 startFontClass(yyscanner,"comment");
693 codifyLines(yyscanner,yyextra->docBlock);
694 endFontClass(yyscanner);
695 unput(*yytext);
696 yyextra->contLineNr--;
697 pop_state(yyscanner);
699 }
700
701<*>"!"[^><\n].*|"!"$ { // normal comment
702 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
703 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
704 startFontClass(yyscanner,"comment");
705 codifyLines(yyscanner,yytext);
706 endFontClass(yyscanner);
707 }
708
709<*>^[Cc*].* { // normal comment
710 if(! yyextra->isFixedForm) YY_FTN_REJECT;
711
712 startFontClass(yyscanner,"comment");
713 codifyLines(yyscanner,yytext);
714 endFontClass(yyscanner);
715 }
716<*>"assignment"/{BS}"("{BS}"="{BS}")" {
717 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
718 startFontClass(yyscanner,"keyword");
719 codifyLines(yyscanner,yytext);
720 endFontClass(yyscanner);
721 }
722<*>"operator"/{BS}"("[^)]*")" {
723 if(YY_START == String) YY_FTN_REJECT; // ignore in strings
724 startFontClass(yyscanner,"keyword");
725 codifyLines(yyscanner,yytext);
726 endFontClass(yyscanner);
727 }
728
729 /*------ preprocessor --------------------------------------------*/
730<Start>"#".*\n {
731 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
732 yyextra->contLineNr++;
733 startFontClass(yyscanner,"preprocessor");
734 codifyLines(yyscanner,yytext);
735 endFontClass(yyscanner);
737 }
738 /*------ variable references? -------------------------------------*/
739
740<Start>"%"{BS}{ID} { // ignore references to elements
741 yyextra->code->codify(yytext);
742 }
743<Start>{ID} {
744 yyextra->insideBody=TRUE;
745 generateLink(yyscanner,*yyextra->code, yytext);
746 yyextra->insideBody=FALSE;
747 }
748 /*------ strings --------------------------------------------------*/
749<String>\n { // string with \n inside
750 yyextra->contLineNr++;
751 yyextra->str+=yytext;
752 startFontClass(yyscanner,"stringliteral");
753 codifyLines(yyscanner,yyextra->str);
754 endFontClass(yyscanner);
755 yyextra->str = "";
757 }
758<String>\"|\' { // string ends with next quote without previous backspace
759 if(yytext[0]!=yyextra->stringStartSymbol) YY_FTN_REJECT; // single vs double quote
760 yyextra->str+=yytext;
761 startFontClass(yyscanner,"stringliteral");
762 codifyLines(yyscanner,yyextra->str);
763 endFontClass(yyscanner);
764 pop_state(yyscanner);
765 }
766<String>[\x80-\xFF]* |
767<String>. {yyextra->str+=yytext;}
768
769<*>\"|\' { /* string starts */
770 /* if(YY_START == StrIgnore) YY_FTN_REJECT; // ignore in simple comments */
771 if (yyextra->isFixedForm && yy_my_start == 6) YY_FTN_REJECT;
772 yy_push_state(YY_START,yyscanner);
773 yyextra->stringStartSymbol=yytext[0]; // single or double quote
774 BEGIN(String);
775 yyextra->str=yytext;
776 }
777 /*-----------------------------------------------------------------------------*/
778
779<*>\n {
780 if (yyextra->endComment)
781 {
782 yyextra->endComment=FALSE;
783 }
784 else
785 {
786 codifyLines(yyscanner,yytext);
787 // comment cannot extend over the end of a line so should always be terminated at the end of the line.
788 if (yyextra->currentFontClass && !strcmp(yyextra->currentFontClass,"comment")) endFontClass(yyscanner);
789 }
790 yyextra->contLineNr++;
792 }
793<*>^{BS}"type"{BS}"=" { yyextra->code->codify(yytext); }
794
795<*>[\x80-\xFF]* { // keep utf8 characters together...
796 if (yyextra->isFixedForm && yy_my_start > yyextra->fixedCommentAfter)
797 {
798 startFontClass(yyscanner,"comment");
799 codifyLines(yyscanner,yytext);
800 }
801 else
802 {
803 yyextra->code->codify(yytext);
804 }
805 }
806<*>. {
807 if (yyextra->isFixedForm && yy_my_start > yyextra->fixedCommentAfter)
808 {
809 //yy_push_state(YY_START,yyscanner);
810 //BEGIN(DocBlock);
811 //yyextra->docBlock=yytext;
812 startFontClass(yyscanner,"comment");
813 codifyLines(yyscanner,yytext);
814 }
815 else
816 {
817 yyextra->code->codify(yytext);
818 }
819 }
820<*>{LOG_OPER} { // Fortran logical comparison keywords
821 yyextra->code->codify(yytext);
822 }
823<*><<EOF>> {
824 if (YY_START == DocBlock)
825 {
826 startFontClass(yyscanner,"comment");
827 codifyLines(yyscanner,yyextra->docBlock);
828 endFontClass(yyscanner);
829 }
830 yyterminate();
831 }
#define yyterminate()
832%%
833
834/*@ ----------------------------------------------------------------------------
835 */
836
837static int yyread(yyscan_t yyscanner,char *buf,int max_size)
838{
839 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
840 int inputPosition = yyextra->inputPosition;
841 const char *s = yyextra->inputString + inputPosition;
842 int c=0;
843 while( c < max_size && *s)
844 {
845 *buf++ = *s++;
846 c++;
847 }
848 yyextra->inputPosition += c;
849 return c;
850}
851
852static void endFontClass(yyscan_t yyscanner,bool specialComment)
853{
854 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
855 if (yyextra->currentFontClass)
856 {
857 yyextra->code->endFontClass();
858 yyextra->currentFontClass=nullptr;
859 }
860 if (specialComment && yyextra->insideSpecialComment)
861 {
862 yyextra->code->endSpecialComment();
863 yyextra->insideSpecialComment=false;
864 }
865}
866
867static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment)
868{
869 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
870 if (specialComment)
871 {
872 yyextra->code->startSpecialComment();
873 yyextra->insideSpecialComment = true;
874 }
875 // if font class is already set don't stop and start it.
876 if (qstrcmp(yyextra->currentFontClass,s)!=0)
877 {
878 endFontClass(yyscanner);
879 yyextra->code->startFontClass(s);
880 yyextra->currentFontClass=s;
881 }
882}
883
884static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
885{
886 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
887 if (Doxygen::searchIndex.enabled())
888 {
889 if (yyextra->searchCtx)
890 {
891 Doxygen::searchIndex.setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
892 }
893 else
894 {
895 Doxygen::searchIndex.setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
896 }
897 }
898}
899
900static void addToSearchIndex(yyscan_t /*yyscanner*/,const QCString &text)
901{
902 if (Doxygen::searchIndex.enabled())
903 {
904 Doxygen::searchIndex.addWord(text,FALSE);
905 }
906}
907
908static void codeFolding(yyscan_t yyscanner,const Definition *d)
909{
910 if (Config_getBool(HTML_CODE_FOLDING))
911 {
912 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
913 while (!yyextra->foldStack.empty())
914 {
915 const Definition *dd = yyextra->foldStack.back();
916 if (dd->getEndBodyLine()+1==yyextra->yyLineNr) // +1 to close the section after the end of the body
917 {
918 yyextra->code->endFold();
919 //printf("%d: end codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(dd->name()),dd->getStartDefLine(),dd->getEndBodyLine());
920 yyextra->foldStack.pop_back();
921 }
922 else
923 {
924 break;
925 }
926 }
927 if (d)
928 {
929 int startLine = d->getStartDefLine();
930 int endLine = d->getEndBodyLine();
931 if (endLine!=-1 && startLine!=endLine &&
932 // since the end of a section is closed after the last line, we need to avoid starting a
933 // new section if the previous section ends at the same line, i.e. something like
934 // struct X {
935 // ...
936 // }; struct S { <- start of S and end of X at the same line
937 // ...
938 // };
939 (yyextra->foldStack.empty() || yyextra->foldStack.back()->getEndBodyLine()!=startLine))
940 {
941 //printf("%d: start codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(d->name()),d->getStartDefLine(),d->getEndBodyLine());
942 yyextra->code->startFold(yyextra->yyLineNr,"","");
943 yyextra->foldStack.push_back(d);
944 }
945 }
946 }
947}
948
949/*! start a new line of code, inserting a line number if yyextra->sourceFileDef
950 * is TRUE. If a definition starts at the current line, then the line
951 * number is linked to the documentation of that definition.
952 */
953static void startCodeLine(yyscan_t yyscanner)
954{
955 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
956 if (yyextra->sourceFileDef)
957 {
958 //QCString lineNumber,lineAnchor;
959 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
960 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
961
962 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
963 //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,d ? qPrint(d->name()) : "<null>");
964 if (!yyextra->includeCodeFragment && d)
965 {
966 yyextra->currentDefinition = d;
967 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
968 yyextra->insideBody = FALSE;
969 yyextra->endComment = FALSE;
970 QCString lineAnchor;
971 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
972 if (yyextra->currentMemberDef)
973 {
974 codeFolding(yyscanner,yyextra->currentMemberDef);
975 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
976 yyextra->currentMemberDef->getOutputFileBase(),
977 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
978 !yyextra->includeCodeFragment);
979 setCurrentDoc(yyscanner,lineAnchor);
980 }
981 else if (d->isLinkableInProject())
982 {
983 codeFolding(yyscanner,d);
984 yyextra->code->writeLineNumber(d->getReference(),
986 QCString(),yyextra->yyLineNr,
987 !yyextra->includeCodeFragment);
988 setCurrentDoc(yyscanner,lineAnchor);
989 }
990 else
991 {
992 codeFolding(yyscanner,nullptr);
993 }
994 }
995 else
996 {
997 codeFolding(yyscanner,nullptr);
998 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
999 !yyextra->includeCodeFragment);
1000 }
1001 }
1002 yyextra->code->startCodeLine(yyextra->yyLineNr);
1003 yyextra->insideCodeLine=true;
1004 if (yyextra->currentFontClass)
1005 {
1006 yyextra->code->startFontClass(yyextra->currentFontClass);
1007 }
1008}
1009
1010
1011static void endCodeLine(yyscan_t yyscanner)
1012{
1013 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1014 endFontClass(yyscanner);
1015 yyextra->code->endCodeLine();
1016 yyextra->insideCodeLine=false;
1017}
1018
1019static void nextCodeLine(yyscan_t yyscanner)
1020{
1021 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1022 const char * fc = yyextra->currentFontClass;
1023 endCodeLine(yyscanner);
1024 if (yyextra->yyLineNr<yyextra->inputLines)
1025 {
1026 yyextra->currentFontClass = fc;
1027 startCodeLine(yyscanner);
1028 }
1029}
1030
1031/*! write a code fragment 'text' that may span multiple lines, inserting
1032 * line numbers for each line.
1033 */
1034static void codifyLines(yyscan_t yyscanner,const QCString &text)
1035{
1036 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1037 //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text);
1038 if (text.isEmpty()) return;
1039 const char *p=text.data(),*sp=p;
1040 char c = 0;
1041 bool done=FALSE;
1042 while (!done)
1043 {
1044 sp=p;
1045 while ((c=*p++) && c!='\n') { }
1046 if (c=='\n')
1047 {
1048 yyextra->yyLineNr++;
1049 size_t l = static_cast<size_t>(p-sp-1);
1050 yyextra->code->codify(QCString(sp,l));
1051 nextCodeLine(yyscanner);
1052 }
1053 else
1054 {
1055 yyextra->code->codify(sp);
1056 done=TRUE;
1057 }
1058 }
1059}
1060
1061/*! writes a link to a fragment \a text that may span multiple lines, inserting
1062 * line numbers for each line. If \a text contains newlines, the link will be
1063 * split into multiple links with the same destination, one for each line.
1064 */
1066 Definition *d,const QCString &text)
1067{
1068 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1069 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1070 yyextra->tooltipManager.addTooltip(d);
1071 QCString ref = d->getReference();
1072 QCString file = d->getOutputFileBase();
1073 QCString anchor = d->anchor();
1074 QCString tooltip;
1075 if (!sourceTooltips) // fall back to simple "title" tooltips
1076 {
1077 tooltip = d->briefDescriptionAsTooltip();
1078 }
1079 bool done=FALSE;
1080 const char *p=text.data();
1081 while (!done)
1082 {
1083 const char *sp=p;
1084 char c = 0;
1085 while ((c=*p++) && c!='\n') { }
1086 if (c=='\n')
1087 {
1088 yyextra->yyLineNr++;
1089 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1090 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1091 nextCodeLine(yyscanner);
1092 }
1093 else
1094 {
1095 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1096 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1097 done=TRUE;
1098 }
1099 }
1100}
1101//-------------------------------------------------------------------------------
1102/**
1103 searches for definition of a module (Namespace)
1104 @param mname the name of the module
1105 @param cd the entry, if found or null
1106 @returns true, if module is found
1107*/
1108static bool getFortranNamespaceDefs(const QCString &mname,
1109 NamespaceDef *&cd)
1110{
1111 if (mname.isEmpty()) return FALSE; /* empty name => nothing to link */
1112
1113 // search for module
1114 if ((cd=Doxygen::namespaceLinkedMap->find(mname))) return TRUE;
1115
1116 return FALSE;
1117}
1118//-------------------------------------------------------------------------------
1119/**
1120 searches for definition of a type
1121 @param tname the name of the type
1122 @param moduleName name of enclosing module or null, if global entry
1123 @param cd the entry, if found or null
1124 @param useMap map of data of USE-statement
1125 @returns true, if type is found
1126*/
1127static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName,
1128 ClassDef *&cd, const UseMap &useMap)
1129{
1130 if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */
1131
1132 //cout << "=== search for type: " << tname << endl;
1133
1134 // search for type
1135 if ((cd=Doxygen::classLinkedMap->find(tname)))
1136 {
1137 //cout << "=== type found in global module" << endl;
1138 return TRUE;
1139 }
1140 else if (!moduleName.isEmpty() && (cd=Doxygen::classLinkedMap->find(moduleName+"::"+tname)))
1141 {
1142 //cout << "=== type found in local module" << endl;
1143 return TRUE;
1144 }
1145 else
1146 {
1147 for (const auto &[name,useEntry] : useMap)
1148 {
1149 if ((cd=Doxygen::classLinkedMap->find(useEntry.module+"::"+tname)))
1150 {
1151 //cout << "=== type found in used module" << endl;
1152 return TRUE;
1153 }
1154 }
1155 }
1156
1157 return FALSE;
1158}
1159
1160/**
1161 searches for definition of function memberName
1162 @param yyscanner the scanner data to be used
1163 @param memberName the name of the function/variable
1164 @param moduleName name of enclosing module or null, if global entry
1165 @param useMap map of data of USE-statement
1166 @returns MemberDef pointer, if found, or nullptr otherwise
1167*/
1168static MemberDef *getFortranDefs(yyscan_t yyscanner,const QCString &memberName, const QCString &moduleName,
1169 const UseMap &useMap)
1170{
1171 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1172 MemberDef *potentialMd = nullptr;
1173 if (memberName.isEmpty()) return nullptr; /* empty name => nothing to link */
1174
1175 // look in local variables
1176 for (auto it = yyextra->scopeStack.rbegin(); it!=yyextra->scopeStack.rend(); ++it)
1177 {
1178 const Scope &scope = *it;
1179 std::string lowMemName = memberName.lower().str();
1180 if (scope.localVars .find(lowMemName)!=std::end(scope.localVars) && // local var
1181 scope.externalVars.find(lowMemName)==std::end(scope.externalVars)) // and not external
1182 {
1183 return nullptr;
1184 }
1185 }
1186
1187 // search for function
1188 MemberName *mn = Doxygen::functionNameLinkedMap->find(memberName);
1189 if (!mn)
1190 {
1191 mn = Doxygen::memberNameLinkedMap->find(memberName);
1192 }
1193
1194 if (mn) // name is known
1195 {
1196 // all found functions with given name
1197 for (const auto &md : *mn)
1198 {
1199 const FileDef *fd=md->getFileDef();
1200 const GroupDef *gd=md->getGroupDef();
1201 const ClassDef *cd=md->getClassDef();
1202
1203 //cout << "found link with same name: " << fd->fileName() << " " << memberName;
1204 //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl;
1205
1206 if ((gd && gd->isLinkable()) || (fd && fd->isLinkable()))
1207 {
1208 const NamespaceDef *nspace= md->getNamespaceDef();
1209
1210 if (nspace == nullptr)
1211 { // found function in global scope
1212 if (cd == nullptr)
1213 { // Skip if bound to type
1214 if (md.get()->getFileDef() == yyextra->sourceFileDef) return md.get();
1215 else if (!potentialMd) potentialMd = 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 potentialMd;
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
1341/*! counts the number of lines in the input */
1342static int countLines(yyscan_t yyscanner)
1343{
1344 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1345 const char *p=yyextra->inputString;
1346 char c = 0;
1347 int count=1;
1348 while ((c=*p))
1349 {
1350 p++ ;
1351 if (c=='\n') count++;
1352 }
1353 if (p>yyextra->inputString && *(p-1)!='\n')
1354 { // last line does not end with a \n, so we add an extra
1355 // line and explicitly terminate the line after parsing.
1356 count++;
1357 }
1358 return count;
1359}
1360
1361//----------------------------------------------------------------------------
1362/** start scope */
1363static void startScope(yyscan_t yyscanner)
1364{
1365 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1366 DBG_CTX((stderr, "===> startScope %s",yytext));
1367 yyextra->scopeStack.emplace_back();
1368}
1369
1370/** end scope */
1371static void endScope(yyscan_t yyscanner)
1372{
1373 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1374 DBG_CTX((stderr,"===> endScope %s",yytext));
1375 if (yyextra->scopeStack.empty())
1376 {
1377 DBG_CTX((stderr,"WARNING: fortrancode.l: stack empty!\n"));
1378 return;
1379 }
1380
1381 Scope &scope = yyextra->scopeStack.back();
1382 for ( const auto &name : scope.useNames)
1383 {
1384 yyextra->useMembers.erase(name.str());
1385 }
1386 yyextra->scopeStack.pop_back();
1387}
1388
1389static void addUse(yyscan_t yyscanner,const QCString &moduleName)
1390{
1391 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1392 if (!yyextra->scopeStack.empty())
1393 yyextra->scopeStack.back().useNames.push_back(moduleName);
1394}
1395
1396static void addLocalVar(yyscan_t yyscanner,const QCString &varName)
1397{
1398 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1399 if (!yyextra->scopeStack.empty())
1400 {
1401 std::string lowVarName = varName.lower().str();
1402 yyextra->scopeStack.back().localVars.insert(lowVarName);
1403 if (yyextra->isExternal) yyextra->scopeStack.back().externalVars.insert(lowVarName);
1404 }
1405}
1406
1407/*===================================================================*/
1408
1409
1410static void checkContLines(yyscan_t yyscanner,const char *s)
1411{
1412 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1413 int numLines = 0;
1414 int i = 0;
1415 const char *p = s;
1416
1417 numLines = 2; // one for element 0, one in case no \n at end
1418 while (*p)
1419 {
1420 if (*p == '\n') numLines++;
1421 p++;
1422 }
1423
1424 yyextra->hasContLine = (int *) malloc((numLines) * sizeof(int));
1425 for (i = 0; i < numLines; i++)
1426 {
1427 yyextra->hasContLine[i] = 0;
1428 }
1429 p = prepassFixedForm(s, yyextra->hasContLine,yyextra->fixedCommentAfter);
1430 yyextra->hasContLine[0] = 0;
1431}
1432
1433void parseFortranCode(OutputCodeList &,const char *,const QCString &,
1434 bool , const char *,const FileDef *,
1435 int ,int ,bool ,
1436 const MemberDef *,bool,const Definition *,
1437 bool , FortranFormat )
1438{
1439 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1440
1441 return;
1442}
1443
1444//---------------------------------------------------------
1445
1452
1454{
1455 p->format = format;
1456 fortrancodeYYlex_init_extra(&p->state,&p->yyscanner);
1457#ifdef FLEX_DEBUG
1458 fortrancodeYYset_debug(Debug::isFlagSet(Debug::Lex_fortrancode)?1:0,p->yyscanner);
1459#endif
1461}
1462
1464{
1465 fortrancodeYYlex_destroy(p->yyscanner);
1466}
1467
1469{
1470 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1471 yyextra->currentDefinition = nullptr;
1472 yyextra->currentMemberDef = nullptr;
1473 yyextra->currentFontClass = nullptr;
1474 yyextra->insideCodeLine = FALSE;
1475 BEGIN( Start );
1476}
1477
1479 const QCString & /* scopeName */,
1480 const QCString & input,
1481 SrcLangExt /*lang*/,
1482 bool stripCodeComments,
1483 bool isExampleBlock,
1484 const QCString & exampleName,
1485 const FileDef * fileDef,
1486 int startLine,
1487 int endLine,
1488 bool inlineFragment,
1489 const MemberDef * /* memberDef */,
1490 bool /* showLineNumbers */,
1491 const Definition *searchCtx,
1492 bool collectXRefs
1493 )
1494{
1495 yyscan_t yyscanner = p->yyscanner;
1496 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1497 //::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
1498 // fileDef,startLine,endLine,inlineFragment,memberDef,
1499 // showLineNumbers,searchCtx,collectXRefs,m_format);
1500 // parseFortranCode(OutputCodeList &od,const char *,const QCString &s,
1501 // bool exBlock, const char *exName,FileDef *fd,
1502 // int startLine,int endLine,bool inlineFragment,
1503 // const MemberDef *,bool,const Definition *searchCtx,
1504 // bool collectXRefs, FortranFormat format)
1505 if (input.isEmpty()) return;
1506 DebugLex debugLex(Debug::Lex_fortrancode, __FILE__, fileDef ? qPrint(fileDef->fileName()): nullptr);
1507 codeOutIntf.stripCodeComments(stripCodeComments);
1508 yyextra->code = &codeOutIntf;
1509 yyextra->inputString = input.data();
1510 yyextra->inputPosition = 0;
1511 yyextra->fileName = fileDef ? fileDef->fileName():"";
1512 yyextra->isFixedForm = recognizeFixedForm(input,p->format);
1513 yyextra->contLineNr = 1;
1514 yyextra->hasContLine = nullptr;
1515 if (yyextra->isFixedForm)
1516 {
1517 checkContLines(yyscanner,yyextra->inputString);
1518 yyextra->fixedCommentAfter = Config_getInt(FORTRAN_COMMENT_AFTER);
1519 }
1520 yyextra->currentFontClass = nullptr;
1521 yyextra->insideCodeLine = FALSE;
1522 yyextra->searchCtx = searchCtx;
1523 yyextra->collectXRefs = collectXRefs;
1524 if (startLine!=-1)
1525 yyextra->yyLineNr = startLine;
1526 else
1527 yyextra->yyLineNr = 1;
1528
1529 if (endLine!=-1)
1530 yyextra->inputLines = endLine+1;
1531 else
1532 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1533
1534 yyextra->exampleBlock = isExampleBlock;
1535 yyextra->exampleName = exampleName;
1536 yyextra->sourceFileDef = fileDef;
1537 yyextra->foldStack.clear();
1538 yyextra->insideSpecialComment = false;
1539 if (isExampleBlock && fileDef==nullptr)
1540 {
1541 // create a dummy filedef for the example
1542 yyextra->exampleFileDef = createFileDef(QCString(),exampleName);
1543 yyextra->sourceFileDef = yyextra->exampleFileDef.get();
1544 }
1545 if (yyextra->sourceFileDef)
1546 {
1547 setCurrentDoc(yyscanner,QCString("l00001"));
1548 }
1549 yyextra->currentDefinition = nullptr;
1550 yyextra->currentMemberDef = nullptr;
1551 if (!yyextra->exampleName.isEmpty())
1552 {
1553 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example");
1554 }
1555 yyextra->includeCodeFragment = inlineFragment;
1556 startCodeLine(yyscanner);
1557 fortrancodeYYrestart(nullptr, yyscanner);
1558 BEGIN( Start );
1559 fortrancodeYYlex(yyscanner);
1560 if (yyextra->insideCodeLine)
1561 {
1562 endCodeLine(yyscanner);
1563 }
1564 if (Config_getBool(HTML_CODE_FOLDING))
1565 {
1566 while (!yyextra->foldStack.empty())
1567 {
1568 yyextra->code->endFold();
1569 yyextra->foldStack.pop_back();
1570 }
1571 }
1572 if (!fileDef && isExampleBlock && yyextra->sourceFileDef)
1573 {
1574 // delete the temporary file definition used for this example
1575 yyextra->exampleFileDef.reset();
1576 yyextra->sourceFileDef=nullptr;
1577 }
1578 if (yyextra->hasContLine) free(yyextra->hasContLine);
1579 yyextra->hasContLine = nullptr;
1580
1581 // write the tooltips
1582 yyextra->tooltipManager.writeTooltips(codeOutIntf);
1583}
1584
1585static inline void pop_state(yyscan_t yyscanner)
1586{
1587 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1588 if ( yyg->yy_start_stack_ptr <= 0 )
1589 warn(yyextra->fileName,yyextra->yyLineNr,"Unexpected statement '{}'",yytext );
1590 else
1591 yy_pop_state(yyscanner);
1592}
1593//---------------------------------------------------------
1594
1595#include "fortrancode.l.h"
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e.
@ Lex_fortrancode
Definition debug.h:60
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
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: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:2550
static void endCodeLine(yyscan_t yyscanner)
Definition code.l:2478
static void nextCodeLine(yyscan_t yyscanner)
Definition code.l:2487
static void startCodeLine(yyscan_t yyscanner)
Definition code.l:2409
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3963
static int countLines(yyscan_t yyscanner)
Definition code.l:3454
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition code.l:2293
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString(), bool varOnly=FALSE)
Definition code.l:2882
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition code.l:2277
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2351
#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
fortrancodeYY_state state
SrcLangExt
Definition types.h:207
FortranFormat
Definition types.h:572
bool recognizeFixedForm(const QCString &contents, FortranFormat format)
Definition util.cpp:6860
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:4020