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