Orb/Doxygen/src/pycode.l
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Orb/Doxygen/src/pycode.l	Thu Jan 21 17:29:01 2010 +0000
@@ -0,0 +1,1456 @@
+/******************************************************************************
+ *
+ * 
+ *
+ * Copyright (C) 1997-2008 by Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby 
+ * granted. No representations are made about the suitability of this software 
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+/*  This code is based on the work done by the MoxyPyDoxy team
+ *  (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada)
+ *  in Spring 2005 as part of CS 179E: Compiler Design Project
+ *  at the University of California, Riverside; the course was
+ *  taught by Peter H. Froehlich <phf@acm.org>.
+ */
+
+
+%{
+
+#include <stdio.h>
+#include <qvaluestack.h>
+
+#include "pycode.h"
+#include "message.h"
+
+#include "scanner.h"
+#include "entry.h"
+#include "doxygen.h"
+#include "outputlist.h"
+#include "util.h"
+#include "membername.h"
+#include "searchindex.h"
+
+#define YY_NEVER_INTERACTIVE 1
+
+static ClassSDict    g_codeClassSDict(17);
+static QCString      g_curClassName;
+static QStrList      g_curClassBases;
+
+
+static CodeOutputInterface * g_code;
+static const char *  g_inputString;     //!< the code fragment as text
+static int	     g_inputPosition;   //!< read offset during parsing 
+static const char *  g_currentFontClass;
+static bool          g_needsTermination;
+static int           g_inputLines;      //!< number of line in the code fragment
+static int	     g_yyLineNr;        //!< current line number
+static FileDef *     g_sourceFileDef;
+static Definition *  g_currentDefinition;
+static MemberDef *   g_currentMemberDef;
+static bool          g_includeCodeFragment;
+static QCString      g_realScope;
+static bool          g_insideBody;
+static int           g_bodyCurlyCount;
+static bool          g_searchingForBody;
+static QCString      g_classScope;
+static int           g_paramParens;
+//static int           g_anchorCount;
+
+static bool          g_exampleBlock;
+static QCString      g_exampleName;
+static QCString      g_exampleFile;
+
+static QCString      g_type;
+static QCString      g_name;
+
+static bool          g_doubleStringIsDoc;
+static bool          g_doubleQuote;
+static bool          g_noSuiteFound;
+static int           g_stringContext;
+
+static QValueStack<uint> g_indents;  //!< Tracks indentation levels for scoping in python
+
+static void endFontClass();
+static void adjustScopesAndSuites(unsigned indentLength);
+
+
+/*! Represents a stack of variable to class mappings as found in the
+ *  code. Each scope is enclosed in pushScope() and popScope() calls.
+ *  Variables are added by calling addVariables() and one can search
+ *  for variable using findVariable().
+ */
+class PyVariableContext 
+{
+  public:
+    static const ClassDef *dummyContext;    
+    class Scope : public SDict<ClassDef> 
+    {
+      public:
+	Scope() : SDict<ClassDef>(17) {}
+    };
+    
+    PyVariableContext() 
+    {
+      m_scopes.setAutoDelete(TRUE);
+    }
+
+    virtual ~PyVariableContext() 
+    {
+    }
+    
+    void pushScope() 
+    {
+      m_scopes.append(new Scope);
+    }
+
+    void popScope() 
+    {
+      if (m_scopes.count()>0) 
+      {
+	m_scopes.remove(m_scopes.count()-1);
+      }
+    }
+
+    void clear() 
+    {
+      m_scopes.clear();
+      m_globalScope.clear();
+    }
+
+    void clearExceptGlobal() 
+    {
+      m_scopes.clear();
+    }
+
+    void addVariable(const QCString &type,const QCString &name);
+    ClassDef *findVariable(const QCString &name);
+    
+  private:
+    Scope        m_globalScope;
+    QList<Scope> m_scopes;
+};
+
+void PyVariableContext::addVariable(const QCString &type,const QCString &name)
+{
+  //printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data());
+  QCString ltype = type.simplifyWhiteSpace();
+  QCString lname = name.simplifyWhiteSpace();
+
+  Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
+  ClassDef *varType;
+  if (
+      (varType=g_codeClassSDict[ltype]) ||  // look for class definitions inside the code block
+      (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
+     ) 
+  {
+    scope->append(lname,varType); // add it to a list
+  }
+  else 
+  {
+    if (m_scopes.count()>0) // for local variables add a dummy entry so the name 
+                            // is hidden to avoid FALSE links to global variables with the same name
+                            // TODO: make this work for namespaces as well!
+    {
+      scope->append(lname,dummyContext);
+    }
+  }
+}
+
+ClassDef *PyVariableContext::findVariable(const QCString &name)
+{
+  if (name.isEmpty()) return 0;
+  ClassDef *result = 0;
+  QListIterator<Scope> sli(m_scopes);
+  Scope *scope;
+  // search from inner to outer scope
+  for (sli.toLast();(scope=sli.current());--sli)
+  {
+    result = scope->find(name);
+    if (result) 
+    {
+      return result;
+    }
+  }
+  // nothing found -> also try the global scope
+  result=m_globalScope.find(name);
+  return result;
+}
+
+static PyVariableContext g_theVarContext;
+const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8;
+
+class PyCallContext
+{
+  public:
+    struct Ctx
+    {
+      Ctx() : name(g_name), type(g_type), cd(0) {}
+      QCString name;
+      QCString type;
+      ClassDef *cd;
+    };
+
+    PyCallContext() 
+    {
+      m_classList.append(new Ctx);
+      m_classList.setAutoDelete(TRUE);
+    }
+
+    virtual ~PyCallContext() {}
+
+    void setClass(ClassDef *cd)
+    {
+      Ctx *ctx = m_classList.getLast();
+      if (ctx) 
+      {
+        ctx->cd=cd;
+      }
+    }
+    void pushScope()
+    {
+      m_classList.append(new Ctx);
+    }
+
+    void popScope()
+    {
+      if (m_classList.count()>1)
+      {
+	Ctx *ctx = m_classList.getLast();
+	if (ctx)
+	{
+	  g_name = ctx->name;
+	  g_type = ctx->type;
+	}
+	m_classList.removeLast();
+      }
+      else
+      {
+      }
+    }
+
+    void clear()
+    {
+      m_classList.clear();
+      m_classList.append(new Ctx);
+    }
+
+    ClassDef *getClass() const
+    {
+      Ctx *ctx = m_classList.getLast();
+
+      if (ctx)
+        return ctx->cd;
+      else
+        return 0;
+    }
+
+  private:
+    QList<Ctx> m_classList;    
+};
+
+static PyCallContext g_theCallContext;
+
+
+/*! counts the number of lines in the input */
+static int countLines()
+{
+  const char *p=g_inputString;
+  char c;
+  int count=1;
+  while ((c=*p)) 
+  { 
+    p++ ; 
+    if (c=='\n') count++;  
+  }
+  if (p>g_inputString && *(p-1)!='\n') 
+  { // last line does not end with a \n, so we add an extra
+    // line and explicitly terminate the line after parsing.
+    count++, 
+    g_needsTermination=TRUE; 
+  } 
+  return count;
+}
+
+static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="")
+{
+  if (Doxygen::searchIndex)
+  {
+    Doxygen::searchIndex->setCurrentDoc(name,base,anchor);
+  }
+}
+
+static void addToSearchIndex(const char *text)
+{
+  if (Doxygen::searchIndex)
+  {
+    Doxygen::searchIndex->addWord(text,FALSE);
+  }
+}
+
+
+static ClassDef *stripClassName(const char *s)
+{
+  int pos=0;
+  QCString type = s;
+  QCString className;
+  QCString templSpec;
+  while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
+  {
+    QCString clName=className+templSpec;
+
+    ClassDef *cd=0;
+    if (!g_classScope.isEmpty())
+    {
+      cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope+"::"+clName);
+    }
+    if (cd==0)
+    {
+      cd=getResolvedClass(g_currentDefinition,g_sourceFileDef,clName);
+    }
+    if (cd)
+    {
+      return cd;
+    }
+  }
+
+  return 0;
+}
+
+
+
+/*! start a new line of code, inserting a line number if g_sourceFileDef
+ * is TRUE. If a definition starts at the current line, then the line
+ * number is linked to the documentation of that definition.
+ */
+static void startCodeLine()
+{
+  //if (g_currentFontClass) { g_code->endFontClass(); }
+  if (g_sourceFileDef)
+  {
+    //QCString lineNumber,lineAnchor;
+    //lineNumber.sprintf("%05d",g_yyLineNr);
+    //lineAnchor.sprintf("l%05d",g_yyLineNr);
+   
+    Definition *d   = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
+    //printf("startCodeLine %d d=%p\n",g_yyLineNr,d);
+    //g_code->startLineNumber();
+    if (!g_includeCodeFragment && d && d->isLinkableInProject())
+    {
+      g_currentDefinition = d;
+      g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr);
+      g_insideBody = FALSE;
+      g_searchingForBody = TRUE;
+      g_realScope = d->name().copy();
+      g_classScope = d->name().copy();
+      //printf("Real scope: `%s'\n",g_realScope.data());
+      g_bodyCurlyCount = 0;
+      QCString lineAnchor;
+      lineAnchor.sprintf("l%05d",g_yyLineNr);
+      if (g_currentMemberDef)
+      {
+        g_code->writeLineNumber(g_currentMemberDef->getReference(),
+	                        g_currentMemberDef->getOutputFileBase(),
+	                        g_currentMemberDef->anchor(),g_yyLineNr);
+        setCurrentDoc(
+                                g_currentMemberDef->qualifiedName(),
+	                        g_sourceFileDef->getSourceFileBase(),
+	                        lineAnchor);
+      }
+      else
+      {
+        g_code->writeLineNumber(d->getReference(),
+	                        d->getOutputFileBase(),
+	                        0,g_yyLineNr);
+        setCurrentDoc(
+                                d->qualifiedName(),
+	                        g_sourceFileDef->getSourceFileBase(),
+	                        lineAnchor);
+      }
+    }
+    else
+    {
+      //g_code->codify(lineNumber);
+      g_code->writeLineNumber(0,0,0,g_yyLineNr);
+    }
+    //g_code->endLineNumber();
+  }
+  g_code->startCodeLine(); 
+  if (g_currentFontClass)
+  {
+    g_code->startFontClass(g_currentFontClass);
+  }
+}
+
+static void codify(const char* text) 
+{ 
+  g_code->codify(text);
+}
+
+static void endCodeLine()
+{
+  endFontClass();
+  g_code->endCodeLine();
+}
+
+static void nextCodeLine()
+{
+  const char *fc = g_currentFontClass;
+  endCodeLine();
+  if (g_yyLineNr<g_inputLines) 
+  {
+    g_currentFontClass = fc;
+    startCodeLine();
+  }
+}
+
+
+/*! writes a link to a fragment \a text that may span multiple lines, inserting
+ * line numbers for each line. If \a text contains newlines, the link will be 
+ * split into multiple links with the same destination, one for each line.
+ */
+static void writeMultiLineCodeLink(CodeOutputInterface &ol,
+                  const char *ref,const char *file,
+                  const char *anchor,const char *text,
+                  const char *tooltip)
+{
+  bool done=FALSE;
+  char *p=(char *)text;
+  while (!done)
+  {
+    char *sp=p;
+    char c;
+    while ((c=*p++) && c!='\n') { }
+    if (c=='\n')
+    {
+      g_yyLineNr++;
+      *(p-1)='\0';
+      //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+      ol.writeCodeLink(ref,file,anchor,sp,tooltip);
+      nextCodeLine();
+    }
+    else
+    {
+      //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
+      ol.writeCodeLink(ref,file,anchor,sp,tooltip);
+      done=TRUE;
+    }
+  }
+}
+
+
+static void codifyLines(char *text)
+{
+  //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text);
+  char *p=text,*sp=p;
+  char c;
+  bool done=FALSE;
+  while (!done)
+  {
+    sp=p;
+    while ((c=*p++) && c!='\n') { }
+    if (c=='\n')
+    {
+      g_yyLineNr++;
+      *(p-1)='\0';
+      g_code->codify(sp);
+      nextCodeLine();
+    }
+    else
+    {
+      g_code->codify(sp);
+      done=TRUE;
+    }
+  }
+}
+
+static void addDocCrossReference(MemberDef *src,MemberDef *dst)
+{
+  if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
+  //printf("addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
+  if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) && 
+      (src->isFunction() || src->isSlot()) 
+     )
+  {
+    dst->addSourceReferencedBy(src);
+  }
+  if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && 
+      (src->isFunction() || src->isSlot())
+     )
+  {
+    src->addSourceReferences(dst);
+  }
+
+}
+
+
+
+static bool getLinkInScope(const QCString &c,  // scope
+                           const QCString &m,  // member
+			   const char *memberText, // exact text
+			   CodeOutputInterface &ol,
+			   const char *text
+			  )
+{
+  MemberDef    *md;
+  ClassDef     *cd;
+  FileDef      *fd;
+  NamespaceDef *nd;
+  GroupDef     *gd;
+  //printf("Trying `%s'::`%s'\n",c.data(),m.data());
+  if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) && 
+      md->isLinkable())
+  {
+    //printf("Found!\n");
+    //Definition *d=0;
+    //if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd;
+
+    Definition *d = md->getOuterScope()==Doxygen::globalScope ?
+	            md->getBodyDef() : md->getOuterScope();
+    if (md->getGroupDef()) d = md->getGroupDef();
+    if (d && d->isLinkable())
+    {
+      g_theCallContext.setClass(stripClassName(md->typeString()));
+      //printf("g_currentDefinition=%p g_currentMemberDef=%p g_insideBody=%d\n",
+      //        g_currentDefinition,g_currentMemberDef,g_insideBody);
+
+      if (g_currentDefinition && g_currentMemberDef &&
+	  md!=g_currentMemberDef && g_insideBody)
+      {
+	addDocCrossReference(g_currentMemberDef,md);
+      }
+      //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());
+     
+      writeMultiLineCodeLink(ol,md->getReference(),
+	                        md->getOutputFileBase(),
+	                        md->anchor(),
+				text ? text : memberText,
+                                md->briefDescriptionAsTooltip());
+      addToSearchIndex(text ? text : memberText);
+      return TRUE;
+    } 
+  }
+  return FALSE;
+}
+
+static bool getLink(const char *className,
+                    const char *memberName,
+		    CodeOutputInterface &ol,
+		    const char *text=0)
+{
+  QCString m=removeRedundantWhiteSpace(memberName);
+  QCString c=className;
+  if (!getLinkInScope(c,m,memberName,ol,text))
+  {
+    if (!g_curClassName.isEmpty())
+    {
+      if (!c.isEmpty()) c.prepend("::");
+      c.prepend(g_curClassName);
+      return getLinkInScope(c,m,memberName,ol,text);
+    }
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/*
+  For a given string in the source code,
+  finds its class or global id and links to it.
+
+  As of June 1, '05, this ONLY finds classes
+*/
+static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
+                                      bool /*typeOnly*/=FALSE)
+{
+  QCString className=clName;
+
+  // Don't do anything for empty text
+  if (className.isEmpty()) return;
+
+  ClassDef *cd=0,*lcd=0;  /** Class def that we may find */
+  MemberDef *md=0;        /** Member def that we may find */
+  bool isLocal=FALSE;
+
+  // printf("generateClassOrGlobalLink(className=%s)\n",className.data());
+
+  if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable
+  {
+    Definition *d = g_currentDefinition;
+
+    cd = getResolvedClass(d,g_sourceFileDef,className,&md);
+
+    //printf("d=%p g_sourceFileDef=%p\n",d,g_currentDefinition);
+    //printf("is found as a type %s\n",cd?cd->name().data():"<null>");
+
+    if (cd==0 && md==0) // also see if it is variable or enum or enum value
+    {
+      if (getLink(g_classScope,clName,ol,clName))
+      {
+	return;
+      }
+    }
+  }
+  else
+  {
+    if (lcd!=PyVariableContext::dummyContext) 
+    {
+      g_theCallContext.setClass(lcd);
+    }
+    isLocal=TRUE;
+    //fprintf(stderr,"is a local variable cd=%p!\n",cd);
+  }
+
+  if (cd && cd->isLinkable()) // is it a linkable class
+  {
+    writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,clName,cd->briefDescriptionAsTooltip());
+    addToSearchIndex(className);
+    if (md)
+    {
+      Definition *d = md->getOuterScope()==Doxygen::globalScope ?
+                      md->getBodyDef() : md->getOuterScope();
+      if (md->getGroupDef()) d = md->getGroupDef();
+      if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef)
+      {
+        addDocCrossReference(g_currentMemberDef,md);
+      }
+    }
+  }
+  else // not a class, maybe a global member
+  {
+
+    /*
+      This code requires a going-over in order to
+      make it work for Python
+
+    //printf("class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly);
+    if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
+    {
+      if (md==0) // not found as a typedef
+      {
+	md = setCallContextForVar(clName);
+	//printf("setCallContextForVar(%s) md=%p g_currentDefinition=%p\n",clName,md,g_currentDefinition);
+	if (md && g_currentDefinition)
+	{
+	  //fprintf(stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
+	  //    md->name().data(),g_currentDefinition->name().data(),
+	  //    isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md),
+	  //    md->getOuterScope()->name().data());
+	}
+	     
+        if (md && g_currentDefinition && 
+	    isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)==-1)
+	{
+	  md=0; // variable not accessible
+	}
+      }
+      if (md)
+      {
+        //printf("is a global md=%p g_currentDefinition=%s\n",md,g_currentDefinition?g_currentDefinition->name().data():"<none>");
+	if (md->isLinkable())
+	{
+	  writeMultiLineCodeLink(ol,md->getReference(),md->getOutputFileBase(),md->anchor(),clName,md->briefDescriptionAsTooltip());
+          addToSearchIndex(clName);
+	  if (g_currentMemberDef)
+	  {
+	    addDocCrossReference(g_currentMemberDef,md);
+	  }
+	  return;
+	}
+      }
+    }
+
+    */
+    
+    // nothing found, just write out the word
+    codifyLines(clName);
+    addToSearchIndex(clName);
+  }
+}
+
+/*
+   As of June 1, this function seems to work
+   for file members, but scopes are not
+   being correctly tracked for classes
+   so it doesn't work for classes yet.
+
+*/
+static void generateFunctionLink(CodeOutputInterface &ol,char *funcName)
+{
+  //CodeClassDef *ccd=0;
+  ClassDef *ccd=0;
+  QCString locScope=g_classScope.copy();
+  QCString locFunc=removeRedundantWhiteSpace(funcName);
+  //fprintf(stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data());
+  int i=locFunc.findRev("::");
+  if (i>0)
+  {
+    locScope=locFunc.left(i);
+    locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace();
+  }
+  //printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data());
+  if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope]))
+  {
+    //printf("using classScope %s\n",g_classScope.data());
+    if (ccd->baseClasses())
+    {
+      BaseClassListIterator bcli(*ccd->baseClasses());
+      for ( ; bcli.current() ; ++bcli)
+      {
+	if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName)) 
+	{
+	  return;
+	}
+      }
+    }
+  }
+  if (!getLink(locScope,locFunc,ol,funcName))
+  {
+    generateClassOrGlobalLink(ol,funcName);
+  }
+  return;
+}
+
+static bool findMemberLink(CodeOutputInterface &ol,Definition *sym,const char *symName)
+{
+  //printf("sym %s outerScope=%s equal=%d\n",
+  //    sym->name().data(),sym->getOuterScope()->name().data(),
+  //    sym->getOuterScope()==g_currentDefinition);
+
+  if (sym->getOuterScope() &&
+      sym->getOuterScope()->definitionType()==Definition::TypeClass &&
+      g_currentDefinition->definitionType()==Definition::TypeClass)
+  {
+    ClassDef *cd = (ClassDef*)sym->getOuterScope();
+    ClassDef *thisCd = (ClassDef *)g_currentDefinition;
+    QCString anchor;
+    if (sym->definitionType()==Definition::TypeMember)
+    {
+      anchor=((MemberDef *)sym)->anchor();
+    }
+
+    // TODO: find the nearest base class in case cd is a base class of
+    // thisCd 
+    if (cd==thisCd) 
+    {
+      writeMultiLineCodeLink(ol,sym->getReference(),
+          sym->getOutputFileBase(),
+          anchor,
+          symName,
+          sym->briefDescriptionAsTooltip());
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static void findMemberLink(CodeOutputInterface &ol,char *symName)
+{
+  //printf("Member reference: %s scope=%s member=%s\n",
+  //    yytext,
+  //    g_currentDefinition?g_currentDefinition->name().data():"<none>",
+  //    g_currentMemberDef?g_currentMemberDef->name().data():"<none>"
+  //    );
+  if (g_currentDefinition)
+  {
+    DefinitionIntf *di = Doxygen::symbolMap->find(symName);
+    if (di)
+    {
+      if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multiple symbols
+      {
+	DefinitionListIterator dli(*(DefinitionList*)di);
+	Definition *sym;
+	for (dli.toFirst();(sym=dli.current());++dli)
+	{
+	  if (findMemberLink(ol,sym,symName)) return;
+	}
+      }
+      else // single symbol
+      {
+	if (findMemberLink(ol,(Definition*)di,symName)) return;
+      }
+    }
+  }
+  //printf("sym %s not found\n",&yytext[5]);
+  codify(symName);
+}
+
+static void startFontClass(const char *s)
+{
+  endFontClass();
+  g_code->startFontClass(s);
+  g_currentFontClass=s;
+}
+
+static void endFontClass()
+{
+  if (g_currentFontClass)
+  {
+    g_code->endFontClass();
+    g_currentFontClass=0;
+  }
+}
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
+
+static int yyread(char *buf,int max_size)
+{
+  int c=0;
+  while( c < max_size && g_inputString[g_inputPosition] )
+  {
+    *buf = g_inputString[g_inputPosition++] ;
+    c++; buf++;
+  }
+  return c;
+}
+
+%}
+
+
+BB                [ \t]+
+B                 [ \t]*
+NEWLINE           \n
+
+DIGIT             [0-9]
+LETTER            [A-Za-z]
+NONEMPTY          [A-Za-z0-9_]
+EXPCHAR           [#(){}\[\],:.%/\\=`*~|&<>!;+-]
+NONEMPTYEXP       [^ \t\n:]
+PARAMNONEMPTY     [^ \t\n():]
+IDENTIFIER        ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*  
+BORDER            ([^A-Za-z0-9])
+
+POUNDCOMMENT      "#".*
+
+TRISINGLEQUOTE    "'''"
+TRIDOUBLEQUOTE    "\"\"\""
+LONGSTRINGCHAR    [^\\"']
+ESCAPESEQ         ("\\")(.)
+LONGSTRINGITEM    ({LONGSTRINGCHAR}|{ESCAPESEQ})
+SMALLQUOTE        ("\"\""|"\""|"'"|"''")
+LONGSTRINGBLOCK   ({LONGSTRINGITEM}+|{SMALLQUOTE})
+
+SHORTSTRING       ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
+SHORTSTRINGITEM   ({SHORTSTRINGCHAR}|{ESCAPESEQ})
+SHORTSTRINGCHAR   [^\\\n"]
+STRINGLITERAL     {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})  
+STRINGPREFIX      ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
+KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
+FLOWKW  ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
+QUOTES            ("\""[^"]*"\"")
+SINGLEQUOTES      ("'"[^']*"'")
+
+LONGINTEGER       {INTEGER}("l"|"L")
+INTEGER           ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER})
+DECIMALINTEGER    ({NONZERODIGIT}{DIGIT}*|"0")
+OCTINTEGER        "0"{OCTDIGIT}+
+HEXINTEGER        "0"("x"|"X"){HEXDIGIT}+  
+NONZERODIGIT      [1-9]  
+OCTDIGIT          [0-7]  
+HEXDIGIT          ({DIGIT}|[a-f]|[A-F])
+FLOATNUMBER       ({POINTFLOAT}|{EXPONENTFLOAT})
+POINTFLOAT        ({INTPART}?{FRACTION}|{INTPART}".")  
+EXPONENTFLOAT     ({INTPART}|{POINTFLOAT}){EXPONENT}
+INTPART             {DIGIT}+  
+FRACTION             "."{DIGIT}+  
+EXPONENT             ("e"|"E")("+"|"-")?{DIGIT}+
+IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J")
+ATOM              ({IDENTIFIER}|{LITERAL}|{ENCLOSURE})
+ENCLOSURE             ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION})
+LITERAL             ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER})
+PARENTH_FORM       "("{EXPRESSION_LIST}?")"
+TEST             ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM})
+TESTLIST             {TEST}( ","{TEST})*","?
+LIST_DISPLAY        "["{LISTMAKER}?"]"  
+LISTMAKER             {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?)  
+LIST_ITER             ({LIST_FOR}|{LIST_IF})  
+LIST_FOR             "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}?
+LIST_IF             "if"{TEST}{LIST_ITER}?
+DICT_DISPLAY             "\{"{KEY_DATUM_LIST}?"\}"
+KEY_DATUM_LIST       {KEY_DATUM}(","{KEY_DATUM})*","? 
+KEY_DATUM              {EXPRESSION}":"{EXPRESSION}
+STRING_CONVERSION        "`"{EXPRESSION_LIST}"`"
+PRIMARY             ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL})
+ATTRIBUTEREF             {PRIMARY}"."{IDENTIFIER}
+SUBSCRIPTION             {PRIMARY}"["{EXPRESSION_LIST}"]"
+SLICING            ({SIMPLE_SLICING}|{EXTENDED_SLICING})
+SIMPLE_SLICING             {PRIMARY}"["{SHORT_SLICE}"]"  
+EXTENDED_SLICING           {PRIMARY}"["{SLICE_LIST}"]" 
+SLICE_LIST          {SLICE_ITEM}(","{SLICE_ITEM})*","?
+SLICE_ITEM           ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS})
+PROPER_SLICE           ({SHORT_SLICE}|{LONG_SLICE})
+SHORT_SLICE              {LOWER_BOUND}?":"{UPPER_BOUND}?  
+LONG_SLICE             {SHORT_SLICE}":"{STRIDE}?
+LOWER_BOUND             {EXPRESSION}  
+UPPER_BOUND             {EXPRESSION}
+STRIDE             {EXPRESSION}
+ELLIPSIS             "..."
+CALL             {PRIMARY}"("({ARGUMENT_LIST}","?)?")"
+ARGUMENT_LIST       ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION})
+POSITIONAL_ARGUMENTS             {EXPRESSION}(","{EXPRESSION})*
+KEYWORD_ARGUMENTS              {KEYWORD_ITEM}(","{KEYWORD_ITEM})*
+KEYWORD_ITEM           {IDENTIFIER}"="{EXPRESSION}
+POWER             {PRIMARY}("**"{U_EXPR})?
+U_EXPR            ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR})
+M_EXPR            ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR})
+A_EXPR         ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR}
+SHIFT_EXPR            ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR})
+AND_EXPR            ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR}
+XOR_EXPR            ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR})
+OR_EXPR            ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR})
+
+COMPARISON             {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})*
+COMP_OPERATOR         ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in")
+EXPRESSION            ({OR_TEST}|{LAMBDA_FORM})
+OR_TEST             ({AND_TEST}|{OR_TEST}"or"{AND_TEST})
+AND_TEST          ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST})
+NOT_TEST           ({COMPARISON}|"not"{NOT_TEST})
+LAMBDA_FORM       "lambda"{PARAMETER_LIST}?":"{EXPRESSION}
+EXPRESSION_LIST      {EXPRESSION}(","{EXPRESSION})*","?
+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})
+EXPRESSION_STMT     {EXPRESSION_LIST}
+ASSERT_STMT             "assert"{EXPRESSION}(","{EXPRESSION})?
+ASSIGNMENT_STMT     ({TARGET_LIST}"=")+{EXPRESSION_LIST}
+TARGET_LIST             {TARGET}(","{TARGET})*","?
+TARGET           ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING})
+
+
+%option noyywrap
+%option nounput
+
+%x Body
+
+%x FunctionDec
+%x FunctionParams
+
+%x ClassDec
+%x ClassInheritance
+
+%x Suite
+%x SuiteCaptureIndent
+%x SuiteStart
+%x SuiteMaintain
+%x SuiteContinuing
+
+%x LongString
+
+%x SingleQuoteString
+%x DoubleQuoteString
+%x TripleString
+
+%%
+
+<Body,Suite>{
+      "def"{BB}                     {
+				        startFontClass("keyword");
+					codify(yytext);
+					endFontClass();
+					BEGIN( FunctionDec );
+		                    }
+
+      "class"{BB}                   {
+				        startFontClass("keyword");
+					codify(yytext);
+					endFontClass();
+					BEGIN( ClassDec );
+		                    }
+      "None"                        {
+				        startFontClass("keywordtype");
+					codify(yytext);
+					endFontClass();
+				    }
+      "self."{IDENTIFIER}           {
+				        codify("self.");
+				        findMemberLink(*g_code,&yytext[5]);
+	                            }
+}
+
+<ClassDec>{IDENTIFIER}              {
+
+					generateClassOrGlobalLink(*g_code,yytext);
+					// codify(yytext);
+					g_curClassName = yytext;
+					g_curClassBases.clear();
+					BEGIN( ClassInheritance );
+		                    }
+
+<ClassInheritance>{
+   ({BB}|[(,)])                     {
+					codify(yytext);
+                                    }
+
+   {IDENTIFIER}                     {
+                                        // The parser
+					// is assuming
+					// that ALL identifiers
+					// in this state
+					// are base classes;
+					// it doesn't check to see
+					// that the first parenthesis
+					// has been seen.
+
+					// This is bad - it should
+					// probably be more strict
+					// about what to accept.
+
+                                        g_curClassBases.inSort(yytext);
+					generateClassOrGlobalLink(*g_code,yytext);
+					// codify(yytext);
+                                    }
+
+    ":"                             {
+				      codify(yytext);
+
+				      // Assume this will
+				      // be a one-line suite;
+				      // found counter-example
+				      // in SuiteStart.
+
+                                      // Push a class scope
+
+                                      ClassDef *classDefToAdd = new ClassDef("<code>",1,g_curClassName,ClassDef::Class,0,0,FALSE);
+                                      g_codeClassSDict.append(g_curClassName,classDefToAdd);
+                                      char *s=g_curClassBases.first();
+                                      while (s) 
+				      {
+                                        ClassDef *baseDefToAdd;
+                                        baseDefToAdd=g_codeClassSDict[s];
+
+					// Try to find class in global
+					// scope
+					if (baseDefToAdd==0) 
+					{
+					  baseDefToAdd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s);
+					}
+
+					if (baseDefToAdd && baseDefToAdd!=classDefToAdd) 
+					{
+				          classDefToAdd->insertBaseClass(baseDefToAdd,s,Public,Normal);
+					}
+
+                                        s=g_curClassBases.next();
+			              }
+
+				      // Reset class-parsing variables.
+				      g_curClassName.resize(0);
+				      g_curClassBases.clear();
+				      
+				      g_noSuiteFound = TRUE;
+				      BEGIN( SuiteStart );
+                                    }
+}
+
+
+<FunctionDec>{
+    {IDENTIFIER}                    {
+                                        generateFunctionLink(*g_code,yytext);
+                                    }
+
+    {B}"("                          {
+				        codify(yytext);
+					BEGIN( FunctionParams );
+		                    }
+}
+
+<FunctionParams>{
+    ({BB}|",")                      {
+                                         // Parses delimiters
+				         codify(yytext);
+                                    }
+
+    ({IDENTIFIER}|{PARAMNONEMPTY}+) {
+				         codify(yytext);
+                                    }
+
+    ")"                             {
+                                         codify(yytext);
+                                    }
+
+    ":"                             {
+				      codify(yytext);
+
+				      // Assume this will
+				      // be a one-line suite;
+				      // found counter-example
+				      // in SuiteStart.
+				      g_noSuiteFound = TRUE;
+				      BEGIN( SuiteStart );
+                                    }
+}
+
+<Body,Suite>{
+
+    {KEYWORD}                  {
+                                 // Position-sensitive rules!
+                                 // Must come AFTER keyword-triggered rules
+                                 // Must come BEFORE identifier NONEMPTY-like rules
+                                 //   to syntax highlight.
+
+  		                 startFontClass("keyword");
+  		                 codify(yytext);
+		                 endFontClass();
+                               }
+
+    {FLOWKW}                   {
+  		                 startFontClass("keywordflow");
+  		                 codify(yytext);
+		                 endFontClass();
+                               }
+
+    {IDENTIFIER}               {
+  		                 codify(yytext);
+			       }
+}
+
+
+
+<SuiteStart>{
+
+    {BB}                               {
+                                         codify(yytext);
+                                       }
+    {KEYWORD}                          {
+                                          startFontClass("keyword");
+					  codifyLines(yytext);
+		                          endFontClass();
+
+					  // No indentation necesary
+					  g_noSuiteFound = FALSE;
+                                       }
+
+    {FLOWKW}                           {
+                                          startFontClass("keywordflow");
+					  codifyLines(yytext);
+		                          endFontClass();
+
+					  // No indentation necesary
+					  g_noSuiteFound = FALSE;
+                                       }
+    {IDENTIFIER}                       {
+                                         codify(yytext);
+				       } 
+
+
+    {POUNDCOMMENT}                     {
+                                          // This eats EVERYTHING
+					  // except the newline
+                                          startFontClass("comment");
+					  codifyLines(yytext);
+		                          endFontClass();
+                                       }
+
+    {NEWLINE}                          {
+					  codifyLines(yytext);
+					  if ( g_noSuiteFound ) 
+					  {
+                                            // printf("New suite to capture! [%d]\n", g_yyLineNr);
+					    BEGIN ( SuiteCaptureIndent );
+					  }
+                                       }
+}
+
+<SuiteCaptureIndent>{
+    "\n"|({BB}"\n")            {
+                                 // Blankline - ignore, keep looking for indentation.
+				 codifyLines(yytext);
+                               }
+
+    {BB}                       {
+                                 // This state lasts momentarily,
+                                 // to check the indentation
+                                 // level that is about to be
+                                 // used.
+				 codifyLines(yytext);
+				 g_indents.push(yyleng);
+                                 // printf("Captured indent of %d [line %d]\n", yyleng, g_yyLineNr);
+				 BEGIN( Suite );
+                               }
+}
+
+<SuiteMaintain>{
+
+    {BB}/({NONEMPTY}|{EXPCHAR}) {
+                                 // This implements poor
+				 // indendation-tracking;
+                                 // should be improved.
+				 // (translate tabs to space, etc)
+  		                 codifyLines(yytext);
+                                 adjustScopesAndSuites(yyleng);
+                               }
+
+    "\n"|({BB}"\n")            {
+                                 // If this ever succeeds,
+				 // it means that this is
+				 // a blank line, and
+				 // can be ignored.
+  		                 codifyLines(yytext);
+                               }
+
+    ""/({NONEMPTY}|{EXPCHAR})  {
+                                 // Default rule; matches
+				 // the empty string, assuming
+				 // real text starts here.
+				 // Just go straight to Body.
+                                 adjustScopesAndSuites(0);
+                               }
+}
+
+
+<Suite>{NEWLINE}               {
+                                 codifyLines(yytext);
+			         BEGIN( SuiteMaintain );
+		               }
+<Body>{IDENTIFIER}	       {
+  			         codify(yytext);
+                               }
+<Body>{NEWLINE}                {
+  		                 codifyLines(yytext);
+                               }
+
+<SingleQuoteString>{ // Single quoted string like 'That\'s a """nice""" string!'
+    \\{B}\n                    { // line continuation
+  		                 codifyLines(yytext);
+                               }
+    \\.			       { // espaced char
+  		                 codify(yytext);
+                               }
+    {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // tripple double quotes
+  		                 codify(yytext);
+      			       }
+    "'"			       { // end of the string
+  		                 codify(yytext);
+				 endFontClass();
+      		                 BEGIN(g_stringContext);
+                               }
+    [^"'\n\\]+	               { // normal chars
+  		                 codify(yytext);
+                               }
+    .			       { // normal char
+  		                 codify(yytext);
+                               }
+}
+
+<DoubleQuoteString>{ // Double quoted string like "That's \"a '''nice'''\" string!"
+    \\{B}\n                    { // line continuation
+  		                 codifyLines(yytext);
+                               }
+    \\.			       { // espaced char
+  		                 codify(yytext);
+                               }
+    {STRINGPREFIX}?{TRISINGLEQUOTE} { // tripple single quotes
+  		                 codify(yytext);
+      			       }
+    "\""		       { // end of the string
+  		                 codify(yytext);
+				 endFontClass();
+      		                 BEGIN(g_stringContext);
+                               }
+    [^"'\n\\]+	               { // normal chars
+  		                 codify(yytext);
+                               }
+    .			       { // normal char
+  		                 codify(yytext);
+                               }
+}
+
+<TripleString>{
+    {TRIDOUBLEQUOTE}   | 
+    {TRISINGLEQUOTE}   {
+  		          codify(yytext);
+			  if (g_doubleQuote==(yytext[0]=='"')) 
+			  {
+			    endFontClass();
+			    BEGIN(g_stringContext);
+			  }
+		       }
+    {LONGSTRINGBLOCK}  {
+			 codifyLines(yytext);
+		       }
+    \n		       {
+			 codifyLines(yytext);
+                       }
+    .		       {
+                         codify(yytext);
+                       }
+}
+
+  /*
+<*>({NONEMPTY}|{EXPCHAR}|{BB})           { // This should go one character at a time.
+  		                 codify(yytext);
+				 // printf("[pycode] '%s' [ state %d ]  [line %d] no match\n",
+				 //       yytext, YY_START, g_yyLineNr);
+
+				 //endFontClass();
+				 BEGIN(Body);					
+                               }
+   */
+
+<*>{STRINGPREFIX}?{TRISINGLEQUOTE} |
+<*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} {
+  				 startFontClass("stringliteral");
+				 g_stringContext=YY_START;
+				 g_doubleQuote=yytext[yyleng-1]=='"';
+  		                 codify(yytext);
+				 BEGIN(TripleString);
+                               }
+<*>{STRINGPREFIX}?"'"	       { // single quoted string
+  				 startFontClass("stringliteral");
+				 g_stringContext=YY_START;
+  		                 codify(yytext);
+				 BEGIN(SingleQuoteString);
+  			       }
+<*>{STRINGPREFIX}?"\""         { // double quoted string
+  				 startFontClass("stringliteral");
+				 g_stringContext=YY_START;
+  		                 codify(yytext);
+				 BEGIN(DoubleQuoteString);
+                               }
+<*>{POUNDCOMMENT}              {
+  				 if (YY_START==SingleQuoteString || 
+				     YY_START==DoubleQuoteString || 
+				     YY_START==TripleString
+				    )
+				 {
+				   REJECT;
+				 }
+                                 // This eats EVERYTHING
+				 // except the newline
+                                 startFontClass("comment");
+				 codifyLines(yytext);
+		                 endFontClass();
+                               }
+<*>{NEWLINE}                   {
+  		                 codifyLines(yytext);
+				 //printf("[pycode] %d NEWLINE [line %d] no match\n",
+				 //       YY_START, g_yyLineNr);
+
+				 //endFontClass();
+				 BEGIN(Body);
+                               }
+
+<*>.                           {
+  		                 codify(yytext);
+				 // printf("[pycode] '%s' [ state %d ]  [line %d] no match\n",
+				 //        yytext, YY_START, g_yyLineNr);
+
+				 //endFontClass();
+				 BEGIN(Body);					
+                               }
+
+%%
+
+/*@ ----------------------------------------------------------------------------
+ */
+
+void resetPythonCodeParserState() 
+{
+  g_currentDefinition = 0;
+  g_currentMemberDef = 0;
+  g_doubleStringIsDoc = FALSE;
+  g_paramParens = 0;
+  g_indents.clear();
+  BEGIN( Body );
+}
+
+/*!
+  Examines current stack of white-space indentations;
+  re-syncs the parser with the correct scope.
+*/
+static void adjustScopesAndSuites(unsigned indentLength) 
+{
+  // States to pop
+  if (!g_indents.isEmpty() && indentLength < g_indents.top()) 
+  {
+    while (!g_indents.isEmpty() && indentLength < g_indents.top()) 
+    {
+      // printf("Exited scope indent of [%d]\n", g_indents.top());
+      g_indents.pop(); // Pop the old suite's indentation
+
+      g_currentMemberDef=0;
+      if (g_currentDefinition) 
+	g_currentDefinition=g_currentDefinition->getOuterScope();
+    }
+  }
+
+  // Are there any remaining indentation levels for suites?
+  if (!g_indents.isEmpty()) 
+  {
+    BEGIN( Suite );
+  }
+  else 
+  {
+    BEGIN( Body );
+  }
+}
+
+void parsePythonCode(CodeOutputInterface &od,const char *className,
+                 const QCString &s,bool exBlock, const char *exName,
+		 FileDef *fd,int startLine,int endLine,bool inlineFragment,
+		 MemberDef *) 
+{
+
+  //printf("***parseCode()\n");
+  
+  //--- some code to eliminate warnings---
+  className = "";
+  exBlock = FALSE;
+  exName = "";
+  inlineFragment = "";
+  //--------------------------------------
+  if (s.isEmpty()) return;
+  g_code = &od;
+  g_inputString   = s;
+  g_inputPosition = 0;
+  g_currentFontClass = 0;
+  g_needsTermination = FALSE;
+  if (endLine!=-1)
+    g_inputLines  = endLine+1;
+  else
+    g_inputLines  = countLines();
+  
+  if (startLine!=-1)
+    g_yyLineNr    = startLine;
+  else
+    g_yyLineNr    = 1;
+  
+  g_exampleBlock  = exBlock; 
+  g_exampleName   = exName;
+  g_sourceFileDef = fd;
+
+
+  // Starts line 1 on the output  
+  startCodeLine();
+
+  pycodeYYrestart( pycodeYYin );
+
+  pycodeYYlex();
+
+  if (!g_indents.isEmpty()) 
+  {
+    // printf("Exited pysourceparser in inconsistent state!\n");
+  }
+
+  if (g_needsTermination)
+  {
+    endCodeLine();
+  }
+  return;
+}
+
+
+#if !defined(YY_FLEX_SUBMINOR_VERSION) 
+extern "C" { // some bogus code to keep the compiler happy
+  void pycodeYYdummy() { yy_flex_realloc(0,0); } 
+}
+#elif YY_FLEX_SUBMINOR_VERSION<33
+#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)."
+#endif
+