1 /******************************************************************************
5 * Copyright (C) 1997-2015 by Dimitri van Heesch.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation under the terms of the GNU General Public License is hereby
9 * granted. No representations are made about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 * See the GNU General Public License for more details.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
17 %option never-interactive
18 %option prefix="codeYY"
34 #include "outputlist.h"
36 #include "membername.h"
37 #include "searchindex.h"
38 #include "arguments.h"
41 #include "classlist.h"
44 #include "namespacedef.h"
47 // Toggle for some debugging info
48 //#define DBG_CTX(x) fprintf x
49 #define DBG_CTX(x) do { } while(0)
51 #define YY_NO_UNISTD_H 1
53 #define CLASSBLOCK (int *)4
54 #define SCOPEBLOCK (int *)8
55 #define INNERBLOCK (int *)12
57 /* -----------------------------------------------------------------
61 static CodeOutputInterface * g_code;
63 static ClassSDict *g_codeClassSDict = 0;
64 static QCString g_curClassName;
65 static QStrList g_curClassBases;
67 static QCString g_parmType;
68 static QCString g_parmName;
70 static const char * g_inputString; //!< the code fragment as text
71 static int g_inputPosition; //!< read offset during parsing
72 static int g_inputLines; //!< number of line in the code fragment
73 static int g_yyLineNr; //!< current line number
74 static int g_yyColNr; //!< current column number
75 static bool g_needsTermination;
77 static bool g_exampleBlock;
78 static QCString g_exampleName;
79 static QCString g_exampleFile;
81 static bool g_insideTemplate = FALSE;
82 static QCString g_type;
83 static QCString g_name;
84 static QCString g_args;
85 static QCString g_classScope;
86 static QCString g_realScope;
87 static QStack<int> g_scopeStack; //!< 1 if bracket starts a scope,
88 // 2 for internal blocks
89 static int g_anchorCount;
90 static FileDef * g_sourceFileDef;
91 static bool g_lineNumbers;
92 static Definition * g_currentDefinition;
93 static MemberDef * g_currentMemberDef;
94 static bool g_includeCodeFragment;
95 static const char * g_currentFontClass;
96 static bool g_searchingForBody;
97 static bool g_insideBody;
98 static int g_bodyCurlyCount;
99 static QCString g_saveName;
100 static QCString g_saveType;
101 static QCString g_delimiter;
103 static int g_bracketCount = 0;
104 static int g_curlyCount = 0;
105 static int g_sharpCount = 0;
106 static bool g_inFunctionTryBlock = FALSE;
107 static bool g_inForEachExpression = FALSE;
109 static int g_lastTemplCastContext;
110 static int g_lastSpecialCContext;
111 static int g_lastStringContext;
112 static int g_lastSkipCppContext;
113 static int g_lastVerbStringContext;
114 static int g_lastObjCCallContext;
115 static int g_memCallContext;
116 static int g_lastCContext;
117 static int g_skipInlineInitContext;
119 static bool g_insideCpp;
120 static bool g_insideObjC;
121 static bool g_insideJava;
122 static bool g_insideCS;
123 static bool g_insidePHP;
124 static bool g_insideProtocolList;
125 static bool g_insideSlice;
127 static bool g_lexInit = FALSE;
129 static QStack<int> g_classScopeLengthStack;
131 static int g_prefixed_with_this_keyword = FALSE;
132 static Definition *g_searchCtx;
133 static bool g_collectXRefs;
135 // context for an Objective-C method call
140 QCString objectTypeOrName;
142 ClassDef *objectType;
143 MemberDef *objectVar;
150 // globals for objective-C method calls
151 static ObjCCallCtx *g_currentCtx=0;
152 static int g_currentCtxId=0;
153 static int g_currentNameId=0;
154 static int g_currentObjId=0;
155 static int g_currentWordId=0;
156 static int g_currentCommentId=0;
157 static QStack<ObjCCallCtx> g_contextStack;
158 static QIntDict<ObjCCallCtx> g_contextDict;
159 static QIntDict<QCString> g_nameDict;
160 static QIntDict<QCString> g_objectDict;
161 static QIntDict<QCString> g_wordDict;
162 static QIntDict<QCString> g_commentDict;
163 static int g_braceCount=0;
165 static void saveObjCContext();
166 static void restoreObjCContext();
168 static QCString g_forceTagReference;
171 //-------------------------------------------------------------------
173 /*! Represents a stack of variable to class mappings as found in the
174 * code. Each scope is enclosed in pushScope() and popScope() calls.
175 * Variables are added by calling addVariables() and one can search
176 * for variable using findVariable().
178 class VariableContext
181 static const ClassDef *dummyContext;
183 class Scope : public SDict<ClassDef>
186 Scope() : SDict<ClassDef>(17) {}
191 m_scopes.setAutoDelete(TRUE);
193 virtual ~VariableContext()
199 m_scopes.append(new Scope);
200 DBG_CTX((stderr,"** Push var context %d\n",m_scopes.count()));
205 if (m_scopes.count()>0)
207 DBG_CTX((stderr,"** Pop var context %d\n",m_scopes.count()));
208 m_scopes.remove(m_scopes.count()-1);
212 DBG_CTX((stderr,"** ILLEGAL: Pop var context\n"));
219 m_globalScope.clear();
222 void clearExceptGlobal()
224 DBG_CTX((stderr,"** Clear var context\n"));
228 void addVariable(const QCString &type,const QCString &name);
229 ClassDef *findVariable(const QCString &name);
231 int count() const { return m_scopes.count(); }
235 QList<Scope> m_scopes;
238 void VariableContext::addVariable(const QCString &type,const QCString &name)
240 //printf("VariableContext::addVariable(%s,%s)\n",type.data(),name.data());
241 QCString ltype = type.simplifyWhiteSpace();
242 QCString lname = name.simplifyWhiteSpace();
243 if (ltype.left(7)=="struct ")
245 ltype = ltype.right(ltype.length()-7);
247 else if (ltype.left(6)=="union ")
249 ltype = ltype.right(ltype.length()-6);
251 if (ltype.isEmpty() || lname.isEmpty()) return;
252 DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' g_currentDefinition=%s\n",
253 ltype.data(),lname.data(),g_currentDefinition?g_currentDefinition->name().data():"<none>"));
254 Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
258 (varType=g_codeClassSDict->find(ltype)) || // look for class definitions inside the code block
259 (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
262 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",ltype.data(),lname.data()));
263 scope->append(lname,varType); // add it to a list
265 else if ((i=ltype.find('<'))!=-1)
267 // probably a template class
268 QCString typeName(ltype.left(i));
269 ClassDef* newDef = 0;
270 QCString templateArgs(ltype.right(ltype.length() - i));
272 ( // look for class definitions inside the code block
273 (varType=g_codeClassSDict->find(typeName)) ||
274 // otherwise look for global class definitions
275 (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,typeName,0,0,TRUE,TRUE))
276 ) && // and it must be a template
277 varType->templateArguments())
279 newDef = varType->getVariableInstance( templateArgs );
283 DBG_CTX((stderr,"** addVariable type='%s' templ='%s' name='%s'\n",typeName.data(),templateArgs.data(),lname.data()));
284 scope->append(lname, newDef);
288 // Doesn't seem to be a template. Try just the base name.
289 addVariable(typeName,name);
294 if (m_scopes.count()>0) // for local variables add a dummy entry so the name
295 // is hidden to avoid false links to global variables with the same name
296 // TODO: make this work for namespaces as well!
298 DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",lname.data()));
299 scope->append(lname,dummyContext);
303 DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
308 ClassDef *VariableContext::findVariable(const QCString &name)
310 if (name.isEmpty()) return 0;
311 ClassDef *result = 0;
312 QListIterator<Scope> sli(m_scopes);
315 // search from inner to outer scope
316 for (sli.toLast();(scope=sli.current());--sli)
318 result = scope->find(key);
321 DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result));
325 // nothing found -> also try the global scope
326 result=m_globalScope.find(name);
327 DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result));
331 static VariableContext g_theVarContext;
332 const ClassDef *VariableContext::dummyContext = (ClassDef*)0x8;
334 //-------------------------------------------------------------------
341 Ctx() : name(g_name), type(g_type), d(0) {}
349 m_defList.append(new Ctx);
350 m_defList.setAutoDelete(TRUE);
352 virtual ~CallContext() {}
353 void setScope(Definition *d)
355 Ctx *ctx = m_defList.getLast();
358 DBG_CTX((stderr,"** Set call context %s (%p)\n",d==0 ? "<null>" : d->name().data(),d));
364 m_defList.append(new Ctx);
365 DBG_CTX((stderr,"** Push call context %d\n",m_defList.count()));
369 if (m_defList.count()>1)
371 DBG_CTX((stderr,"** Pop call context %d\n",m_defList.count()));
372 Ctx *ctx = m_defList.getLast();
378 m_defList.removeLast();
382 DBG_CTX((stderr,"** ILLEGAL: Pop call context\n"));
387 DBG_CTX((stderr,"** Clear call context\n"));
389 m_defList.append(new Ctx);
391 Definition *getScope() const
393 Ctx *ctx = m_defList.getLast();
394 if (ctx) return ctx->d; else return 0;
398 QList<Ctx> m_defList;
401 static CallContext g_theCallContext;
403 //-------------------------------------------------------------------
405 /*! add class/namespace name s to the scope */
406 static void pushScope(const char *s)
408 g_classScopeLengthStack.push(new int(g_classScope.length()));
409 if (g_classScope.isEmpty() || leftScopeMatch(s,g_classScope))
415 g_classScope += "::";
418 //printf("pushScope(%s) result: `%s'\n",s,g_classScope.data());
421 /*! remove the top class/namespace name from the scope */
422 static void popScope()
424 if (!g_classScopeLengthStack.isEmpty())
426 int *pLength = g_classScopeLengthStack.pop();
427 g_classScope.truncate(*pLength);
432 //err("Too many end of scopes found!\n");
434 //printf("popScope() result: `%s'\n",g_classScope.data());
437 static void setCurrentDoc(const QCString &anchor)
439 if (Doxygen::searchIndex)
443 g_code->setCurrentDoc(g_searchCtx,g_searchCtx->anchor(),FALSE);
447 g_code->setCurrentDoc(g_sourceFileDef,anchor,TRUE);
452 static void addToSearchIndex(const char *text)
454 if (Doxygen::searchIndex)
456 g_code->addWord(text,FALSE);
460 static void setClassScope(const QCString &name)
462 //printf("setClassScope(%s)\n",name.data());
464 n=n.simplifyWhiteSpace();
465 int ts=n.find('<'); // start of template
466 int te=n.findRev('>'); // end of template
467 //printf("ts=%d te=%d\n",ts,te);
468 if (ts!=-1 && te!=-1 && te>ts)
470 // remove template from scope
471 n=n.left(ts)+n.right(n.length()-te-1);
473 while (!g_classScopeLengthStack.isEmpty())
477 g_classScope.resize(0);
479 while ((i=n.find("::"))!=-1)
481 pushScope(n.left(i));
485 //printf("--->New class scope `%s'\n",g_classScope.data());
488 /*! start a new line of code, inserting a line number if g_sourceFileDef
489 * is TRUE. If a definition starts at the current line, then the line
490 * number is linked to the documentation of that definition.
492 static void startCodeLine()
494 //if (g_currentFontClass) { g_code->endFontClass(); }
495 if (g_sourceFileDef && g_lineNumbers)
497 //QCString lineNumber,lineAnchor;
498 //lineNumber.sprintf("%05d",g_yyLineNr);
499 //lineAnchor.sprintf("l%05d",g_yyLineNr);
501 Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
502 //printf("%s:startCodeLine(%d)=%p\n",g_sourceFileDef->name().data(),g_yyLineNr,d);
503 if (!g_includeCodeFragment && d)
505 g_currentDefinition = d;
506 g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
507 g_insideBody = FALSE;
508 g_searchingForBody = TRUE;
509 g_realScope = d->name();
514 g_parmType.resize(0);
515 g_parmName.resize(0);
516 //printf("Real scope: `%s'\n",g_realScope.data());
517 g_bodyCurlyCount = 0;
519 lineAnchor.sprintf("l%05d",g_yyLineNr);
520 if (g_currentMemberDef)
522 g_code->writeLineNumber(g_currentMemberDef->getReference(),
523 g_currentMemberDef->getOutputFileBase(),
524 g_currentMemberDef->anchor(),g_yyLineNr);
525 setCurrentDoc(lineAnchor);
527 else if (d->isLinkableInProject())
529 g_code->writeLineNumber(d->getReference(),
530 d->getOutputFileBase(),
532 setCurrentDoc(lineAnchor);
537 g_code->writeLineNumber(0,0,0,g_yyLineNr);
540 DBG_CTX((stderr,"startCodeLine(%d)\n",g_yyLineNr));
541 g_code->startCodeLine(g_sourceFileDef && g_lineNumbers);
542 if (g_currentFontClass)
544 g_code->startFontClass(g_currentFontClass);
549 static void endFontClass();
550 static void startFontClass(const char *s);
552 static void endCodeLine()
554 DBG_CTX((stderr,"endCodeLine(%d)\n",g_yyLineNr));
556 g_code->endCodeLine();
559 static void nextCodeLine()
561 const char * fc = g_currentFontClass;
563 if (g_yyLineNr<g_inputLines)
565 g_currentFontClass = fc;
570 /*! write a code fragment `text' that may span multiple lines, inserting
571 * line numbers for each line.
573 static void codifyLines(const char *text)
575 //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
576 const char *p=text,*sp=p;
582 while ((c=*p++) && c!='\n') { g_yyColNr++; }
588 int l = (int)(p-sp-1);
589 char *tmp = (char*)malloc(l+1);
604 /*! writes a link to a fragment \a text that may span multiple lines, inserting
605 * line numbers for each line. If \a text contains newlines, the link will be
606 * split into multiple links with the same destination, one for each line.
608 static void writeMultiLineCodeLink(CodeOutputInterface &ol,
612 static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
613 TooltipManager::instance()->addTooltip(d);
614 QCString ref = d->getReference();
615 QCString file = d->getOutputFileBase();
616 QCString anchor = d->anchor();
618 if (!sourceTooltips) // fall back to simple "title" tooltips
620 tooltip = d->briefDescriptionAsTooltip();
623 char *p=(char *)text;
628 while ((c=*p++) && c!='\n') { }
633 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
634 ol.writeCodeLink(ref,file,anchor,sp,tooltip);
639 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
640 ol.writeCodeLink(ref,file,anchor,sp,tooltip);
646 static void addType()
648 if (g_name=="const") { g_name.resize(0); return; }
649 if (!g_type.isEmpty()) g_type += ' ' ;
652 if (!g_type.isEmpty()) g_type += ' ' ;
657 static void addParmType()
659 if (g_parmName=="const") { g_parmName.resize(0); return; }
660 if (!g_parmType.isEmpty()) g_parmType += ' ' ;
661 g_parmType += g_parmName ;
662 g_parmName.resize(0) ;
665 static void addUsingDirective(const char *name)
667 if (g_sourceFileDef && name)
669 NamespaceDef *nd = Doxygen::namespaceSDict->find(name);
672 g_sourceFileDef->addUsingDirective(nd);
677 static void setParameterList(MemberDef *md)
679 g_classScope = md->getClassDef() ? md->getClassDef()->name().data() : "";
680 ArgumentList *al = md->argumentList();
682 ArgumentListIterator it(*al);
684 for (;(a=it.current());++it)
686 g_parmName = a->name.copy();
687 g_parmType = a->type.copy();
688 int i = g_parmType.find('*');
689 if (i!=-1) g_parmType = g_parmType.left(i);
690 i = g_parmType.find('&');
691 if (i!=-1) g_parmType = g_parmType.left(i);
692 g_parmType.stripPrefix("const ");
693 g_parmType=g_parmType.stripWhiteSpace();
694 g_theVarContext.addVariable(g_parmType,g_parmName);
698 static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
704 while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
706 QCString clName=className+templSpec;
708 if (!g_classScope.isEmpty())
710 cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName);
714 cd=getResolvedClass(d,g_sourceFileDef,clName);
716 //printf("stripClass trying `%s' = %p\n",clName.data(),cd);
726 static MemberDef *setCallContextForVar(const QCString &name)
728 if (name.isEmpty()) return 0;
729 DBG_CTX((stderr,"setCallContextForVar(%s) g_classScope=%s\n",name.data(),g_classScope.data()));
731 int scopeEnd = name.findRev("::");
732 if (scopeEnd!=-1) // name with explicit scope
734 QCString scope = name.left(scopeEnd);
735 QCString locName = name.right(name.length()-scopeEnd-2);
736 //printf("explicit scope: name=%s scope=%s\n",locName.data(),scope.data());
737 ClassDef *mcd = getClass(scope);
738 if (mcd && !locName.isEmpty())
740 MemberDef *md=mcd->getMemberByName(locName);
743 //printf("name=%s scope=%s\n",locName.data(),scope.data());
744 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
748 else // check namespace as well
750 NamespaceDef *mnd = getResolvedNamespace(scope);
751 if (mnd && !locName.isEmpty())
753 MemberDef *md=mnd->getMemberByName(locName);
756 //printf("name=%s scope=%s\n",locName.data(),scope.data());
757 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
765 ClassDef *mcd = g_theVarContext.findVariable(name);
766 if (mcd) // local variable
768 DBG_CTX((stderr,"local variable?\n"));
769 if (mcd!=VariableContext::dummyContext)
771 DBG_CTX((stderr,"local var `%s' mcd=%s\n",name.data(),mcd->name().data()));
772 g_theCallContext.setScope(mcd);
777 DBG_CTX((stderr,"class member? scope=%s\n",g_classScope.data()));
778 // look for a class member
779 mcd = getClass(g_classScope);
782 DBG_CTX((stderr,"Inside class %s\n",mcd->name().data()));
783 MemberDef *md=mcd->getMemberByName(name);
786 DBG_CTX((stderr,"Found member %s\n",md->name().data()));
787 if (g_scopeStack.top()!=CLASSBLOCK)
789 DBG_CTX((stderr,"class member `%s' mcd=%s\n",name.data(),mcd->name().data()));
790 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
797 // look for a global member
798 if ((mn=Doxygen::functionNameSDict->find(name)))
800 //printf("global var `%s'\n",name.data());
801 if (mn->count()==1) // global defined only once
803 MemberDef *md=mn->getFirst();
804 if (!md->isStatic() || md->getBodyDef()==g_sourceFileDef)
806 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
811 else if (mn->count()>1) // global defined more than once
813 MemberNameIterator it(*mn);
815 for (;(md=it.current());++it)
817 //printf("mn=%p md=%p md->getBodyDef()=%p g_sourceFileDef=%p\n",
819 // md->getBodyDef(),g_sourceFileDef);
821 // in case there are multiple members we could link to, we
822 // only link to members if defined in the same file or
823 // defined as external.
824 if ((!md->isStatic() || md->getBodyDef()==g_sourceFileDef) &&
825 (g_forceTagReference.isEmpty() || g_forceTagReference==md->getReference())
828 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
829 //printf("returning member %s in source file %s\n",md->name().data(),g_sourceFileDef->name().data());
839 static void updateCallContextForSmartPointer()
841 Definition *d = g_theCallContext.getScope();
842 //printf("updateCallContextForSmartPointer() cd=%s\n",cd ? d->name().data() : "<none>");
844 if (d && d->definitionType()==Definition::TypeClass && (md=((ClassDef*)d)->isSmartPointer()))
846 ClassDef *ncd = stripClassName(md->typeString(),md->getOuterScope());
849 g_theCallContext.setScope(ncd);
850 //printf("Found smart pointer call %s->%s!\n",cd->name().data(),ncd->name().data());
855 static bool getLinkInScope(const QCString &c, // scope
856 const QCString &m, // member
857 const char *memberText, // exact text
858 CodeOutputInterface &ol,
868 DBG_CTX((stderr,"getLinkInScope: trying `%s'::`%s' varOnly=%d\n",c.data(),m.data(),varOnly));
869 if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef,FALSE,g_forceTagReference) &&
870 (!varOnly || md->isVariable()))
872 if (md->isLinkable())
874 //printf("found it %s!\n",md->qualifiedName().data());
878 anchor.sprintf("a%d",g_anchorCount);
879 //printf("addExampleFile(%s,%s,%s)\n",anchor.data(),g_exampleName.data(),
880 // g_exampleFile.data());
881 if (md->addExample(anchor,g_exampleName,g_exampleFile))
883 ol.writeCodeAnchor(anchor);
888 Definition *d = md->getOuterScope()==Doxygen::globalScope ?
889 md->getFileDef() : md->getOuterScope();
890 if (md->getGroupDef()) d = md->getGroupDef();
891 if (d && d->isLinkable())
893 g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
894 //printf("g_currentDefinition=%p g_currentMemberDef=%p g_insideBody=%d\n",
895 // g_currentDefinition,g_currentMemberDef,g_insideBody);
897 if (g_currentDefinition && g_currentMemberDef &&
898 md!=g_currentMemberDef && g_insideBody && g_collectXRefs)
900 addDocCrossReference(g_currentMemberDef,md);
902 //printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
904 writeMultiLineCodeLink(ol,md, text ? text : memberText);
905 addToSearchIndex(text ? text : memberText);
909 else // found member, but it is not linkable, so make sure content inside is not assigned
910 // to the previous member, see bug762760
912 DBG_CTX((stderr,"unlinkable member %s\n",md->name().data()));
913 g_currentMemberDef = 0;
919 static bool getLink(const char *className,
920 const char *memberName,
921 CodeOutputInterface &ol,
925 //printf("getLink(%s,%s) g_curClassName=%s\n",className,memberName,g_curClassName.data());
926 QCString m=removeRedundantWhiteSpace(memberName);
927 QCString c=className;
928 if (!getLinkInScope(c,m,memberName,ol,text,varOnly))
930 if (!g_curClassName.isEmpty())
932 if (!c.isEmpty()) c.prepend("::");
933 c.prepend(g_curClassName);
934 return getLinkInScope(c,m,memberName,ol,text,varOnly);
941 static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName,
942 bool typeOnly=FALSE,bool varOnly=FALSE)
945 if (*clName=='~') // correct for matching negated values i.s.o. destructors.
950 QCString className=clName;
951 if (className.isEmpty()) return;
952 if (g_insideProtocolList) // for Obj-C
958 className = substitute(className,"\\","::"); // for PHP namespaces
960 else if (g_insideCS || g_insideJava)
962 className = substitute(className,".","::"); // for PHP namespaces
964 ClassDef *cd=0,*lcd=0;
968 //printf("generateClassOrGlobalLink(className=%s)\n",className.data());
969 if (!g_prefixed_with_this_keyword || (lcd=g_theVarContext.findVariable(className))==0) // not a local variable
971 Definition *d = g_currentDefinition;
972 //printf("d=%s g_sourceFileDef=%s\n",d?d->name().data():"<none>",g_sourceFileDef?g_sourceFileDef->name().data():"<none>");
973 cd = getResolvedClass(d,g_sourceFileDef,className,&md);
974 DBG_CTX((stderr,"non-local variable name=%s context=%d cd=%s md=%s!\n",
975 className.data(),g_theVarContext.count(),cd?cd->name().data():"<none>",
976 md?md->name().data():"<none>"));
977 if (cd==0 && md==0 && (i=className.find('<'))!=-1)
979 QCString bareName = className.left(i); //stripTemplateSpecifiersFromScope(className);
980 DBG_CTX((stderr,"bareName=%s\n",bareName.data()));
981 if (bareName!=className)
983 cd=getResolvedClass(d,g_sourceFileDef,bareName,&md); // try unspecialized version
986 NamespaceDef *nd = getResolvedNamespace(className);
987 if (nd && nd->isLinkableInProject())
989 g_theCallContext.setScope(nd);
990 addToSearchIndex(className);
991 writeMultiLineCodeLink(*g_code,nd,clName);
994 //printf("md=%s\n",md?md->name().data():"<none>");
995 DBG_CTX((stderr,"is found as a type cd=%s nd=%s\n",
996 cd?cd->name().data():"<null>",
997 nd?nd->name().data():"<null>"));
998 if (cd==0 && md==0) // also see if it is variable or enum or enum value
1000 if (getLink(g_classScope,clName,ol,clName,varOnly))
1008 //printf("local variable!\n");
1009 if (lcd!=VariableContext::dummyContext)
1011 //printf("non-dummy context lcd=%s!\n",lcd->name().data());
1012 g_theCallContext.setScope(lcd);
1014 // to following is needed for links to a global variable, but is
1015 // no good for a link to a local variable that is also a global symbol.
1017 //if (getLink(g_classScope,clName,ol,clName))
1023 DBG_CTX((stderr,"is a local variable cd=%p!\n",cd));
1025 g_prefixed_with_this_keyword = FALSE; // discard the "this" prefix for the next calls
1027 if (cd && cd->isLinkable()) // is it a linkable class
1029 DBG_CTX((stderr,"is linkable class %s\n",clName));
1033 anchor.sprintf("_a%d",g_anchorCount);
1034 //printf("addExampleClass(%s,%s,%s)\n",anchor.data(),g_exampleName.data(),
1035 // g_exampleFile.data());
1036 if (cd->addExample(anchor,g_exampleName,g_exampleFile))
1038 ol.writeCodeAnchor(anchor);
1042 writeMultiLineCodeLink(ol,cd,clName);
1043 addToSearchIndex(className);
1044 g_theCallContext.setScope(cd);
1047 Definition *d = md->getOuterScope()==Doxygen::globalScope ?
1048 md->getFileDef() : md->getOuterScope();
1049 if (md->getGroupDef()) d = md->getGroupDef();
1050 if (d && d->isLinkable() && md->isLinkable() &&
1051 g_currentMemberDef && g_collectXRefs)
1053 addDocCrossReference(g_currentMemberDef,md);
1057 else // not a class, maybe a global member
1059 DBG_CTX((stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly));
1060 if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
1062 if (md==0) // not found as a typedef
1064 md = setCallContextForVar(clName);
1065 //printf("setCallContextForVar(%s) md=%p g_currentDefinition=%p\n",clName,md,g_currentDefinition);
1066 if (md && g_currentDefinition)
1068 DBG_CTX((stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
1069 md->name().data(),g_currentDefinition->name().data(),
1070 isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md),
1071 md->getOuterScope()->name().data()));
1074 if (md && g_currentDefinition &&
1075 isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)==-1)
1077 md=0; // variable not accessible
1080 if (md && (!varOnly || md->isVariable()))
1082 DBG_CTX((stderr,"is a global md=%p g_currentDefinition=%s linkable=%d\n",md,g_currentDefinition?g_currentDefinition->name().data():"<none>",md->isLinkable()));
1083 if (md->isLinkable())
1086 if (!g_forceTagReference.isEmpty()) // explicit reference to symbol in tag file
1088 text=g_forceTagReference;
1089 if (text.right(4)==".tag") // strip .tag if present
1091 text=text.left(text.length()-4);
1093 text+=getLanguageSpecificSeparator(md->getLanguage());
1096 md->setLocalName(text);
1098 else // normal reference
1102 writeMultiLineCodeLink(ol,md,text);
1103 addToSearchIndex(clName);
1104 if (g_currentMemberDef && g_collectXRefs)
1106 addDocCrossReference(g_currentMemberDef,md);
1113 // nothing found, just write out the word
1114 DBG_CTX((stderr,"not found!\n"));
1115 codifyLines(clName);
1116 addToSearchIndex(clName);
1120 static bool generateClassMemberLink(CodeOutputInterface &ol,MemberDef *xmd,const char *memName)
1122 // extract class definition of the return type in order to resolve
1123 // a->b()->c() like call chains
1125 //printf("type=`%s' args=`%s' class=%s\n",
1126 // xmd->typeString(),xmd->argsString(),
1127 // xmd->getClassDef()->name().data());
1132 anchor.sprintf("a%d",g_anchorCount);
1133 //printf("addExampleFile(%s,%s,%s)\n",anchor.data(),g_exampleName.data(),
1134 // g_exampleFile.data());
1135 if (xmd->addExample(anchor,g_exampleName,g_exampleFile))
1137 ol.writeCodeAnchor(anchor);
1142 ClassDef *typeClass = stripClassName(removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
1143 DBG_CTX((stderr,"%s -> typeName=%p\n",xmd->typeString(),typeClass));
1144 g_theCallContext.setScope(typeClass);
1146 Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ?
1147 xmd->getFileDef() : xmd->getOuterScope();
1148 if (xmd->getGroupDef()) xd = xmd->getGroupDef();
1149 if (xd && xd->isLinkable())
1152 //printf("g_currentDefiniton=%p g_currentMemberDef=%p xmd=%p g_insideBody=%d\n",g_currentDefinition,g_currentMemberDef,xmd,g_insideBody);
1154 if (xmd->templateMaster()) xmd = xmd->templateMaster();
1156 if (xmd->isLinkable())
1158 // add usage reference
1159 if (g_currentDefinition && g_currentMemberDef &&
1160 /*xmd!=g_currentMemberDef &&*/ g_insideBody && g_collectXRefs)
1162 addDocCrossReference(g_currentMemberDef,xmd);
1165 // write the actual link
1166 writeMultiLineCodeLink(ol,xmd,memName);
1167 addToSearchIndex(memName);
1175 static bool generateClassMemberLink(CodeOutputInterface &ol,Definition *def,const char *memName)
1177 if (def && def->definitionType()==Definition::TypeClass)
1179 ClassDef *cd = (ClassDef*)def;
1180 MemberDef *xmd = cd->getMemberByName(memName);
1181 //printf("generateClassMemberLink(class=%s,member=%s)=%p\n",def->name().data(),memName,xmd);
1184 return generateClassMemberLink(ol,xmd,memName);
1188 Definition *innerDef = cd->findInnerCompound(memName);
1191 g_theCallContext.setScope(innerDef);
1192 addToSearchIndex(memName);
1193 writeMultiLineCodeLink(*g_code,innerDef,memName);
1198 else if (def && def->definitionType()==Definition::TypeNamespace)
1200 NamespaceDef *nd = (NamespaceDef*)def;
1201 //printf("Looking for %s inside namespace %s\n",memName,nd->name().data());
1202 Definition *innerDef = nd->findInnerCompound(memName);
1205 g_theCallContext.setScope(innerDef);
1206 addToSearchIndex(memName);
1207 writeMultiLineCodeLink(*g_code,innerDef,memName);
1214 static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
1217 //printf("generateMemberLink(object=%s,mem=%s) classScope=%s\n",
1218 // varName.data(),memName,g_classScope.data());
1220 if (varName.isEmpty()) return;
1222 // look for the variable in the current context
1223 ClassDef *vcd = g_theVarContext.findVariable(varName);
1226 if (vcd!=VariableContext::dummyContext)
1228 //printf("Class found!\n");
1229 if (getLink(vcd->name(),memName,ol))
1231 //printf("Found result!\n");
1234 if (vcd->baseClasses())
1236 BaseClassListIterator bcli(*vcd->baseClasses());
1237 for ( ; bcli.current() ; ++bcli)
1239 if (getLink(bcli.current()->classDef->name(),memName,ol))
1241 //printf("Found result!\n");
1248 else // variable not in current context, maybe it is in a parent context
1250 vcd = getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope);
1251 if (vcd && vcd->isLinkable())
1253 //printf("Found class %s for variable `%s'\n",g_classScope.data(),varName.data());
1254 MemberName *vmn=Doxygen::memberNameSDict->find(varName);
1258 QCString vn=varName;
1259 if ((vi=vn.findRev("::"))!=-1 || (vi=vn.findRev('.'))!=-1) // explicit scope A::b(), probably static member
1261 ClassDef *jcd = getClass(vn.left(vi));
1262 vn=vn.right(vn.length()-vi-2);
1263 vmn=Doxygen::memberNameSDict->find(vn);
1264 //printf("Trying name `%s' scope=%s\n",vn.data(),scope.data());
1267 MemberNameIterator vmni(*vmn);
1269 for (;(vmd=vmni.current());++vmni)
1271 if (/*(vmd->isVariable() || vmd->isFunction()) && */
1272 vmd->getClassDef()==jcd)
1274 //printf("Found variable type=%s\n",vmd->typeString());
1275 ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
1276 if (mcd && mcd->isLinkable())
1278 if (generateClassMemberLink(ol,mcd,memName)) return;
1287 //printf("There is a variable with name `%s'\n",varName);
1288 MemberNameIterator vmni(*vmn);
1290 for (;(vmd=vmni.current());++vmni)
1292 if (/*(vmd->isVariable() || vmd->isFunction()) && */
1293 vmd->getClassDef()==vcd)
1295 //printf("Found variable type=%s\n",vmd->typeString());
1296 ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
1297 if (mcd && mcd->isLinkable())
1299 if (generateClassMemberLink(ol,mcd,memName)) return;
1306 // nothing found -> write result as is
1307 codifyLines(memName);
1308 addToSearchIndex(memName);
1312 static void generatePHPVariableLink(CodeOutputInterface &ol,const char *varName)
1314 QCString name = varName+7; // strip $this->
1316 //printf("generatePHPVariableLink(%s) name=%s scope=%s\n",varName,name.data(),g_classScope.data());
1317 if (!getLink(g_classScope,name,ol,varName))
1319 codifyLines(varName);
1323 static void generateFunctionLink(CodeOutputInterface &ol,const char *funcName)
1325 //CodeClassDef *ccd=0;
1327 QCString locScope=g_classScope;
1328 QString qq=removeRedundantWhiteSpace(funcName);
1329 if (g_insidePHP && qq.startsWith("self::")) qq=qq.mid(4);
1330 QCString locFunc(qq.data());
1332 QCString funcWithScope=locFunc;
1333 QCString funcWithFullScope=locFunc;
1334 QCString fullScope=locScope;
1335 DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data()));
1337 int i=locFunc.findRev("::");
1338 if (g_currentMemberDef && g_currentMemberDef->getClassDef() &&
1339 funcName==g_currentMemberDef->localName() &&
1340 g_currentMemberDef->getDefLine()==g_yyLineNr &&
1341 generateClassMemberLink(ol,g_currentMemberDef,funcName)
1344 // special case where funcName is the name of a method that is also
1345 // defined on this line. In this case we can directly link to
1346 // g_currentMemberDef, which is not only faster, but
1347 // in case of overloaded methods, this will make sure that we link to
1348 // the correct method, and thereby get the correct reimplemented relations.
1349 // See also bug 549022.
1352 if (i==-1) i=locFunc.findRev("."),len=1;
1353 if (i==-1) i=locFunc.findRev("\\"),len=1; // for PHP
1356 funcScope=locFunc.left(i);
1357 locFunc=locFunc.right(locFunc.length()-i-len).stripWhiteSpace();
1358 int ts=locScope.find('<'); // start of template
1359 int te=locScope.findRev('>'); // end of template
1360 //printf("ts=%d te=%d\n",ts,te);
1361 if (ts!=-1 && te!=-1 && te>ts)
1363 // remove template from scope
1364 locScope=locScope.left(ts)+locScope.right(locScope.length()-te-1);
1366 ts=funcScope.find('<'); // start of template
1367 te=funcScope.findRev('>'); // end of template
1368 //printf("ts=%d te=%d\n",ts,te);
1369 if (ts!=-1 && te!=-1 && te>ts)
1371 // remove template from scope
1372 funcScope=funcScope.left(ts)+funcScope.right(funcScope.length()-te-1);
1374 if (!funcScope.isEmpty())
1376 funcWithScope = funcScope+"::"+locFunc;
1377 if (!locScope.isEmpty())
1379 fullScope=locScope+"::"+funcScope;
1382 if (!locScope.isEmpty())
1384 funcWithFullScope = locScope+"::"+funcWithScope;
1387 if (!fullScope.isEmpty() && (ccd=g_codeClassSDict->find(fullScope)))
1389 //printf("using classScope %s\n",g_classScope.data());
1390 if (ccd->baseClasses())
1392 BaseClassListIterator bcli(*ccd->baseClasses());
1393 for ( ; bcli.current() ; ++bcli)
1395 if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName))
1402 if (!locScope.isEmpty() && fullScope!=locScope && (ccd=g_codeClassSDict->find(locScope)))
1404 //printf("using classScope %s\n",g_classScope.data());
1405 if (ccd->baseClasses())
1407 BaseClassListIterator bcli(*ccd->baseClasses());
1408 for ( ; bcli.current() ; ++bcli)
1410 if (getLink(bcli.current()->classDef->name(),funcWithScope,ol,funcName))
1417 if (!getLink(locScope,funcWithScope,ol,funcName))
1419 generateClassOrGlobalLink(ol,funcName);
1422 g_forceTagReference.resize(0);
1426 /*! counts the number of lines in the input */
1427 static int countLines()
1429 const char *p=g_inputString;
1435 if (c=='\n') count++;
1437 if (p>g_inputString && *(p-1)!='\n')
1438 { // last line does not end with a \n, so we add an extra
1439 // line and explicitly terminate the line after parsing.
1441 g_needsTermination=TRUE;
1446 static void endFontClass()
1448 if (g_currentFontClass)
1450 g_code->endFontClass();
1451 g_currentFontClass=0;
1455 static void startFontClass(const char *s)
1458 g_code->startFontClass(s);
1459 g_currentFontClass=s;
1462 //----------------------------------------------------------------------------
1464 // recursively writes a linkified Objective-C method call
1465 static void writeObjCMethodCall(ObjCCallCtx *ctx)
1469 const char *p = ctx->format.data();
1470 if (!ctx->methodName.isEmpty())
1472 //printf("writeObjCMethodCall(%s) obj=%s method=%s\n",
1473 // ctx->format.data(),ctx->objectTypeOrName.data(),ctx->methodName.data());
1474 if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$')
1476 //printf("Looking for object=%s method=%s\n",ctx->objectTypeOrName.data(),
1477 // ctx->methodName.data());
1478 ClassDef *cd = g_theVarContext.findVariable(ctx->objectTypeOrName);
1479 if (cd==0) // not a local variable
1481 if (ctx->objectTypeOrName=="self")
1483 if (g_currentDefinition &&
1484 g_currentDefinition->definitionType()==Definition::TypeClass)
1486 ctx->objectType = (ClassDef *)g_currentDefinition;
1491 ctx->objectType = getResolvedClass(
1492 g_currentDefinition,
1494 ctx->objectTypeOrName,
1497 //printf(" object is class? %p\n",ctx->objectType);
1498 if (ctx->objectType) // found class
1500 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
1501 //printf(" yes->method=%s\n",ctx->method?ctx->method->name().data():"<none>");
1503 else if (ctx->method==0) // search for class variable with the same name
1506 //printf("g_currentDefinition=%p\n",g_currentDefinition);
1507 if (g_currentDefinition &&
1508 g_currentDefinition->definitionType()==Definition::TypeClass)
1510 ctx->objectVar = ((ClassDef *)g_currentDefinition)->getMemberByName(ctx->objectTypeOrName);
1511 //printf(" ctx->objectVar=%p\n",ctx->objectVar);
1514 ctx->objectType = stripClassName(ctx->objectVar->typeString());
1515 //printf(" ctx->objectType=%p\n",ctx->objectType);
1516 if (ctx->objectType)
1518 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
1519 //printf(" ctx->method=%p\n",ctx->method);
1525 else // local variable
1527 //printf(" object is local variable\n");
1528 if (cd!=VariableContext::dummyContext)
1530 ctx->method = cd->getMemberByName(ctx->methodName);
1531 //printf(" class=%p method=%p\n",cd,ctx->method);
1538 while ((c=*p++)) // for each character in ctx->format
1543 if (nc=='$') // escaped $
1545 g_code->codify("$");
1547 else // name fragment or reference to a nested call
1549 if (nc=='n') // name fragment
1553 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
1555 int refId=refIdStr.toInt();
1556 QCString *pName = g_nameDict.find(refId);
1559 if (ctx->method && ctx->method->isLinkable())
1561 writeMultiLineCodeLink(*g_code,ctx->method,pName->data());
1562 if (g_currentMemberDef && g_collectXRefs)
1564 addDocCrossReference(g_currentMemberDef,ctx->method);
1569 codifyLines(pName->data());
1574 //printf("Invalid name: id=%d\n",refId);
1577 else if (nc=='o') // reference to potential object name
1581 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
1583 int refId=refIdStr.toInt();
1584 QCString *pObject = g_objectDict.find(refId);
1587 if (*pObject=="self")
1589 if (g_currentDefinition &&
1590 g_currentDefinition->definitionType()==Definition::TypeClass)
1592 ctx->objectType = (ClassDef *)g_currentDefinition;
1593 if (ctx->objectType->categoryOf())
1595 ctx->objectType = ctx->objectType->categoryOf();
1597 if (ctx->objectType)
1599 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
1602 startFontClass("keyword");
1603 codifyLines(pObject->data());
1606 else if (*pObject=="super")
1608 if (g_currentDefinition &&
1609 g_currentDefinition->definitionType()==Definition::TypeClass)
1611 ClassDef *cd = (ClassDef *)g_currentDefinition;
1612 if (cd->categoryOf())
1614 cd = cd->categoryOf();
1616 BaseClassList *bcd = cd->baseClasses();
1617 if (bcd) // get direct base class (there should be only one)
1619 BaseClassListIterator bli(*bcd);
1620 BaseClassDef *bclass;
1621 for (bli.toFirst();(bclass=bli.current());++bli)
1623 if (bclass->classDef->compoundType()!=ClassDef::Protocol)
1625 ctx->objectType = bclass->classDef;
1626 if (ctx->objectType)
1628 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
1634 startFontClass("keyword");
1635 codifyLines(pObject->data());
1638 else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable
1640 writeMultiLineCodeLink(*g_code,ctx->objectVar,pObject->data());
1641 if (g_currentMemberDef && g_collectXRefs)
1643 addDocCrossReference(g_currentMemberDef,ctx->objectVar);
1646 else if (ctx->objectType &&
1647 ctx->objectType!=VariableContext::dummyContext &&
1648 ctx->objectType->isLinkable()
1649 ) // object is class name
1651 ClassDef *cd = ctx->objectType;
1652 writeMultiLineCodeLink(*g_code,cd,pObject->data());
1654 else // object still needs to be resolved
1656 ClassDef *cd = getResolvedClass(g_currentDefinition,
1657 g_sourceFileDef, *pObject);
1658 if (cd && cd->isLinkable())
1660 if (ctx->objectType==0) ctx->objectType=cd;
1661 writeMultiLineCodeLink(*g_code,cd,pObject->data());
1665 codifyLines(pObject->data());
1671 //printf("Invalid object: id=%d\n",refId);
1674 else if (nc=='c') // reference to nested call
1678 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
1680 int refId=refIdStr.toInt();
1681 ObjCCallCtx *ictx = g_contextDict.find(refId);
1682 if (ictx) // recurse into nested call
1684 writeObjCMethodCall(ictx);
1685 if (ictx->method) // link to nested call successfully
1687 // get the ClassDef representing the method's return type
1688 if (QCString(ictx->method->typeString())=="id")
1690 // see if the method name is unique, if so we link to it
1691 MemberName *mn=Doxygen::memberNameSDict->find(ctx->methodName);
1692 //printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n",
1693 // mn==0?-1:(int)mn->count(),
1694 // ictx->method->name().data(),
1695 // ctx->methodName.data());
1696 if (mn && mn->count()==1) // member name unique
1698 ctx->method = mn->getFirst();
1703 ctx->objectType = stripClassName(ictx->method->typeString());
1704 if (ctx->objectType)
1706 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
1709 //printf(" ***** method=%s -> object=%p\n",ictx->method->name().data(),ctx->objectType);
1714 //printf("Invalid context: id=%d\n",refId);
1717 else if (nc=='w') // some word
1721 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
1723 int refId=refIdStr.toInt();
1724 QCString *pWord = g_wordDict.find(refId);
1727 codifyLines(pWord->data());
1730 else if (nc=='d') // comment block
1734 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
1736 int refId=refIdStr.toInt();
1737 QCString *pComment = g_commentDict.find(refId);
1740 startFontClass("comment");
1741 codifyLines(pComment->data());
1745 else // illegal marker
1747 ASSERT(!"invalid escape sequence");
1751 else // normal non-marker character
1758 //printf("%s %s]\n",ctx->objectTypeOrName.data(),ctx->methodName.data());
1759 //printf("}=(type='%s',name='%s')",
1760 // ctx->objectTypeOrName.data(),
1761 // ctx->methodName.data());
1764 // Replaces an Objective-C method name fragment s by a marker of the form
1765 // $n12, the number (12) can later be used as a key for obtaining the name
1766 // fragment, from g_nameDict
1767 static QCString escapeName(const char *s)
1770 result.sprintf("$n%d",g_currentNameId);
1771 g_nameDict.insert(g_currentNameId,new QCString(s));
1776 static QCString escapeObject(const char *s)
1779 result.sprintf("$o%d",g_currentObjId);
1780 g_objectDict.insert(g_currentObjId,new QCString(s));
1785 static QCString escapeWord(const char *s)
1788 result.sprintf("$w%d",g_currentWordId);
1789 g_wordDict.insert(g_currentWordId,new QCString(s));
1794 static QCString escapeComment(const char *s)
1797 result.sprintf("$d%d",g_currentCommentId);
1798 g_commentDict.insert(g_currentCommentId,new QCString(s));
1799 g_currentCommentId++;
1803 static bool skipLanguageSpecificKeyword(const QCString &kw)
1805 return g_insideCpp && (kw == "remove" || kw == "set" || kw == "get");
1808 /* -----------------------------------------------------------------
1811 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1813 static int yyread(char *buf,int max_size)
1816 while( c < max_size && g_inputString[g_inputPosition] )
1818 *buf = g_inputString[g_inputPosition++] ;
1828 ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
1830 SCOPENAME ({SEP}{BN}*)?({ID}{BN}*{SEP}{BN}*)*("~"{BN}*)?{ID}
1831 TEMPLIST "<"[^\"\}\{\(\)\/\n\>]*">"
1832 SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID})
1833 SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+
1834 KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property")
1835 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"|{KEYWORD_OBJC})
1836 FLOWKW ("break"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"return"|"switch"|"throw"|"throws"|"@catch"|"@finally")
1837 FLOWCONDITION ("case"|"for"|"foreach"|"for each"|"goto"|"if"|"try"|"while"|"@try")
1838 TYPEKW ("bool"|"byte"|"char"|"double"|"float"|"int"|"long"|"object"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"size_t"|"boolean"|"id"|"SEL"|"string"|"nullptr")
1839 TYPEKWSL ("LocalObject"|"Object"|"Value")
1840 CASTKW ("const_cast"|"dynamic_cast"|"reinterpret_cast"|"static_cast")
1841 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
1842 ARITHOP "+"|"-"|"/"|"*"|"%"|"--"|"++"
1843 ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
1844 LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!"
1845 BITOP "&"|"|"|"^"|"<<"|">>"|"~"
1846 OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
1847 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
1848 RAWEND ")"[^ \t\(\)\\]{0,16}\"
1858 %x RemoveSpecialCComment
1859 %x StripSpecialCComment
1870 %x CppCliTypeModifierFollowup
1892 <Body>^([ \t]*"#"[ \t]*("include"|"import")[ \t]*)("<"|"\"") {
1893 startFontClass("preprocessor");
1894 g_code->codify(yytext);
1895 BEGIN( ReadInclude );
1897 <Body>("@interface"|"@implementation"|"@protocol")[ \t\n]+ {
1899 startFontClass("keyword");
1900 codifyLines(yytext);
1902 if (!g_insideTemplate)
1905 <Body>(("public"|"private"){B}+)?("ref"|"value"|"interface"|"enum"){B}+("class"|"struct") {
1906 if (g_insideTemplate) REJECT;
1907 startFontClass("keyword");
1908 codifyLines(yytext);
1912 <Body>"property"|"event"/{BN}* {
1913 if (g_insideTemplate) REJECT;
1914 startFontClass("keyword");
1915 codifyLines(yytext);
1918 <Body>(KEYWORD_CPPCLI_DATATYPE|("partial"{B}+)?"class"|"struct"|"union"|"namespace"|"interface"){B}+ {
1919 startFontClass("keyword");
1920 codifyLines(yytext);
1922 if (!g_insideTemplate)
1925 <Body>("package")[ \t\n]+ {
1926 startFontClass("keyword");
1927 codifyLines(yytext);
1929 BEGIN( PackageName );
1932 if (!g_insideObjC) REJECT;
1933 codifyLines(yytext);
1936 <Body,ClassVar,Bases>"-"|"+" {
1937 if (!g_insideObjC || g_insideBody)
1939 g_code->codify(yytext);
1941 else // Start of Objective-C method
1943 //printf("Method!\n");
1944 g_code->codify(yytext);
1949 g_code->codify(yytext);
1953 g_code->codify(yytext);
1954 BEGIN(ObjCParamType);
1956 <ObjCParams,ObjCMethod>";"|"{" {
1957 g_code->codify(yytext);
1960 if (g_searchingForBody)
1962 g_searchingForBody=FALSE;
1965 if (g_insideBody) g_bodyCurlyCount++;
1966 if (!g_curClassName.isEmpty()) // valid class name
1968 pushScope(g_curClassName);
1969 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1970 g_scopeStack.push(SCOPEBLOCK);
1977 <ObjCParams>{ID}{B}*":" {
1978 g_code->codify(yytext);
1980 <ObjCParamType>{TYPEKW} {
1981 startFontClass("keywordtype");
1982 g_code->codify(yytext);
1986 <ObjCParamType>{ID} {
1987 generateClassOrGlobalLink(*g_code,yytext);
1990 <ObjCParamType>")" {
1991 g_code->codify(yytext);
1995 g_code->codify(yytext);
1997 g_theVarContext.addVariable(g_parmType,g_parmName);
1998 g_parmType.resize(0);g_parmName.resize(0);
2000 <ObjCMethod,ObjCParams,ObjCParamType>{ID} {
2001 generateClassOrGlobalLink(*g_code,yytext);
2003 <ObjCMethod,ObjCParams,ObjCParamType>. {
2004 g_code->codify(yytext);
2006 <ObjCMethod,ObjCParams,ObjCParamType>\n {
2007 codifyLines(yytext);
2009 <ReadInclude>[^\n\"\>]+/(">"|"\"") {
2013 //QCString absPath = yytext;
2014 //if (g_sourceFileDef && QDir::isRelativePath(absPath))
2016 // absPath = QDir::cleanDirPath(g_sourceFileDef->getPath()+"/"+absPath);
2019 FileDef *fd=findFileDef(Doxygen::inputNameDict,yytext,ambig);
2020 //printf("looking for include %s -> %s fd=%p\n",yytext,absPath.data(),fd);
2021 if (fd && fd->isLinkable())
2023 if (ambig) // multiple input files match the name
2025 //printf("===== yes %s is ambiguous\n",yytext);
2026 QCString name = QDir::cleanDirPath(yytext).utf8();
2027 if (!name.isEmpty() && g_sourceFileDef)
2029 FileName *fn = Doxygen::inputNameDict->find(name);
2032 FileNameIterator fni(*fn);
2033 // for each include name
2034 for (fni.toFirst();!found && (fd=fni.current());++fni)
2036 // see if this source file actually includes the file
2037 found = g_sourceFileDef->isIncluded(fd->absFilePath());
2038 //printf(" include file %s found=%d\n",fd->absFilePath().data(),found);
2043 else // not ambiguous
2048 //printf(" include file %s found=%d\n",fd ? fd->absFilePath().data() : "<none>",found);
2051 writeMultiLineCodeLink(*g_code,fd,yytext);
2055 g_code->codify(yytext);
2060 g_code->codify(text);
2064 <Body,Bases>^[ \t]*"#" {
2065 startFontClass("preprocessor");
2066 g_lastSkipCppContext = YY_START;
2067 g_code->codify(yytext);
2071 g_code->codify(yytext);
2073 <SkipCPP>[^\n\/\\]+ {
2074 g_code->codify(yytext);
2076 <SkipCPP>\\[\r]?\n {
2077 codifyLines(yytext);
2080 g_code->codify(yytext);
2082 <Body,FuncCall>"{" {
2083 g_theVarContext.pushScope();
2085 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
2086 g_scopeStack.push(INNERBLOCK);
2088 if (g_searchingForBody)
2090 g_searchingForBody=FALSE;
2093 g_code->codify(yytext);
2102 <Body,FuncCall,MemberCall,MemberCall2>"}" {
2103 g_theVarContext.popScope();
2107 int *scope = g_scopeStack.pop();
2108 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
2109 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
2114 g_code->codify(yytext);
2116 DBG_CTX((stderr,"g_bodyCurlyCount=%d\n",g_bodyCurlyCount));
2117 if (--g_bodyCurlyCount<=0)
2120 g_currentMemberDef=0;
2121 if (g_currentDefinition)
2122 g_currentDefinition=g_currentDefinition->getOuterScope();
2126 <Body,ClassVar>"@end" {
2127 //printf("End of objc scope fd=%s\n",g_sourceFileDef->name().data());
2128 if (g_sourceFileDef)
2130 FileDef *fd=g_sourceFileDef;
2131 g_insideObjC = fd->name().lower().right(2)==".m" ||
2132 fd->name().lower().right(3)==".mm";
2133 //printf("insideObjC=%d\n",g_insideObjC);
2137 g_insideObjC = FALSE;
2141 g_theVarContext.popScope();
2143 int *scope = g_scopeStack.pop();
2144 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
2145 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
2152 startFontClass("keyword");
2153 g_code->codify(yytext);
2156 g_currentMemberDef=0;
2157 if (g_currentDefinition)
2158 g_currentDefinition=g_currentDefinition->getOuterScope();
2161 <ClassName,ClassVar>";" {
2162 g_code->codify(yytext);
2163 g_searchingForBody=FALSE;
2166 <ClassName,ClassVar>[*&^%]+ {
2167 g_type=g_curClassName.copy();
2169 g_code->codify(yytext);
2170 BEGIN( Body ); // variable of type struct *
2172 <ClassName>"__declspec"{B}*"("{B}*{ID}{B}*")" {
2173 startFontClass("keyword");
2174 g_code->codify(yytext);
2177 <ClassName>{ID}("."{ID})* |
2178 <ClassName>{ID}("::"{ID})* {
2180 g_curClassName=substitute(yytext,".","::");
2182 g_curClassName=yytext;
2184 if (g_curClassName=="alignas")
2186 startFontClass("keyword");
2187 g_code->codify(yytext);
2193 generateClassOrGlobalLink(*g_code,yytext);
2199 g_code->codify(yytext);
2200 BEGIN( AlignAsEnd );
2202 <AlignAs>\n { g_yyLineNr++;
2203 codifyLines(yytext);
2205 <AlignAs>. { g_code->codify(yytext); }
2206 <AlignAsEnd>"(" { g_code->codify(yytext);
2210 g_code->codify(yytext);
2211 if (--g_bracketCount<=0)
2216 <AlignAsEnd>\n { g_yyLineNr++;
2217 codifyLines(yytext);
2219 <AlignAsEnd>. { g_code->codify(yytext); }
2220 <ClassName>{ID}("\\"{ID})* { // PHP namespace
2221 g_curClassName=substitute(yytext,"\\","::");
2222 g_scopeStack.push(CLASSBLOCK);
2223 pushScope(g_curClassName);
2225 generateClassOrGlobalLink(*g_code,yytext);
2228 <ClassName>{ID}{B}*"("{ID}")" { // Obj-C category
2229 g_curClassName=removeRedundantWhiteSpace(yytext);
2230 g_scopeStack.push(CLASSBLOCK);
2231 pushScope(g_curClassName);
2233 generateClassOrGlobalLink(*g_code,yytext);
2236 <PackageName>{ID}("."{ID})* {
2237 g_curClassName=substitute(yytext,".","::");
2238 //printf("found package: %s\n",g_curClassName.data());
2240 codifyLines(yytext);
2246 <ClassVar>("extends"|"implements") { // Java, Slice
2247 startFontClass("keyword");
2248 codifyLines(yytext);
2250 g_curClassBases.clear();
2253 <ClassVar>("sealed"|"abstract")/{BN}*(":"|"{") {
2254 DBG_CTX((stderr,"***** C++/CLI modifier %s on g_curClassName=%s\n",yytext,g_curClassName.data()));
2255 startFontClass("keyword");
2256 codifyLines(yytext);
2258 BEGIN( CppCliTypeModifierFollowup );
2261 g_type = g_curClassName.copy();
2265 g_theVarContext.addVariable(g_type,g_name);
2267 generateClassOrGlobalLink(*g_code,yytext);
2269 <ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*":"{B}* {
2270 codifyLines(yytext);
2271 g_curClassBases.clear();
2274 <PackageName>[ \t]*";" |
2275 <Bases>^{B}*/"@"{ID} | // Objective-C interface
2276 <Bases,ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*"{"{B}* {
2277 g_theVarContext.pushScope();
2278 g_code->codify(yytext);
2279 if (YY_START==ClassVar && g_curClassName.isEmpty())
2281 g_curClassName = g_name.copy();
2283 if (g_searchingForBody)
2285 g_searchingForBody=FALSE;
2288 if (g_insideBody) g_bodyCurlyCount++;
2289 if (!g_curClassName.isEmpty()) // valid class name
2291 DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n"));
2292 g_scopeStack.push(CLASSBLOCK);
2293 pushScope(g_curClassName);
2294 DBG_CTX((stderr,"***** g_curClassName=%s\n",g_curClassName.data()));
2295 if (getResolvedClass(g_currentDefinition,g_sourceFileDef,g_curClassName)==0)
2297 DBG_CTX((stderr,"Adding new class %s\n",g_curClassName.data()));
2298 ClassDef *ncd=new ClassDef("<code>",1,1,
2299 g_curClassName,ClassDef::Class,0,0,FALSE);
2300 g_codeClassSDict->append(g_curClassName,ncd);
2301 // insert base classes.
2302 char *s=g_curClassBases.first();
2306 bcd=g_codeClassSDict->find(s);
2307 if (bcd==0) bcd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s);
2308 if (bcd && bcd!=ncd)
2310 ncd->insertBaseClass(bcd,s,Public,Normal);
2312 s=g_curClassBases.next();
2315 //printf("g_codeClassList.count()=%d\n",g_codeClassList.count());
2317 else // not a class name -> assume inner block
2319 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
2320 g_scopeStack.push(INNERBLOCK);
2322 g_curClassName.resize(0);
2323 g_curClassBases.clear();
2326 <Bases>"virtual"|"public"|"protected"|"private"|"@public"|"@private"|"@protected" {
2327 startFontClass("keyword");
2328 g_code->codify(yytext);
2331 <Bases>{SEP}?({ID}{SEP})*{ID} {
2332 DBG_CTX((stderr,"%s:addBase(%s)\n",g_curClassName.data(),yytext));
2333 g_curClassBases.inSort(yytext);
2334 generateClassOrGlobalLink(*g_code,yytext);
2337 g_code->codify(yytext);
2341 BEGIN ( SkipSharp );
2345 g_insideProtocolList=TRUE;
2349 g_code->codify(yytext);
2350 g_insideProtocolList=FALSE;
2353 g_code->codify(yytext);
2357 g_code->codify(yytext);
2358 if (--g_sharpCount<=0)
2362 g_code->codify(yytext);
2364 BEGIN ( SkipSharp );
2367 g_code->codify(yytext);
2371 g_code->codify(yytext);
2372 if (--g_sharpCount<=0)
2378 g_code->codify(yytext);
2382 <Body>{SCOPEPREFIX}?"operator"{B}*"()"{B}*/"(" {
2384 generateFunctionLink(*g_code,yytext);
2390 <Body>{SCOPEPREFIX}?"operator"/"(" {
2392 generateFunctionLink(*g_code,yytext);
2398 <Body>{SCOPEPREFIX}?"operator"[^a-z_A-Z0-9\(\n]+/"(" {
2400 generateFunctionLink(*g_code,yytext);
2406 <Body,TemplDecl>("template"|"generic")/([^a-zA-Z0-9]) {
2407 startFontClass("keyword");
2408 codifyLines(yytext);
2410 g_insideTemplate=TRUE;
2413 <Body>"using"{BN}+"namespace"{BN}+ {
2414 startFontClass("keyword");
2415 codifyLines(yytext);
2419 <UsingName>{ID}("::"{ID})* { addUsingDirective(yytext);
2420 generateClassOrGlobalLink(*g_code,yytext);
2421 DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n"));
2422 g_scopeStack.push(CLASSBLOCK);
2426 <UsingName>\n { codifyLines(yytext); BEGIN(Body); }
2427 <UsingName>. { codifyLines(yytext); BEGIN(Body); }
2428 <Body,FuncCall>"$"?"this"("->"|".") { g_code->codify(yytext); // this-> for C++, this. for C#
2429 g_prefixed_with_this_keyword = TRUE;
2431 <Body>{KEYWORD}/([^a-z_A-Z0-9]) {
2432 if (g_insideJava && qstrcmp("internal",yytext) ==0) REJECT;
2433 if (skipLanguageSpecificKeyword(yytext)) REJECT;
2434 startFontClass("keyword");
2435 codifyLines(yytext);
2436 if (QCString(yytext)=="typedef")
2443 <Body>{KEYWORD}/{B}* {
2444 if (skipLanguageSpecificKeyword(yytext)) REJECT;
2445 startFontClass("keyword");
2446 codifyLines(yytext);
2449 <Body>{KEYWORD}/{BN}*"(" {
2450 if (skipLanguageSpecificKeyword(yytext)) REJECT;
2451 startFontClass("keyword");
2452 codifyLines(yytext);
2454 g_name.resize(0);g_type.resize(0);
2456 <FuncCall>"in"/{BN}* {
2457 if (!g_inForEachExpression) REJECT;
2458 startFontClass("keywordflow");
2459 codifyLines(yytext);
2461 // insert the variable in the parent scope, see bug 546158
2462 g_theVarContext.popScope();
2463 g_theVarContext.addVariable(g_parmType,g_parmName);
2464 g_theVarContext.pushScope();
2465 g_name.resize(0);g_type.resize(0);
2467 <Body>{FLOWKW}/{BN}*"(" {
2468 startFontClass("keywordflow");
2469 codifyLines(yytext);
2471 g_name.resize(0);g_type.resize(0);
2472 g_inForEachExpression = (qstrcmp(yytext,"for each")==0 || qstrcmp(yytext, "foreach")==0);
2475 <Body>{FLOWCONDITION}/{BN}*"(" {
2476 if (g_currentMemberDef && g_currentMemberDef->isFunction())
2478 g_currentMemberDef->addFlowKeyWord();
2480 startFontClass("keywordflow");
2481 codifyLines(yytext);
2483 g_name.resize(0);g_type.resize(0);
2484 g_inForEachExpression = (strcmp(yytext,"for each")==0 || strcmp(yytext, "foreach")==0);
2487 <Body>{FLOWKW}/([^a-z_A-Z0-9]) {
2488 startFontClass("keywordflow");
2489 codifyLines(yytext);
2491 if (g_inFunctionTryBlock && (qstrcmp(yytext,"catch")==0 || qstrcmp(yytext,"finally")==0))
2493 g_inFunctionTryBlock=FALSE;
2496 <Body>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
2497 if (g_currentMemberDef && g_currentMemberDef->isFunction())
2499 g_currentMemberDef->addFlowKeyWord();
2501 startFontClass("keywordflow");
2502 codifyLines(yytext);
2504 if (g_inFunctionTryBlock && (strcmp(yytext,"catch")==0 || strcmp(yytext,"finally")==0))
2506 g_inFunctionTryBlock=FALSE;
2509 <Body>{FLOWKW}/{B}* {
2510 startFontClass("keywordflow");
2511 codifyLines(yytext);
2514 <Body>{FLOWCONDITION}/{B}* {
2515 if (g_currentMemberDef && g_currentMemberDef->isFunction())
2517 g_currentMemberDef->addFlowKeyWord();
2519 startFontClass("keywordflow");
2520 codifyLines(yytext);
2523 <Body>"*"{B}*")" { // end of cast?
2524 g_code->codify(yytext);
2525 g_theCallContext.popScope();
2527 g_parmType = g_name;
2530 <Body>[\\|\)\+\-\/\%\~\!] {
2531 g_code->codify(yytext);
2532 g_name.resize(0);g_type.resize(0);
2535 g_theCallContext.popScope();
2540 <Body,TemplDecl,ObjCMethod>{TYPEKW}/{B}* {
2541 startFontClass("keywordtype");
2542 g_code->codify(yytext);
2547 <Body,TemplDecl,ObjCMethod>{TYPEKWSL}/{B}* {
2554 startFontClass("keywordtype");
2555 g_code->codify(yytext);
2561 <Body>"generic"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* {
2562 startFontClass("keyword");
2563 g_code->codify(yytext);
2568 <Body>"template"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* { // template<...>
2569 startFontClass("keyword");
2570 g_code->codify(yytext);
2575 <TemplDecl>"class"|"typename" {
2576 startFontClass("keyword");
2577 codifyLines(yytext);
2581 g_code->codify(yytext);
2585 g_code->codify(yytext);
2587 if (g_sharpCount<=0)
2593 startFontClass("keyword");
2594 codifyLines(yytext);
2596 BEGIN( g_lastTemplCastContext );
2598 <TemplCast>{ID}("::"{ID})* {
2599 generateClassOrGlobalLink(*g_code,yytext);
2601 <TemplCast>("const"|"volatile"){B}* {
2602 startFontClass("keyword");
2603 codifyLines(yytext);
2607 codifyLines(yytext);
2609 <Body,FuncCall>{CASTKW}"<" { // static_cast<T>(
2610 startFontClass("keyword");
2611 codifyLines(yytext);
2613 g_lastTemplCastContext = YY_START;
2616 <Body>"$this->"{SCOPENAME}/{BN}*[;,)\]] { // PHP member variable
2618 generatePHPVariableLink(*g_code,yytext);
2621 <Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>\(]*">"("::"{ID})*/{B}* { // A<T> *pt;
2622 int i=QCString(yytext).find('<');
2623 QCString kw = QCString(yytext).left(i).stripWhiteSpace();
2624 if (kw.right(5)=="_cast" && YY_START==Body)
2629 generateClassOrGlobalLink(*g_code,yytext);
2632 <Body>{SCOPENAME}/{BN}*[:;,)\]] { // "int var;" or "var, var2" or "debug(f) macro" , or int var : 5;
2634 // changed this to generateFunctionLink, see bug 624514
2635 //generateClassOrGlobalLink(*g_code,yytext,FALSE,TRUE);
2636 generateFunctionLink(*g_code,yytext);
2639 <Body>{SCOPENAME}/{B}* { // p->func()
2641 generateClassOrGlobalLink(*g_code,yytext);
2644 <Body>"("{B}*("*"{B}*)+{SCOPENAME}*{B}*")"/{B}* { // (*p)->func() but not "if (p) ..."
2645 g_code->codify(yytext);
2646 int s=0;while (s<(int)yyleng && !isId(yytext[s])) s++;
2647 int e=(int)yyleng-1;while (e>=0 && !isId(yytext[e])) e--;
2648 QCString varname = ((QCString)yytext).mid(s,e-s+1);
2652 <Body>{SCOPETNAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"/{BN}*"(" |
2653 <Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo()
2655 generateFunctionLink(*g_code,yytext);
2661 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{RAWBEGIN} {
2662 QCString text=yytext;
2663 int i=text.find('R');
2664 g_code->codify(text.left(i+1));
2665 startFontClass("stringliteral");
2666 g_code->codify(yytext+i+1);
2667 g_lastStringContext=YY_START;
2668 g_inForEachExpression = FALSE;
2669 g_delimiter = yytext+i+2;
2670 g_delimiter=g_delimiter.left(g_delimiter.length()-1);
2673 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\" {
2674 startFontClass("stringliteral");
2675 g_code->codify(yytext);
2676 g_lastStringContext=YY_START;
2677 g_inForEachExpression = FALSE;
2678 BEGIN( SkipString );
2680 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\' {
2681 startFontClass("stringliteral");
2682 g_code->codify(yytext);
2683 g_lastStringContext=YY_START;
2684 g_inForEachExpression = FALSE;
2685 BEGIN( SkipStringS );
2687 <SkipString>[^\"\\\r\n]* {
2688 g_code->codify(yytext);
2690 <SkipStringS>[^\'\\\r\n]* {
2691 g_code->codify(yytext);
2693 <SkipString,SkipStringS>"//"|"/*" {
2694 g_code->codify(yytext);
2697 g_code->codify(yytext);
2699 BEGIN( g_lastStringContext );
2702 g_code->codify(yytext);
2704 BEGIN( g_lastStringContext );
2706 <SkipString,SkipStringS>\\. {
2707 g_code->codify(yytext);
2709 <RawString>{RAWEND} {
2710 g_code->codify(yytext);
2711 QCString delimiter = yytext+1;
2712 delimiter=delimiter.left(delimiter.length()-1);
2713 if (delimiter==g_delimiter)
2715 BEGIN( g_lastStringContext );
2718 <RawString>[^)\n]+ { g_code->codify(yytext); }
2719 <RawString>. { g_code->codify(yytext); }
2720 <RawString>\n { codifyLines(yytext); }
2721 <SkipVerbString>[^"\n]+ {
2722 g_code->codify(yytext);
2724 <SkipVerbString>\"\" { // escaped quote
2725 g_code->codify(yytext);
2727 <SkipVerbString>\" { // end of string
2728 g_code->codify(yytext);
2730 BEGIN( g_lastVerbStringContext );
2733 g_code->codify(yytext);
2735 <SkipVerbString>\n {
2736 codifyLines(yytext);
2739 g_code->codify(yytext);
2740 g_name.resize(0);g_type.resize(0);
2743 if (g_insideTemplate)
2747 g_code->codify(yytext);
2750 if (g_insideTemplate)
2752 if (--g_sharpCount<=0)
2754 g_insideTemplate=FALSE;
2757 g_code->codify(yytext);
2759 <Body,MemberCall,MemberCall2,FuncCall>"'"((\\0[Xx0-9]+)|(\\.)|(.))"'" {
2760 startFontClass("charliteral");
2761 g_code->codify(yytext);
2765 if (yytext[0]=='-') // -> could be overloaded
2767 updateCallContextForSmartPointer();
2769 g_code->codify(yytext);
2770 g_memCallContext = YY_START;
2771 BEGIN( MemberCall );
2773 <MemberCall>{SCOPETNAME}/{BN}*"(" {
2774 if (g_theCallContext.getScope())
2776 if (!generateClassMemberLink(*g_code,g_theCallContext.getScope(),yytext))
2778 g_code->codify(yytext);
2779 addToSearchIndex(yytext);
2785 g_code->codify(yytext);
2786 addToSearchIndex(yytext);
2791 if (g_memCallContext==Body)
2797 BEGIN(g_memCallContext);
2800 <MemberCall>{SCOPENAME}/{B}* {
2801 if (g_theCallContext.getScope())
2803 DBG_CTX((stderr,"g_theCallContext.getClass()=%p\n",g_theCallContext.getScope()));
2804 if (!generateClassMemberLink(*g_code,g_theCallContext.getScope(),yytext))
2806 g_code->codify(yytext);
2807 addToSearchIndex(yytext);
2813 DBG_CTX((stderr,"no class context!\n"));
2814 g_code->codify(yytext);
2815 addToSearchIndex(yytext);
2819 BEGIN(g_memCallContext);
2822 if (g_insideObjC && *yytext=='[')
2824 //printf("Found start of ObjC call!\n");
2825 // start of a method call
2826 g_contextDict.setAutoDelete(TRUE);
2827 g_nameDict.setAutoDelete(TRUE);
2828 g_objectDict.setAutoDelete(TRUE);
2829 g_wordDict.setAutoDelete(TRUE);
2830 g_commentDict.setAutoDelete(TRUE);
2831 g_contextDict.clear();
2833 g_objectDict.clear();
2835 g_commentDict.clear();
2837 g_currentNameId = 0;
2846 g_code->codify(yytext);
2847 g_saveName = g_name.copy();
2848 g_saveType = g_type.copy();
2849 if (*yytext!='[' && !g_type.isEmpty())
2851 //printf("g_scopeStack.bottom()=%p\n",g_scopeStack.bottom());
2852 //if (g_scopeStack.top()!=CLASSBLOCK) // commented out for bug731363
2854 //printf("AddVariable: '%s' '%s' context=%d\n",
2855 // g_type.data(),g_name.data(),g_theVarContext.count());
2856 g_theVarContext.addVariable(g_type,g_name);
2860 if (*yytext==';' || *yytext=='=')
2865 else if (*yytext=='[')
2867 g_theCallContext.pushScope();
2870 g_parmType.resize(0);
2871 g_parmName.resize(0);
2875 <ObjCMemberCall>{ID} {
2876 if (qstrcmp(yytext,"self")==0 || qstrcmp(yytext,"super")==0)
2878 // TODO: get proper base class for "super"
2879 g_theCallContext.setClass(getClass(g_curClassName));
2880 startFontClass("keyword");
2881 g_code->codify(yytext);
2886 generateClassOrGlobalLink(*g_code,yytext);
2889 BEGIN(ObjCMemberCall2);
2891 <ObjCMemberCall>"[" {
2892 g_code->codify(yytext);
2893 g_theCallContext.pushScope();
2895 <ObjCMemberCall2>{ID}":"? {
2897 if (g_theCallContext.getClass())
2899 //printf("Calling method %s\n",g_name.data());
2900 if (!generateClassMemberLink(*g_code,g_theCallContext.getClass(),g_name))
2902 g_code->codify(yytext);
2903 addToSearchIndex(g_name);
2908 g_code->codify(yytext);
2909 addToSearchIndex(g_name);
2912 BEGIN(ObjCMemberCall3);
2914 <ObjCMemberCall2,ObjCMemberCall3>"]" {
2915 g_theCallContext.popScope();
2916 g_code->codify(yytext);
2920 <ObjCCall,ObjCMName>"["|"{" {
2922 g_currentCtx->format+=*yytext;
2926 <ObjCCall,ObjCMName>"]"|"}" {
2927 g_currentCtx->format+=*yytext;
2928 restoreObjCContext();
2930 if (g_currentCtx==0)
2933 writeObjCMethodCall(g_contextDict.find(0));
2936 //printf("close\n");
2938 <ObjCCall,ObjCMName>"//".* {
2939 g_currentCtx->format+=escapeComment(yytext);
2941 <ObjCCall,ObjCMName>"/*" {
2942 g_lastObjCCallContext = YY_START;
2943 g_currentCtx->comment=yytext;
2944 BEGIN(ObjCCallComment);
2946 <ObjCCallComment>"*/" {
2947 g_currentCtx->comment+=yytext;
2948 g_currentCtx->format+=escapeComment(g_currentCtx->comment);
2949 BEGIN(g_lastObjCCallContext);
2951 <ObjCCallComment>[^*\n]+ { g_currentCtx->comment+=yytext; }
2952 <ObjCCallComment>"//"|"/*" { g_currentCtx->comment+=yytext; }
2953 <ObjCCallComment>\n { g_currentCtx->comment+=*yytext; }
2954 <ObjCCallComment>. { g_currentCtx->comment+=*yytext; }
2956 g_currentCtx->format+=escapeObject(yytext);
2957 if (g_braceCount==0)
2959 g_currentCtx->objectTypeOrName=yytext;
2960 //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data());
2964 <ObjCMName>{ID}/{BN}*"]" {
2965 if (g_braceCount==0 &&
2966 g_currentCtx->methodName.isEmpty())
2968 g_currentCtx->methodName=yytext;
2969 g_currentCtx->format+=escapeName(yytext);
2973 g_currentCtx->format+=escapeWord(yytext);
2976 <ObjCMName>{ID}/{BN}*":" {
2977 if (g_braceCount==0)
2979 g_currentCtx->methodName+=yytext;
2980 g_currentCtx->methodName+=":";
2982 g_currentCtx->format+=escapeName(yytext);
2984 <ObjCSkipStr>[^\n\"$\\]* { g_currentCtx->format+=yytext; }
2985 <ObjCSkipStr>\\. { g_currentCtx->format+=yytext; }
2986 <ObjCSkipStr>"\"" { g_currentCtx->format+=yytext;
2987 BEGIN(g_lastStringContext);
2989 <ObjCCall,ObjCMName>{CHARLIT} { g_currentCtx->format+=yytext; }
2990 <ObjCCall,ObjCMName>"@"?"\"" { g_currentCtx->format+=yytext;
2991 g_lastStringContext=YY_START;
2994 <ObjCCall,ObjCMName,ObjCSkipStr>"$" { g_currentCtx->format+="$$"; }
2995 <ObjCCall,ObjCMName>"(" { g_currentCtx->format+=*yytext; g_braceCount++; }
2996 <ObjCCall,ObjCMName>")" { g_currentCtx->format+=*yytext; g_braceCount--; }
2997 <ObjCSkipStr>"@"/"\"" { // needed to prevent matching the global rule (for C#)
2998 g_currentCtx->format+=yytext;
3000 <ObjCCall,ObjCMName,ObjCSkipStr>{ID} { g_currentCtx->format+=escapeWord(yytext); }
3001 <ObjCCall,ObjCMName,ObjCSkipStr>. { g_currentCtx->format+=*yytext; }
3002 <ObjCCall,ObjCMName,ObjCSkipStr>\n { g_currentCtx->format+=*yytext; }
3005 g_theCallContext.popScope();
3006 g_code->codify(yytext);
3007 // TODO: nested arrays like: a[b[0]->func()]->func()
3008 g_name = g_saveName.copy();
3009 g_type = g_saveType.copy();
3012 g_code->codify(yytext);
3014 <Body>[0-9]+[xX][0-9A-Fa-f]+ {
3015 g_code->codify(yytext);
3017 <MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
3019 //g_parmName=yytext;
3020 if (skipLanguageSpecificKeyword(yytext)) REJECT;
3021 startFontClass("keyword");
3022 g_code->codify(yytext);
3025 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKW}/([^a-z_A-Z0-9]) {
3028 startFontClass("keywordtype");
3029 g_code->codify(yytext);
3032 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKWSL}/([^a-z_A-Z0-9]) {
3041 startFontClass("keywordtype");
3042 g_code->codify(yytext);
3046 <MemberCall2,FuncCall>{FLOWKW}/([^a-z_A-Z0-9]) {
3049 startFontClass("keywordflow");
3050 g_code->codify(yytext);
3053 <MemberCall2,FuncCall>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
3054 if (g_currentMemberDef && g_currentMemberDef->isFunction())
3056 g_currentMemberDef->addFlowKeyWord();
3060 startFontClass("keywordflow");
3061 g_code->codify(yytext);
3064 <MemberCall2,FuncCall>{ID}(({B}*"<"[^\n\[\](){}<>]*">")?({B}*"::"{B}*{ID})?)* {
3067 generateClassOrGlobalLink(*g_code,yytext,!g_insideBody);
3069 <FuncCall>";" { // probably a cast, not a function call
3070 g_code->codify(yytext);
3071 g_inForEachExpression = FALSE;
3074 <MemberCall2,FuncCall>, {
3075 g_code->codify(yytext);
3076 g_theVarContext.addVariable(g_parmType,g_parmName);
3077 g_parmType.resize(0);g_parmName.resize(0);
3079 <MemberCall2,FuncCall>"{" {
3080 if (g_bracketCount>0)
3082 g_code->codify(yytext);
3083 g_skipInlineInitContext=YY_START;
3092 <InlineInit>"{" { g_curlyCount++;
3093 g_code->codify(yytext);
3096 g_code->codify(yytext);
3097 if (--g_curlyCount<=0)
3099 BEGIN(g_skipInlineInitContext);
3103 codifyLines(yytext);
3106 g_code->codify(yytext);
3108 <MemberCall2,FuncCall>"(" {
3109 g_parmType.resize(0);g_parmName.resize(0);
3110 g_code->codify(yytext);
3112 g_theCallContext.pushScope();
3113 if (YY_START==FuncCall && !g_insideBody)
3115 g_theVarContext.pushScope();
3118 <MemberCall2,FuncCall>{OPERATOR} { // operator
3119 if (qstrcmp(yytext,"*") &&
3120 qstrcmp(yytext,"&") &&
3121 qstrcmp(yytext,"^") &&
3122 qstrcmp(yytext,"%")) // typically a pointer or reference
3124 // not a * or &, or C++/CLI's ^ or %
3125 g_parmType.resize(0);g_parmName.resize(0);
3127 g_code->codify(yytext);
3129 <MemberCall,MemberCall2,FuncCall>("*"{B}*)?")" {
3130 if (yytext[0]==')') // no a pointer cast
3132 //printf("addVariable(%s,%s)\n",g_parmType.data(),g_parmName.data());
3133 if (g_parmType.isEmpty())
3135 g_parmType=g_parmName;
3136 g_parmName.resize(0);
3138 g_theVarContext.addVariable(g_parmType,g_parmName);
3142 g_parmType = g_parmName;
3143 g_parmName.resize(0);
3144 g_theVarContext.addVariable(g_parmType,g_parmName);
3146 g_theCallContext.popScope();
3147 g_inForEachExpression = FALSE;
3148 //g_theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b().
3149 g_code->codify(yytext);
3150 if (--g_bracketCount<=0)
3152 if (g_name.isEmpty())
3162 <CallEnd>[ \t\n]* { codifyLines(yytext); }
3164 <MemberCall2,FuncCall>")"[ \t\n]*[;:] {
3167 codifyLines(yytext);
3169 if (*yytext==';') g_searchingForBody=FALSE;
3170 if (!g_type.isEmpty())
3172 DBG_CTX((stderr,"add variable g_type=%s g_name=%s)\n",g_type.data(),g_name.data()));
3173 g_theVarContext.addVariable(g_type,g_name);
3175 g_parmType.resize(0);g_parmName.resize(0);
3176 g_theCallContext.setScope(0);
3177 if (*yytext==';' || g_insideBody)
3181 g_theVarContext.popScope();
3183 g_name.resize(0);g_type.resize(0);
3192 <CallEnd>("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"sealed"|"override"))*/{BN}*(";"|"="|"throw"{BN}*"(") {
3193 startFontClass("keyword");
3194 codifyLines(yytext);
3197 <CallEnd,OldStyleArgs>("const"|"volatile"|"sealed"|"override")*({BN}+("const"|"volatile"|"sealed"|"override"))*{BN}*"{" {
3200 g_theVarContext.pushScope();
3202 g_theVarContext.addVariable(g_parmType,g_parmName);
3203 //g_theCallContext.popScope();
3204 g_parmType.resize(0);g_parmName.resize(0);
3205 int index = g_name.findRev("::");
3206 DBG_CTX((stderr,"g_name=%s\n",g_name.data()));
3209 QCString scope = g_name.left(index);
3210 if (!g_classScope.isEmpty()) scope.prepend(g_classScope+"::");
3211 ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_sourceFileDef,scope);
3214 setClassScope(cd->name());
3215 g_scopeStack.push(SCOPEBLOCK);
3216 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
3220 //setClassScope(g_realScope);
3221 g_scopeStack.push(INNERBLOCK);
3222 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
3227 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
3228 g_scopeStack.push(INNERBLOCK);
3230 yytext[yyleng-1]='\0';
3231 QCString cv(yytext);
3232 if (!cv.stripWhiteSpace().isEmpty())
3234 startFontClass("keyword");
3235 codifyLines(yytext);
3238 else // just whitespace
3240 codifyLines(yytext);
3242 g_code->codify("{");
3243 if (g_searchingForBody)
3245 g_searchingForBody=FALSE;
3248 if (g_insideBody) g_bodyCurlyCount++;
3249 g_type.resize(0); g_name.resize(0);
3252 <CallEnd>"try" { // function-try-block
3253 startFontClass("keyword");
3254 g_code->codify(yytext);
3256 g_inFunctionTryBlock=TRUE;
3259 if (g_insideBody || !g_parmType.isEmpty())
3263 // could be K&R style definition
3266 generateClassOrGlobalLink(*g_code,yytext,!g_insideBody);
3267 BEGIN(OldStyleArgs);
3269 <OldStyleArgs>{ID} {
3272 generateClassOrGlobalLink(*g_code,yytext,!g_insideBody);
3274 <OldStyleArgs>[,;] {
3275 g_code->codify(yytext);
3276 g_theVarContext.addVariable(g_parmType,g_parmName);
3277 if (*yytext==';') g_parmType.resize(0);
3278 g_parmName.resize(0);
3280 <CallEnd,OldStyleArgs>"#" {
3281 startFontClass("preprocessor");
3282 g_lastSkipCppContext = Body;
3283 g_code->codify(yytext);
3290 g_theVarContext.popScope();
3292 g_name.resize(0);g_args.resize(0);
3293 g_parmType.resize(0);g_parmName.resize(0);
3297 g_code->codify(yytext);
3298 g_type.resize(0); g_name.resize(0);
3302 g_code->codify(yytext);
3303 if (g_searchingForBody)
3305 g_searchingForBody=FALSE;
3308 if (g_insideBody) g_bodyCurlyCount++;
3309 if (g_name.find("::")!=-1)
3311 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
3312 g_scopeStack.push(SCOPEBLOCK);
3313 setClassScope(g_realScope);
3317 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
3318 g_scopeStack.push(INNERBLOCK);
3320 g_type.resize(0); g_name.resize(0);
3324 generateClassOrGlobalLink(*g_code,yytext);
3326 <FuncCall>{ID}/"(" {
3327 generateFunctionLink(*g_code,yytext);
3329 <FuncCall>{ID}/("."|"->") {
3331 generateClassOrGlobalLink(*g_code,yytext);
3332 BEGIN( MemberCall2 );
3334 <FuncCall,MemberCall2>("("{B}*("*"{B}*)+{ID}*{B}*")"{B}*)/("."|"->") {
3335 g_code->codify(yytext);
3336 int s=0;while (!isId(yytext[s])) s++;
3337 int e=(int)yyleng-1;while (!isId(yytext[e])) e--;
3338 g_name=((QCString)yytext).mid(s,e-s+1);
3339 BEGIN( MemberCall2 );
3341 <MemberCall2>{ID}/([ \t\n]*"(") {
3342 if (!g_args.isEmpty())
3343 generateMemberLink(*g_code,g_args,yytext);
3345 generateClassOrGlobalLink(*g_code,yytext);
3349 <MemberCall2>{ID}/([ \t\n]*("."|"->")) {
3350 //g_code->codify(yytext);
3352 generateClassOrGlobalLink(*g_code,yytext);
3353 BEGIN( MemberCall2 );
3355 <MemberCall2>"->"|"." {
3356 if (yytext[0]=='-') // -> could be overloaded
3358 updateCallContextForSmartPointer();
3360 g_code->codify(yytext);
3361 g_memCallContext = YY_START;
3362 BEGIN( MemberCall );
3364 <SkipComment>"/*"("!"?)"*/" {
3365 g_code->codify(yytext);
3367 BEGIN( g_lastCContext ) ;
3369 <SkipComment>"//"|"/*" {
3370 g_code->codify(yytext);
3372 <SkipComment>[^*/\n]+ {
3373 g_code->codify(yytext);
3375 <SkipComment>[ \t]*"*/" {
3376 g_code->codify(yytext);
3378 if (g_lastCContext==SkipCPP)
3380 startFontClass("preprocessor");
3382 BEGIN( g_lastCContext ) ;
3384 <SkipCxxComment>[^\r\n]*"\\"[\r]?\n { // line continuation
3385 codifyLines(yytext);
3387 <SkipCxxComment>[^\r\n]+ {
3388 g_code->codify(yytext);
3391 <SkipCxxComment>\n {
3394 BEGIN( g_lastCContext ) ;
3397 g_code->codify(yytext);
3399 <RemoveSpecialCComment>"*/"{B}*\n({B}*\n)*({B}*(("//@"[{}])|("/*@"[{}]"*/")){B}*\n)?{B}*"/*"[*!]/[^/*] {
3400 g_yyLineNr+=QCString(yytext).contains('\n');
3402 <RemoveSpecialCComment>"*/"{B}*\n({B}*\n)*({B}*(("//@"[{}])|("/*@"[{}]"*/")){B}*\n)? {
3403 g_yyLineNr+=QCString(yytext).contains('\n');
3405 if (g_lastSpecialCContext==SkipCxxComment)
3406 { // force end of C++ comment here
3408 BEGIN( g_lastCContext ) ;
3412 BEGIN(g_lastSpecialCContext);
3415 <RemoveSpecialCComment>"*/" {
3416 BEGIN(g_lastSpecialCContext);
3418 <RemoveSpecialCComment>[^*\n]+
3419 <RemoveSpecialCComment>"//"|"/*"
3420 <RemoveSpecialCComment>\n { g_yyLineNr++; }
3421 <RemoveSpecialCComment>.
3422 <MemberCall>[^a-z_A-Z0-9(\n] {
3423 g_code->codify(yytext);
3426 BEGIN(g_memCallContext);
3428 <*>\n({B}*"//"[!/][^\n]*\n)+ { // remove special one-line comment
3429 if (YY_START==SkipCPP) REJECT;
3430 if (Config_getBool(STRIP_CODE_COMMENTS))
3432 g_yyLineNr+=((QCString)yytext).contains('\n');
3437 startFontClass("comment");
3438 codifyLines(yytext);
3441 if (YY_START==SkipCxxComment)
3444 BEGIN( g_lastCContext ) ;
3449 codifyLines(yytext);
3450 BEGIN( g_lastSkipCppContext ) ;
3452 <*>\n{B}*"//@"[{}].*\n { // remove one-line group marker
3453 if (Config_getBool(STRIP_CODE_COMMENTS))
3460 startFontClass("comment");
3461 codifyLines(yytext);
3464 if (YY_START==SkipCxxComment)
3467 BEGIN( g_lastCContext ) ;
3470 <*>\n{B}*"/*@"[{}] { // remove one-line group marker
3471 if (Config_getBool(STRIP_CODE_COMMENTS))
3473 g_lastSpecialCContext = YY_START;
3475 BEGIN(RemoveSpecialCComment);
3479 // check is to prevent getting stuck in skipping C++ comments
3480 if (YY_START != SkipCxxComment)
3482 g_lastCContext = YY_START ;
3484 startFontClass("comment");
3485 codifyLines(yytext);
3489 <*>^{B}*"//@"[{}].*\n { // remove one-line group marker
3490 if (Config_getBool(STRIP_CODE_COMMENTS))
3497 startFontClass("comment");
3498 codifyLines(yytext);
3502 <*>^{B}*"/*@"[{}] { // remove multi-line group marker
3503 if (Config_getBool(STRIP_CODE_COMMENTS))
3505 g_lastSpecialCContext = YY_START;
3506 BEGIN(RemoveSpecialCComment);
3510 // check is to prevent getting stuck in skipping C++ comments
3511 if (YY_START != SkipCxxComment)
3513 g_lastCContext = YY_START ;
3515 startFontClass("comment");
3516 g_code->codify(yytext);
3520 <*>^{B}*"//"[!/][^\n]*\n { // remove special one-line comment
3521 if (Config_getBool(STRIP_CODE_COMMENTS))
3528 startFontClass("comment");
3529 codifyLines(yytext);
3533 <*>"//"[!/][^\n]*\n { // strip special one-line comment
3534 if (YY_START==SkipComment || YY_START==SkipString) REJECT;
3535 if (Config_getBool(STRIP_CODE_COMMENTS))
3537 char c[2]; c[0]='\n'; c[1]=0;
3542 startFontClass("comment");
3543 codifyLines(yytext);
3547 <*>"/*[tag:"[^\]\n]*"]*/"{B}* { // special pattern /*[tag:filename]*/ to force linking to a tag file
3548 g_forceTagReference=yytext;
3549 int s=g_forceTagReference.find(':');
3550 int e=g_forceTagReference.findRev(']');
3551 g_forceTagReference = g_forceTagReference.mid(s+1,e-s-1);
3553 <*>\n{B}*"/*"[!*]/[^/*] {
3554 if (Config_getBool(STRIP_CODE_COMMENTS))
3556 g_lastSpecialCContext = YY_START;
3558 BEGIN(RemoveSpecialCComment);
3562 // check is to prevent getting stuck in skipping C++ comments
3563 if (YY_START != SkipCxxComment)
3565 g_lastCContext = YY_START ;
3567 startFontClass("comment");
3568 codifyLines(yytext);
3572 <*>^{B}*"/*"[!*]/[^/*] { // special C comment block at a new line
3573 if (Config_getBool(STRIP_CODE_COMMENTS))
3575 g_lastSpecialCContext = YY_START;
3576 BEGIN(RemoveSpecialCComment);
3580 // check is to prevent getting stuck in skipping C++ comments
3581 if (YY_START != SkipCxxComment)
3583 g_lastCContext = YY_START ;
3585 startFontClass("comment");
3586 g_code->codify(yytext);
3590 <*>"/*"[!*]/[^/*] { // special C comment block half way a line
3591 if (YY_START==SkipString) REJECT;
3592 if (Config_getBool(STRIP_CODE_COMMENTS))
3594 g_lastSpecialCContext = YY_START;
3595 BEGIN(RemoveSpecialCComment);
3599 // check is to prevent getting stuck in skipping C++ comments
3600 if (YY_START != SkipCxxComment)
3602 g_lastCContext = YY_START ;
3604 startFontClass("comment");
3605 g_code->codify(yytext);
3610 if (YY_START==SkipString) REJECT;
3611 if (!Config_getBool(STRIP_CODE_COMMENTS))
3613 startFontClass("comment");
3614 g_code->codify(yytext);
3618 <SkipComment>[^\*\n]+ {
3619 g_code->codify(yytext);
3622 startFontClass("comment");
3623 g_code->codify(yytext);
3624 // check is to prevent getting stuck in skipping C++ comments
3625 if (YY_START != SkipCxxComment)
3627 g_lastCContext = YY_START ;
3629 BEGIN( SkipComment ) ;
3631 <*>@\" { // C# verbatim string
3632 startFontClass("stringliteral");
3633 g_code->codify(yytext);
3634 g_lastVerbStringContext=YY_START;
3635 BEGIN(SkipVerbString);
3638 startFontClass("comment");
3639 g_code->codify(yytext);
3640 g_lastCContext = YY_START ;
3641 BEGIN( SkipCxxComment ) ;
3644 g_code->codify(yytext);
3645 g_theCallContext.pushScope();
3648 g_code->codify(yytext);
3649 g_theCallContext.popScope();
3653 codifyLines(yytext);
3657 g_code->codify(yytext);
3660 <*>([ \t\n]*"\n"){2,} { // combine multiple blank lines
3661 //QCString sepLine=yytext;
3662 //g_code->codify("\n\n");
3663 //g_yyLineNr+=sepLine.contains('\n');
3664 //char sepLine[3]="\n\n";
3665 codifyLines(yytext);
3671 /*@ ----------------------------------------------------------------------------
3674 static void saveObjCContext()
3678 g_currentCtx->format+=QCString().sprintf("$c%d",g_currentCtxId);
3679 if (g_braceCount==0 && YY_START==ObjCCall)
3681 g_currentCtx->objectTypeOrName=g_currentCtx->format.mid(1);
3682 //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data());
3684 g_contextStack.push(g_currentCtx);
3688 //printf("Trying to save NULL context!\n");
3690 ObjCCallCtx *newCtx = new ObjCCallCtx;
3691 newCtx->id = g_currentCtxId;
3692 newCtx->lexState = YY_START;
3693 newCtx->braceCount = g_braceCount;
3694 newCtx->objectType = 0;
3695 newCtx->objectVar = 0;
3697 //printf("save state=%d\n",YY_START);
3698 g_contextDict.insert(g_currentCtxId,newCtx);
3699 g_currentCtx = newCtx;
3704 static void restoreObjCContext()
3706 //printf("restore state=%d->%d\n",YY_START,g_currentCtx->lexState);
3707 BEGIN(g_currentCtx->lexState);
3708 g_braceCount = g_currentCtx->braceCount;
3709 if (!g_contextStack.isEmpty())
3711 g_currentCtx = g_contextStack.pop();
3716 //printf("Trying to pop context while g_contextStack is empty!\n");
3720 void resetCCodeParserState()
3722 //printf("***initParseCodeContext()\n");
3723 g_forceTagReference.resize(0);
3724 g_theVarContext.clear();
3725 g_classScopeLengthStack.setAutoDelete(TRUE);
3726 g_classScopeLengthStack.clear();
3727 delete g_codeClassSDict;
3728 g_codeClassSDict = new ClassSDict(17);
3729 g_codeClassSDict->setAutoDelete(TRUE);
3730 g_codeClassSDict->clear();
3731 g_curClassBases.clear();
3735 void parseCCode(CodeOutputInterface &od,const char *className,const QCString &s,
3736 SrcLangExt lang,bool exBlock, const char *exName,FileDef *fd,
3737 int startLine,int endLine,bool inlineFragment,
3738 MemberDef *memberDef,bool showLineNumbers,Definition *searchCtx,
3741 //printf("***parseCode() exBlock=%d exName=%s fd=%p className=%s searchCtx=%s\n",
3742 // exBlock,exName,fd,className,searchCtx?searchCtx->name().data():"<none>");
3744 if (s.isEmpty()) return;
3746 printlex(yy_flex_debug, TRUE, __FILE__, fd ? fd->fileName().data(): NULL);
3748 TooltipManager::instance()->clearTooltips();
3749 if (g_codeClassSDict==0)
3751 resetCCodeParserState();
3755 g_inputPosition = 0;
3756 g_currentFontClass = 0;
3757 g_needsTermination = FALSE;
3758 g_searchCtx = searchCtx;
3759 g_collectXRefs = collectXRefs;
3760 g_inFunctionTryBlock = FALSE;
3763 g_yyLineNr = startLine;
3768 g_inputLines = endLine+1;
3770 g_inputLines = g_yyLineNr + countLines() - 1;
3773 g_bodyCurlyCount = 0;
3776 g_insideTemplate = FALSE;
3777 g_theCallContext.clear();
3778 g_scopeStack.clear();
3779 g_classScope = className;
3780 //printf("parseCCode %s\n",className);
3781 g_exampleBlock = exBlock;
3782 g_exampleName = exName;
3783 g_sourceFileDef = fd;
3784 g_lineNumbers = fd!=0 && showLineNumbers;
3785 bool cleanupSourceDef = FALSE;
3788 // create a dummy filedef for the example
3789 g_sourceFileDef = new FileDef("",(exName?exName:"generated"));
3790 cleanupSourceDef = TRUE;
3792 g_insideObjC = lang==SrcLangExt_ObjC;
3793 g_insideJava = lang==SrcLangExt_Java;
3794 g_insideCS = lang==SrcLangExt_CSharp;
3795 g_insidePHP = lang==SrcLangExt_PHP;
3796 g_insideCpp = lang==SrcLangExt_Cpp;
3797 g_insideSlice = lang==SrcLangExt_Slice;
3798 if (g_sourceFileDef)
3800 setCurrentDoc("l00001");
3802 g_currentDefinition = 0;
3803 g_currentMemberDef = 0;
3804 g_searchingForBody = exBlock;
3805 g_insideBody = FALSE;
3807 if (!g_exampleName.isEmpty())
3809 g_exampleFile = convertNameToFile(g_exampleName+"-example",FALSE,TRUE);
3810 //printf("g_exampleFile=%s\n",g_exampleFile.data());
3812 g_includeCodeFragment = inlineFragment;
3813 //printf("** exBlock=%d exName=%s include=%d\n",exBlock,exName,inlineFragment);
3818 g_parmName.resize(0);
3819 g_parmType.resize(0);
3820 if (memberDef) setParameterList(memberDef);
3821 codeYYrestart( codeYYin );
3825 if (g_needsTermination)
3828 DBG_CTX((stderr,"endCodeLine(%d)\n",g_yyLineNr));
3829 g_code->endCodeLine();
3833 TooltipManager::instance()->writeTooltips(*g_code);
3835 if (cleanupSourceDef)
3837 // delete the temporary file definition used for this example
3838 delete g_sourceFileDef;
3842 printlex(yy_flex_debug, FALSE, __FILE__, fd ? fd->fileName().data(): NULL);
3846 void codeFreeScanner()
3848 #if defined(YY_FLEX_SUBMINOR_VERSION)
3851 codeYYlex_destroy();
3858 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3859 extern "C" { // some bogus code to keep the compiler happy
3860 void codeYYdummy() { yy_flex_realloc(0,0); }
3862 #elif YY_FLEX_MAJOR_VERSION<=2 && YY_FLEX_MINOR_VERSION<=5 && YY_FLEX_SUBMINOR_VERSION<33
3863 #error "You seem to be using a version of flex newer than 2.5.4. These are currently incompatible with 2.5.4, and do NOT work with doxygen! Please use version 2.5.4 or expect things to be parsed wrongly! A bug report has been submitted (#732132)."