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