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