fe1eef50ff97b450f11a28865e06b26e0852a2ad
[platform/upstream/doxygen.git] / src / pycode.l
1 /******************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
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.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17 /*  This code is based on the work done by the MoxyPyDoxy team
18  *  (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada)
19  *  in Spring 2005 as part of CS 179E: Compiler Design Project
20  *  at the University of California, Riverside; the course was
21  *  taught by Peter H. Froehlich <phf@acm.org>.
22  */
23
24 %option never-interactive
25 %option prefix="pycodeYY"
26
27 %{
28
29 #include <stdio.h>
30 #include <qvaluestack.h>
31
32 #include "pycode.h"
33 #include "message.h"
34
35 #include "scanner.h"
36 #include "entry.h"
37 #include "doxygen.h"
38 #include "outputlist.h"
39 #include "util.h"
40 #include "membername.h"
41 #include "searchindex.h"
42 #include "config.h"
43 #include "groupdef.h"
44 #include "classlist.h"
45 #include "filedef.h"
46 #include "namespacedef.h"
47 #include "tooltip.h"
48
49 // Toggle for some debugging info
50 //#define DBG_CTX(x) fprintf x
51 #define DBG_CTX(x) do { } while(0)
52
53 #define YY_NO_INPUT 1
54 #define YY_NO_UNISTD_H 1
55
56 static ClassSDict    g_codeClassSDict(17);
57 static QCString      g_curClassName;
58 static QStrList      g_curClassBases;
59
60
61 static CodeOutputInterface * g_code;
62 static const char *  g_inputString;     //!< the code fragment as text
63 static int           g_inputPosition;   //!< read offset during parsing 
64 static const char *  g_currentFontClass;
65 static bool          g_needsTermination;
66 static Definition   *g_searchCtx;
67 static bool          g_collectXRefs;
68 static int           g_inputLines;      //!< number of line in the code fragment
69 static int           g_yyLineNr;        //!< current line number
70 static FileDef *     g_sourceFileDef;
71 static Definition *  g_currentDefinition;
72 static MemberDef *   g_currentMemberDef;
73 static bool          g_includeCodeFragment;
74 static QCString      g_realScope;
75 //static bool          g_insideBody;
76 static int           g_bodyCurlyCount;
77 static bool          g_searchingForBody;
78 static QCString      g_classScope;
79 static int           g_paramParens;
80 //static int           g_anchorCount;
81
82 static bool          g_exampleBlock;
83 static QCString      g_exampleName;
84
85 static QCString      g_type;
86 static QCString      g_name;
87
88 static bool          g_doubleStringIsDoc;
89 static bool          g_doubleQuote;
90 static bool          g_noSuiteFound;
91 static int           g_stringContext;
92
93 static QValueStack<uint> g_indents;  //!< Tracks indentation levels for scoping in python
94
95 static QCString      g_docBlock;     //!< contents of all lines of a documentation block
96 static bool          g_endComment;
97
98 static void endFontClass();
99 static void adjustScopesAndSuites(unsigned indentLength);
100
101
102 /*! Represents a stack of variable to class mappings as found in the
103  *  code. Each scope is enclosed in pushScope() and popScope() calls.
104  *  Variables are added by calling addVariables() and one can search
105  *  for variable using findVariable().
106  */
107 class PyVariableContext 
108 {
109   public:
110     static const ClassDef *dummyContext;    
111     class Scope : public SDict<ClassDef> 
112     {
113       public:
114         Scope() : SDict<ClassDef>(17) {}
115     };
116     
117     PyVariableContext() 
118     {
119       m_scopes.setAutoDelete(TRUE);
120     }
121
122     virtual ~PyVariableContext() 
123     {
124     }
125     
126     void pushScope() 
127     {
128       m_scopes.append(new Scope);
129     }
130
131     void popScope() 
132     {
133       if (m_scopes.count()>0) 
134       {
135         m_scopes.remove(m_scopes.count()-1);
136       }
137     }
138
139     void clear() 
140     {
141       m_scopes.clear();
142       m_globalScope.clear();
143     }
144
145     void clearExceptGlobal() 
146     {
147       m_scopes.clear();
148     }
149
150     void addVariable(const QCString &type,const QCString &name);
151     ClassDef *findVariable(const QCString &name);
152     
153   private:
154     Scope        m_globalScope;
155     QList<Scope> m_scopes;
156 };
157
158 void PyVariableContext::addVariable(const QCString &type,const QCString &name)
159 {
160   //printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data());
161   QCString ltype = type.simplifyWhiteSpace();
162   QCString lname = name.simplifyWhiteSpace();
163
164   Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
165   ClassDef *varType;
166   if (
167       (varType=g_codeClassSDict[ltype]) ||  // look for class definitions inside the code block
168       (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
169      ) 
170   {
171     scope->append(lname,varType); // add it to a list
172   }
173   else 
174   {
175     if (m_scopes.count()>0) // for local variables add a dummy entry so the name 
176                             // is hidden to avoid FALSE links to global variables with the same name
177                             // TODO: make this work for namespaces as well!
178     {
179       scope->append(lname,dummyContext);
180     }
181   }
182 }
183
184 ClassDef *PyVariableContext::findVariable(const QCString &name)
185 {
186   if (name.isEmpty()) return 0;
187   ClassDef *result = 0;
188   QListIterator<Scope> sli(m_scopes);
189   Scope *scope;
190   // search from inner to outer scope
191   for (sli.toLast();(scope=sli.current());--sli)
192   {
193     result = scope->find(name);
194     if (result) 
195     {
196       return result;
197     }
198   }
199   // nothing found -> also try the global scope
200   result=m_globalScope.find(name);
201   return result;
202 }
203
204 static PyVariableContext g_theVarContext;
205 const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8;
206
207 class PyCallContext
208 {
209   public:
210     struct Ctx
211     {
212       Ctx() : name(g_name), type(g_type), cd(0) {}
213       QCString name;
214       QCString type;
215       ClassDef *cd;
216     };
217
218     PyCallContext() 
219     {
220       m_classList.append(new Ctx);
221       m_classList.setAutoDelete(TRUE);
222     }
223
224     virtual ~PyCallContext() {}
225
226     void setClass(ClassDef *cd)
227     {
228       Ctx *ctx = m_classList.getLast();
229       if (ctx) 
230       {
231         ctx->cd=cd;
232       }
233     }
234     void pushScope()
235     {
236       m_classList.append(new Ctx);
237     }
238
239     void popScope()
240     {
241       if (m_classList.count()>1)
242       {
243         Ctx *ctx = m_classList.getLast();
244         if (ctx)
245         {
246           g_name = ctx->name;
247           g_type = ctx->type;
248         }
249         m_classList.removeLast();
250       }
251       else
252       {
253       }
254     }
255
256     void clear()
257     {
258       m_classList.clear();
259       m_classList.append(new Ctx);
260     }
261
262     ClassDef *getClass() const
263     {
264       Ctx *ctx = m_classList.getLast();
265
266       if (ctx)
267         return ctx->cd;
268       else
269         return 0;
270     }
271
272   private:
273     QList<Ctx> m_classList;    
274 };
275
276 static PyCallContext g_theCallContext;
277
278
279 /*! counts the number of lines in the input */
280 static int countLines()
281 {
282   const char *p=g_inputString;
283   char c;
284   int count=1;
285   while ((c=*p)) 
286   { 
287     p++ ; 
288     if (c=='\n') count++;  
289   }
290   if (p>g_inputString && *(p-1)!='\n') 
291   { // last line does not end with a \n, so we add an extra
292     // line and explicitly terminate the line after parsing.
293     count++, 
294     g_needsTermination=TRUE; 
295   } 
296   return count;
297 }
298
299 static void setCurrentDoc(const QCString &anchor)
300 {
301   if (Doxygen::searchIndex)
302   {
303     if (g_searchCtx)
304     {
305       Doxygen::searchIndex->setCurrentDoc(g_searchCtx,g_searchCtx->anchor(),FALSE);
306     }
307     else
308     {
309       Doxygen::searchIndex->setCurrentDoc(g_sourceFileDef,anchor,TRUE);
310     }
311   }
312 }
313
314 static void addToSearchIndex(const char *text)
315 {
316   if (Doxygen::searchIndex)
317   {
318     Doxygen::searchIndex->addWord(text,FALSE);
319   }
320 }
321
322
323 static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
324 {
325   int pos=0;
326   QCString type = s;
327   QCString className;
328   QCString templSpec;
329   while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
330   {
331     QCString clName=className+templSpec;
332
333     ClassDef *cd=0;
334     if (!g_classScope.isEmpty())
335     {
336       cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName);
337     }
338     if (cd==0)
339     {
340       cd=getResolvedClass(d,g_sourceFileDef,clName);
341     }
342     if (cd)
343     {
344       return cd;
345     }
346   }
347
348   return 0;
349 }
350
351
352
353 /*! start a new line of code, inserting a line number if g_sourceFileDef
354  * is TRUE. If a definition starts at the current line, then the line
355  * number is linked to the documentation of that definition.
356  */
357 static void startCodeLine()
358 {
359   //if (g_currentFontClass) { g_code->endFontClass(); }
360   if (g_sourceFileDef)
361   {
362     //QCString lineNumber,lineAnchor;
363     //lineNumber.sprintf("%05d",g_yyLineNr);
364     //lineAnchor.sprintf("l%05d",g_yyLineNr);
365    
366     Definition *d   = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
367     //printf("startCodeLine %d d=%p\n",g_yyLineNr,d);
368     //g_code->startLineNumber();
369
370     if (!g_includeCodeFragment && d && d->isLinkableInProject())
371     {
372       g_currentDefinition = d;
373       g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
374       //g_insideBody = FALSE;
375       g_endComment = FALSE;
376       g_searchingForBody = TRUE;
377       g_realScope = d->name().copy();
378       g_classScope = d->name().copy();
379       //printf("Real scope: `%s'\n",g_realScope.data());
380       g_bodyCurlyCount = 0;
381       QCString lineAnchor;
382       lineAnchor.sprintf("l%05d",g_yyLineNr);
383       if (g_currentMemberDef)
384       {
385         g_code->writeLineNumber(g_currentMemberDef->getReference(),
386                                 g_currentMemberDef->getOutputFileBase(),
387                                 g_currentMemberDef->anchor(),g_yyLineNr);
388         setCurrentDoc(lineAnchor);
389       }
390       else
391       {
392         g_code->writeLineNumber(d->getReference(),
393                                 d->getOutputFileBase(),
394                                 0,g_yyLineNr);
395         setCurrentDoc(lineAnchor);
396       }
397     }
398     else
399     {
400       //g_code->codify(lineNumber);
401       g_code->writeLineNumber(0,0,0,g_yyLineNr);
402     }
403     //g_code->endLineNumber();
404   }
405   g_code->startCodeLine(g_sourceFileDef); 
406   if (g_currentFontClass)
407   {
408     g_code->startFontClass(g_currentFontClass);
409   }
410 }
411
412 static void codify(const char* text) 
413
414   g_code->codify(text);
415 }
416
417 static void endCodeLine()
418 {
419   endFontClass();
420   g_code->endCodeLine();
421 }
422
423 static void nextCodeLine()
424 {
425   const char *fc = g_currentFontClass;
426   endCodeLine();
427   if (g_yyLineNr<g_inputLines) 
428   {
429     g_currentFontClass = fc;
430     startCodeLine();
431   }
432 }
433
434
435 /*! writes a link to a fragment \a text that may span multiple lines, inserting
436  * line numbers for each line. If \a text contains newlines, the link will be 
437  * split into multiple links with the same destination, one for each line.
438  */
439 static void writeMultiLineCodeLink(CodeOutputInterface &ol,
440                   Definition *d,
441                   const char *text)
442 {
443   static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
444   TooltipManager::instance()->addTooltip(d);
445   QCString ref  = d->getReference();
446   QCString file = d->getOutputFileBase();
447   QCString anchor = d->anchor();
448   QCString tooltip; 
449   if (!sourceTooltips) // fall back to simple "title" tooltips
450   {
451     tooltip = d->briefDescriptionAsTooltip();
452   }
453   bool done=FALSE;
454   char *p=(char *)text;
455   while (!done)
456   {
457     char *sp=p;
458     char c;
459     while ((c=*p++) && c!='\n') { }
460     if (c=='\n')
461     {
462       g_yyLineNr++;
463       *(p-1)='\0';
464       //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
465       ol.writeCodeLink(ref,file,anchor,sp,tooltip);
466       nextCodeLine();
467     }
468     else
469     {
470       //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
471       ol.writeCodeLink(ref,file,anchor,sp,tooltip);
472       done=TRUE;
473     }
474   }
475 }
476
477 static void startFontClass(const char *s)
478 {
479   // if font class is already set don't stop and start it.
480   // strcmp does not like null pointers as input.
481   if (!g_currentFontClass || !s || strcmp(g_currentFontClass,s))
482   {
483     endFontClass();
484     g_code->startFontClass(s);
485     g_currentFontClass=s;
486   }
487 }
488
489 static void endFontClass()
490 {
491   if (g_currentFontClass)
492   {
493     g_code->endFontClass();
494     g_currentFontClass=0;
495   }
496 }
497
498 static void codifyLines(char *text)
499 {
500   //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
501   char *p=text,*sp=p;
502   char c;
503   bool done=FALSE;
504   const char *  tmp_currentFontClass = g_currentFontClass;
505   while (!done)
506   {
507     sp=p;
508     while ((c=*p++) && c!='\n') { }
509     if (c=='\n')
510     {
511       g_yyLineNr++;
512       *(p-1)='\0';
513       g_code->codify(sp);
514       endCodeLine();
515       if (g_yyLineNr<g_inputLines)
516       {
517         startCodeLine();
518       }
519       if (tmp_currentFontClass)
520       {
521         startFontClass(tmp_currentFontClass);
522       }
523     }
524     else
525     {
526       g_code->codify(sp);
527       done=TRUE;
528     }
529   }
530 }
531
532 static void codifyLines(const QCString &str)
533 {
534   char *tmp= (char *)malloc(str.length()+1);
535   qstrcpy(tmp, str);
536   codifyLines(tmp);
537   free(tmp);
538 }
539
540 static bool getLinkInScope(const QCString &c,  // scope
541                            const QCString &m,  // member
542                            const char *memberText, // exact text
543                            CodeOutputInterface &ol,
544                            const char *text
545                           )
546 {
547   MemberDef    *md;
548   ClassDef     *cd;
549   FileDef      *fd;
550   NamespaceDef *nd;
551   GroupDef     *gd;
552   //printf("Trying `%s'::`%s'\n",c.data(),m.data());
553   if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) && 
554       md->isLinkable())
555   {
556     //Definition *d=0;
557     //if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd;
558
559     Definition *d = md->getOuterScope()==Doxygen::globalScope ?
560                     md->getBodyDef() : md->getOuterScope();
561     //printf("Found! d=%s\n",d?d->name().data():"<none>");
562     if (md->getGroupDef()) d = md->getGroupDef();
563     if (d && d->isLinkable())
564     {
565       g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope()));
566       //printf("g_currentDefinition=%p g_currentMemberDef=%p\n",
567       //        g_currentDefinition,g_currentMemberDef);
568
569       if (g_currentDefinition && g_currentMemberDef &&
570           md!=g_currentMemberDef && g_collectXRefs)
571       {
572         addDocCrossReference(g_currentMemberDef,md);
573       }
574       //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());
575      
576       writeMultiLineCodeLink(ol,md, text ? text : memberText);
577       addToSearchIndex(text ? text : memberText);
578       return TRUE;
579     } 
580   }
581   return FALSE;
582 }
583
584 static bool getLink(const char *className,
585                     const char *memberName,
586                     CodeOutputInterface &ol,
587                     const char *text=0)
588 {
589   QCString m=removeRedundantWhiteSpace(memberName);
590   QCString c=className;
591   if (!getLinkInScope(c,m,memberName,ol,text))
592   {
593     if (!g_curClassName.isEmpty())
594     {
595       if (!c.isEmpty()) c.prepend("::");
596       c.prepend(g_curClassName);
597       return getLinkInScope(c,m,memberName,ol,text);
598     }
599     return FALSE;
600   }
601   return TRUE;
602 }
603
604
605 /*
606   For a given string in the source code,
607   finds its class or global id and links to it.
608 */
609 static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
610                                       bool typeOnly=FALSE)
611 {
612   QCString className=clName;
613
614   // Don't do anything for empty text
615   if (className.isEmpty()) return;
616
617   DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",className.data()));
618
619   ClassDef *cd=0,*lcd=0;  /** Class def that we may find */
620   MemberDef *md=0;        /** Member def that we may find */
621   //bool isLocal=FALSE;
622
623   if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable
624   {
625     Definition *d = g_currentDefinition;
626     QCString scope = substitute(className,".","::");
627
628     cd = getResolvedClass(d,g_sourceFileDef,substitute(className,".","::"),&md);
629
630     DBG_CTX((stderr,"d=%s g_sourceFileDef=%s\n",
631         d?d->displayName().data():"<null>",
632         g_currentDefinition?g_currentDefinition->displayName().data():"<null>"));
633     DBG_CTX((stderr,"is found as a type %s\n",cd?cd->name().data():"<null>"));
634
635     if (cd==0 && md==0) // also see if it is variable or enum or enum value
636     {
637       NamespaceDef *nd = getResolvedNamespace(scope);
638       if (nd)
639       {
640         writeMultiLineCodeLink(ol,nd,clName);
641         addToSearchIndex(className);
642         return;
643       }
644       else if (getLink(g_classScope,clName,ol,clName))
645       {
646         return;
647       }
648     }
649   }
650   else
651   {
652     if (lcd!=PyVariableContext::dummyContext) 
653     {
654       g_theCallContext.setClass(lcd);
655     }
656     //isLocal=TRUE;
657     DBG_CTX((stderr,"is a local variable cd=%p!\n",cd));
658   }
659
660   if (cd && cd->isLinkable()) // is it a linkable class
661   {
662     writeMultiLineCodeLink(ol,cd,clName);
663     addToSearchIndex(className);
664     if (md)
665     {
666       Definition *d = md->getOuterScope()==Doxygen::globalScope ?
667                       md->getBodyDef() : md->getOuterScope();
668       if (md->getGroupDef()) d = md->getGroupDef();
669       if (d && d->isLinkable() && md->isLinkable() && 
670           g_currentMemberDef && g_collectXRefs)
671       {
672         addDocCrossReference(g_currentMemberDef,md);
673       }
674     }
675   }
676   else // not a class, maybe a global member
677   {
678     int scopeEnd = className.findRev(".");
679     if (scopeEnd!=-1 && !typeOnly) // name with explicit scope
680     {
681       QCString scope = substitute(className.left(scopeEnd),".","::");
682       QCString locName = className.right(className.length()-scopeEnd-1);
683       ClassDef *mcd = getClass(scope);
684       DBG_CTX((stderr,"scope=%s locName=%s mcd=%p\n",scope.data(),locName.data(),mcd));
685       if (mcd)
686       {
687         MemberDef *md = mcd->getMemberByName(locName);
688         if (md)
689         {
690           g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope()));
691           writeMultiLineCodeLink(ol,md,clName);
692           addToSearchIndex(className);
693           Definition *d = md->getOuterScope()==Doxygen::globalScope ?
694                           md->getBodyDef() : md->getOuterScope();
695           if (md->getGroupDef()) d = md->getGroupDef();
696           if (d && d->isLinkable() && md->isLinkable() && 
697               g_currentMemberDef && g_collectXRefs)
698           {
699             addDocCrossReference(g_currentMemberDef,md);
700           }
701           return;
702         }
703       }
704       else // check namespace as well
705       {
706         NamespaceDef *mnd = getResolvedNamespace(scope);
707         if (mnd)
708         {
709           MemberDef *md=mnd->getMemberByName(locName);
710           if (md)
711           {
712             //printf("name=%s scope=%s\n",locName.data(),scope.data());
713             g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope()));
714             writeMultiLineCodeLink(ol,md,clName);
715             addToSearchIndex(className);
716             Definition *d = md->getOuterScope()==Doxygen::globalScope ?
717                             md->getBodyDef() : md->getOuterScope();
718             if (md->getGroupDef()) d = md->getGroupDef();
719             if (d && d->isLinkable() && md->isLinkable() && 
720                 g_currentMemberDef && g_collectXRefs)
721             {
722               addDocCrossReference(g_currentMemberDef,md);
723             }
724             return;
725           }
726         }
727       }
728     }
729     
730     // nothing found, just write out the word
731     codifyLines(clName);
732     addToSearchIndex(clName);
733   }
734 }
735
736 /*
737    As of June 1, this function seems to work
738    for file members, but scopes are not
739    being correctly tracked for classes
740    so it doesn't work for classes yet.
741
742 */
743 static void generateFunctionLink(CodeOutputInterface &ol,char *funcName)
744 {
745   //CodeClassDef *ccd=0;
746   ClassDef *ccd=0;
747   QCString locScope=g_classScope.copy();
748   QCString locFunc=removeRedundantWhiteSpace(funcName);
749   DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data()));
750   int i=locFunc.findRev("::");
751   if (i>0)
752   {
753     locScope=locFunc.left(i);
754     locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace();
755   }
756   //printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data());
757   if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope]))
758   {
759     //printf("using classScope %s\n",g_classScope.data());
760     if (ccd->baseClasses())
761     {
762       BaseClassListIterator bcli(*ccd->baseClasses());
763       for ( ; bcli.current() ; ++bcli)
764       {
765         if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName)) 
766         {
767           return;
768         }
769       }
770     }
771   }
772   if (!getLink(locScope,locFunc,ol,funcName))
773   {
774     generateClassOrGlobalLink(ol,funcName);
775   }
776   return;
777 }
778
779 static bool findMemberLink(CodeOutputInterface &ol,Definition *sym,const char *symName)
780 {
781   //printf("sym %s outerScope=%s equal=%d\n",
782   //    sym->name().data(),sym->getOuterScope()->name().data(),
783   //    sym->getOuterScope()==g_currentDefinition);
784
785   if (sym->getOuterScope() &&
786       sym->getOuterScope()->definitionType()==Definition::TypeClass &&
787       g_currentDefinition->definitionType()==Definition::TypeClass)
788   {
789     ClassDef *cd = (ClassDef*)sym->getOuterScope();
790     ClassDef *thisCd = (ClassDef *)g_currentDefinition;
791     if (sym->definitionType()==Definition::TypeMember)
792     {
793       if (g_currentMemberDef && g_collectXRefs)
794       {
795         addDocCrossReference(g_currentMemberDef,(MemberDef*)sym);
796       }
797     }
798     DBG_CTX((stderr,"cd=%s thisCd=%s\n",cd?cd->name().data():"<none>",thisCd?thisCd->name().data():"<none>"));
799
800     // TODO: find the nearest base class in case cd is a base class of
801     // thisCd 
802     if (cd==thisCd || (thisCd && thisCd->isBaseClass(cd,TRUE)))
803     {
804       writeMultiLineCodeLink(ol,sym,symName);
805       return TRUE;
806     }
807   }
808   return FALSE;
809 }
810
811 static void findMemberLink(CodeOutputInterface &ol,char *symName)
812 {
813   //printf("Member reference: %s scope=%s member=%s\n",
814   //    yytext,
815   //    g_currentDefinition?g_currentDefinition->name().data():"<none>",
816   //    g_currentMemberDef?g_currentMemberDef->name().data():"<none>"
817   //    );
818   if (g_currentDefinition)
819   {
820     DefinitionIntf *di = Doxygen::symbolMap->find(symName);
821     if (di)
822     {
823       if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multiple symbols
824       {
825         DefinitionListIterator dli(*(DefinitionList*)di);
826         Definition *sym;
827         for (dli.toFirst();(sym=dli.current());++dli)
828         {
829           if (findMemberLink(ol,sym,symName)) return;
830         }
831       }
832       else // single symbol
833       {
834         if (findMemberLink(ol,(Definition*)di,symName)) return;
835       }
836     }
837   }
838   //printf("sym %s not found\n",&yytext[5]);
839   codify(symName);
840 }
841
842 #undef YY_INPUT
843 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
844
845 static int yyread(char *buf,int max_size)
846 {
847   int c=0;
848   while( c < max_size && g_inputString[g_inputPosition] )
849   {
850     *buf = g_inputString[g_inputPosition++] ;
851     c++; buf++;
852   }
853   return c;
854 }
855
856 %}
857
858
859 BB                [ \t]+
860 B                 [ \t]*
861 NEWLINE           \n
862
863 DIGIT             [0-9]
864 LETTER            [A-Za-z\x80-\xFF]
865 NONEMPTY          [A-Za-z0-9_\x80-\xFF]
866 EXPCHAR           [#(){}\[\],:.%/\\=`*~|&<>!;+-]
867 NONEMPTYEXP       [^ \t\n:]
868 PARAMNONEMPTY     [^ \t\n():]
869 IDENTIFIER        ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*  
870 BORDER            ([^A-Za-z0-9])
871
872 POUNDCOMMENT      "##"
873
874 TRISINGLEQUOTE    "'''"
875 TRIDOUBLEQUOTE    "\"\"\""
876 LONGSTRINGCHAR    [^\\"']
877 ESCAPESEQ         ("\\")(.)
878 LONGSTRINGITEM    ({LONGSTRINGCHAR}|{ESCAPESEQ})
879 SMALLQUOTE        ("\"\""|"\""|"'"|"''")
880 LONGSTRINGBLOCK   ({LONGSTRINGITEM}+|{SMALLQUOTE})
881
882 SHORTSTRING       ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
883 SHORTSTRINGITEM   ({SHORTSTRINGCHAR}|{ESCAPESEQ})
884 SHORTSTRINGCHAR   [^\\\n"]
885 STRINGLITERAL     {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})  
886 STRINGPREFIX      ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
887 KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
888 FLOWKW  ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
889 QUOTES            ("\""[^"]*"\"")
890 SINGLEQUOTES      ("'"[^']*"'")
891
892 LONGINTEGER       {INTEGER}("l"|"L")
893 INTEGER           ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER})
894 DECIMALINTEGER    ({NONZERODIGIT}{DIGIT}*|"0")
895 OCTINTEGER        "0"{OCTDIGIT}+
896 HEXINTEGER        "0"("x"|"X"){HEXDIGIT}+  
897 NONZERODIGIT      [1-9]  
898 OCTDIGIT          [0-7]  
899 HEXDIGIT          ({DIGIT}|[a-f]|[A-F])
900 FLOATNUMBER       ({POINTFLOAT}|{EXPONENTFLOAT})
901 POINTFLOAT        ({INTPART}?{FRACTION}|{INTPART}".")  
902 EXPONENTFLOAT     ({INTPART}|{POINTFLOAT}){EXPONENT}
903 INTPART             {DIGIT}+  
904 FRACTION             "."{DIGIT}+  
905 EXPONENT             ("e"|"E")("+"|"-")?{DIGIT}+
906 IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J")
907 ATOM              ({IDENTIFIER}|{LITERAL}|{ENCLOSURE})
908 ENCLOSURE             ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION})
909 LITERAL             ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER})
910 PARENTH_FORM       "("{EXPRESSION_LIST}?")"
911 TEST             ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM})
912 TESTLIST             {TEST}( ","{TEST})*","?
913 LIST_DISPLAY        "["{LISTMAKER}?"]"  
914 LISTMAKER             {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?)  
915 LIST_ITER             ({LIST_FOR}|{LIST_IF})  
916 LIST_FOR             "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}?
917 LIST_IF             "if"{TEST}{LIST_ITER}?
918 DICT_DISPLAY             "\{"{KEY_DATUM_LIST}?"\}"
919 KEY_DATUM_LIST       {KEY_DATUM}(","{KEY_DATUM})*","? 
920 KEY_DATUM              {EXPRESSION}":"{EXPRESSION}
921 STRING_CONVERSION        "`"{EXPRESSION_LIST}"`"
922 PRIMARY             ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL})
923 ATTRIBUTEREF             {PRIMARY}"."{IDENTIFIER}
924 SUBSCRIPTION             {PRIMARY}"["{EXPRESSION_LIST}"]"
925 SLICING            ({SIMPLE_SLICING}|{EXTENDED_SLICING})
926 SIMPLE_SLICING             {PRIMARY}"["{SHORT_SLICE}"]"  
927 EXTENDED_SLICING           {PRIMARY}"["{SLICE_LIST}"]" 
928 SLICE_LIST          {SLICE_ITEM}(","{SLICE_ITEM})*","?
929 SLICE_ITEM           ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS})
930 PROPER_SLICE           ({SHORT_SLICE}|{LONG_SLICE})
931 SHORT_SLICE              {LOWER_BOUND}?":"{UPPER_BOUND}?  
932 LONG_SLICE             {SHORT_SLICE}":"{STRIDE}?
933 LOWER_BOUND             {EXPRESSION}  
934 UPPER_BOUND             {EXPRESSION}
935 STRIDE             {EXPRESSION}
936 ELLIPSIS             "..."
937 CALL             {PRIMARY}"("({ARGUMENT_LIST}","?)?")"
938 ARGUMENT_LIST       ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION})
939 POSITIONAL_ARGUMENTS             {EXPRESSION}(","{EXPRESSION})*
940 KEYWORD_ARGUMENTS              {KEYWORD_ITEM}(","{KEYWORD_ITEM})*
941 KEYWORD_ITEM           {IDENTIFIER}"="{EXPRESSION}
942 POWER             {PRIMARY}("**"{U_EXPR})?
943 U_EXPR            ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR})
944 M_EXPR            ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR})
945 A_EXPR         ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR}
946 SHIFT_EXPR            ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR})
947 AND_EXPR            ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR}
948 XOR_EXPR            ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR})
949 OR_EXPR            ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR})
950
951 COMPARISON             {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})*
952 COMP_OPERATOR         ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in")
953 EXPRESSION            ({OR_TEST}|{LAMBDA_FORM})
954 OR_TEST             ({AND_TEST}|{OR_TEST}"or"{AND_TEST})
955 AND_TEST          ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST})
956 NOT_TEST           ({COMPARISON}|"not"{NOT_TEST})
957 LAMBDA_FORM       "lambda"{PARAMETER_LIST}?":"{EXPRESSION}
958 EXPRESSION_LIST      {EXPRESSION}(","{EXPRESSION})*","?
959 SIMPLE_STMT       ({EXPRESSION_STMT}|{ASSERT_STMT}|{ASSIGNMENT_STMT}|{AUGMENTED_ASSIGNMENT_STMT}|{PASS_STMT}|{DEL_STMT}|{PRINT_STMT}|{RETURN_STMT}|{YIELD_STMT}|{RAISE_STMT}|{BREAK_STMT}|{CONTINUE_STMT}|{IMPORT_STMT}|{GLOBAL_STMT}|{EXEC_STMT})
960 EXPRESSION_STMT     {EXPRESSION_LIST}
961 ASSERT_STMT             "assert"{EXPRESSION}(","{EXPRESSION})?
962 ASSIGNMENT_STMT     ({TARGET_LIST}"=")+{EXPRESSION_LIST}
963 TARGET_LIST             {TARGET}(","{TARGET})*","?
964 TARGET           ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING})
965
966
967 %option noyywrap
968 %option stack
969
970 %x Body
971
972 %x FunctionDec
973 %x FunctionParams
974
975 %x ClassDec
976 %x ClassInheritance
977
978 %x Suite
979 %x SuiteCaptureIndent
980 %x SuiteStart
981 %x SuiteMaintain
982 %x SuiteContinuing
983
984 %x LongString
985
986 %x SingleQuoteString
987 %x DoubleQuoteString
988 %x TripleString
989
990 %x DocBlock
991 %%
992
993 <Body,Suite>{
994       "def"{BB}                     {
995                                         startFontClass("keyword");
996                                         codify(yytext);
997                                         endFontClass();
998                                         BEGIN( FunctionDec );
999                                     }
1000
1001       "class"{BB}                   {
1002                                         startFontClass("keyword");
1003                                         codify(yytext);
1004                                         endFontClass();
1005                                         BEGIN( ClassDec );
1006                                     }
1007       "None"                        {
1008                                         startFontClass("keywordtype");
1009                                         codify(yytext);
1010                                         endFontClass();
1011                                     }
1012       "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" {
1013                                         codify("self.");
1014                                         findMemberLink(*g_code,&yytext[5]);
1015                                     }
1016       "self."{IDENTIFIER}/"("       {
1017                                         codify("self.");
1018                                         findMemberLink(*g_code,&yytext[5]);
1019                                     }
1020       "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} {
1021                                         codify("self.");
1022                                         findMemberLink(*g_code,&yytext[5]);
1023                                     }
1024       "self."{IDENTIFIER}           {
1025                                         codify("self.");
1026                                         findMemberLink(*g_code,&yytext[5]);
1027                                     }
1028       "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" {
1029                                         codify("cls.");
1030                                         findMemberLink(*g_code,&yytext[4]);
1031                                     }
1032       "cls."{IDENTIFIER}/"("       {
1033                                         codify("cls.");
1034                                         findMemberLink(*g_code,&yytext[4]);
1035                                     }
1036       "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} {
1037                                         codify("cls.");
1038                                         findMemberLink(*g_code,&yytext[4]);
1039                                     }
1040       "cls."{IDENTIFIER}           {
1041                                         codify("cls.");
1042                                         findMemberLink(*g_code,&yytext[4]);
1043                                     }
1044 }
1045
1046 <ClassDec>{IDENTIFIER}              {
1047
1048                                         generateClassOrGlobalLink(*g_code,yytext);
1049                                         // codify(yytext);
1050                                         g_curClassName = yytext;
1051                                         g_curClassBases.clear();
1052                                         BEGIN( ClassInheritance );
1053                                     }
1054
1055 <ClassInheritance>{
1056    ({BB}|[(,)])                     {
1057                                         codify(yytext);
1058                                     }
1059
1060    ({IDENTIFIER}".")*{IDENTIFIER}   {
1061                                         // The parser
1062                                         // is assuming
1063                                         // that ALL identifiers
1064                                         // in this state
1065                                         // are base classes;
1066                                         // it doesn't check to see
1067                                         // that the first parenthesis
1068                                         // has been seen.
1069
1070                                         // This is bad - it should
1071                                         // probably be more strict
1072                                         // about what to accept.
1073
1074                                         g_curClassBases.inSort(yytext);
1075                                         generateClassOrGlobalLink(*g_code,yytext);
1076                                         // codify(yytext);
1077                                     }
1078
1079     ":"                             {
1080                                       codify(yytext);
1081
1082                                       // Assume this will
1083                                       // be a one-line suite;
1084                                       // found counter-example
1085                                       // in SuiteStart.
1086
1087                                       // Push a class scope
1088
1089                                       ClassDef *classDefToAdd = new ClassDef("<code>",1,1,g_curClassName,ClassDef::Class,0,0,FALSE);
1090                                       g_codeClassSDict.append(g_curClassName,classDefToAdd);
1091                                       char *s=g_curClassBases.first();
1092                                       while (s) 
1093                                       {
1094                                         ClassDef *baseDefToAdd;
1095                                         baseDefToAdd=g_codeClassSDict[s];
1096
1097                                         // Try to find class in global
1098                                         // scope
1099                                         if (baseDefToAdd==0) 
1100                                         {
1101                                           baseDefToAdd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s);
1102                                         }
1103
1104                                         if (baseDefToAdd && baseDefToAdd!=classDefToAdd) 
1105                                         {
1106                                           classDefToAdd->insertBaseClass(baseDefToAdd,s,Public,Normal);
1107                                         }
1108
1109                                         s=g_curClassBases.next();
1110                                       }
1111
1112                                       // Reset class-parsing variables.
1113                                       g_curClassName.resize(0);
1114                                       g_curClassBases.clear();
1115                                       
1116                                       g_noSuiteFound = TRUE;
1117                                       BEGIN( SuiteStart );
1118                                     }
1119 }
1120
1121
1122 <FunctionDec>{
1123     {IDENTIFIER}                    {
1124                                         generateFunctionLink(*g_code,yytext);
1125                                     }
1126
1127     {B}"("                          {
1128                                         codify(yytext);
1129                                         BEGIN( FunctionParams );
1130                                     }
1131 }
1132
1133 <FunctionParams>{
1134     ({BB}|",")                      {
1135                                          // Parses delimiters
1136                                          codify(yytext);
1137                                     }
1138
1139     ({IDENTIFIER}|{PARAMNONEMPTY}+) {
1140                                          codify(yytext);
1141                                     }
1142
1143     ")"                             {
1144                                          codify(yytext);
1145                                     }
1146
1147     "\n"                            {
1148                                          codifyLines(yytext);
1149                                     }
1150
1151     ":"                             {
1152                                       codify(yytext);
1153
1154                                       // Assume this will
1155                                       // be a one-line suite;
1156                                       // found counter-example
1157                                       // in SuiteStart.
1158                                       g_noSuiteFound = TRUE;
1159                                       BEGIN( SuiteStart );
1160                                     }
1161 }
1162
1163 <Body,Suite>{
1164
1165     {KEYWORD}                  {
1166                                  // Position-sensitive rules!
1167                                  // Must come AFTER keyword-triggered rules
1168                                  // Must come BEFORE identifier NONEMPTY-like rules
1169                                  //   to syntax highlight.
1170
1171                                  startFontClass("keyword");
1172                                  codify(yytext);
1173                                  endFontClass();
1174                                }
1175
1176     {FLOWKW}                   {
1177                                  startFontClass("keywordflow");
1178                                  codify(yytext);
1179                                  endFontClass();
1180                                }
1181     ({IDENTIFIER}".")*{IDENTIFIER}/"("  {
1182                                  generateClassOrGlobalLink(*g_code,yytext);
1183                                }
1184     ({IDENTIFIER}".")+{IDENTIFIER} {
1185                                  generateClassOrGlobalLink(*g_code,yytext,TRUE);
1186                                }
1187     {IDENTIFIER}               { codify(yytext); }
1188                         
1189 }
1190
1191
1192
1193 <SuiteStart>{
1194
1195     {BB}                               {
1196                                          codify(yytext);
1197                                        }
1198     "pass"                             {
1199                                           startFontClass("keyword");
1200                                           codifyLines(yytext);
1201                                           endFontClass();
1202                                           BEGIN(Body);
1203                                        }
1204     {KEYWORD}                          {
1205                                           startFontClass("keyword");
1206                                           codifyLines(yytext);
1207                                           endFontClass();
1208
1209                                           // No indentation necessary
1210                                           g_noSuiteFound = FALSE;
1211                                        }
1212
1213     {FLOWKW}                           {
1214                                           startFontClass("keywordflow");
1215                                           codifyLines(yytext);
1216                                           endFontClass();
1217
1218                                           // No indentation necessary
1219                                           g_noSuiteFound = FALSE;
1220                                        }
1221     {IDENTIFIER}                       {
1222                                          codify(yytext);
1223                                        } 
1224
1225
1226     {POUNDCOMMENT}                     {
1227                                          if (YY_START==SingleQuoteString || 
1228                                              YY_START==DoubleQuoteString || 
1229                                              YY_START==TripleString
1230                                             )
1231                                          {
1232                                            REJECT;
1233                                          }
1234                                          yy_push_state(YY_START);
1235                                          BEGIN(DocBlock);
1236                                          g_docBlock=yytext;
1237                                        }
1238
1239     {NEWLINE}                          {
1240                                           codifyLines(yytext);
1241                                           if ( g_noSuiteFound ) 
1242                                           {
1243                                             // printf("New suite to capture! [%d]\n", g_yyLineNr);
1244                                             BEGIN ( SuiteCaptureIndent );
1245                                           }
1246                                        }
1247 }
1248
1249 <SuiteCaptureIndent>{
1250     "\n"|({BB}"\n")            {
1251                                  // Blankline - ignore, keep looking for indentation.
1252                                  codifyLines(yytext);
1253                                }
1254
1255     {BB}                       {
1256                                  // This state lasts momentarily,
1257                                  // to check the indentation
1258                                  // level that is about to be
1259                                  // used.
1260                                  codifyLines(yytext);
1261                                  g_indents.push(yyleng);
1262                                  // printf("Captured indent of %d [line %d]\n", yyleng, g_yyLineNr);
1263                                  BEGIN( Suite );
1264                                }
1265 }
1266
1267 <SuiteMaintain>{
1268
1269     {BB}/({NONEMPTY}|{EXPCHAR}) {
1270                                  // This implements poor
1271                                  // indendation-tracking;
1272                                  // should be improved.
1273                                  // (translate tabs to space, etc)
1274                                  codifyLines(yytext);
1275                                  adjustScopesAndSuites((int)yyleng);
1276                                }
1277
1278     "\n"|({BB}"\n")            {
1279                                  // If this ever succeeds,
1280                                  // it means that this is
1281                                  // a blank line, and
1282                                  // can be ignored.
1283                                  codifyLines(yytext);
1284                                }
1285
1286     ""/({NONEMPTY}|{EXPCHAR})  {
1287                                  // Default rule; matches
1288                                  // the empty string, assuming
1289                                  // real text starts here.
1290                                  // Just go straight to Body.
1291                                  adjustScopesAndSuites(0);
1292                                }
1293 }
1294
1295
1296 <Suite>{NEWLINE}               {
1297                                  codifyLines(yytext);
1298                                  BEGIN( SuiteMaintain );
1299                                }
1300 <Body>{IDENTIFIER}             {
1301                                  codify(yytext);
1302                                }
1303 <Body>{NEWLINE}                {
1304                                  codifyLines(yytext);
1305                                }
1306
1307 <SingleQuoteString>{ // Single quoted string like 'That\'s a """nice""" string!'
1308     \\{B}\n                    { // line continuation
1309                                  codifyLines(yytext);
1310                                }
1311     \\.                        { // espaced char
1312                                  codify(yytext);
1313                                }
1314     {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // tripple double quotes
1315                                  codify(yytext);
1316                                }
1317     "'"                        { // end of the string
1318                                  codify(yytext);
1319                                  endFontClass();
1320                                  BEGIN(g_stringContext);
1321                                }
1322     [^"'\n\\]+                 { // normal chars
1323                                  codify(yytext);
1324                                }
1325     .                          { // normal char
1326                                  codify(yytext);
1327                                }
1328 }
1329
1330 <DoubleQuoteString>{ // Double quoted string like "That's \"a '''nice'''\" string!"
1331     \\{B}\n                    { // line continuation
1332                                  codifyLines(yytext);
1333                                }
1334     \\.                        { // espaced char
1335                                  codify(yytext);
1336                                }
1337     {STRINGPREFIX}?{TRISINGLEQUOTE} { // tripple single quotes
1338                                  codify(yytext);
1339                                }
1340     "\""                       { // end of the string
1341                                  codify(yytext);
1342                                  endFontClass();
1343                                  BEGIN(g_stringContext);
1344                                }
1345     [^"'\n\\]+                 { // normal chars
1346                                  codify(yytext);
1347                                }
1348     .                          { // normal char
1349                                  codify(yytext);
1350                                }
1351 }
1352
1353 <TripleString>{
1354     {TRIDOUBLEQUOTE}   | 
1355     {TRISINGLEQUOTE}   {
1356                           codify(yytext);
1357                           if (g_doubleQuote==(yytext[0]=='"')) 
1358                           {
1359                             endFontClass();
1360                             BEGIN(g_stringContext);
1361                           }
1362                        }
1363     {LONGSTRINGBLOCK}  {
1364                          codifyLines(yytext);
1365                        }
1366     \n                 {
1367                          codifyLines(yytext);
1368                        }
1369     .                  {
1370                          codify(yytext);
1371                        }
1372 }
1373
1374   /*
1375 <*>({NONEMPTY}|{EXPCHAR}|{BB})           { // This should go one character at a time.
1376                                  codify(yytext);
1377                                  // printf("[pycode] '%s' [ state %d ]  [line %d] no match\n",
1378                                  //       yytext, YY_START, g_yyLineNr);
1379
1380                                  //endFontClass();
1381                                  BEGIN(Body);                                   
1382                                }
1383    */
1384
1385 <*>{STRINGPREFIX}?{TRISINGLEQUOTE} |
1386 <*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} {
1387                                  startFontClass("stringliteral");
1388                                  g_stringContext=YY_START;
1389                                  g_doubleQuote=yytext[yyleng-1]=='"';
1390                                  codify(yytext);
1391                                  BEGIN(TripleString);
1392                                }
1393 <*>{STRINGPREFIX}?"'"          { // single quoted string
1394                                  startFontClass("stringliteral");
1395                                  g_stringContext=YY_START;
1396                                  codify(yytext);
1397                                  BEGIN(SingleQuoteString);
1398                                }
1399 <*>{STRINGPREFIX}?"\""         { // double quoted string
1400                                  startFontClass("stringliteral");
1401                                  g_stringContext=YY_START;
1402                                  codify(yytext);
1403                                  BEGIN(DoubleQuoteString);
1404                                }
1405 <DocBlock>.*                   { // contents of current comment line
1406                                  g_docBlock+=yytext;
1407                                }
1408 <DocBlock>"\n"{B}("#")         { // comment block (next line is also comment line)
1409                                  g_docBlock+=yytext; 
1410                                }
1411 <DocBlock>{NEWLINE}            { // comment block ends at the end of this line
1412                                  // remove special comment (default config)
1413                                  if (Config_getBool(STRIP_CODE_COMMENTS))
1414                                  {
1415                                     g_yyLineNr+=((QCString)g_docBlock).contains('\n');
1416                                     g_endComment=TRUE;
1417                                   }
1418                                   else // do not remove comment
1419                                   {
1420                                     startFontClass("comment");
1421                                     codifyLines(g_docBlock);
1422                                     endFontClass();
1423                                   }
1424                                   unput(*yytext);
1425                                   yy_pop_state();
1426                                }
1427 <*>{POUNDCOMMENT}.*            {
1428                                  if (YY_START==SingleQuoteString || 
1429                                      YY_START==DoubleQuoteString || 
1430                                      YY_START==TripleString
1431                                     )
1432                                  {
1433                                    REJECT;
1434                                  }
1435                                  yy_push_state(YY_START);
1436                                  BEGIN(DocBlock);
1437                                  g_docBlock=yytext;
1438                                }
1439 <*>"#".*                       { // normal comment
1440                                  if (YY_START==SingleQuoteString || 
1441                                      YY_START==DoubleQuoteString || 
1442                                      YY_START==TripleString
1443                                     )
1444                                  {
1445                                    REJECT;
1446                                  }
1447                                  startFontClass("comment");
1448                                  codifyLines(yytext);
1449                                  endFontClass();
1450                                }
1451 <*>{NEWLINE}                   {
1452                                   if (g_endComment)
1453                                   {
1454                                     g_endComment=FALSE;
1455                                   }
1456                                   else
1457                                   {
1458                                     codifyLines(yytext);
1459                                   }
1460                                  //printf("[pycode] %d NEWLINE [line %d] no match\n",
1461                                  //       YY_START, g_yyLineNr);
1462
1463                                  //endFontClass();
1464                                  BEGIN(Body);
1465                                }
1466
1467 <*>[ \t]+                      {
1468                                  codify(yytext);
1469                                  BEGIN(Body);                                   
1470                                }
1471 <*>.                           {
1472                                  codify(yytext);
1473                                  // printf("[pycode] '%s' [ state %d ]  [line %d] no match\n",
1474                                  //        yytext, YY_START, g_yyLineNr);
1475
1476                                  //endFontClass();
1477                                  BEGIN(Body);                                   
1478                                }
1479
1480 <*><<EOF>>                     {
1481                                  if (YY_START == DocBlock) {
1482                                    if (!Config_getBool(STRIP_CODE_COMMENTS))
1483                                    {
1484                                      startFontClass("comment");
1485                                      codifyLines(g_docBlock);
1486                                      endFontClass();
1487                                    }
1488                                  }
1489                                  yyterminate();
1490                                }
1491 %%
1492
1493 /*@ ----------------------------------------------------------------------------
1494  */
1495
1496 void resetPythonCodeParserState() 
1497 {
1498   g_currentDefinition = 0;
1499   g_currentMemberDef = 0;
1500   g_doubleStringIsDoc = FALSE;
1501   g_paramParens = 0;
1502   g_indents.clear();
1503   BEGIN( Body );
1504 }
1505
1506 /*!
1507   Examines current stack of white-space indentations;
1508   re-syncs the parser with the correct scope.
1509 */
1510 static void adjustScopesAndSuites(unsigned indentLength) 
1511 {
1512   // States to pop
1513   if (!g_indents.isEmpty() && indentLength < g_indents.top()) 
1514   {
1515     while (!g_indents.isEmpty() && indentLength < g_indents.top()) 
1516     {
1517       // printf("Exited scope indent of [%d]\n", g_indents.top());
1518       g_indents.pop(); // Pop the old suite's indentation
1519
1520       g_currentMemberDef=0;
1521       if (g_currentDefinition) 
1522         g_currentDefinition=g_currentDefinition->getOuterScope();
1523     }
1524   }
1525
1526   // Are there any remaining indentation levels for suites?
1527   if (!g_indents.isEmpty()) 
1528   {
1529     BEGIN( Suite );
1530   }
1531   else 
1532   {
1533     BEGIN( Body );
1534   }
1535 }
1536
1537 void parsePythonCode(CodeOutputInterface &od,const char * /*className*/,
1538                  const QCString &s,bool exBlock, const char *exName,
1539                  FileDef *fd,int startLine,int endLine,bool inlineFragment,
1540                  MemberDef *,bool,Definition *searchCtx,bool collectXRefs) 
1541 {
1542
1543   //printf("***parseCode()\n");
1544   
1545   //--------------------------------------
1546   if (s.isEmpty()) return;
1547   printlex(yy_flex_debug, TRUE, __FILE__, fd ? fd->fileName().data(): NULL);
1548   TooltipManager::instance()->clearTooltips();
1549   g_code = &od;
1550   g_inputString   = s;
1551   g_inputPosition = 0;
1552   g_currentFontClass = 0;
1553   g_needsTermination = FALSE;
1554   g_searchCtx=searchCtx;
1555   g_collectXRefs=collectXRefs;
1556   if (startLine!=-1)
1557     g_yyLineNr    = startLine;
1558   else
1559     g_yyLineNr    = 1;
1560   if (endLine!=-1)
1561     g_inputLines  = endLine+1;
1562   else
1563     g_inputLines  = g_yyLineNr + countLines() - 1;
1564   
1565   
1566   g_exampleBlock  = exBlock; 
1567   g_exampleName   = exName;
1568   g_sourceFileDef = fd;
1569
1570   bool cleanupSourceDef = FALSE;
1571   if (exBlock && fd==0)
1572   {
1573     // create a dummy filedef for the example
1574     g_sourceFileDef = new FileDef("",(exName?exName:"generated"));
1575     cleanupSourceDef = TRUE;
1576   }
1577   if (g_sourceFileDef) 
1578   {
1579     setCurrentDoc("l00001");
1580   }
1581
1582   g_includeCodeFragment = inlineFragment;
1583   // Starts line 1 on the output  
1584   startCodeLine();
1585
1586   pycodeYYrestart( pycodeYYin );
1587
1588   pycodeYYlex();
1589
1590   if (!g_indents.isEmpty()) 
1591   {
1592     // printf("Exited pysourceparser in inconsistent state!\n");
1593   }
1594
1595   if (g_needsTermination)
1596   {
1597     endCodeLine();
1598   }
1599   if (fd)
1600   {
1601     TooltipManager::instance()->writeTooltips(*g_code);
1602   }
1603   if (cleanupSourceDef)
1604   {
1605     // delete the temporary file definition used for this example
1606     delete g_sourceFileDef;
1607     g_sourceFileDef=0;
1608   }
1609   printlex(yy_flex_debug, FALSE, __FILE__, fd ? fd->fileName().data(): NULL);
1610   return;
1611 }
1612
1613
1614 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
1615 extern "C" { // some bogus code to keep the compiler happy
1616   void pycodeYYdummy() { yy_flex_realloc(0,0); } 
1617 }
1618 #elif YY_FLEX_MAJOR_VERSION<=2 && YY_FLEX_MINOR_VERSION<=5 && YY_FLEX_SUBMINOR_VERSION<33
1619 #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)."
1620 #endif
1621