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