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