1 /******************************************************************************
2 *
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15 %option never-interactive
16 %option prefix="codeYY"
17 %option reentrant
18 %option extra-type="struct codeYY_state *"
19 %top{
20 #include <stdint.h>
21 // forward declare yyscan_t to improve type safety
22 #define YY_TYPEDEF_YY_SCANNER_T
23 struct yyguts_t;
24 typedef yyguts_t *yyscan_t;
25 }
26
27 %{
28
29 /*
30 * includes
31 */
32
33 #include <utility>
34 #include <memory>
35 #include <algorithm>
36 #include <unordered_map>
37 #include <unordered_set>
38 #include <stack>
39 #include <vector>
40 #include <string>
41 #include <mutex>
42 #include <sstream>
43
44 #include <stdio.h>
45 #include <assert.h>
46 #include <ctype.h>
47
48 #include "code.h"
49 #include "entry.h"
50 #include "doxygen.h"
51 #include "message.h"
52 #include "outputlist.h"
53 #include "util.h"
54 #include "membername.h"
55 #include "searchindex.h"
56 #include "arguments.h"
57 #include "config.h"
58 #include "groupdef.h"
59 #include "classlist.h"
60 #include "filedef.h"
61 #include "filename.h"
62 #include "namespacedef.h"
63 #include "tooltip.h"
64 #include "scopedtypevariant.h"
65 #include "symbolresolver.h"
66 #include "dir.h"
67
68 // Toggle for some debugging info
69 //#define DBG_CTX(x) fprintf x
70 #define DBG_CTX(x) do { } while(0)
71
72 #define YY_NO_UNISTD_H 1
73
74 #define CLASSBLOCK 1
75 #define SCOPEBLOCK 2
76 #define INNERBLOCK 3
77
78 #define USE_STATE2STRING 0
79
80 // context for an Objective-C method call
81 struct ObjCCallCtx
82 {
83 int id;
84 QCString methodName;
85 QCString objectTypeOrName;
86 TextStream comment;
87 const ClassDef *objectType;
88 const MemberDef *objectVar;
89 const MemberDef *method;
90 QCString format;
91 int lexState;
92 int braceCount;
93 };
94
95 struct codeYY_state
96 {
97 CodeOutputInterface * code = 0;
98
99 std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
100 QCString curClassName;
101 StringVector curClassBases;
102
103 QCString parmType;
104 QCString parmName;
105
106 const char * inputString = 0; //!< the code fragment as text
107 yy_size_t inputPosition = 0; //!< read offset during parsing
108 QCString fileName;
109 int inputLines = 0; //!< number of line in the code fragment
110 int yyLineNr = 0; //!< current line number
111 yy_size_t yyColNr = 0; //!< current column number
112 bool insideCodeLine = FALSE;
113
114 bool exampleBlock = FALSE;
115 QCString exampleName;
116 QCString exampleFile;
117
118 bool insideTemplate = FALSE;
119 QCString type;
120 QCString name;
121 QCString args;
122 QCString classScope;
123 QCString realScope;
124 std::stack<int> scopeStack; //!< 1 if bracket starts a scope,
125 // 2 for internal blocks
126 int anchorCount = 0;
127 const FileDef * sourceFileDef = 0;
128 bool lineNumbers = FALSE;
129 const Definition * currentDefinition = 0;
130 const MemberDef * currentMemberDef = 0;
131 bool includeCodeFragment = FALSE;
132 const char * currentFontClass = 0;
133 bool searchingForBody = FALSE;
134 bool insideBody = FALSE;
135 int bodyCurlyCount = 0;
136 QCString saveName;
137 QCString saveType;
138 QCString delimiter;
139
140 int bracketCount = 0;
141 int curlyCount = 0;
142 int sharpCount = 0;
143 bool inFunctionTryBlock = FALSE;
144 bool inForEachExpression = FALSE;
145
146 int lastTemplCastContext = 0;
147 int lastSpecialCContext = 0;
148 int lastStringContext = 0;
149 int lastSkipCppContext = 0;
150 int lastVerbStringContext = 0;
151 int lastObjCCallContext = 0;
152 int memCallContext = 0;
153 int lastCContext = 0;
154 int skipInlineInitContext = 0;
155
156 SrcLangExt lang = SrcLangExt_Unknown;
157 bool insideObjC = FALSE;
158 bool insideProtocolList = FALSE;
159
160 bool lexInit = FALSE;
161
162 std::stack<int> classScopeLengthStack;
163
164 int isPrefixedWithThis = FALSE;
165 const Definition *searchCtx = 0;
166 bool collectXRefs = FALSE;
167
168 ObjCCallCtx * currentCtx=0;
169 int currentCtxId=0;
170 int currentNameId=0;
171 int currentObjId=0;
172 int currentWordId=0;
173 int currentCommentId=0;
174 std::stack<ObjCCallCtx*> contextStack;
175 std::unordered_map< int,std::unique_ptr<ObjCCallCtx> > contextMap;
176 std::unordered_map< int, QCString> nameMap;
177 std::unordered_map< int, QCString> objectMap;
178 std::unordered_map< int, QCString> wordMap;
179 std::unordered_map< int, QCString> commentMap;
180 int braceCount=0;
181
182 VariableContext theVarContext;
183 CallContext theCallContext;
184 SymbolResolver symbolResolver;
185 TooltipManager tooltipManager;
186 };
187
188 static bool isCastKeyword(const char *s);
189
190 //-------------------------------------------------------------------
191 #if USE_STATE2STRING
192 static const char *stateToString(int state);
193 #endif
194
195 static void saveObjCContext(yyscan_t yyscanner);
196 static void restoreObjCContext(yyscan_t yyscanner);
197 static void pushScope(yyscan_t yyscanner,const QCString &s);
198 static void popScope(yyscan_t yyscanner);
199 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
200 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
201 static void addToSearchIndex(yyscan_t yyscanner,const char *text);
202 static void setClassScope(yyscan_t yyscanner,const QCString &name);
203 static void startCodeLine(yyscan_t yyscanner);
204 static void endCodeLine(yyscan_t yyscanner);
205 static void nextCodeLine(yyscan_t yyscanner);
206 static void startFontClass(yyscan_t yyscanner,const char *s);
207 static void endFontClass(yyscan_t yyscanner);
208 static void codifyLines(yyscan_t yyscanner,const QCString &text);
209 static void codifyLines(yyscan_t yyscanner,const char *text);
210 static void incrementFlowKeyWordCount(yyscan_t yyscanner);
211 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
212 const Definition *d,
213 const QCString &text);
214 static void addType(yyscan_t yyscanner);
215 static void addParmType(yyscan_t yyscanner);
216 static void addUsingDirective(yyscan_t yyscanner,const char *name);
217 static void setParameterList(yyscan_t yyscanner,const MemberDef *md);
218 static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d);
219 static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name);
220 static void updateCallContextForSmartPointer(yyscan_t yyscanner);
221 static bool getLinkInScope(yyscan_t yyscanner,const QCString &c, // scope
222 const QCString &m, // member
223 const QCString &memberText, // exact text
224 CodeOutputInterface &ol,
225 const QCString &text,
226 bool varOnly=FALSE
227 );
228 static bool getLink(yyscan_t yyscanner,const QCString &className,
229 const QCString &memberName,
230 CodeOutputInterface &ol,
231 const QCString &text=QCString(),
232 bool varOnly=FALSE);
233 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &clName,
234 bool typeOnly=FALSE,bool varOnly=FALSE);
235 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *clName,
236 bool typeOnly=FALSE,bool varOnly=FALSE);
237 static bool generateClassMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef *xmd,const QCString &memName);
238 static bool generateClassMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const Definition *def,const QCString &memName);
239 static void generateMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &varName,
240 const QCString &memName);
241 static void generatePHPVariableLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *varName);
242 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &funcName);
243 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *funcName);
244 static int countLines(yyscan_t yyscanner);
245 static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx);
246 static QCString escapeName(yyscan_t yyscanner,const char *s);
247 static QCString escapeObject(yyscan_t yyscanner,const char *s);
248 static QCString escapeWord(yyscan_t yyscanner,const char *s);
249 static QCString escapeComment(yyscan_t yyscanner,const char *s);
250 static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *kw);
251 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
252 static void addVariable(yyscan_t yyscanner,QCString type,QCString name);
253 static bool startsWithKeyword(const QCString &str,const QCString &kw);
254
255 //-------------------------------------------------------------------
256
257 static std::mutex g_searchIndexMutex;
258 static std::mutex g_docCrossReferenceMutex;
259 static std::mutex g_addExampleMutex;
260 static std::mutex g_countFlowKeywordsMutex;
261 static std::mutex g_usingDirectiveMutex;
262
263 /* -----------------------------------------------------------------
264 */
265 #undef YY_INPUT
266 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
267
268 // otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
getLexerFILE()269 static inline const char *getLexerFILE() {return __FILE__;}
270 #include "doxygen_lex.h"
271
272 %}
273
274 B [ \t]
275 Bopt {B}*
276 BN [ \t\n\r]
277 ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
278 SEP ("::"|"\\")
279 SCOPENAME ({SEP}{BN}*)?({ID}{BN}*{SEP}{BN}*)*("~"{BN}*)?{ID}
280 TEMPLIST "<"[^\"\}\{\(\)\/\n\>]*">"
281 SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID})
282 SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+
283 KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property")
284 /* please also pay attention to skipLanguageSpecificKeyword when changing the list of keywords. */
285 KEYWORD ("asm"|"__assume"|"auto"|"class"|"const"|"delete"|"enum"|"explicit"|"extern"|"false"|"friend"|"gcnew"|"gcroot"|"set"|"get"|"inline"|"internal"|"mutable"|"namespace"|"new"|"null"|"nullptr"|"override"|"operator"|"pin_ptr"|"private"|"protected"|"public"|"raise"|"register"|"remove"|"self"|"sizeof"|"static"|"struct"|"__super"|"function"|"template"|"generic"|"this"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|"alignas"|"alignof"|"concept"|"requires"|"decltype"|{KEYWORD_OBJC}|"constexpr"|"consteval"|"constinit"|"co_await"|"co_return"|"co_yield"|"static_assert"|"noexcept"|"thread_local"|"enum"{B}+("class"|"struct"))
286 FLOWKW ("break"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"return"|"switch"|"throw"|"throws"|"@catch"|"@finally")
287 FLOWCONDITION ("case"|"for"|"foreach"|"for each"|"goto"|"if"|"try"|"while"|"@try")
288 TYPEKW ("bool"|"byte"|"char"|"char8_t"|"char16_t"|"char32_t"|"double"|"float"|"int"|"long"|"object"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"size_t"|"boolean"|"id"|"SEL"|"string"|"nullptr")
289 TYPEKWSL ("LocalObject"|"Object"|"Value")
290 CASTKW ("const_cast"|"dynamic_cast"|"reinterpret_cast"|"static_cast")
291 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
292 ARITHOP "+"|"-"|"/"|"*"|"%"|"--"|"++"
293 ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
294 LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!"|"<=>"
295 BITOP "&"|"|"|"^"|"<<"|">>"|"~"
296 OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
297 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
298 RAWEND ")"[^ \t\(\)\\]{0,16}\"
299
300 /* no comment start / end signs inside square brackets */
301 NCOMM [^/\*]
302 //- start: NUMBER -------------------------------------------------------------------------
303 // Note same defines in commentcnv.l: keep in sync
304 DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
305 HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
306 OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
307 BINARY_INTEGER "0"[bB][01][01']*[01]?
308 INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
309
310 FP_SUF [fFlL]
311
312 DIGIT_SEQ [0-9][0-9']*[0-9]?
313 FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
314 FP_EXP [eE][+-]?{DIGIT_SEQ}
315 DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
316 DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
317
318 HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
319 HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
320 BIN_EXP [pP][+-]?{DIGIT_SEQ}
321 HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
322 HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
323
324 FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
325 FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
326 FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
327 NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
328 //- end: NUMBER ---------------------------------------------------------------------------
329
330 // C start comment
331 CCS "/\*"
332 // C end comment
333 CCE "*\/"
334 // Cpp comment
335 CPPC "/\/"
336
337 // ENDIDopt
338 ENDIDopt ("::"{ID})*
339 // Optional end qualifiers
340 ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"sealed"|"override"))*
341
342 %option noyywrap
343
344 %x SkipString
345 %x SkipStringS
346 %x SkipVerbString
347 %x SkipCPP
348 %x SkipComment
349 %x SkipCxxComment
350 %x RemoveSpecialCComment
351 %x Body
352 %x FuncCall
353 %x MemberCall
354 %x MemberCall2
355 %x SkipInits
356 %x ClassName
357 %x AlignAs
358 %x AlignAsEnd
359 %x PackageName
360 %x ClassVar
361 %x CppCliTypeModifierFollowup
362 %x Bases
363 %x SkipSharp
364 %x ReadInclude
365 %x TemplDecl
366 %x TemplCast
367 %x CallEnd
368 %x ObjCMethod
369 %x ObjCParams
370 %x ObjCParamType
371 %x ObjCCall
372 %x ObjCMName
373 %x ObjCSkipStr
374 %x ObjCCallComment
375 %x OldStyleArgs
376 %x ConceptName
377 %x UsingName
378 %x RawString
379 %x InlineInit
380
381 %%
382
383 <*>\x0d
384 <Body>^([ \t]*"#"[ \t]*("include"|"import")[ \t]*)("<"|"\"") {
385 startFontClass(yyscanner,"preprocessor");
386 yyextra->code->codify(yytext);
387 BEGIN( ReadInclude );
388 }
389 <Body>("@interface"|"@implementation"|"@protocol")[ \t\n]+ {
390 yyextra->insideObjC=TRUE;
391 startFontClass(yyscanner,"keyword");
392 codifyLines(yyscanner,yytext);
393 endFontClass(yyscanner);
394 if (!yyextra->insideTemplate)
395 BEGIN( ClassName );
396 }
397 <Body>(("public"|"private"){B}+)?("ref"|"value"|"interface"|"enum"){B}+("class"|"struct") {
398 if (yyextra->insideTemplate) REJECT;
399 startFontClass(yyscanner,"keyword");
400 codifyLines(yyscanner,yytext);
401 endFontClass(yyscanner);
402 BEGIN( ClassName );
403 }
404 <Body>"property"|"event"/{BN}* {
405 if (yyextra->insideTemplate) REJECT;
406 startFontClass(yyscanner,"keyword");
407 codifyLines(yyscanner,yytext);
408 endFontClass(yyscanner);
409 }
410 <Body>("partial"{B}+)?("class"|"struct"|"union"|"namespace"|"interface"){B}+ {
411 startFontClass(yyscanner,"keyword");
412 codifyLines(yyscanner,yytext);
413 endFontClass(yyscanner);
414 if (!yyextra->insideTemplate)
415 BEGIN( ClassName );
416 }
417 <Body>("package")[ \t\n]+ {
418 startFontClass(yyscanner,"keyword");
419 codifyLines(yyscanner,yytext);
420 endFontClass(yyscanner);
421 BEGIN( PackageName );
422 }
423 <ClassVar>\n {
424 if (!yyextra->insideObjC) REJECT;
425 codifyLines(yyscanner,yytext);
426 BEGIN(Body);
427 }
428 <Body,ClassVar,Bases>"-"|"+" {
429 if (!yyextra->insideObjC || yyextra->insideBody)
430 {
431 yyextra->code->codify(yytext);
432 }
433 else // Start of Objective-C method
434 {
435 DBG_CTX((stderr,"Start of Objective-C method!\n"));
436 yyextra->code->codify(yytext);
437 BEGIN(ObjCMethod);
438 }
439 }
440 <ObjCMethod>":" {
441 yyextra->code->codify(yytext);
442 BEGIN(ObjCParams);
443 }
444 <ObjCParams>"(" {
445 yyextra->code->codify(yytext);
446 BEGIN(ObjCParamType);
447 }
448 <ObjCParams,ObjCMethod>";"|"{" {
449 yyextra->code->codify(yytext);
450 if (*yytext=='{')
451 {
452 if (yyextra->searchingForBody)
453 {
454 yyextra->searchingForBody=FALSE;
455 yyextra->insideBody=TRUE;
456 }
457 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
458 if (!yyextra->curClassName.isEmpty()) // valid class name
459 {
460 pushScope(yyscanner,yyextra->curClassName);
461 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
462 yyextra->scopeStack.push(SCOPEBLOCK);
463 }
464 }
465 yyextra->type.resize(0);
466 yyextra->name.resize(0);
467 BEGIN(Body);
468 }
469 <ObjCParams>{ID}{B}*":" {
470 yyextra->code->codify(yytext);
471 }
472 <ObjCParamType>{TYPEKW} {
473 startFontClass(yyscanner,"keywordtype");
474 yyextra->code->codify(yytext);
475 endFontClass(yyscanner);
476 yyextra->parmType=yytext;
477 }
478 <ObjCParamType>{ID} {
479 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
480 yyextra->parmType=yytext;
481 }
482 <ObjCParamType>")" {
483 yyextra->code->codify(yytext);
484 BEGIN(ObjCParams);
485 }
486 <ObjCParams>{ID} {
487 yyextra->code->codify(yytext);
488 yyextra->parmName=yytext;
489 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
490 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
491 }
492 <ObjCMethod,ObjCParams,ObjCParamType>{ID} {
493 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
494 }
495 <ObjCMethod,ObjCParams,ObjCParamType>. {
496 yyextra->code->codify(yytext);
497 }
498 <ObjCMethod,ObjCParams,ObjCParamType>\n {
499 codifyLines(yyscanner,yytext);
500 }
501 <ReadInclude>[^\n\"\>]+/(">"|"\"") {
502 //FileInfo *f;
503 bool ambig;
504 bool found=FALSE;
505
506 const FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,yytext,ambig);
507 //printf("looking for include %s -> %s fd=%p\n",yytext,qPrint(absPath),fd);
508 if (fd && fd->isLinkable())
509 {
510 if (ambig) // multiple input files match the name
511 {
512 DBG_CTX((stderr,"===== yes %s is ambiguous\n",yytext));
513 QCString name(Dir::cleanDirPath(yytext));
514 if (!name.isEmpty() && yyextra->sourceFileDef)
515 {
516 const FileName *fn = Doxygen::inputNameLinkedMap->find(name);
517 if (fn)
518 {
519 // see if this source file actually includes the file
520 auto it = std::find_if(fn->begin(),
521 fn->end(),
522 [&sfd=yyextra->sourceFileDef]
523 (const auto &lfd)
524 { return sfd->isIncluded(lfd->absFilePath()); });
525 found = it!=fn->end();
526 }
527 }
528 }
529 else // not ambiguous
530 {
531 found = TRUE;
532 }
533 }
534 DBG_CTX((stderr," include file %s found=%d\n",fd ? qPrint(fd->absFilePath()) : "<none>",found));
535 if (found)
536 {
537 writeMultiLineCodeLink(yyscanner,*yyextra->code,fd,yytext);
538 }
539 else
540 {
541 yyextra->code->codify(yytext);
542 }
543 char c=(char)yyinput(yyscanner);
544 QCString text;
545 text+=c;
546 yyextra->code->codify(text);
547 endFontClass(yyscanner);
548 BEGIN( Body );
549 }
550 <Body,Bases>^[ \t]*"#" {
551 startFontClass(yyscanner,"preprocessor");
552 yyextra->lastSkipCppContext = YY_START;
553 yyextra->code->codify(yytext);
554 BEGIN( SkipCPP ) ;
555 }
556 <SkipCPP>\" {
557 yyextra->code->codify(yytext);
558 yyextra->lastStringContext=YY_START;
559 BEGIN( SkipString ) ;
560 }
561 <SkipCPP>. {
562 yyextra->code->codify(yytext);
563 }
564 <SkipCPP>[^\n\/\\\"]+ {
565 yyextra->code->codify(yytext);
566 }
567 <SkipCPP>\\[\r]?\n {
568 codifyLines(yyscanner,yytext);
569 }
570 <SkipCPP>{CPPC}/[^/!] {
571 REJECT;
572 }
573 <Body,FuncCall>"{" {
574 yyextra->theVarContext.pushScope();
575
576 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
577 yyextra->scopeStack.push(INNERBLOCK);
578
579 if (yyextra->searchingForBody)
580 {
581 yyextra->searchingForBody=FALSE;
582 yyextra->insideBody=TRUE;
583 }
584 yyextra->code->codify(yytext);
585 if (yyextra->insideBody)
586 {
587 yyextra->bodyCurlyCount++;
588 }
589 yyextra->type.resize(0);
590 yyextra->name.resize(0);
591 BEGIN( Body );
592 }
593 <Body,FuncCall,MemberCall,MemberCall2>"}" {
594 yyextra->theVarContext.popScope();
595 yyextra->type.resize(0);
596 yyextra->name.resize(0);
597
598 if (!yyextra->scopeStack.empty())
599 {
600 int scope = yyextra->scopeStack.top();
601 yyextra->scopeStack.pop();
602 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
603 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
604 {
605 popScope(yyscanner);
606 }
607 }
608
609 yyextra->code->codify(yytext);
610
611 DBG_CTX((stderr,"yyextra->bodyCurlyCount=%d\n",yyextra->bodyCurlyCount));
612 if (--yyextra->bodyCurlyCount<=0)
613 {
614 yyextra->insideBody=FALSE;
615 yyextra->currentMemberDef=0;
616 if (yyextra->currentDefinition)
617 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
618 }
619 BEGIN(Body);
620 }
621 <Body,ClassVar>"@end" {
622 DBG_CTX((stderr,"End of objc scope fd=%s\n",qPrint(yyextra->sourceFileDef->name())));
623 if (yyextra->sourceFileDef)
624 {
625 const FileDef *fd=yyextra->sourceFileDef;
626 yyextra->insideObjC = fd->name().lower().right(2)==".m" ||
627 fd->name().lower().right(3)==".mm";
628 DBG_CTX((stderr,"insideObjC=%d\n",yyextra->insideObjC));
629 }
630 else
631 {
632 yyextra->insideObjC = FALSE;
633 }
634 if (yyextra->insideBody)
635 {
636 yyextra->theVarContext.popScope();
637
638 if (!yyextra->scopeStack.empty())
639 {
640 int scope = yyextra->scopeStack.top();
641 yyextra->scopeStack.pop();
642 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
643 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
644 {
645 popScope(yyscanner);
646 }
647 }
648 yyextra->insideBody=FALSE;
649 }
650
651 startFontClass(yyscanner,"keyword");
652 yyextra->code->codify(yytext);
653 endFontClass(yyscanner);
654
655 yyextra->currentMemberDef=0;
656 if (yyextra->currentDefinition)
657 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
658 BEGIN(Body);
659 }
660 <ClassName,ClassVar>";" {
661 yyextra->code->codify(yytext);
662 yyextra->searchingForBody=FALSE;
663 BEGIN( Body );
664 }
665 <ClassName,ClassVar>[*&^%]+ {
666 yyextra->type=yyextra->curClassName;
667 yyextra->name.resize(0);
668 yyextra->code->codify(yytext);
669 BEGIN( Body ); // variable of type struct *
670 }
671 <ClassName>"__declspec"{B}*"("{B}*{ID}{B}*")" {
672 startFontClass(yyscanner,"keyword");
673 yyextra->code->codify(yytext);
674 endFontClass(yyscanner);
675 }
676 <ClassName>{ID}("."{ID})* |
677 <ClassName>{ID}("::"{ID})* {
678 if (yyextra->lang==SrcLangExt_CSharp)
679 yyextra->curClassName=substitute(yytext,".","::");
680 else
681 yyextra->curClassName=yytext;
682 addType(yyscanner);
683 if (yyextra->curClassName=="alignas")
684 {
685 startFontClass(yyscanner,"keyword");
686 yyextra->code->codify(yytext);
687 endFontClass(yyscanner);
688 BEGIN( AlignAs );
689 }
690 else
691 {
692 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
693 BEGIN( ClassVar );
694 }
695 }
696 <AlignAs>"(" {
697 yyextra->bracketCount=1;
698 yyextra->code->codify(yytext);
699 BEGIN( AlignAsEnd );
700 }
701 <AlignAs>\n { yyextra->yyLineNr++;
702 codifyLines(yyscanner,yytext);
703 }
704 <AlignAs>. { yyextra->code->codify(yytext); }
705 <AlignAsEnd>"(" { yyextra->code->codify(yytext);
706 yyextra->bracketCount++;
707 }
708 <AlignAsEnd>")" {
709 yyextra->code->codify(yytext);
710 if (--yyextra->bracketCount<=0)
711 {
712 BEGIN(ClassName);
713 }
714 }
715 <AlignAsEnd>\n { yyextra->yyLineNr++;
716 codifyLines(yyscanner,yytext);
717 }
718 <AlignAsEnd>. { yyextra->code->codify(yytext); }
719 <ClassName>{ID}("\\"{ID})* { // PHP namespace
720 yyextra->curClassName=substitute(yytext,"\\","::");
721 yyextra->scopeStack.push(CLASSBLOCK);
722 pushScope(yyscanner,yyextra->curClassName);
723 addType(yyscanner);
724 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
725 BEGIN( ClassVar );
726 }
727 <ClassName>{ID}{B}*"("{ID}")" { // Obj-C category
728 yyextra->curClassName=removeRedundantWhiteSpace(yytext);
729 yyextra->scopeStack.push(CLASSBLOCK);
730 pushScope(yyscanner,yyextra->curClassName);
731 addType(yyscanner);
732 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
733 BEGIN( ClassVar );
734 }
735 <PackageName>{ID}("."{ID})* {
736 yyextra->curClassName=substitute(yytext,".","::");
737 DBG_CTX((stderr,"found package: %s\n",qPrint(yyextra->curClassName)));
738 addType(yyscanner);
739 codifyLines(yyscanner,yytext);
740 }
741 <ClassVar>"=" {
742 unput(*yytext);
743 BEGIN( Body );
744 }
745 <ClassVar>("extends"|"implements") { // Java, Slice
746 startFontClass(yyscanner,"keyword");
747 codifyLines(yyscanner,yytext);
748 endFontClass(yyscanner);
749 yyextra->curClassBases.clear();
750 BEGIN( Bases );
751 }
752 <ClassVar>("sealed"|"abstract")/{BN}*(":"|"{") {
753 DBG_CTX((stderr,"***** C++/CLI modifier %s on yyextra->curClassName=%s\n",yytext,qPrint(yyextra->curClassName)));
754 startFontClass(yyscanner,"keyword");
755 codifyLines(yyscanner,yytext);
756 endFontClass(yyscanner);
757 BEGIN( CppCliTypeModifierFollowup );
758 }
759 <ClassVar>{ID} {
760 yyextra->type = yyextra->curClassName;
761 yyextra->name = yytext;
762 if (yyextra->insideBody)
763 {
764 addVariable(yyscanner,yyextra->type,yyextra->name);
765 }
766 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
767 }
768 <ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*":"{B}* {
769 codifyLines(yyscanner,yytext);
770 yyextra->curClassBases.clear();
771 BEGIN( Bases );
772 }
773 <PackageName>[ \t]*";" |
774 <Bases>^{Bopt}/"@"{ID} | // Objective-C interface
775 <Bases,ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*"{"{B}* {
776 yyextra->theVarContext.pushScope();
777 yyextra->code->codify(yytext);
778 if (YY_START==ClassVar && yyextra->curClassName.isEmpty())
779 {
780 yyextra->curClassName = yyextra->name;
781 }
782 if (yyextra->searchingForBody)
783 {
784 yyextra->searchingForBody=FALSE;
785 yyextra->insideBody=TRUE;
786 }
787 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
788 if (!yyextra->curClassName.isEmpty()) // valid class name
789 {
790 DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n"));
791 yyextra->scopeStack.push(CLASSBLOCK);
792 pushScope(yyscanner,yyextra->curClassName);
793 DBG_CTX((stderr,"***** yyextra->curClassName=%s\n",qPrint(yyextra->curClassName)));
794 if (yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->curClassName)==0)
795 {
796 DBG_CTX((stderr,"Adding new class %s\n",qPrint(yyextra->curClassName)));
797 ScopedTypeVariant var(yyextra->curClassName);
798 // insert base classes.
799 for (const auto &s : yyextra->curClassBases)
800 {
801 const ClassDef *bcd=0;
802 auto it = yyextra->codeClassMap.find(s);
803 if (it!=yyextra->codeClassMap.end())
804 {
805 bcd = toClassDef(it->second.globalDef());
806 }
807 if (bcd==0) bcd=yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,QCString(s));
808 if (bcd && bcd->name()!=yyextra->curClassName)
809 {
810 var.localDef()->insertBaseClass(bcd->name());
811 }
812 }
813 yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(var)));
814 }
815 //printf("yyextra->codeClassList.count()=%d\n",yyextra->codeClassList.count());
816 }
817 else // not a class name -> assume inner block
818 {
819 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
820 yyextra->scopeStack.push(INNERBLOCK);
821 }
822 yyextra->curClassName.resize(0);
823 yyextra->curClassBases.clear();
824 BEGIN( Body );
825 }
826 <Bases>"virtual"|"public"|"protected"|"private"|"@public"|"@private"|"@protected" {
827 startFontClass(yyscanner,"keyword");
828 yyextra->code->codify(yytext);
829 endFontClass(yyscanner);
830 }
831 <Bases>{SEP}?({ID}{SEP})*{ID} {
832 DBG_CTX((stderr,"%s:addBase(%s)\n",qPrint(yyextra->curClassName),yytext));
833 yyextra->curClassBases.push_back(yytext);
834 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
835 }
836 <Bases>"<" {
837 yyextra->code->codify(yytext);
838 if (!yyextra->insideObjC)
839 {
840 yyextra->sharpCount=1;
841 BEGIN ( SkipSharp );
842 }
843 else
844 {
845 yyextra->insideProtocolList=TRUE;
846 }
847 }
848 <Bases>">" {
849 yyextra->code->codify(yytext);
850 yyextra->insideProtocolList=FALSE;
851 }
852 <SkipSharp>"<" {
853 yyextra->code->codify(yytext);
854 ++yyextra->sharpCount;
855 }
856 <SkipSharp>">" {
857 yyextra->code->codify(yytext);
858 if (--yyextra->sharpCount<=0)
859 BEGIN ( Bases );
860 }
861 <SkipSharp>"\"" {
862 yyextra->code->codify(yytext);
863 yyextra->lastStringContext=YY_START;
864 BEGIN(SkipString);
865 }
866 <SkipSharp>"\'" {
867 yyextra->code->codify(yytext);
868 yyextra->lastStringContext=YY_START;
869 BEGIN(SkipStringS);
870 }
871 <Bases>"(" {
872 yyextra->code->codify(yytext);
873 yyextra->sharpCount=1;
874 BEGIN ( SkipSharp );
875 }
876 <SkipSharp>"(" {
877 yyextra->code->codify(yytext);
878 ++yyextra->sharpCount;
879 }
880 <SkipSharp>")" {
881 yyextra->code->codify(yytext);
882 if (--yyextra->sharpCount<=0)
883 BEGIN ( Bases );
884 }
885
886
887 <Bases>"," {
888 yyextra->code->codify(yytext);
889 }
890
891
892 <Body>{SCOPEPREFIX}?"operator"{B}*"()"{Bopt}/"(" {
893 addType(yyscanner);
894 generateFunctionLink(yyscanner,*yyextra->code,yytext);
895 yyextra->bracketCount=0;
896 yyextra->args.resize(0);
897 yyextra->name+=yytext;
898 BEGIN( FuncCall );
899 }
900 <Body>{SCOPEPREFIX}?"operator"/"(" {
901 addType(yyscanner);
902 generateFunctionLink(yyscanner,*yyextra->code,yytext);
903 yyextra->bracketCount=0;
904 yyextra->args.resize(0);
905 yyextra->name+=yytext;
906 BEGIN( FuncCall );
907 }
908 <Body>{SCOPEPREFIX}?"operator"[^a-z_A-Z0-9\(\n]+/"(" {
909 addType(yyscanner);
910 generateFunctionLink(yyscanner,*yyextra->code,yytext);
911 yyextra->bracketCount=0;
912 yyextra->args.resize(0);
913 yyextra->name+=yytext;
914 BEGIN( FuncCall );
915 }
916 <Body,TemplDecl>("template"|"generic")/([^a-zA-Z0-9]) {
917 startFontClass(yyscanner,"keyword");
918 codifyLines(yyscanner,yytext);
919 endFontClass(yyscanner);
920 yyextra->insideTemplate=TRUE;
921 yyextra->sharpCount=0;
922 }
923 <Body>"concept"{BN}+ {
924 startFontClass(yyscanner,"keyword");
925 codifyLines(yyscanner,yytext);
926 endFontClass(yyscanner);
927 BEGIN(ConceptName);
928 }
929 <Body>"using"{BN}+"namespace"{BN}+ {
930 startFontClass(yyscanner,"keyword");
931 codifyLines(yyscanner,yytext);
932 endFontClass(yyscanner);
933 BEGIN(UsingName);
934 }
935 <ConceptName>{ID}("::"{ID})* {
936 addUsingDirective(yyscanner,yytext);
937 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
938 }
939 <ConceptName>"=" { codifyLines(yyscanner,yytext); BEGIN(Body); }
940 <UsingName>{ID}("::"{ID})* {
941 addUsingDirective(yyscanner,yytext);
942 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
943 BEGIN(Body);
944 }
945 <UsingName>\n { codifyLines(yyscanner,yytext); BEGIN(Body); }
946 <UsingName>. { codifyLines(yyscanner,yytext); BEGIN(Body); }
947 <Body,FuncCall>"$"?"this"("->"|".") { yyextra->code->codify(yytext); // this-> for C++, this. for C#
948 yyextra->isPrefixedWithThis = TRUE;
949 }
950 <Body>{KEYWORD}/([^a-z_A-Z0-9]) {
951 if (yyextra->lang==SrcLangExt_Java && qstrcmp("internal",yytext) ==0) REJECT;
952 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
953 startFontClass(yyscanner,"keyword");
954 codifyLines(yyscanner,yytext);
955 if (QCString(yytext)=="typedef")
956 {
957 addType(yyscanner);
958 yyextra->name+=yytext;
959 }
960 endFontClass(yyscanner);
961 }
962 <Body>{KEYWORD}/{B}* {
963 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
964 startFontClass(yyscanner,"keyword");
965 codifyLines(yyscanner,yytext);
966 endFontClass(yyscanner);
967 }
968 <Body>{KEYWORD}/{BN}*"(" {
969 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
970 startFontClass(yyscanner,"keyword");
971 codifyLines(yyscanner,yytext);
972 endFontClass(yyscanner);
973 yyextra->name.resize(0);yyextra->type.resize(0);
974 }
975 <FuncCall>"in"/{BN}* {
976 if (!yyextra->inForEachExpression) REJECT;
977 startFontClass(yyscanner,"keywordflow");
978 codifyLines(yyscanner,yytext);
979 endFontClass(yyscanner);
980 // insert the variable in the parent scope, see bug 546158
981 yyextra->theVarContext.popScope();
982 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
983 yyextra->theVarContext.pushScope();
984 yyextra->name.resize(0);yyextra->type.resize(0);
985 }
986 <Body>{FLOWKW}/{BN}*"(" {
987 startFontClass(yyscanner,"keywordflow");
988 codifyLines(yyscanner,yytext);
989 endFontClass(yyscanner);
990 yyextra->name.resize(0);yyextra->type.resize(0);
991 yyextra->inForEachExpression = (qstrcmp(yytext,"for each")==0 || qstrcmp(yytext, "foreach")==0);
992 BEGIN(FuncCall);
993 }
994 <Body>{FLOWCONDITION}/{BN}*"(" {
995 incrementFlowKeyWordCount(yyscanner);
996 startFontClass(yyscanner,"keywordflow");
997 codifyLines(yyscanner,yytext);
998 endFontClass(yyscanner);
999 yyextra->name.resize(0);yyextra->type.resize(0);
1000 yyextra->inForEachExpression = (strcmp(yytext,"for each")==0 || strcmp(yytext, "foreach")==0);
1001 BEGIN(FuncCall);
1002 }
1003 <Body>{FLOWKW}/([^a-z_A-Z0-9]) {
1004 startFontClass(yyscanner,"keywordflow");
1005 codifyLines(yyscanner,yytext);
1006 endFontClass(yyscanner);
1007 if (yyextra->inFunctionTryBlock && (qstrcmp(yytext,"catch")==0 || qstrcmp(yytext,"finally")==0))
1008 {
1009 yyextra->inFunctionTryBlock=FALSE;
1010 }
1011 }
1012 <Body>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1013 incrementFlowKeyWordCount(yyscanner);
1014 startFontClass(yyscanner,"keywordflow");
1015 codifyLines(yyscanner,yytext);
1016 endFontClass(yyscanner);
1017 if (yyextra->inFunctionTryBlock && (strcmp(yytext,"catch")==0 || strcmp(yytext,"finally")==0))
1018 {
1019 yyextra->inFunctionTryBlock=FALSE;
1020 }
1021 }
1022 <Body>{FLOWKW}/{B}* {
1023 startFontClass(yyscanner,"keywordflow");
1024 codifyLines(yyscanner,yytext);
1025 endFontClass(yyscanner);
1026 }
1027 <Body>{FLOWCONDITION}/{B}* {
1028 incrementFlowKeyWordCount(yyscanner);
1029 startFontClass(yyscanner,"keywordflow");
1030 codifyLines(yyscanner,yytext);
1031 endFontClass(yyscanner);
1032 }
1033 <Body>"*"{B}*")" { // end of cast?
1034 yyextra->code->codify(yytext);
1035 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1036 yyextra->bracketCount--;
1037 yyextra->parmType = yyextra->name;
1038 BEGIN(FuncCall);
1039 }
1040 <Body>"\\)"|"\\(" {
1041 yyextra->code->codify(yytext);
1042 }
1043 <Body>[\\|\)\+\-\/\%\~\!] {
1044 yyextra->code->codify(yytext);
1045 yyextra->name.resize(0);yyextra->type.resize(0);
1046 if (*yytext==')')
1047 {
1048 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1049 yyextra->bracketCount--;
1050 BEGIN(FuncCall);
1051 }
1052 }
1053 <Body,TemplDecl,ObjCMethod>{TYPEKW}/{B}* {
1054 startFontClass(yyscanner,"keywordtype");
1055 yyextra->code->codify(yytext);
1056 endFontClass(yyscanner);
1057 addType(yyscanner);
1058 yyextra->name+=yytext;
1059 }
1060 <Body,TemplDecl,ObjCMethod>{TYPEKWSL}/{B}* {
1061 if (yyextra->lang!=SrcLangExt_Slice)
1062 {
1063 REJECT;
1064 }
1065 else
1066 {
1067 startFontClass(yyscanner,"keywordtype");
1068 yyextra->code->codify(yytext);
1069 endFontClass(yyscanner);
1070 addType(yyscanner);
1071 yyextra->name+=yytext;
1072 }
1073 }
1074 <Body>"generic"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* {
1075 startFontClass(yyscanner,"keyword");
1076 yyextra->code->codify(yytext);
1077 endFontClass(yyscanner);
1078 yyextra->sharpCount=0;
1079 BEGIN(TemplDecl);
1080 }
1081 <Body>"template"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* { // template<...>
1082 startFontClass(yyscanner,"keyword");
1083 yyextra->code->codify(yytext);
1084 endFontClass(yyscanner);
1085 yyextra->sharpCount=0;
1086 BEGIN(TemplDecl);
1087 }
1088 <TemplDecl>"class"|"typename" {
1089 startFontClass(yyscanner,"keyword");
1090 codifyLines(yyscanner,yytext);
1091 endFontClass(yyscanner);
1092 }
1093 <TemplDecl>"<" {
1094 yyextra->code->codify(yytext);
1095 yyextra->sharpCount++;
1096 }
1097 <TemplDecl>">" {
1098 yyextra->code->codify(yytext);
1099 yyextra->sharpCount--;
1100 if (yyextra->sharpCount<=0)
1101 {
1102 BEGIN(Body);
1103 }
1104 }
1105 <TemplCast>">" {
1106 startFontClass(yyscanner,"keyword");
1107 codifyLines(yyscanner,yytext);
1108 endFontClass(yyscanner);
1109 BEGIN( yyextra->lastTemplCastContext );
1110 }
1111 <TemplCast>{ID}("::"{ID})* {
1112 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1113 }
1114 <TemplCast>("const"|"volatile"){B}* {
1115 startFontClass(yyscanner,"keyword");
1116 codifyLines(yyscanner,yytext);
1117 endFontClass(yyscanner);
1118 }
1119 <TemplCast>[*^]* {
1120 codifyLines(yyscanner,yytext);
1121 }
1122 <Body,MemberCall2,FuncCall>{CASTKW}{B}*"<" { // static_cast<T>(
1123 startFontClass(yyscanner,"keyword");
1124 codifyLines(yyscanner,yytext);
1125 endFontClass(yyscanner);
1126 yyextra->lastTemplCastContext = YY_START;
1127 BEGIN(TemplCast);
1128 }
1129 <Body>"$this->"{SCOPENAME}/{BN}*[;,)\]] { // PHP member variable
1130 addType(yyscanner);
1131 generatePHPVariableLink(yyscanner,*yyextra->code,yytext);
1132 yyextra->name+=yytext+7;
1133 }
1134 <Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>\(]*">"{ENDIDopt}/{B}* { // A<T> *pt;
1135 if (isCastKeyword(yytext) && YY_START==Body)
1136 {
1137 REJECT;
1138 }
1139 addType(yyscanner);
1140 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1141 yyextra->name+=yytext;
1142 }
1143 <Body>{SCOPENAME}/{BN}*[:;,)\]] { // "int var;" or "var, var2" or "debug(f) macro" , or int var : 5;
1144 if (startsWithKeyword(yytext,"typedef")) REJECT;
1145 addType(yyscanner);
1146 // changed this to generateFunctionLink, see bug 624514
1147 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1148 yyextra->name+=yytext;
1149 }
1150 <Body>{SCOPENAME}/{B}* { // p->func()
1151 if (startsWithKeyword(yytext,"typedef")) REJECT;
1152 addType(yyscanner);
1153 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1154 yyextra->name+=yytext;
1155 }
1156 <Body>"("{B}*("*"{B}*)+{SCOPENAME}+{B}*")"/{B}* { // (*p)->func() but not "if (p) ..."
1157 yyextra->code->codify(yytext);
1158 uint s=0;while (s<(uint)yyleng && !isId(yytext[s])) s++;
1159 uint e=(uint)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1160 QCString varname = ((QCString)yytext).mid(s,e-s+1);
1161 addType(yyscanner);
1162 yyextra->name=varname;
1163 }
1164 <Body>{SCOPETNAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"/{BN}*"(" |
1165 <Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo()
1166 if (isCastKeyword(yytext))
1167 {
1168 REJECT;
1169 }
1170 addType(yyscanner);
1171 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1172 yyextra->bracketCount=0;
1173 yyextra->args.resize(0);
1174 yyextra->name+=yytext;
1175 BEGIN( FuncCall );
1176 }
1177 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{RAWBEGIN} {
1178 QCString text(yytext);
1179 uint i=(uint)text.find('R');
1180 yyextra->code->codify(text.left(i+1));
1181 startFontClass(yyscanner,"stringliteral");
1182 yyextra->code->codify(QCString(yytext+i+1));
1183 yyextra->lastStringContext=YY_START;
1184 yyextra->inForEachExpression = FALSE;
1185 yyextra->delimiter = yytext+i+2;
1186 yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
1187 BEGIN( RawString );
1188 }
1189 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\" {
1190 startFontClass(yyscanner,"stringliteral");
1191 yyextra->code->codify(yytext);
1192 yyextra->lastStringContext=YY_START;
1193 yyextra->inForEachExpression = FALSE;
1194 BEGIN( SkipString );
1195 }
1196 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{NUMBER} { //Note similar code in commentcnv.l
1197 if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
1198 yyextra->code->codify(yytext);
1199 }
1200 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\' {
1201 startFontClass(yyscanner,"stringliteral");
1202 yyextra->code->codify(yytext);
1203 yyextra->lastStringContext=YY_START;
1204 yyextra->inForEachExpression = FALSE;
1205 BEGIN( SkipStringS );
1206 }
1207 <SkipString>[^\"\\\r\n]* {
1208 yyextra->code->codify(yytext);
1209 }
1210 <SkipStringS>[^\'\\\r\n]* {
1211 yyextra->code->codify(yytext);
1212 }
1213 <SkipString,SkipStringS>{CPPC}|{CCS} {
1214 yyextra->code->codify(yytext);
1215 }
1216 <SkipString>@?\" {
1217 yyextra->code->codify(yytext);
1218 endFontClass(yyscanner);
1219 BEGIN( yyextra->lastStringContext );
1220 }
1221 <SkipStringS>\' {
1222 yyextra->code->codify(yytext);
1223 endFontClass(yyscanner);
1224 BEGIN( yyextra->lastStringContext );
1225 }
1226 <SkipString,SkipStringS>\\. {
1227 yyextra->code->codify(yytext);
1228 }
1229 <RawString>{RAWEND} {
1230 yyextra->code->codify(yytext);
1231 QCString delimiter(yytext+1);
1232 delimiter=delimiter.left(delimiter.length()-1);
1233 if (delimiter==yyextra->delimiter)
1234 {
1235 BEGIN( yyextra->lastStringContext );
1236 }
1237 }
1238 <RawString>[^)\n]+ { yyextra->code->codify(yytext); }
1239 <RawString>. { yyextra->code->codify(yytext); }
1240 <RawString>\n { codifyLines(yyscanner,yytext); }
1241 <SkipVerbString>[^"\n]+ {
1242 yyextra->code->codify(yytext);
1243 }
1244 <SkipVerbString>\"\" { // escaped quote
1245 yyextra->code->codify(yytext);
1246 }
1247 <SkipVerbString>\" { // end of string
1248 yyextra->code->codify(yytext);
1249 endFontClass(yyscanner);
1250 BEGIN( yyextra->lastVerbStringContext );
1251 }
1252 <SkipVerbString>. {
1253 yyextra->code->codify(yytext);
1254 }
1255 <SkipVerbString>\n {
1256 codifyLines(yyscanner,yytext);
1257 }
1258 <Body>":" {
1259 yyextra->code->codify(yytext);
1260 yyextra->name.resize(0);yyextra->type.resize(0);
1261 }
1262 <Body>"<" {
1263 if (yyextra->insideTemplate)
1264 {
1265 yyextra->sharpCount++;
1266 }
1267 yyextra->code->codify(yytext);
1268 }
1269 <Body>">" {
1270 if (yyextra->insideTemplate)
1271 {
1272 if (--yyextra->sharpCount<=0)
1273 {
1274 yyextra->insideTemplate=FALSE;
1275 }
1276 }
1277 yyextra->code->codify(yytext);
1278 }
1279 <Body,MemberCall,MemberCall2,FuncCall>"'"((\\0[Xx0-9]+)|(\\.)|(.))"'" {
1280 startFontClass(yyscanner,"charliteral");
1281 yyextra->code->codify(yytext);
1282 endFontClass(yyscanner);
1283 }
1284 <Body>"."|"->" {
1285 if (yytext[0]=='-') // -> could be overloaded
1286 {
1287 updateCallContextForSmartPointer(yyscanner);
1288 }
1289 yyextra->code->codify(yytext);
1290 yyextra->memCallContext = YY_START;
1291 BEGIN( MemberCall );
1292 }
1293 <MemberCall>{SCOPETNAME}/{BN}*"(" {
1294 if (yyextra->theCallContext.getScope().globalDef())
1295 {
1296 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1297 {
1298 codifyLines(yyscanner,yytext);
1299 addToSearchIndex(yyscanner,yytext);
1300 }
1301 yyextra->name.resize(0);
1302 }
1303 else
1304 {
1305 codifyLines(yyscanner,yytext);
1306 addToSearchIndex(yyscanner,yytext);
1307 yyextra->name.resize(0);
1308 }
1309 yyextra->type.resize(0);
1310 if (yyextra->memCallContext==Body)
1311 {
1312 BEGIN(FuncCall);
1313 }
1314 else
1315 {
1316 BEGIN(yyextra->memCallContext);
1317 }
1318 }
1319 <MemberCall>{SCOPENAME}/{B}* {
1320 if (yyextra->theCallContext.getScope().globalDef())
1321 {
1322 DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",(void*)yyextra->theCallContext.getScope().globalDef()));
1323 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1324 {
1325 codifyLines(yyscanner,yytext);
1326 addToSearchIndex(yyscanner,yytext);
1327 }
1328 yyextra->name.resize(0);
1329 }
1330 else
1331 {
1332 DBG_CTX((stderr,"no class context!\n"));
1333 codifyLines(yyscanner,yytext);
1334 addToSearchIndex(yyscanner,yytext);
1335 yyextra->name.resize(0);
1336 }
1337 yyextra->type.resize(0);
1338 BEGIN(yyextra->memCallContext);
1339 }
1340 <Body>[,=;\[] {
1341 if (yyextra->insideObjC && *yytext=='[')
1342 {
1343 DBG_CTX((stderr,"Found start of ObjC call!\n"));
1344 // start of a method call
1345 yyextra->contextMap.clear();
1346 yyextra->nameMap.clear();
1347 yyextra->objectMap.clear();
1348 yyextra->wordMap.clear();
1349 yyextra->commentMap.clear();
1350 yyextra->currentCtxId = 0;
1351 yyextra->currentNameId = 0;
1352 yyextra->currentObjId = 0;
1353 yyextra->currentCtx = 0;
1354 yyextra->braceCount = 0;
1355 unput('[');
1356 BEGIN(ObjCCall);
1357 }
1358 else
1359 {
1360 yyextra->code->codify(yytext);
1361 yyextra->saveName = yyextra->name;
1362 yyextra->saveType = yyextra->type;
1363 if (*yytext!='[' && !yyextra->type.isEmpty())
1364 {
1365 //printf("yyextra->scopeStack.bottom()=%p\n",yyextra->scopeStack.bottom());
1366 //if (yyextra->scopeStack.top()!=CLASSBLOCK) // commented out for bug731363
1367 {
1368 //printf("AddVariable: '%s' '%s' context=%d\n",
1369 // qPrint(yyextra->type),qPrint(yyextra->name),yyextra->theVarContext.count());
1370 addVariable(yyscanner,yyextra->type,yyextra->name);
1371 }
1372 yyextra->name.resize(0);
1373 }
1374 if (*yytext==';' || *yytext=='=')
1375 {
1376 yyextra->type.resize(0);
1377 yyextra->name.resize(0);
1378 }
1379 else if (*yytext=='[')
1380 {
1381 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
1382 }
1383 yyextra->args.resize(0);
1384 yyextra->parmType.resize(0);
1385 yyextra->parmName.resize(0);
1386 }
1387 }
1388 <ObjCCall,ObjCMName>"["|"{" {
1389 saveObjCContext(yyscanner);
1390 yyextra->currentCtx->format+=*yytext;
1391 BEGIN(ObjCCall);
1392 DBG_CTX((stderr,"open\n"));
1393 }
1394 <ObjCCall,ObjCMName>"]"|"}" {
1395 yyextra->currentCtx->format+=*yytext;
1396 restoreObjCContext(yyscanner);
1397 BEGIN(ObjCMName);
1398 if (yyextra->currentCtx==0)
1399 {
1400 // end of call
1401 ObjCCallCtx *ctx = 0;
1402 auto it = yyextra->contextMap.find(0);
1403 if (it!=yyextra->contextMap.end())
1404 {
1405 ctx = it->second.get();
1406 }
1407 writeObjCMethodCall(yyscanner,ctx);
1408 BEGIN(Body);
1409 }
1410 DBG_CTX((stderr,"close\n"));
1411 }
1412 <ObjCCall,ObjCMName>{CPPC}.* {
1413 yyextra->currentCtx->format+=escapeComment(yyscanner,yytext);
1414 }
1415 <ObjCCall,ObjCMName>{CCS} {
1416 yyextra->lastObjCCallContext = YY_START;
1417 yyextra->currentCtx->comment.str(yytext);
1418 BEGIN(ObjCCallComment);
1419 }
1420 <ObjCCallComment>{CCE} {
1421 yyextra->currentCtx->comment << yytext;
1422 std::string commentStr = yyextra->currentCtx->comment.str();
1423 yyextra->currentCtx->format+=escapeComment(yyscanner,commentStr.c_str());
1424 BEGIN(yyextra->lastObjCCallContext);
1425 }
1426 <ObjCCallComment>[^*\n]+ { yyextra->currentCtx->comment << yytext; }
1427 <ObjCCallComment>{CPPC}|{CCS} { yyextra->currentCtx->comment << yytext; }
1428 <ObjCCallComment>\n { yyextra->currentCtx->comment << *yytext; }
1429 <ObjCCallComment>. { yyextra->currentCtx->comment << *yytext; }
1430 <ObjCCall>{ID} {
1431 yyextra->currentCtx->format+=escapeObject(yyscanner,yytext);
1432 if (yyextra->braceCount==0)
1433 {
1434 yyextra->currentCtx->objectTypeOrName=yytext;
1435 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
1436 BEGIN(ObjCMName);
1437 }
1438 }
1439 <ObjCMName>{ID}/{BN}*"]" {
1440 if (yyextra->braceCount==0 &&
1441 yyextra->currentCtx->methodName.isEmpty())
1442 {
1443 yyextra->currentCtx->methodName=yytext;
1444 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1445 }
1446 else
1447 {
1448 yyextra->currentCtx->format+=escapeWord(yyscanner,yytext);
1449 }
1450 }
1451 <ObjCMName>{ID}/{BN}*":" {
1452 if (yyextra->braceCount==0)
1453 {
1454 yyextra->currentCtx->methodName+=yytext;
1455 yyextra->currentCtx->methodName+=":";
1456 }
1457 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1458 }
1459 <ObjCSkipStr>[^\n\"$\\]* { yyextra->currentCtx->format+=yytext; }
1460 <ObjCSkipStr>\\. { yyextra->currentCtx->format+=yytext; }
1461 <ObjCSkipStr>"\"" { yyextra->currentCtx->format+=yytext;
1462 BEGIN(yyextra->lastStringContext);
1463 }
1464 <ObjCCall,ObjCMName>{CHARLIT} { yyextra->currentCtx->format+=yytext; }
1465 <ObjCCall,ObjCMName>"@"?"\"" { yyextra->currentCtx->format+=yytext;
1466 yyextra->lastStringContext=YY_START;
1467 BEGIN(ObjCSkipStr);
1468 }
1469 <ObjCCall,ObjCMName,ObjCSkipStr>"$" { yyextra->currentCtx->format+="$$"; }
1470 <ObjCCall,ObjCMName>"(" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount++; }
1471 <ObjCCall,ObjCMName>")" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount--; }
1472 <ObjCSkipStr>"@"/"\"" { // needed to prevent matching the global rule (for C#)
1473 yyextra->currentCtx->format+=yytext;
1474 }
1475 <ObjCCall,ObjCMName,ObjCSkipStr>{ID} { yyextra->currentCtx->format+=escapeWord(yyscanner,yytext); }
1476 <ObjCCall,ObjCMName,ObjCSkipStr>. { yyextra->currentCtx->format+=*yytext; }
1477 <ObjCCall,ObjCMName,ObjCSkipStr>\n { yyextra->currentCtx->format+=*yytext; }
1478
1479 <Body>"]" {
1480 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1481 yyextra->code->codify(yytext);
1482 // TODO: nested arrays like: a[b[0]->func()]->func()
1483 yyextra->name = yyextra->saveName;
1484 yyextra->type = yyextra->saveType;
1485 }
1486 <Body>[0-9]+ {
1487 yyextra->code->codify(yytext);
1488 }
1489 <Body>[0-9]+[xX][0-9A-Fa-f]+ {
1490 yyextra->code->codify(yytext);
1491 }
1492 <MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
1493 //addParmType(yyscanner);
1494 //yyextra->parmName=yytext;
1495 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
1496 startFontClass(yyscanner,"keyword");
1497 yyextra->code->codify(yytext);
1498 endFontClass(yyscanner);
1499 }
1500 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKW}/([^a-z_A-Z0-9]) {
1501 addParmType(yyscanner);
1502 yyextra->parmName=yytext;
1503 startFontClass(yyscanner,"keywordtype");
1504 yyextra->code->codify(yytext);
1505 endFontClass(yyscanner);
1506 }
1507 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKWSL}/([^a-z_A-Z0-9]) {
1508 if (yyextra->lang!=SrcLangExt_Slice)
1509 {
1510 REJECT;
1511 }
1512 else
1513 {
1514 addParmType(yyscanner);
1515 yyextra->parmName=yytext;
1516 startFontClass(yyscanner,"keywordtype");
1517 yyextra->code->codify(yytext);
1518 endFontClass(yyscanner);
1519 }
1520 }
1521 <MemberCall2,FuncCall>{FLOWKW}/([^a-z_A-Z0-9]) {
1522 addParmType(yyscanner);
1523 yyextra->parmName=yytext;
1524 startFontClass(yyscanner,"keywordflow");
1525 yyextra->code->codify(yytext);
1526 endFontClass(yyscanner);
1527 }
1528 <MemberCall2,FuncCall>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1529 incrementFlowKeyWordCount(yyscanner);
1530 addParmType(yyscanner);
1531 yyextra->parmName=yytext;
1532 startFontClass(yyscanner,"keywordflow");
1533 yyextra->code->codify(yytext);
1534 endFontClass(yyscanner);
1535 }
1536 <MemberCall2,FuncCall>("::")?{ID}(({B}*"<"[^\n\[\](){}<>]*">")?({B}*"::"{B}*{ID})?)* {
1537 if (isCastKeyword(yytext))
1538 {
1539 REJECT;
1540 }
1541 addParmType(yyscanner);
1542 yyextra->parmName=yytext;
1543 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1544 }
1545 <FuncCall>";" { // probably a cast, not a function call
1546 yyextra->code->codify(yytext);
1547 yyextra->inForEachExpression = FALSE;
1548 BEGIN( Body );
1549 }
1550 <MemberCall2,FuncCall>, {
1551 yyextra->code->codify(yytext);
1552 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1553 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1554 }
1555 <MemberCall2,FuncCall>"{" {
1556 if (yyextra->bracketCount>0)
1557 {
1558 yyextra->code->codify(yytext);
1559 yyextra->skipInlineInitContext=YY_START;
1560 yyextra->curlyCount=0;
1561 BEGIN(InlineInit);
1562 }
1563 else
1564 {
1565 REJECT;
1566 }
1567 }
1568 <InlineInit>"{" { yyextra->curlyCount++;
1569 yyextra->code->codify(yytext);
1570 }
1571 <InlineInit>"}" {
1572 yyextra->code->codify(yytext);
1573 if (--yyextra->curlyCount<=0)
1574 {
1575 BEGIN(yyextra->skipInlineInitContext);
1576 }
1577 }
1578 <InlineInit>\n {
1579 codifyLines(yyscanner,yytext);
1580 }
1581 <InlineInit>. {
1582 yyextra->code->codify(yytext);
1583 }
1584 <MemberCall2,FuncCall>"(" {
1585 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1586 yyextra->code->codify(yytext);
1587 yyextra->bracketCount++;
1588 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
1589 if (YY_START==FuncCall && !yyextra->insideBody)
1590 {
1591 yyextra->theVarContext.pushScope();
1592 }
1593 }
1594 <MemberCall2,FuncCall>{OPERATOR} { // operator
1595 if (qstrcmp(yytext,"*") &&
1596 qstrcmp(yytext,"&") &&
1597 qstrcmp(yytext,"^") &&
1598 qstrcmp(yytext,"%")) // typically a pointer or reference
1599 {
1600 // not a * or &, or C++/CLI's ^ or %
1601 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1602 }
1603 yyextra->code->codify(yytext);
1604 }
1605 <MemberCall,MemberCall2,FuncCall>("*"{B}*)?")" {
1606 if (yytext[0]==')') // no a pointer cast
1607 {
1608 DBG_CTX((stderr,"addVariable(%s,%s)\n",qPrint(yyextra->parmType),qPrint(yyextra->parmName)));
1609 if (yyextra->parmType.isEmpty())
1610 {
1611 yyextra->parmType=yyextra->parmName;
1612 yyextra->parmName.resize(0);
1613 }
1614 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1615 }
1616 else
1617 {
1618 yyextra->parmType = yyextra->parmName;
1619 yyextra->parmName.resize(0);
1620 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1621 }
1622 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1623 yyextra->inForEachExpression = FALSE;
1624 //yyextra->theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b().
1625 yyextra->code->codify(yytext);
1626 if (--yyextra->bracketCount<=0)
1627 {
1628 if (yyextra->name.isEmpty())
1629 {
1630 BEGIN( Body );
1631 }
1632 else
1633 {
1634 BEGIN( CallEnd );
1635 }
1636 }
1637 }
1638 <CallEnd>[ \t\n]* { codifyLines(yyscanner,yytext); }
1639 /*
1640 <MemberCall2,FuncCall>")"[ \t\n]*[;:] {
1641 */
1642 <CallEnd>[;:] {
1643 codifyLines(yyscanner,yytext);
1644 yyextra->bracketCount=0;
1645 if (*yytext==';') yyextra->searchingForBody=FALSE;
1646 if (!yyextra->type.isEmpty())
1647 {
1648 DBG_CTX((stderr,"add variable yyextra->type=%s yyextra->name=%s)\n",qPrint(yyextra->type),qPrint(yyextra->name)));
1649 addVariable(yyscanner,yyextra->type,yyextra->name);
1650 }
1651 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1652 yyextra->theCallContext.setScope(ScopedTypeVariant());
1653 if (*yytext==';' || yyextra->insideBody)
1654 {
1655 if (!yyextra->insideBody)
1656 {
1657 yyextra->theVarContext.popScope();
1658 }
1659 yyextra->name.resize(0);yyextra->type.resize(0);
1660 BEGIN( Body );
1661 }
1662 else
1663 {
1664 yyextra->bracketCount=0;
1665 BEGIN( SkipInits );
1666 }
1667 }
1668 <CallEnd>{ENDQopt}/{BN}*(";"|"="|"throw"{BN}*"(") {
1669 startFontClass(yyscanner,"keyword");
1670 codifyLines(yyscanner,yytext);
1671 endFontClass(yyscanner);
1672 }
1673 <CallEnd,OldStyleArgs>("const"|"volatile"|"sealed"|"override")*({BN}+("const"|"volatile"|"sealed"|"override"))*{BN}*"{" {
1674 if (yyextra->insideBody)
1675 {
1676 yyextra->theVarContext.pushScope();
1677 }
1678 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1679 //yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1680 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1681 int index = yyextra->name.findRev("::");
1682 DBG_CTX((stderr,"yyextra->name=%s\n",qPrint(yyextra->name)));
1683 if (index!=-1)
1684 {
1685 QCString scope = yyextra->name.left((uint)index);
1686 if (!yyextra->classScope.isEmpty()) scope.prepend((yyextra->classScope+"::"));
1687 const ClassDef *cd=yyextra->symbolResolver.resolveClass(Doxygen::globalScope,scope);
1688 if (cd)
1689 {
1690 setClassScope(yyscanner,cd->name());
1691 yyextra->scopeStack.push(SCOPEBLOCK);
1692 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1693 }
1694 else
1695 {
1696 //setClassScope(yyscanner,yyextra->realScope);
1697 yyextra->scopeStack.push(INNERBLOCK);
1698 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1699 }
1700 }
1701 else
1702 {
1703 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1704 yyextra->scopeStack.push(INNERBLOCK);
1705 }
1706 yytext[yyleng-1]='\0';
1707 QCString cv(yytext);
1708 if (!cv.stripWhiteSpace().isEmpty())
1709 {
1710 startFontClass(yyscanner,"keyword");
1711 codifyLines(yyscanner,yytext);
1712 endFontClass(yyscanner);
1713 }
1714 else // just whitespace
1715 {
1716 codifyLines(yyscanner,yytext);
1717 }
1718 yyextra->code->codify("{");
1719 if (yyextra->searchingForBody)
1720 {
1721 yyextra->searchingForBody=FALSE;
1722 yyextra->insideBody=TRUE;
1723 }
1724 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1725 yyextra->type.resize(0); yyextra->name.resize(0);
1726 BEGIN( Body );
1727 }
1728 <CallEnd>"try" { // function-try-block
1729 startFontClass(yyscanner,"keyword");
1730 yyextra->code->codify(yytext);
1731 endFontClass(yyscanner);
1732 yyextra->inFunctionTryBlock=TRUE;
1733 }
1734 <CallEnd>"requires" { // function-try-block
1735 startFontClass(yyscanner,"keyword");
1736 yyextra->code->codify(yytext);
1737 endFontClass(yyscanner);
1738 }
1739 <CallEnd>{ID} {
1740 if (yyextra->insideBody || !yyextra->parmType.isEmpty())
1741 {
1742 REJECT;
1743 }
1744 // could be K&R style definition
1745 addParmType(yyscanner);
1746 yyextra->parmName=yytext;
1747 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1748 BEGIN(OldStyleArgs);
1749 }
1750 <OldStyleArgs>{ID} {
1751 addParmType(yyscanner);
1752 yyextra->parmName=yytext;
1753 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1754 }
1755 <OldStyleArgs>[,;] {
1756 yyextra->code->codify(yytext);
1757 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1758 if (*yytext==';') yyextra->parmType.resize(0);
1759 yyextra->parmName.resize(0);
1760 }
1761 <CallEnd,OldStyleArgs>"#" {
1762 startFontClass(yyscanner,"preprocessor");
1763 yyextra->lastSkipCppContext = Body;
1764 yyextra->code->codify(yytext);
1765 BEGIN( SkipCPP );
1766 }
1767 <CallEnd>. {
1768 unput(*yytext);
1769 if (!yyextra->insideBody)
1770 {
1771 yyextra->theVarContext.popScope();
1772 }
1773 yyextra->name.resize(0);yyextra->args.resize(0);
1774 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1775 BEGIN( Body );
1776 }
1777 <SkipInits>";" {
1778 yyextra->code->codify(yytext);
1779 yyextra->type.resize(0); yyextra->name.resize(0);
1780 BEGIN( Body );
1781 }
1782 <SkipInits>"{" {
1783 yyextra->code->codify(yytext);
1784 if (yyextra->searchingForBody)
1785 {
1786 yyextra->searchingForBody=FALSE;
1787 yyextra->insideBody=TRUE;
1788 }
1789 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1790 if (yyextra->name.find("::")!=-1)
1791 {
1792 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1793 yyextra->scopeStack.push(SCOPEBLOCK);
1794 setClassScope(yyscanner,yyextra->realScope);
1795 }
1796 else
1797 {
1798 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1799 yyextra->scopeStack.push(INNERBLOCK);
1800 }
1801 yyextra->type.resize(0); yyextra->name.resize(0);
1802 BEGIN( Body );
1803 }
1804 <SkipInits>{ID}{B}*"{" {
1805 QCString text(yytext);
1806 int bracketPos = text.find('{');
1807 int spacePos = text.find(' ');
1808 int len = spacePos==-1 ? bracketPos : spacePos;
1809 generateClassOrGlobalLink(yyscanner,*yyextra->code,text.left(len));
1810 yyextra->code->codify(QCString(yytext+len));
1811 }
1812 <SkipInits>{ID} {
1813 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1814 }
1815 <FuncCall>{ID}/"(" {
1816 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1817 }
1818 <FuncCall>{ID}/("."|"->") {
1819 yyextra->name=yytext;
1820 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1821 BEGIN( MemberCall2 );
1822 }
1823 <FuncCall,MemberCall2>("("{B}*("*"{B}*)+{ID}+{B}*")"{B}*)/("."|"->") {
1824 yyextra->code->codify(yytext);
1825 uint s=0;while (!isId(yytext[s])) s++;
1826 uint e=(uint)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1827 yyextra->name=((QCString)yytext).mid(s,e-s+1);
1828 BEGIN( MemberCall2 );
1829 }
1830 <MemberCall2>{ID}/([ \t\n]*"(") {
1831 if (!yyextra->args.isEmpty())
1832 generateMemberLink(yyscanner,*yyextra->code,yyextra->args,yytext);
1833 else
1834 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1835 yyextra->args.resize(0);
1836 BEGIN( FuncCall );
1837 }
1838 <MemberCall2>{ID}/([ \t\n]*("."|"->")) {
1839 //yyextra->code->codify(yytext);
1840 yyextra->name=yytext;
1841 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1842 BEGIN( MemberCall2 );
1843 }
1844 <MemberCall2>"->"|"." {
1845 if (yytext[0]=='-') // -> could be overloaded
1846 {
1847 updateCallContextForSmartPointer(yyscanner);
1848 }
1849 yyextra->code->codify(yytext);
1850 yyextra->memCallContext = YY_START;
1851 BEGIN( MemberCall );
1852 }
1853 <SkipComment>{CCS}("!"?){CCE} {
1854 yyextra->code->codify(yytext);
1855 endFontClass(yyscanner);
1856 BEGIN( yyextra->lastCContext ) ;
1857 }
1858 <SkipComment>{CPPC}|{CCS} {
1859 yyextra->code->codify(yytext);
1860 }
1861 <SkipComment>[^*\/\n]+ {
1862 yyextra->code->codify(yytext);
1863 }
1864 <SkipComment>[ \t]*{CCE} {
1865 yyextra->code->codify(yytext);
1866 endFontClass(yyscanner);
1867 if (yyextra->lastCContext==SkipCPP)
1868 {
1869 startFontClass(yyscanner,"preprocessor");
1870 }
1871 BEGIN( yyextra->lastCContext ) ;
1872 }
1873 <SkipCxxComment>[^\r\n]*"\\"[\r]?\n { // line continuation
1874 codifyLines(yyscanner,yytext);
1875 }
1876 <SkipCxxComment>[^\r\n]+ {
1877 yyextra->code->codify(yytext);
1878 }
1879 <SkipCxxComment>\r
1880 <SkipCxxComment>\n {
1881 unput('\n');
1882 endFontClass(yyscanner);
1883 BEGIN( yyextra->lastCContext ) ;
1884 }
1885 <SkipCxxComment>. {
1886 yyextra->code->codify(yytext);
1887 }
1888 <RemoveSpecialCComment>{CCE}{B}*\n({B}*\n)*({B}*(({CPPC}"@"[{}])|({CCS}"@"[{}]{CCE})){B}*\n)?{B}*{CCS}[*!]/{NCOMM} {
1889 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1890 }
1891 <RemoveSpecialCComment>{CCE}{B}*\n({B}*\n)*({B}*(({CPPC}"@"[{}])|({CCS}"@"[{}]{CCE})){B}*\n)? {
1892 if (yyextra->lastSpecialCContext==SkipCxxComment)
1893 { // force end of C++ comment here
1894 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1895 nextCodeLine(yyscanner);
1896 endFontClass(yyscanner);
1897 BEGIN( yyextra->lastCContext ) ;
1898 }
1899 else
1900 {
1901 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1902 if (yytext[yyleng-1]=='\n')
1903 {
1904 yyextra->yyLineNr--;
1905 unput('\n');
1906 }
1907 else
1908 {
1909 nextCodeLine(yyscanner);
1910 }
1911 BEGIN(yyextra->lastSpecialCContext);
1912 }
1913 }
1914 <RemoveSpecialCComment>{CCE} {
1915 BEGIN(yyextra->lastSpecialCContext);
1916 }
1917 <RemoveSpecialCComment>[^*\n]+
1918 <RemoveSpecialCComment>{CPPC}|{CCS}
1919 <RemoveSpecialCComment>\n { yyextra->yyLineNr++; }
1920 <RemoveSpecialCComment>.
1921 <MemberCall>[^a-z_A-Z0-9(\n] {
1922 yyextra->code->codify(yytext);
1923 yyextra->type.resize(0);
1924 yyextra->name.resize(0);
1925 BEGIN(yyextra->memCallContext);
1926 }
1927 <*>\n({B}*{CPPC}[!/][^\n]*\n)+ { // remove special one-line comment
1928 if (YY_START==SkipCPP) REJECT;
1929 if (Config_getBool(STRIP_CODE_COMMENTS))
1930 {
1931 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1932 nextCodeLine(yyscanner);
1933 }
1934 else
1935 {
1936 startFontClass(yyscanner,"comment");
1937 codifyLines(yyscanner,yytext);
1938 endFontClass(yyscanner);
1939 }
1940 if (YY_START==SkipCxxComment)
1941 {
1942 endFontClass(yyscanner);
1943 BEGIN( yyextra->lastCContext ) ;
1944 }
1945 }
1946 <SkipCPP>\n/(.|\n) {
1947 endFontClass(yyscanner);
1948 BEGIN( yyextra->lastSkipCppContext ) ;
1949 unput('\n');
1950 }
1951 <*>\n{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
1952 if (Config_getBool(STRIP_CODE_COMMENTS))
1953 {
1954 yyextra->yyLineNr+=2;
1955 nextCodeLine(yyscanner);
1956 }
1957 else
1958 {
1959 startFontClass(yyscanner,"comment");
1960 codifyLines(yyscanner,yytext);
1961 endFontClass(yyscanner);
1962 }
1963 if (YY_START==SkipCxxComment)
1964 {
1965 endFontClass(yyscanner);
1966 BEGIN( yyextra->lastCContext ) ;
1967 }
1968 }
1969 <*>\n{B}*{CCS}"@"[{}] { // remove one-line group marker
1970 if (Config_getBool(STRIP_CODE_COMMENTS))
1971 {
1972 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
1973 yyextra->yyLineNr++;
1974 BEGIN(RemoveSpecialCComment);
1975 }
1976 else
1977 {
1978 // check is to prevent getting stuck in skipping C++ comments
1979 if (YY_START != SkipComment && YY_START != SkipCxxComment)
1980 {
1981 yyextra->lastCContext = YY_START ;
1982 }
1983 startFontClass(yyscanner,"comment");
1984 codifyLines(yyscanner,yytext);
1985 BEGIN(SkipComment);
1986 }
1987 }
1988 <*>^{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
1989 if (Config_getBool(STRIP_CODE_COMMENTS))
1990 {
1991 yyextra->yyLineNr++;
1992 nextCodeLine(yyscanner);
1993 }
1994 else
1995 {
1996 startFontClass(yyscanner,"comment");
1997 codifyLines(yyscanner,yytext);
1998 endFontClass(yyscanner);
1999 }
2000 }
2001 <*>^{B}*{CCS}"@"[{}] { // remove multi-line group marker
2002 if (Config_getBool(STRIP_CODE_COMMENTS))
2003 {
2004 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2005 BEGIN(RemoveSpecialCComment);
2006 }
2007 else
2008 {
2009 // check is to prevent getting stuck in skipping C++ comments
2010 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2011 {
2012 yyextra->lastCContext = YY_START ;
2013 }
2014 startFontClass(yyscanner,"comment");
2015 yyextra->code->codify(yytext);
2016 BEGIN(SkipComment);
2017 }
2018 }
2019 <*>^{B}*{CPPC}[!/][^\n]* { // remove special one-line comment
2020 if (!Config_getBool(STRIP_CODE_COMMENTS))
2021 {
2022 startFontClass(yyscanner,"comment");
2023 codifyLines(yyscanner,yytext);
2024 endFontClass(yyscanner);
2025 }
2026 }
2027 <*>{CPPC}[!/][^\n]* { // strip special one-line comment
2028 if (YY_START==SkipComment || YY_START==SkipString) REJECT;
2029 if (!Config_getBool(STRIP_CODE_COMMENTS))
2030 {
2031 startFontClass(yyscanner,"comment");
2032 codifyLines(yyscanner,yytext);
2033 endFontClass(yyscanner);
2034 }
2035 }
2036 <*>\n{B}*{CCS}[!*]/{NCOMM} {
2037 if (Config_getBool(STRIP_CODE_COMMENTS))
2038 {
2039 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2040 yyextra->yyLineNr++;
2041 BEGIN(RemoveSpecialCComment);
2042 }
2043 else
2044 {
2045 // check is to prevent getting stuck in skipping C++ comments
2046 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2047 {
2048 yyextra->lastCContext = YY_START ;
2049 }
2050 startFontClass(yyscanner,"comment");
2051 codifyLines(yyscanner,yytext);
2052 BEGIN(SkipComment);
2053 }
2054 }
2055 <*>^{B}*{CCS}"*"[*]+/[^/] { // special C "banner" comment block at a new line
2056 if (Config_getBool(JAVADOC_BANNER) && Config_getBool(STRIP_CODE_COMMENTS))
2057 {
2058 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2059 BEGIN(RemoveSpecialCComment);
2060 }
2061 else
2062 {
2063 // check is to prevent getting stuck in skipping C++ comments
2064 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2065 {
2066 yyextra->lastCContext = YY_START ;
2067 }
2068 startFontClass(yyscanner,"comment");
2069 yyextra->code->codify(yytext);
2070 BEGIN(SkipComment);
2071 }
2072 }
2073 <*>^{B}*{CCS}[!*]/{NCOMM} { // special C comment block at a new line
2074 if (Config_getBool(STRIP_CODE_COMMENTS))
2075 {
2076 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2077 BEGIN(RemoveSpecialCComment);
2078 }
2079 else
2080 {
2081 // check is to prevent getting stuck in skipping C++ comments
2082 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2083 {
2084 yyextra->lastCContext = YY_START ;
2085 }
2086 startFontClass(yyscanner,"comment");
2087 yyextra->code->codify(yytext);
2088 BEGIN(SkipComment);
2089 }
2090 }
2091 <*>{CCS}[!*]/{NCOMM} { // special C comment block half way a line
2092 if (YY_START==SkipString) REJECT;
2093 if (Config_getBool(STRIP_CODE_COMMENTS))
2094 {
2095 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2096 BEGIN(RemoveSpecialCComment);
2097 }
2098 else
2099 {
2100 // check is to prevent getting stuck in skipping C++ comments
2101 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2102 {
2103 yyextra->lastCContext = YY_START ;
2104 }
2105 startFontClass(yyscanner,"comment");
2106 yyextra->code->codify(yytext);
2107 BEGIN(SkipComment);
2108 }
2109 }
2110 <*>{CCS}("!"?){CCE} {
2111 if (YY_START==SkipString) REJECT;
2112 if (!Config_getBool(STRIP_CODE_COMMENTS))
2113 {
2114 startFontClass(yyscanner,"comment");
2115 yyextra->code->codify(yytext);
2116 endFontClass(yyscanner);
2117 }
2118 }
2119 <SkipComment>[^\*\n]+ {
2120 yyextra->code->codify(yytext);
2121 }
2122 <*>{CCS} {
2123 startFontClass(yyscanner,"comment");
2124 yyextra->code->codify(yytext);
2125 // check is to prevent getting stuck in skipping C++ comments
2126 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2127 {
2128 yyextra->lastCContext = YY_START ;
2129 }
2130 BEGIN( SkipComment ) ;
2131 }
2132 <*>@\" { // C# verbatim string
2133 startFontClass(yyscanner,"stringliteral");
2134 yyextra->code->codify(yytext);
2135 yyextra->lastVerbStringContext=YY_START;
2136 BEGIN(SkipVerbString);
2137 }
2138 <*>{CPPC} {
2139 startFontClass(yyscanner,"comment");
2140 yyextra->code->codify(yytext);
2141 yyextra->lastCContext = YY_START ;
2142 BEGIN( SkipCxxComment ) ;
2143 }
2144 <*>"("|"[" {
2145 yyextra->code->codify(yytext);
2146 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
2147 }
2148 <*>")"|"]" {
2149 yyextra->code->codify(yytext);
2150 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
2151 }
2152 <*>\n {
2153 yyextra->yyColNr++;
2154 codifyLines(yyscanner,yytext);
2155 }
2156 <*>[\x80-\xFF]* { // keep utf8 characters together...
2157 yyextra->yyColNr+=yyleng;
2158 yyextra->code->codify(yytext);
2159 }
2160 <*>. {
2161 yyextra->yyColNr++;
2162 yyextra->code->codify(yytext);
2163 }
2164 /*
2165 <*>([ \t\n]*"\n"){2,} { // combine multiple blank lines
2166 //QCString sepLine=yytext;
2167 //yyextra->code->codify("\n\n");
2168 //yyextra->yyLineNr+=sepLine.contains('\n');
2169 //char sepLine[3]="\n\n";
2170 codifyLines(yyscanner,yytext);
2171 }
2172 */
2173
2174 %%
2175
2176 /*@ ----------------------------------------------------------------------------
2177 */
2178
2179 static bool startsWithKeyword(const QCString &str,const QCString &kw)
2180 {
2181 if (str.length()<kw.length()) return false; // string too short to match
2182 return str==kw || // exact match
2183 (str.startsWith(kw) && !isId(str.at(kw.length()))); // match that is not a substring
2184 }
2185
2186 static void addVariable(yyscan_t yyscanner,QCString type,QCString name)
2187 {
2188 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2189 DBG_CTX((stderr,"VariableContext::addVariable(%s,%s)\n",qPrint(type),qPrint(name)));
2190 QCString ltype = type.simplifyWhiteSpace();
2191 QCString lname = name.simplifyWhiteSpace();
2192 if (ltype.left(7)=="struct ")
2193 {
2194 ltype = ltype.right(ltype.length()-7);
2195 }
2196 else if (ltype.left(6)=="union ")
2197 {
2198 ltype = ltype.right(ltype.length()-6);
2199 }
2200 if (ltype.isEmpty() || lname.isEmpty()) return;
2201 DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' currentDefinition=%s\n",
2202 qPrint(ltype),qPrint(lname),yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>"));
2203 auto it = yyextra->codeClassMap.find(ltype.str());
2204 if (it!=yyextra->codeClassMap.end()) // look for class definitions inside the code block
2205 {
2206 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2207 yyextra->theVarContext.addVariable(lname,std::move(it->second)); // add it to a list
2208 }
2209 else
2210 {
2211 const ClassDef *varDef = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ltype);
2212 int i=0;
2213 if (varDef)
2214 {
2215 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2216 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
2217 }
2218 else if ((i=ltype.find('<'))!=-1)
2219 {
2220 // probably a template class
2221 QCString typeName(ltype.left(i));
2222 addVariable(yyscanner,typeName,name);
2223 }
2224 else
2225 {
2226 if (!yyextra->theVarContext.atGlobalScope()) // for local variables add a dummy entry so the name
2227 // is hidden to avoid false links to global variables with the same name
2228 // TODO: make this work for namespaces as well!
2229 {
2230 DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",qPrint(lname)));
2231 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant());
2232 }
2233 else
2234 {
2235 DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
2236 }
2237 }
2238 }
2239 }
2240
2241 //-------------------------------------------------------------------
2242
2243 /*! add class/namespace name s to the scope */
2244 static void pushScope(yyscan_t yyscanner,const QCString &s)
2245 {
2246 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2247 yyextra->classScopeLengthStack.push(int(yyextra->classScope.length()));
2248 if (yyextra->classScope.isEmpty() || leftScopeMatch(s,yyextra->classScope))
2249 {
2250 yyextra->classScope = s;
2251 }
2252 else
2253 {
2254 yyextra->classScope += "::";
2255 yyextra->classScope += s;
2256 }
2257 DBG_CTX((stderr,"pushScope(%s) result: '%s'\n",qPrint(s),qPrint(yyextra->classScope)));
2258 }
2259
2260
2261 /*! remove the top class/namespace name from the scope */
2262 static void popScope(yyscan_t yyscanner)
2263 {
2264 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2265 if (!yyextra->classScopeLengthStack.empty())
2266 {
2267 int length = yyextra->classScopeLengthStack.top();
2268 yyextra->classScopeLengthStack.pop();
2269 yyextra->classScope.truncate(length);
2270 }
2271 else
2272 {
2273 //err("Too many end of scopes found!\n");
2274 }
2275 DBG_CTX((stderr,"popScope() result: '%s'\n",qPrint(yyextra->classScope)));
2276 }
2277
2278 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
2279 {
2280 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2281 if (Doxygen::searchIndex)
2282 {
2283 std::lock_guard<std::mutex> lock(g_searchIndexMutex);
2284 if (yyextra->searchCtx)
2285 {
2286 yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
2287 }
2288 else
2289 {
2290 yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
2291 }
2292 }
2293 }
2294
2295 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text)
2296 {
2297 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2298 if (Doxygen::searchIndex)
2299 {
2300 std::lock_guard<std::mutex> lock(g_searchIndexMutex);
2301 yyextra->code->addWord(text,FALSE);
2302 }
2303 }
2304
2305 static void addToSearchIndex(yyscan_t yyscanner,const char *text)
2306 {
2307 addToSearchIndex(yyscanner,QCString(text));
2308 }
2309
2310
2311 static void setClassScope(yyscan_t yyscanner,const QCString &name)
2312 {
2313 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2314 DBG_CTX((stderr,"setClassScope(%s)\n",qPrint(name)));
2315 QCString n=name;
2316 n=n.simplifyWhiteSpace();
2317 int ts=n.find('<'); // start of template
2318 int te=n.findRev('>'); // end of template
2319 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
2320 if (ts!=-1 && te!=-1 && te>ts)
2321 {
2322 // remove template from scope
2323 n=n.left(ts)+n.right(n.length()-te-1);
2324 }
2325 while (!yyextra->classScopeLengthStack.empty())
2326 {
2327 popScope(yyscanner);
2328 }
2329 yyextra->classScope.resize(0);
2330 int i;
2331 while ((i=n.find("::"))!=-1)
2332 {
2333 pushScope(yyscanner,n.left(i));
2334 n = n.mid(i+2);
2335 }
2336 pushScope(yyscanner,n);
2337 DBG_CTX((stderr,"--->New class scope '%s'\n",qPrint(yyextra->classScope)));
2338 }
2339
2340 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
2341 * is TRUE. If a definition starts at the current line, then the line
2342 * number is linked to the documentation of that definition.
2343 */
2344 static void startCodeLine(yyscan_t yyscanner)
2345 {
2346 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2347 //if (yyextra->currentFontClass) { yyextra->code->endFontClass(yyscanner); }
2348 if (yyextra->sourceFileDef && yyextra->lineNumbers)
2349 {
2350 //QCString lineNumber,lineAnchor;
2351 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
2352 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2353
2354 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
2355 DBG_CTX((stderr,"%s:startCodeLine(%d)=%p\n",qPrint(yyextra->sourceFileDef->name()),yyextra->yyLineNr,(void*)d));
2356 if (!yyextra->includeCodeFragment && d)
2357 {
2358 yyextra->currentDefinition = d;
2359 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
2360 yyextra->insideBody = FALSE;
2361 yyextra->searchingForBody = TRUE;
2362 yyextra->realScope = d->name();
2363 //yyextra->classScope = "";
2364 yyextra->type.resize(0);
2365 yyextra->name.resize(0);
2366 yyextra->args.resize(0);
2367 yyextra->parmType.resize(0);
2368 yyextra->parmName.resize(0);
2369 DBG_CTX((stderr,"Real scope: '%s'\n",qPrint(yyextra->realScope)));
2370 yyextra->bodyCurlyCount = 0;
2371 QCString lineAnchor;
2372 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2373 if (yyextra->currentMemberDef)
2374 {
2375 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
2376 yyextra->currentMemberDef->getOutputFileBase(),
2377 yyextra->currentMemberDef->anchor(),
2378 yyextra->yyLineNr,!yyextra->includeCodeFragment);
2379 setCurrentDoc(yyscanner,lineAnchor);
2380 }
2381 else if (d->isLinkableInProject())
2382 {
2383 yyextra->code->writeLineNumber(d->getReference(),
2384 d->getOutputFileBase(),
2385 QCString(),yyextra->yyLineNr,!yyextra->includeCodeFragment);
2386 setCurrentDoc(yyscanner,lineAnchor);
2387 }
2388 }
2389 else
2390 {
2391 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
2392 !yyextra->includeCodeFragment);
2393 }
2394 }
2395 DBG_CTX((stderr,"startCodeLine(%d)\n",yyextra->yyLineNr));
2396 yyextra->code->startCodeLine(yyextra->sourceFileDef && yyextra->lineNumbers);
2397 yyextra->insideCodeLine = true;
2398 if (yyextra->currentFontClass)
2399 {
2400 yyextra->code->startFontClass(QCString(yyextra->currentFontClass));
2401 }
2402 }
2403
2404
2405
2406 static void endCodeLine(yyscan_t yyscanner)
2407 {
2408 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2409 DBG_CTX((stderr,"endCodeLine(%d)\n",yyextra->yyLineNr));
2410 endFontClass(yyscanner);
2411 yyextra->code->endCodeLine();
2412 yyextra->insideCodeLine = false;
2413 }
2414
2415 static void nextCodeLine(yyscan_t yyscanner)
2416 {
2417 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2418 const char * fc = yyextra->currentFontClass;
2419 if (yyextra->insideCodeLine)
2420 {
2421 endCodeLine(yyscanner);
2422 }
2423 if (yyextra->yyLineNr<yyextra->inputLines)
2424 {
2425 yyextra->currentFontClass = fc;
2426 startCodeLine(yyscanner);
2427 }
2428 }
2429
2430 /*! write a code fragment 'text' that may span multiple lines, inserting
2431 * line numbers for each line.
2432 */
2433 static void codifyLines(yyscan_t yyscanner,const QCString &text)
2434 {
2435 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2436 DBG_CTX((stderr,"codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,qPrint(text)));
2437 if (text.isEmpty()) return;
2438 const char *p=text.data(),*sp=p;
2439 char c;
2440 bool done=FALSE;
2441 while (!done)
2442 {
2443 sp=p;
2444 while ((c=*p++) && c!='\n') { yyextra->yyColNr++; }
2445 if (c=='\n')
2446 {
2447 yyextra->yyLineNr++;
2448 yyextra->yyColNr=1;
2449 int l = (int)(p-sp-1);
2450 char *tmp = (char*)malloc(l+1);
2451 memcpy(tmp,sp,l);
2452 tmp[l]='\0';
2453 yyextra->code->codify(QCString(tmp));
2454 free(tmp);
2455 nextCodeLine(yyscanner);
2456 }
2457 else
2458 {
2459 yyextra->code->codify(QCString(sp));
2460 done=TRUE;
2461 }
2462 }
2463 }
2464
2465 static void codifyLines(yyscan_t yyscanner,const char *text)
2466 {
2467 codifyLines(yyscanner,QCString(text));
2468 }
2469
2470 static void incrementFlowKeyWordCount(yyscan_t yyscanner)
2471 {
2472 std::lock_guard<std::mutex> lock(g_countFlowKeywordsMutex);
2473 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2474 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
2475 {
2476 MemberDefMutable *md = toMemberDefMutable(yyextra->currentMemberDef);
2477 if (md)
2478 {
2479 md->incrementFlowKeyWordCount();
2480 }
2481 }
2482 }
2483
2484 /*! writes a link to a fragment \a text that may span multiple lines, inserting
2485 * line numbers for each line. If \a text contains newlines, the link will be
2486 * split into multiple links with the same destination, one for each line.
2487 */
2488 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
2489 const Definition *d,
2490 const QCString &text)
2491 {
2492 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2493 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
2494 yyextra->tooltipManager.addTooltip(ol,d);
2495 QCString ref = d->getReference();
2496 QCString file = d->getOutputFileBase();
2497 QCString anchor = d->anchor();
2498 QCString tooltip;
2499 if (!sourceTooltips) // fall back to simple "title" tooltips
2500 {
2501 tooltip = d->briefDescriptionAsTooltip();
2502 }
2503 bool done=FALSE;
2504 const char *p=text.data();
2505 while (!done)
2506 {
2507 const char *sp=p;
2508 char c;
2509 while ((c=*p++) && c!='\n') { }
2510 if (c=='\n')
2511 {
2512 yyextra->yyLineNr++;
2513 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),qPrint(QCString(sp,p-sp-1))));
2514 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
2515 nextCodeLine(yyscanner);
2516 }
2517 else
2518 {
2519 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),sp));
2520 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp),tooltip);
2521 done=TRUE;
2522 }
2523 }
2524 }
2525
2526 static void addType(yyscan_t yyscanner)
2527 {
2528 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2529 if (yyextra->name=="const") { yyextra->name.resize(0); return; }
2530 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2531 yyextra->type += yyextra->name ;
2532 yyextra->name.resize(0) ;
2533 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2534 yyextra->type += yyextra->args ;
2535 yyextra->args.resize(0) ;
2536 }
2537
2538 static void addParmType(yyscan_t yyscanner)
2539 {
2540 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2541 if (yyextra->parmName=="const") { yyextra->parmName.resize(0); return; }
2542 if (!yyextra->parmType.isEmpty()) yyextra->parmType += ' ' ;
2543 yyextra->parmType += yyextra->parmName ;
2544 yyextra->parmName.resize(0) ;
2545 }
2546
2547 // TODO: make this have a scope only effect, at least not modifying the FileDef object.
2548 static void addUsingDirective(yyscan_t yyscanner,const char *name)
2549 {
2550 std::lock_guard<std::mutex> lock(g_usingDirectiveMutex);
2551 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2552 if (yyextra->sourceFileDef && name)
2553 {
2554 const NamespaceDef *nd = Doxygen::namespaceLinkedMap->find(name);
2555 if (nd)
2556 {
2557 const_cast<FileDef*>(yyextra->sourceFileDef)->addUsingDirective(nd);
2558 }
2559 }
2560 }
2561
2562 static void setParameterList(yyscan_t yyscanner,const MemberDef *md)
2563 {
2564 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2565 yyextra->classScope = md->getClassDef() ? md->getClassDef()->name() : QCString();
2566 for (const Argument &a : md->argumentList())
2567 {
2568 yyextra->parmName = a.name;
2569 yyextra->parmType = a.type;
2570 int i = yyextra->parmType.find('*');
2571 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2572 i = yyextra->parmType.find('&');
2573 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2574 yyextra->parmType.stripPrefix("const ");
2575 yyextra->parmType=yyextra->parmType.stripWhiteSpace();
2576 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
2577 }
2578 }
2579
2580 static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d)
2581 {
2582 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2583 int pos=0;
2584 QCString type = s;
2585 QCString className;
2586 QCString templSpec;
2587 while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
2588 {
2589 QCString clName=className+templSpec;
2590 const ClassDef *cd=0;
2591 if (!yyextra->classScope.isEmpty())
2592 {
2593 cd=yyextra->symbolResolver.resolveClass(d,yyextra->classScope+"::"+clName);
2594 }
2595 if (cd==0)
2596 {
2597 cd=yyextra->symbolResolver.resolveClass(d,clName);
2598 }
2599 DBG_CTX((stderr,"stripClass trying '%s' = %p\n",qPrint(clName),(void*)cd));
2600 if (cd)
2601 {
2602 return cd;
2603 }
2604 }
2605
2606 return 0;
2607 }
2608
2609 static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
2610 {
2611 if (name.isEmpty()) return 0;
2612 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2613 DBG_CTX((stderr,"setCallContextForVar(%s) yyextra->classScope=%s\n",qPrint(name),qPrint(yyextra->classScope)));
2614
2615 int scopeEnd = name.findRev("::");
2616 if (scopeEnd!=-1) // name with explicit scope
2617 {
2618 QCString scope = name.left(scopeEnd);
2619 QCString locName = name.right(name.length()-scopeEnd-2);
2620 DBG_CTX((stderr,"explicit scope: name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2621 const ClassDef *mcd = getClass(scope);
2622 if (mcd && !locName.isEmpty())
2623 {
2624 const MemberDef *md=mcd->getMemberByName(locName);
2625 if (md)
2626 {
2627 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2628 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2629 return md;
2630 }
2631 }
2632 else // check namespace as well
2633 {
2634 const NamespaceDef *mnd = getResolvedNamespace(scope);
2635 if (mnd && !locName.isEmpty())
2636 {
2637 const MemberDef *md=mnd->getMemberByName(locName);
2638 if (md)
2639 {
2640 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2641 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2642 return md;
2643 }
2644 }
2645 }
2646 }
2647
2648 const MemberName *mn;
2649 const ScopedTypeVariant *mcv = yyextra->theVarContext.findVariable(name);
2650 if (mcv)
2651 {
2652 DBG_CTX((stderr,"local variable?\n"));
2653 if (mcv->type()!=ScopedTypeVariant::Dummy) // locally found variable
2654 {
2655 DBG_CTX((stderr,"local var '%s' mcd=%s\n",qPrint(name),qPrint(mcv->name())));
2656 yyextra->theCallContext.setScope(*mcv);
2657 }
2658 }
2659 else
2660 {
2661 DBG_CTX((stderr,"class member? scope=%s\n",qPrint(yyextra->classScope)));
2662 // look for a class member
2663 const ClassDef *mcd = getClass(yyextra->classScope);
2664 if (mcd)
2665 {
2666 DBG_CTX((stderr,"Inside class %s\n",qPrint(mcd->name())));
2667 const MemberDef *md=mcd->getMemberByName(name);
2668 if (md)
2669 {
2670 DBG_CTX((stderr,"Found member %s\n",qPrint(md->name())));
2671 if (yyextra->scopeStack.empty() || yyextra->scopeStack.top()!=CLASSBLOCK)
2672 {
2673 DBG_CTX((stderr,"class member '%s' mcd=%s\n",qPrint(name),qPrint(mcd->name())));
2674 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2675 }
2676 return md;
2677 }
2678 }
2679 }
2680
2681 // look for a global member
2682 if ((mn=Doxygen::functionNameLinkedMap->find(name)))
2683 {
2684 DBG_CTX((stderr,"global var '%s'\n",qPrint(name)));
2685 if (mn->size()==1) // global defined only once
2686 {
2687 const std::unique_ptr<MemberDef> &md=mn->front();
2688 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2689 {
2690 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2691 return md.get();
2692 }
2693 return 0;
2694 }
2695 else if (mn->size()>1) // global defined more than once
2696 {
2697 for (const auto &md : *mn)
2698 {
2699 //printf("mn=%p md=%p md->getBodyDef()=%p yyextra->sourceFileDef=%p\n",
2700 // mn,md,
2701 // md->getBodyDef(),yyextra->sourceFileDef);
2702
2703 // in case there are multiple members we could link to, we
2704 // only link to members if defined in the same file or
2705 // defined as external.
2706 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2707 {
2708 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2709 DBG_CTX((stderr,"returning member %s in source file %s\n",qPrint(md->name()),qPrint(yyextra->sourceFileDef->name())));
2710 return md.get();
2711 }
2712 }
2713 return 0;
2714 }
2715 }
2716 return 0;
2717 }
2718
2719 static void updateCallContextForSmartPointer(yyscan_t yyscanner)
2720 {
2721 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2722 const Definition *d = yyextra->theCallContext.getScope().globalDef();
2723 //printf("updateCallContextForSmartPointer() cd=%s\n",cd ? qPrint(d->name()) : "<none>");
2724 const MemberDef *md;
2725 if (d && d->definitionType()==Definition::TypeClass && (md=(toClassDef(d))->isSmartPointer()))
2726 {
2727 const ClassDef *ncd = stripClassName(yyscanner,md->typeString(),md->getOuterScope());
2728 if (ncd)
2729 {
2730 yyextra->theCallContext.setScope(ScopedTypeVariant(ncd));
2731 //printf("Found smart pointer call %s->%s!\n",qPrint(cd->name()),qPrint(ncd->name()));
2732 }
2733 }
2734 }
2735
2736 static bool getLinkInScope(yyscan_t yyscanner,
2737 const QCString &c, // scope
2738 const QCString &m, // member
2739 const QCString &memberText, // exact text
2740 CodeOutputInterface &ol,
2741 const QCString &text,
2742 bool varOnly
2743 )
2744 {
2745 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2746 const MemberDef *md = 0;
2747 const ClassDef *cd = 0;
2748 const FileDef *fd = 0;
2749 const NamespaceDef *nd = 0;
2750 const GroupDef *gd = 0;
2751 DBG_CTX((stderr,"getLinkInScope: trying '%s'::'%s' varOnly=%d\n",qPrint(c),qPrint(m),varOnly));
2752 if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,yyextra->sourceFileDef,FALSE) &&
2753 (!varOnly || md->isVariable()))
2754 {
2755 if (md->isLinkable())
2756 {
2757 DBG_CTX((stderr,"found it %s!\n",qPrint(md->qualifiedName())));
2758 if (yyextra->exampleBlock)
2759 {
2760 std::lock_guard<std::mutex> lock(g_addExampleMutex);
2761 QCString anchor;
2762 anchor.sprintf("a%d",yyextra->anchorCount);
2763 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
2764 qPrint(yyextra->exampleFile)));
2765 MemberDefMutable *mdm = toMemberDefMutable(md);
2766 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
2767 {
2768 ol.writeCodeAnchor(anchor);
2769 yyextra->anchorCount++;
2770 }
2771 }
2772
2773 const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
2774 md->resolveAlias()->getFileDef() : md->getOuterScope();
2775 if (md->resolveAlias()->getGroupDef()) d = md->resolveAlias()->getGroupDef();
2776 if (d && d->isLinkable())
2777 {
2778 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2779 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p yyextra->insideBody=%d\n",
2780 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,yyextra->insideBody));
2781
2782 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
2783 yyextra->insideBody && yyextra->collectXRefs)
2784 {
2785 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
2786 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
2787 }
2788 DBG_CTX((stderr,"d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",qPrint(d->getReference()),qPrint(d->getOutputFileBase()),qPrint(d->name()),qPrint(md->name())));
2789
2790 writeMultiLineCodeLink(yyscanner,ol,md, !text.isEmpty() ? text : memberText);
2791 addToSearchIndex(yyscanner,!text.isEmpty() ? text : memberText);
2792 return TRUE;
2793 }
2794 }
2795 else // found member, but it is not linkable, so make sure content inside is not assigned
2796 // to the previous member, see bug762760
2797 {
2798 DBG_CTX((stderr,"unlinkable member %s\n",qPrint(md->name())));
2799 yyextra->currentMemberDef = 0;
2800 }
2801 }
2802 return FALSE;
2803 }
2804
2805 static bool getLink(yyscan_t yyscanner,
2806 const QCString &className,
2807 const QCString &memberName,
2808 CodeOutputInterface &ol,
2809 const QCString &text,
2810 bool varOnly)
2811 {
2812 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2813 DBG_CTX((stderr,"getLink(%s,%s) yyextra->curClassName=%s\n",
2814 qPrint(className),qPrint(memberName),qPrint(yyextra->curClassName)));
2815 QCString m=removeRedundantWhiteSpace(memberName);
2816 QCString c=className;
2817 if (!getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly))
2818 {
2819 if (!yyextra->curClassName.isEmpty())
2820 {
2821 if (!c.isEmpty()) c.prepend("::");
2822 c.prepend(yyextra->curClassName);
2823 return getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly);
2824 }
2825 return FALSE;
2826 }
2827 return TRUE;
2828 }
2829
2830 static void generateClassOrGlobalLink(yyscan_t yyscanner,
2831 CodeOutputInterface &ol,
2832 const QCString &clName,
2833 bool typeOnly,
2834 bool varOnly)
2835 {
2836 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2837 int i=0;
2838 QCString className=clName;
2839 if (!className.isEmpty() && className[0]=='~') // correct for matching negated values i.s.o. destructors.
2840 {
2841 className=className.mid(1);
2842 }
2843 if (className.isEmpty())
2844 {
2845 yyextra->code->codify("~");
2846 return;
2847 }
2848 if (yyextra->insideProtocolList) // for Obj-C
2849 {
2850 className+="-p";
2851 }
2852 if (yyextra->lang==SrcLangExt_PHP)
2853 {
2854 className = substitute(className,"\\","::"); // for PHP namespaces
2855 }
2856 else if (yyextra->lang==SrcLangExt_CSharp || yyextra->lang==SrcLangExt_Java)
2857 {
2858 className = substitute(className,".","::"); // for PHP namespaces
2859 }
2860 const ScopedTypeVariant *lcd=0;
2861 const ClassDef *cd=0;
2862 const MemberDef *md=0;
2863 bool isLocal=FALSE;
2864
2865 DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",qPrint(className)));
2866 if (!yyextra->isPrefixedWithThis || (lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
2867 {
2868 const Definition *d = yyextra->currentDefinition;
2869 DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",d?qPrint(d->name()):"<none>",yyextra->sourceFileDef?qPrint(yyextra->sourceFileDef->name()):"<none>"));
2870 cd = yyextra->symbolResolver.resolveClass(d,className);
2871 md = yyextra->symbolResolver.getTypedef();
2872 DBG_CTX((stderr,"non-local variable name=%s cd=%s md=%s!\n",
2873 qPrint(className),cd?qPrint(cd->name()):"<none>",
2874 md?qPrint(md->name()):"<none>"));
2875 i=className.find('<');
2876 QCString bareName = className;
2877 if (i!=-1) bareName = bareName.left(i);
2878 if (cd==0 && md==0 && i!=-1)
2879 {
2880 DBG_CTX((stderr,"bareName=%s\n",qPrint(bareName)));
2881 if (bareName!=className)
2882 {
2883 cd = yyextra->symbolResolver.resolveClass(d,bareName); // try unspecialized version
2884 md = yyextra->symbolResolver.getTypedef();
2885 }
2886 }
2887 const NamespaceDef *nd = getResolvedNamespace(className);
2888 if (nd && nd->isLinkable())
2889 {
2890 yyextra->theCallContext.setScope(ScopedTypeVariant(nd));
2891 addToSearchIndex(yyscanner,className);
2892 writeMultiLineCodeLink(yyscanner,*yyextra->code,nd,clName);
2893 return;
2894 }
2895 const ConceptDef *conceptDef = getResolvedConcept(d,bareName);
2896 if (conceptDef && conceptDef->isLinkable())
2897 {
2898 yyextra->theCallContext.setScope(ScopedTypeVariant(conceptDef));
2899 addToSearchIndex(yyscanner,className);
2900 writeMultiLineCodeLink(yyscanner,*yyextra->code,conceptDef,clName);
2901 return;
2902 }
2903 DBG_CTX((stderr,"md=%s\n",md?qPrint(md->name()):"<none>"));
2904 DBG_CTX((stderr,"is found as a type cd=%s nd=%s\n",
2905 cd?qPrint(cd->name()):"<null>",
2906 nd?qPrint(nd->name()):"<null>"));
2907 if (cd==0 && md==0) // also see if it is variable or enum or enum value
2908 {
2909 if (getLink(yyscanner,yyextra->classScope,clName,ol,clName,varOnly))
2910 {
2911 return;
2912 }
2913 }
2914 }
2915 else
2916 {
2917 DBG_CTX((stderr,"local variable!\n"));
2918 if (lcd->type()!=ScopedTypeVariant::Dummy)
2919 {
2920 DBG_CTX((stderr,"non-dummy context lcd=%s!\n",qPrint(lcd->name())));
2921 yyextra->theCallContext.setScope(*lcd);
2922
2923 // to following is needed for links to a global variable, but is
2924 // no good for a link to a local variable that is also a global symbol.
2925
2926 //if (getLink(yyscanner,yyextra->classScope,clName,ol,clName))
2927 //{
2928 //return;
2929 //}
2930 }
2931 isLocal=TRUE;
2932 DBG_CTX((stderr,"is a local variable cd=%p!\n",(void*)cd));
2933 }
2934 yyextra->isPrefixedWithThis = FALSE; // discard the "this" prefix for the next calls
2935
2936 if (cd && cd->isLinkable()) // is it a linkable class
2937 {
2938 DBG_CTX((stderr,"is linkable class %s\n",qPrint(clName)));
2939 if (yyextra->exampleBlock)
2940 {
2941 std::lock_guard<std::mutex> lock(g_addExampleMutex);
2942 QCString anchor;
2943 anchor.sprintf("_a%d",yyextra->anchorCount);
2944 DBG_CTX((stderr,"addExampleClass(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
2945 qPrint(yyextra->exampleFile)));
2946 ClassDefMutable *cdm = toClassDefMutable(const_cast<ClassDef*>(cd));
2947 if (cdm && cdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
2948 {
2949 ol.writeCodeAnchor(anchor);
2950 yyextra->anchorCount++;
2951 }
2952 }
2953 writeMultiLineCodeLink(yyscanner,ol,cd,clName);
2954 addToSearchIndex(yyscanner,className);
2955 yyextra->theCallContext.setScope(ScopedTypeVariant(cd));
2956 if (md)
2957 {
2958 const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
2959 md->getFileDef() : md->getOuterScope();
2960 if (md->getGroupDef()) d = md->getGroupDef();
2961 if (d && d->isLinkable() && md->isLinkable() &&
2962 yyextra->currentMemberDef && yyextra->collectXRefs)
2963 {
2964 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
2965 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
2966 }
2967 }
2968 }
2969 else // not a class, maybe a global member
2970 {
2971 DBG_CTX((stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",qPrint(clName),(void*)cd,(void*)md,typeOnly));
2972 if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
2973 {
2974 if (md==0) // not found as a typedef
2975 {
2976 md = setCallContextForVar(yyscanner,clName);
2977 DBG_CTX((stderr,"setCallContextForVar(%s) md=%p yyextra->currentDefinition=%p\n",qPrint(clName),(void*)md,(void*)yyextra->currentDefinition));
2978 if (md && yyextra->currentDefinition)
2979 {
2980 DBG_CTX((stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
2981 qPrint(md->name()),qPrint(yyextra->currentDefinition->name()),
2982 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md),
2983 qPrint(md->getOuterScope()->name())));
2984 }
2985
2986 if (md && yyextra->currentDefinition &&
2987 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md)==-1)
2988 {
2989 md=0; // variable not accessible
2990 }
2991 }
2992 if (md && (!varOnly || md->isVariable()))
2993 {
2994 DBG_CTX((stderr,"is a global md=%p yyextra->currentDefinition=%s linkable=%d\n",(void*)md,yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>",md->isLinkable()));
2995 if (md->isLinkable())
2996 {
2997 writeMultiLineCodeLink(yyscanner,ol,md,clName);
2998 addToSearchIndex(yyscanner,clName);
2999 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3000 {
3001 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3002 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
3003 }
3004 return;
3005 }
3006 }
3007 }
3008
3009 // nothing found, just write out the word
3010 DBG_CTX((stderr,"not found!\n"));
3011 codifyLines(yyscanner,clName);
3012 addToSearchIndex(yyscanner,clName);
3013 }
3014 }
3015
3016 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *clName,
3017 bool typeOnly,bool varOnly)
3018 {
3019 generateClassOrGlobalLink(yyscanner,ol,QCString(clName),typeOnly,varOnly);
3020 }
3021
3022 static bool generateClassMemberLink(yyscan_t yyscanner,
3023 CodeOutputInterface &ol,
3024 const MemberDef *xmd,
3025 const QCString &memName)
3026 {
3027 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3028 // extract class definition of the return type in order to resolve
3029 // a->b()->c() like call chains
3030
3031 DBG_CTX((stderr,"type='%s' args='%s' class=%s\n",
3032 qPrint(xmd->typeString()),qPrint(xmd->argsString()),
3033 qPrint(xmd->getClassDef()->name())));
3034
3035 if (yyextra->exampleBlock)
3036 {
3037 std::lock_guard<std::mutex> lock(g_addExampleMutex);
3038 QCString anchor;
3039 anchor.sprintf("a%d",yyextra->anchorCount);
3040 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
3041 qPrint(yyextra->exampleFile)));
3042 MemberDefMutable *mdm = toMemberDefMutable(xmd);
3043 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
3044 {
3045 ol.writeCodeAnchor(anchor);
3046 yyextra->anchorCount++;
3047 }
3048 }
3049
3050 const ClassDef *typeClass = stripClassName(yyscanner,removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
3051 DBG_CTX((stderr,"%s -> typeName=%p\n",qPrint(xmd->typeString()),(void*)typeClass));
3052 yyextra->theCallContext.setScope(ScopedTypeVariant(typeClass));
3053
3054 const Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ?
3055 xmd->getFileDef() : xmd->getOuterScope();
3056 if (xmd->getGroupDef()) xd = xmd->getGroupDef();
3057 if (xd && xd->isLinkable())
3058 {
3059
3060 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p xmd=%p yyextra->insideBody=%d\n",
3061 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,(void*)xmd,yyextra->insideBody));
3062
3063 if (xmd->templateMaster()) xmd = xmd->templateMaster();
3064
3065 if (xmd->isLinkable())
3066 {
3067 // add usage reference
3068 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
3069 yyextra->insideBody && yyextra->collectXRefs)
3070 {
3071 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3072 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(xmd));
3073 }
3074
3075 // write the actual link
3076 writeMultiLineCodeLink(yyscanner,ol,xmd,memName);
3077 addToSearchIndex(yyscanner,memName);
3078 return TRUE;
3079 }
3080 }
3081
3082 return FALSE;
3083 }
3084
3085 static bool generateClassMemberLink(yyscan_t yyscanner,
3086 CodeOutputInterface &ol,
3087 const Definition *def,
3088 const QCString &memName)
3089 {
3090 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3091 if (def && def->definitionType()==Definition::TypeClass)
3092 {
3093 const ClassDef *cd = toClassDef(def);
3094 const MemberDef *xmd = cd->getMemberByName(memName);
3095 DBG_CTX((stderr,"generateClassMemberLink(class=%s,member=%s)=%p\n",qPrint(def->name()),qPrint(memName),(void*)xmd));
3096 if (xmd)
3097 {
3098 return generateClassMemberLink(yyscanner,ol,xmd,memName);
3099 }
3100 else
3101 {
3102 const Definition *innerDef = cd->findInnerCompound(memName);
3103 if (innerDef)
3104 {
3105 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3106 addToSearchIndex(yyscanner,memName);
3107 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3108 return TRUE;
3109 }
3110 }
3111 }
3112 else if (def && def->definitionType()==Definition::TypeNamespace)
3113 {
3114 const NamespaceDef *nd = toNamespaceDef(def);
3115 DBG_CTX((stderr,"Looking for %s inside namespace %s\n",qPrint(memName),qPrint(nd->name())));
3116 const Definition *innerDef = nd->findInnerCompound(memName);
3117 if (innerDef)
3118 {
3119 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3120 addToSearchIndex(yyscanner,memName);
3121 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3122 return TRUE;
3123 }
3124 }
3125 return FALSE;
3126 }
3127
3128 static void generateMemberLink(yyscan_t yyscanner,
3129 CodeOutputInterface &ol,
3130 const QCString &varName,
3131 const QCString &memName)
3132 {
3133 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3134 DBG_CTX((stderr,"generateMemberLink(object=%s,mem=%s) classScope=%s\n",
3135 qPrint(varName),qPrint(memName),qPrint(yyextra->classScope)));
3136
3137 if (varName.isEmpty()) return;
3138
3139 // look for the variable in the current context
3140 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(varName);
3141 if (stv)
3142 {
3143 if (stv->type()!=ScopedTypeVariant::Dummy)
3144 {
3145 DBG_CTX((stderr,"Class found!\n"));
3146 if (getLink(yyscanner,stv->name(),memName,ol))
3147 {
3148 DBG_CTX((stderr,"Found result!\n"));
3149 return;
3150 }
3151 if (stv->localDef() && !stv->localDef()->baseClasses().empty())
3152 {
3153 for (const auto &bcName : stv->localDef()->baseClasses())
3154 {
3155 if (getLink(yyscanner,bcName,memName,ol))
3156 {
3157 DBG_CTX((stderr,"Found result!\n"));
3158 return;
3159 }
3160 }
3161 }
3162 }
3163 }
3164 else // variable not in current context, maybe it is in a parent context
3165 {
3166 const ClassDef *vcd = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->classScope);
3167 if (vcd && vcd->isLinkable())
3168 {
3169 DBG_CTX((stderr,"Found class %s for variable '%s'\n",qPrint(yyextra->classScope),qPrint(varName)));
3170 MemberName *vmn=Doxygen::memberNameLinkedMap->find(varName);
3171 if (vmn==0)
3172 {
3173 int vi;
3174 QCString vn=varName;
3175 if ((vi=vn.findRev("::"))!=-1 || (vi=vn.findRev('.'))!=-1) // explicit scope A::b(), probably static member
3176 {
3177 const ClassDef *jcd = getClass(vn.left(vi));
3178 vn=vn.right(vn.length()-vi-2);
3179 vmn=Doxygen::memberNameLinkedMap->find(vn);
3180 //printf("Trying name '%s' scope=%s\n",qPrint(vn),qPrint(scope));
3181 if (vmn)
3182 {
3183 for (const auto &vmd : *vmn)
3184 {
3185 if (vmd->getClassDef()==jcd)
3186 {
3187 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3188 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3189 if (mcd && mcd->isLinkable())
3190 {
3191 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3192 }
3193 }
3194 }
3195 }
3196 }
3197 }
3198 if (vmn)
3199 {
3200 DBG_CTX((stderr,"There is a variable with name '%s'\n",qPrint(varName)));
3201 for (const auto &vmd : *vmn)
3202 {
3203 if (vmd->getClassDef()==vcd)
3204 {
3205 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3206 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3207 if (mcd && mcd->isLinkable())
3208 {
3209 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3210 }
3211 }
3212 }
3213 }
3214 }
3215 }
3216 // nothing found -> write result as is
3217 codifyLines(yyscanner,memName);
3218 addToSearchIndex(yyscanner,memName);
3219 return;
3220 }
3221
3222 static void generatePHPVariableLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *varName)
3223 {
3224 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3225 QCString name(varName+7); // strip $this->
3226 name.prepend("$");
3227 DBG_CTX((stderr,"generatePHPVariableLink(%s) name=%s scope=%s\n",varName,qPrint(name),qPrint(yyextra->classScope)));
3228 if (!getLink(yyscanner,yyextra->classScope,name,ol,QCString(varName)))
3229 {
3230 codifyLines(yyscanner,varName);
3231 }
3232 }
3233
3234 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &funcName)
3235 {
3236 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3237 //CodeClassDef *ccd=0;
3238 QCString locScope=yyextra->classScope;
3239 QCString locFunc=removeRedundantWhiteSpace(funcName);
3240 if (yyextra->lang==SrcLangExt_PHP && locFunc.startsWith("self::")) locFunc=locFunc.mid(4);
3241 QCString funcScope;
3242 QCString funcWithScope=locFunc;
3243 QCString funcWithFullScope=locFunc;
3244 QCString fullScope=locScope;
3245 DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",qPrint(locScope),qPrint(locFunc)));
3246 int len=2;
3247 int i=locFunc.findRev("::");
3248 if (yyextra->currentMemberDef && yyextra->currentMemberDef->resolveAlias()->getClassDef() &&
3249 funcName==yyextra->currentMemberDef->localName() &&
3250 yyextra->currentMemberDef->getDefLine()==yyextra->yyLineNr &&
3251 generateClassMemberLink(yyscanner,ol,yyextra->currentMemberDef,funcName)
3252 )
3253 {
3254 // special case where funcName is the name of a method that is also
3255 // defined on this line. In this case we can directly link to
3256 // yyextra->currentMemberDef, which is not only faster, but
3257 // in case of overloaded methods, this will make sure that we link to
3258 // the correct method, and thereby get the correct reimplemented relations.
3259 // See also bug 549022.
3260 goto exit;
3261 }
3262 if (i==-1) i=locFunc.findRev("."),len=1;
3263 if (i==-1) i=locFunc.findRev("\\"),len=1; // for PHP
3264 if (i>0)
3265 {
3266 funcScope=locFunc.left(i);
3267 locFunc=locFunc.right(locFunc.length()-i-len).stripWhiteSpace();
3268 int ts=locScope.find('<'); // start of template
3269 int te=locScope.findRev('>'); // end of template
3270 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3271 if (ts!=-1 && te!=-1 && te>ts)
3272 {
3273 // remove template from scope
3274 locScope=locScope.left(ts)+locScope.right(locScope.length()-te-1);
3275 }
3276 ts=funcScope.find('<'); // start of template
3277 te=funcScope.findRev('>'); // end of template
3278 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3279 if (ts!=-1 && te!=-1 && te>ts)
3280 {
3281 // remove template from scope
3282 funcScope=funcScope.left(ts)+funcScope.right(funcScope.length()-te-1);
3283 }
3284 if (!funcScope.isEmpty())
3285 {
3286 funcWithScope = funcScope+"::"+locFunc;
3287 if (!locScope.isEmpty())
3288 {
3289 fullScope=locScope+"::"+funcScope;
3290 }
3291 }
3292 if (!locScope.isEmpty())
3293 {
3294 funcWithFullScope = locScope+"::"+funcWithScope;
3295 }
3296 }
3297
3298 if (!fullScope.isEmpty())
3299 {
3300 auto it = yyextra->codeClassMap.find(fullScope.str());
3301 if (it!=yyextra->codeClassMap.end())
3302 {
3303 ScopedTypeVariant ccd = it->second;
3304 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3305 {
3306 for (const auto &bcName : ccd.localDef()->baseClasses())
3307 {
3308 if (getLink(yyscanner,bcName,locFunc,ol,funcName))
3309 {
3310 goto exit;
3311 }
3312 }
3313 }
3314 }
3315 }
3316
3317 if (!locScope.isEmpty() && fullScope!=locScope)
3318 {
3319 auto it = yyextra->codeClassMap.find(locScope.str());
3320 if (it!=yyextra->codeClassMap.end())
3321 {
3322 ScopedTypeVariant ccd = it->second;
3323 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3324 {
3325 for (const auto &bcName : ccd.localDef()->baseClasses())
3326 {
3327 if (getLink(yyscanner,bcName,funcWithScope,ol,funcName))
3328 {
3329 goto exit;
3330 }
3331 }
3332 }
3333 }
3334 }
3335 if (!getLink(yyscanner,locScope,funcWithScope,ol,funcName))
3336 {
3337 generateClassOrGlobalLink(yyscanner,ol,funcName);
3338 }
3339 exit:
3340 return;
3341 }
3342
3343 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *funcName)
3344 {
3345 generateFunctionLink(yyscanner,ol,QCString(funcName));
3346 }
3347
3348 /*! counts the number of lines in the input */
3349 static int countLines(yyscan_t yyscanner)
3350 {
3351 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3352 const char *p=yyextra->inputString;
3353 char c;
3354 int count=1;
3355 while ((c=*p))
3356 {
3357 p++ ;
3358 if (c=='\n') count++;
3359 }
3360 if (p>yyextra->inputString && *(p-1)!='\n')
3361 { // last line does not end with a \n, so we add an extra
3362 count++;
3363 }
3364 return count;
3365 }
3366
3367 static void endFontClass(yyscan_t yyscanner)
3368 {
3369 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3370 if (yyextra->currentFontClass)
3371 {
3372 yyextra->code->endFontClass();
3373 yyextra->currentFontClass=0;
3374 }
3375 }
3376
3377 static void startFontClass(yyscan_t yyscanner,const char *s)
3378 {
3379 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3380 endFontClass(yyscanner);
3381 yyextra->code->startFontClass(QCString(s));
3382 yyextra->currentFontClass=s;
3383 }
3384
3385 //----------------------------------------------------------------------------
3386
3387 // recursively writes a linkified Objective-C method call
3388 static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
3389 {
3390 if (ctx==0) return;
3391 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3392 char c;
3393 if (!ctx->methodName.isEmpty())
3394 {
3395 DBG_CTX((stderr,"writeObjCMethodCall(%s) obj=%s method=%s\n",
3396 qPrint(ctx->format),qPrint(ctx->objectTypeOrName),qPrint(ctx->methodName)));
3397 if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$')
3398 {
3399 DBG_CTX((stderr,"Looking for object=%s method=%s\n",qPrint(ctx->objectTypeOrName),
3400 qPrint(ctx->methodName)));
3401 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(ctx->objectTypeOrName);
3402 if (stv==0) // not a local variable
3403 {
3404 if (ctx->objectTypeOrName=="self")
3405 {
3406 if (yyextra->currentDefinition &&
3407 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3408 {
3409 ctx->objectType = toClassDef(yyextra->currentDefinition);
3410 }
3411 }
3412 else
3413 {
3414 ctx->objectType = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ctx->objectTypeOrName);
3415 ctx->method = yyextra->symbolResolver.getTypedef();
3416 }
3417 DBG_CTX((stderr," object is class? %p\n",(void*)ctx->objectType));
3418 if (ctx->objectType) // found class
3419 {
3420 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3421 DBG_CTX((stderr," yes->method=%s\n",ctx->method?qPrint(ctx->method->name()):"<none>"));
3422 }
3423 else if (ctx->method==0) // search for class variable with the same name
3424 {
3425 DBG_CTX((stderr," no\n"));
3426 DBG_CTX((stderr,"yyextra->currentDefinition=%p\n",(void*)yyextra->currentDefinition));
3427 if (yyextra->currentDefinition &&
3428 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3429 {
3430 ctx->objectVar = (toClassDef(yyextra->currentDefinition))->getMemberByName(ctx->objectTypeOrName);
3431 DBG_CTX((stderr," ctx->objectVar=%p\n",(void*)ctx->objectVar));
3432 if (ctx->objectVar)
3433 {
3434 ctx->objectType = stripClassName(yyscanner,ctx->objectVar->typeString(),yyextra->currentDefinition);
3435 DBG_CTX((stderr," ctx->objectType=%p\n",(void*)ctx->objectType));
3436 if (ctx->objectType && !ctx->methodName.isEmpty())
3437 {
3438 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3439 DBG_CTX((stderr," ctx->method=%p\n",(void*)ctx->method));
3440 }
3441 }
3442 }
3443 }
3444 }
3445 else // local variable
3446 {
3447 DBG_CTX((stderr," object is local variable\n"));
3448 if (stv->globalDef() && !ctx->methodName.isEmpty())
3449 {
3450 const ClassDef *cd = toClassDef(stv->globalDef());
3451 if (cd)
3452 {
3453 ctx->method = cd->getMemberByName(ctx->methodName);
3454 }
3455 DBG_CTX((stderr," class=%p method=%p\n",(void*)cd,(void*)ctx->method));
3456 }
3457 }
3458 }
3459 }
3460
3461 DBG_CTX((stderr,"["));
3462 if (!ctx->format.isEmpty())
3463 {
3464 const char *p = ctx->format.data();
3465 while ((c=*p++)) // for each character in ctx->format
3466 {
3467 if (c=='$')
3468 {
3469 char nc=*p++;
3470 if (nc=='$') // escaped $
3471 {
3472 yyextra->code->codify("$");
3473 }
3474 else // name fragment or reference to a nested call
3475 {
3476 if (nc=='n') // name fragment
3477 {
3478 nc=*p++;
3479 QCString refIdStr;
3480 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3481 p--;
3482 int refId=refIdStr.toInt();
3483 auto it = yyextra->nameMap.find(refId);
3484 if (it!=yyextra->nameMap.end())
3485 {
3486 QCString name = it->second;
3487 if (ctx->method && ctx->method->isLinkable())
3488 {
3489 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->method,name);
3490 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3491 {
3492 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3493 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(ctx->method));
3494 }
3495 }
3496 else
3497 {
3498 codifyLines(yyscanner,name);
3499 }
3500 }
3501 else
3502 {
3503 DBG_CTX((stderr,"Invalid name: id=%d\n",refId));
3504 }
3505 }
3506 else if (nc=='o') // reference to potential object name
3507 {
3508 nc=*p++;
3509 QCString refIdStr;
3510 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3511 p--;
3512 int refId=refIdStr.toInt();
3513 auto it = yyextra->objectMap.find(refId);
3514 if (it!=yyextra->objectMap.end())
3515 {
3516 QCString object = it->second;
3517 if (object=="self")
3518 {
3519 if (yyextra->currentDefinition &&
3520 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3521 {
3522 ctx->objectType = toClassDef(yyextra->currentDefinition);
3523 if (ctx->objectType->categoryOf())
3524 {
3525 ctx->objectType = ctx->objectType->categoryOf();
3526 }
3527 if (ctx->objectType && !ctx->methodName.isEmpty())
3528 {
3529 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3530 }
3531 }
3532 startFontClass(yyscanner,"keyword");
3533 codifyLines(yyscanner,object);
3534 endFontClass(yyscanner);
3535 }
3536 else if (object=="super")
3537 {
3538 if (yyextra->currentDefinition &&
3539 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3540 {
3541 const ClassDef *cd = toClassDef(yyextra->currentDefinition);
3542 if (cd->categoryOf())
3543 {
3544 cd = cd->categoryOf();
3545 }
3546 for (const auto &bclass : cd->baseClasses())
3547 {
3548 if (bclass.classDef->compoundType()!=ClassDef::Protocol)
3549 {
3550 ctx->objectType = bclass.classDef;
3551 if (ctx->objectType && !ctx->methodName.isEmpty())
3552 {
3553 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3554 }
3555 }
3556 }
3557 }
3558 startFontClass(yyscanner,"keyword");
3559 codifyLines(yyscanner,object);
3560 endFontClass(yyscanner);
3561 }
3562 else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable
3563 {
3564 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->objectVar,object);
3565 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3566 {
3567 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3568 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(ctx->objectVar));
3569 }
3570 }
3571 else if (ctx->objectType &&
3572 ctx->objectType->isLinkable()
3573 ) // object is class name
3574 {
3575 const ClassDef *cd = ctx->objectType;
3576 writeMultiLineCodeLink(yyscanner,*yyextra->code,cd,object);
3577 }
3578 else // object still needs to be resolved
3579 {
3580 const ClassDef *cd = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition, object);
3581 if (cd && cd->isLinkable())
3582 {
3583 if (ctx->objectType==0) ctx->objectType=cd;
3584 writeMultiLineCodeLink(yyscanner,*yyextra->code,cd,object);
3585 }
3586 else
3587 {
3588 codifyLines(yyscanner,object);
3589 }
3590 }
3591 }
3592 else
3593 {
3594 DBG_CTX((stderr,"Invalid object: id=%d\n",refId));
3595 }
3596 }
3597 else if (nc=='c') // reference to nested call
3598 {
3599 nc=*p++;
3600 QCString refIdStr;
3601 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3602 p--;
3603 int refId=refIdStr.toInt();
3604 auto it = yyextra->contextMap.find(refId);
3605 if (it!=yyextra->contextMap.end()) // recurse into nested call
3606 {
3607 ObjCCallCtx *ictx = it->second.get();
3608 writeObjCMethodCall(yyscanner,ictx);
3609 if (ictx->method) // link to nested call successfully
3610 {
3611 // get the ClassDef representing the method's return type
3612 if (QCString(ictx->method->typeString())=="id")
3613 {
3614 // see if the method name is unique, if so we link to it
3615 MemberName *mn=Doxygen::memberNameLinkedMap->find(ctx->methodName);
3616 //printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n",
3617 // mn==0?-1:(int)mn->count(),
3618 // qPrint(ictx->method->name()),
3619 // qPrint(ctx->methodName));
3620 if (mn && mn->size()==1) // member name unique
3621 {
3622 ctx->method = mn->front().get();
3623 }
3624 }
3625 else
3626 {
3627 ctx->objectType = stripClassName(yyscanner,ictx->method->typeString(),yyextra->currentDefinition);
3628 if (ctx->objectType && !ctx->methodName.isEmpty())
3629 {
3630 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3631 }
3632 }
3633 DBG_CTX((stderr," ***** method=%s -> object=%p\n",qPrint(ictx->method->name()),(void*)ctx->objectType));
3634 }
3635 }
3636 else
3637 {
3638 DBG_CTX((stderr,"Invalid context: id=%d\n",refId));
3639 }
3640 }
3641 else if (nc=='w') // some word
3642 {
3643 nc=*p++;
3644 QCString refIdStr;
3645 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3646 p--;
3647 int refId=refIdStr.toInt();
3648 auto it = yyextra->wordMap.find(refId);
3649 if (it!=yyextra->wordMap.end())
3650 {
3651 QCString word = it->second;
3652 codifyLines(yyscanner,word);
3653 }
3654 }
3655 else if (nc=='d') // comment block
3656 {
3657 nc=*p++;
3658 QCString refIdStr;
3659 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3660 p--;
3661 int refId=refIdStr.toInt();
3662 auto it = yyextra->commentMap.find(refId);
3663 if (it!=yyextra->commentMap.end())
3664 {
3665 QCString comment = it->second;
3666 startFontClass(yyscanner,"comment");
3667 codifyLines(yyscanner,comment);
3668 endFontClass(yyscanner);
3669 }
3670 }
3671 else // illegal marker
3672 {
3673 ASSERT("invalid escape sequence"==0);
3674 }
3675 }
3676 }
3677 else // normal non-marker character
3678 {
3679 char s[2];
3680 s[0]=c;s[1]=0;
3681 codifyLines(yyscanner,s);
3682 }
3683 }
3684 }
3685 DBG_CTX((stderr,"%s %s]\n",qPrint(ctx->objectTypeOrName),qPrint(ctx->methodName)));
3686 DBG_CTX((stderr,"}=(type='%s',name='%s')",
3687 qPrint(ctx->objectTypeOrName),
3688 qPrint(ctx->methodName)));
3689 }
3690
3691 // Replaces an Objective-C method name fragment s by a marker of the form
3692 // $n12, the number (12) can later be used as a key for obtaining the name
3693 // fragment, from yyextra->nameMap
3694 static QCString escapeName(yyscan_t yyscanner,const char *s)
3695 {
3696 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3697 QCString result;
3698 result.sprintf("$n%d",yyextra->currentNameId);
3699 yyextra->nameMap.emplace(std::make_pair(yyextra->currentNameId,s));
3700 yyextra->currentNameId++;
3701 return result;
3702 }
3703
3704 static QCString escapeObject(yyscan_t yyscanner,const char *s)
3705 {
3706 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3707 QCString result;
3708 result.sprintf("$o%d",yyextra->currentObjId);
3709 yyextra->objectMap.emplace(std::make_pair(yyextra->currentObjId,s));
3710 yyextra->currentObjId++;
3711 return result;
3712 }
3713
3714 static QCString escapeWord(yyscan_t yyscanner,const char *s)
3715 {
3716 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3717 QCString result;
3718 result.sprintf("$w%d",yyextra->currentWordId);
3719 yyextra->wordMap.emplace(std::make_pair(yyextra->currentWordId,s));
3720 yyextra->currentWordId++;
3721 return result;
3722 }
3723
3724 static QCString escapeComment(yyscan_t yyscanner,const char *s)
3725 {
3726 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3727 QCString result;
3728 result.sprintf("$d%d",yyextra->currentCommentId);
3729 yyextra->commentMap.emplace(std::make_pair(yyextra->currentCommentId,s));
3730 yyextra->currentCommentId++;
3731 return result;
3732 }
3733
3734 static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *keyword)
3735 {
3736 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3737 static std::unordered_set<std::string> non_cpp_keywords = {
3738 "__assume", "__super", "abstract", "function",
3739 "gcnew", "gcroot", "generic", "get",
3740 "internal", "null", "pin_ptr", "raise",
3741 "remove", "self", "set", "transient"};
3742 static std::unordered_set<std::string> non_java_keywords = {
3743 "alignas", "alignof", "and", "and_eq", "asm",
3744 "atomic_cancel", "atomic_commit", "atomic_noexcept", "auto", "bitand",
3745 "bitor", "bool", "char8_t", "char16_t", "char32_t",
3746 "compl", "concept", "consteval", "constexpr", "constinit",
3747 "const_cast", "co_await", "co_return", "co_yield", "decltype",
3748 "delete", "dynamic_cast", "explicit", "export", "extern",
3749 "friend", "inline", "mutable", "namespace", "noexcept",
3750 "not", "not_eq", "nullptr", "operator", "or",
3751 "or_eq", "reflexpr", "register", "reinterpret_cast", "requires",
3752 "signed", "sizeof", "static_assert", "static_cast", "struct",
3753 "template", "thread_local", "typedef", "typeid", "typename",
3754 "union", "unsigned", "using", "virtual", "wchar_t",
3755 "xor", "xor_eq",
3756 "override"
3757 };
3758 bool retval;
3759 switch (yyextra->lang)
3760 {
3761 case SrcLangExt_Cpp:
3762 retval = (non_cpp_keywords.find(keyword) != non_cpp_keywords.end());
3763 break;
3764 case SrcLangExt_Java:
3765 retval = (non_java_keywords.find(keyword) != non_java_keywords.end());
3766 break;
3767 default:
3768 retval = false;
3769 break;
3770 }
3771 return retval;
3772 }
3773
3774 static bool isCastKeyword(const char *keyword)
3775 {
3776 QCString s(keyword);
3777 int i=s.find('<');
3778 if (i==-1) return FALSE;
3779 QCString kw = s.left(i).stripWhiteSpace();
3780 return kw=="const_cast" || kw=="static_cast" || kw=="dynamic_cast" || kw=="reinterpret_cast";
3781 }
3782
3783 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
3784 {
3785 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3786 yy_size_t inputPosition = yyextra->inputPosition;
3787 const char *s = yyextra->inputString + inputPosition;
3788 yy_size_t c=0;
3789 while( c < max_size && *s )
3790 {
3791 *buf++ = *s++;
3792 c++;
3793 }
3794 yyextra->inputPosition += c;
3795 return c;
3796 }
3797
3798
3799 static void saveObjCContext(yyscan_t yyscanner)
3800 {
3801 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3802 if (yyextra->currentCtx)
3803 {
3804 yyextra->currentCtx->format+=QCString().sprintf("$c%d",yyextra->currentCtxId);
3805 if (yyextra->braceCount==0 && YY_START==ObjCCall)
3806 {
3807 yyextra->currentCtx->objectTypeOrName=yyextra->currentCtx->format.mid(1);
3808 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
3809 }
3810 yyextra->contextStack.push(yyextra->currentCtx);
3811 }
3812 else
3813 {
3814 DBG_CTX((stderr,"Trying to save NULL context!\n"));
3815 }
3816 auto newCtx = std::make_unique<ObjCCallCtx>();
3817 newCtx->id = yyextra->currentCtxId;
3818 newCtx->lexState = YY_START;
3819 newCtx->braceCount = yyextra->braceCount;
3820 newCtx->objectType = 0;
3821 newCtx->objectVar = 0;
3822 newCtx->method = 0;
3823 DBG_CTX((stderr,"save state=%d\n",YY_START));
3824 yyextra->currentCtx = newCtx.get();
3825 yyextra->contextMap.emplace(std::make_pair(yyextra->currentCtxId,std::move(newCtx)));
3826 yyextra->braceCount = 0;
3827 yyextra->currentCtxId++;
3828 }
3829
3830 static void restoreObjCContext(yyscan_t yyscanner)
3831 {
3832 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3833 DBG_CTX((stderr,"restore state=%d->%d\n",YY_START,yyextra->currentCtx->lexState));
3834 BEGIN(yyextra->currentCtx->lexState);
3835 yyextra->braceCount = yyextra->currentCtx->braceCount;
3836 if (!yyextra->contextStack.empty())
3837 {
3838 yyextra->currentCtx = yyextra->contextStack.top();
3839 yyextra->contextStack.pop();
3840 }
3841 else
3842 {
3843 yyextra->currentCtx = 0;
3844 DBG_CTX((stderr,"Trying to pop context while yyextra->contextStack is empty!\n"));
3845 }
3846 }
3847
3848 struct CCodeParser::Private
3849 {
3850 yyscan_t yyscanner;
3851 codeYY_state state;
3852 };
3853
3854 CCodeParser::CCodeParser() : p(std::make_unique<CCodeParser::Private>())
3855 {
3856 codeYYlex_init_extra(&p->state,&p->yyscanner);
3857 #ifdef FLEX_DEBUG
3858 codeYYset_debug(1,p->yyscanner);
3859 #endif
3860 resetCodeParserState();
3861 }
3862
3863 CCodeParser::~CCodeParser()
3864 {
3865 codeYYlex_destroy(p->yyscanner);
3866 }
3867
3868 void CCodeParser::resetCodeParserState()
3869 {
3870 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3871 DBG_CTX((stderr,"***CodeParser::reset()\n"));
3872 yyextra->theVarContext.clear();
3873 while (!yyextra->classScopeLengthStack.empty()) yyextra->classScopeLengthStack.pop();
3874 yyextra->codeClassMap.clear();
3875 yyextra->curClassBases.clear();
3876 yyextra->anchorCount = 0;
3877 yyextra->insideCodeLine = false;
3878 }
3879
3880 void CCodeParser::setInsideCodeLine(bool inp)
3881 {
3882 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3883 yyextra->insideCodeLine = inp;
3884 }
3885
3886 bool CCodeParser::insideCodeLine() const
3887 {
3888 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3889 return yyextra->insideCodeLine;
3890 }
3891
3892 void CCodeParser::parseCode(CodeOutputInterface &od,const QCString &className,const QCString &s,
3893 SrcLangExt lang,bool exBlock, const QCString &exName,const FileDef *fd,
3894 int startLine,int endLine,bool inlineFragment,
3895 const MemberDef *memberDef,bool showLineNumbers,const Definition *searchCtx,
3896 bool collectXRefs)
3897 {
3898 yyscan_t yyscanner = p->yyscanner;
3899 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3900 DBG_CTX((stderr,"***parseCode() exBlock=%d exName=%s fd=%p className=%s searchCtx=%s\n",
3901 exBlock,qPrint(exName),(void*)fd,qPrint(className),searchCtx?qPrint(searchCtx->name()):"<none>"));
3902
3903 if (s.isEmpty()) return;
3904
3905 printlex(yy_flex_debug, TRUE, __FILE__, fd ? qPrint(fd->fileName()): NULL);
3906
3907 yyextra->code = &od;
3908 yyextra->inputString = s.data();
3909 yyextra->fileName = fd ? fd->fileName():"";
3910 yyextra->inputPosition = 0;
3911 codeYYrestart(0,yyscanner);
3912 yyextra->currentFontClass = 0;
3913 yyextra->searchCtx = searchCtx;
3914 yyextra->collectXRefs = collectXRefs;
3915 yyextra->inFunctionTryBlock = FALSE;
3916 yyextra->symbolResolver.setFileScope(fd);
3917
3918 if (startLine!=-1)
3919 yyextra->yyLineNr = startLine;
3920 else
3921 yyextra->yyLineNr = 1;
3922
3923 if (endLine!=-1)
3924 yyextra->inputLines = endLine+1;
3925 else
3926 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
3927
3928 yyextra->curlyCount = 0;
3929 yyextra->bodyCurlyCount = 0;
3930 yyextra->bracketCount = 0;
3931 yyextra->sharpCount = 0;
3932 yyextra->insideTemplate = FALSE;
3933 yyextra->theCallContext.clear();
3934 while (!yyextra->scopeStack.empty()) yyextra->scopeStack.pop();
3935 yyextra->classScope = className;
3936 DBG_CTX((stderr,"parseCCode %s\n",qPrint(className)));
3937 yyextra->exampleBlock = exBlock;
3938 yyextra->exampleName = exName;
3939 yyextra->sourceFileDef = fd;
3940 yyextra->lineNumbers = fd!=0 && showLineNumbers;
3941 bool cleanupSourceDef = FALSE;
3942 if (fd==0)
3943 {
3944 // create a dummy filedef for the example
3945 yyextra->sourceFileDef = createFileDef(QCString(),(!exName.isEmpty()?exName:"generated"));
3946 cleanupSourceDef = TRUE;
3947 }
3948 yyextra->lang = lang;
3949 yyextra->insideObjC = lang==SrcLangExt_ObjC;
3950 if (yyextra->sourceFileDef)
3951 {
3952 setCurrentDoc(yyscanner,"l00001");
3953 }
3954 yyextra->currentDefinition = getResolvedNamespace(className);
3955 yyextra->currentMemberDef = 0;
3956 yyextra->searchingForBody = exBlock;
3957 yyextra->insideBody = FALSE;
3958 yyextra->bracketCount = 0;
3959 if (!yyextra->exampleName.isEmpty())
3960 {
3961 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example",FALSE,TRUE);
3962 DBG_CTX((stderr,"yyextra->exampleFile=%s\n",qPrint(yyextra->exampleFile)));
3963 }
3964 yyextra->includeCodeFragment = inlineFragment;
3965 DBG_CTX((stderr,"** exBlock=%d exName=%s include=%d\n",exBlock,qPrint(exName),inlineFragment));
3966 if (!yyextra->insideCodeLine)
3967 {
3968 startCodeLine(yyscanner);
3969 }
3970 yyextra->type.resize(0);
3971 yyextra->name.resize(0);
3972 yyextra->args.resize(0);
3973 yyextra->parmName.resize(0);
3974 yyextra->parmType.resize(0);
3975 if (memberDef) setParameterList(yyscanner,memberDef);
3976 BEGIN( Body );
3977 codeYYlex(yyscanner);
3978 yyextra->lexInit=TRUE;
3979 if (yyextra->insideCodeLine)
3980 {
3981 endCodeLine(yyscanner);
3982 }
3983 if (cleanupSourceDef)
3984 {
3985 // delete the temporary file definition used for this example
3986 delete yyextra->sourceFileDef;
3987 yyextra->sourceFileDef=0;
3988 }
3989 // write the tooltips
3990 yyextra->tooltipManager.writeTooltips(od);
3991
3992 printlex(yy_flex_debug, FALSE, __FILE__, fd ? qPrint(fd->fileName()): NULL);
3993 }
3994
3995 #if USE_STATE2STRING
3996 #include "code.l.h"
3997 #endif
3998