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