Orb/Doxygen/src/pre.l
changeset 3 d8fccb2cd802
child 4 468f4c8d3d5b
equal deleted inserted replaced
2:932c358ece3e 3:d8fccb2cd802
       
     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 
       
    18 %{
       
    19 
       
    20 /*
       
    21  *	includes
       
    22  */
       
    23 
       
    24 #include <stdio.h>
       
    25 #include <assert.h>
       
    26 #include <ctype.h>
       
    27 #include <errno.h>
       
    28 
       
    29 #include "qtbc.h"
       
    30 #include <qarray.h>
       
    31 #include <qstack.h>
       
    32 #include <qfile.h>
       
    33 #include <qstrlist.h>
       
    34 #include <qdict.h>
       
    35 #include <qregexp.h>
       
    36 #include <qfileinfo.h>
       
    37 #include <qdir.h>
       
    38 #include <qmap.h>
       
    39   
       
    40 #include "pre.h"
       
    41 #include "constexp.h"
       
    42 #include "define.h"
       
    43 #include "doxygen.h"
       
    44 #include "message.h"
       
    45 #include "util.h"
       
    46 #include "defargs.h"
       
    47 #include "debug.h"
       
    48 #include "bufstr.h"
       
    49 #include "portable.h"
       
    50 #include "bufstr.h"
       
    51 
       
    52 #define YY_NEVER_INTERACTIVE 1
       
    53 
       
    54 struct FileState
       
    55 {
       
    56   FileState(int size) : fileBuf(size), oldFileBuf(0), oldFileBufPos(0) {}
       
    57   int lineNr;
       
    58   //FILE *filePtr;
       
    59   BufStr fileBuf;
       
    60   //FILE *oldYYin;
       
    61   BufStr *oldFileBuf;
       
    62   int oldFileBufPos;
       
    63   //bool isPlainFile;
       
    64   YY_BUFFER_STATE bufState;
       
    65   QCString fileName;
       
    66 };  
       
    67 
       
    68 /* -----------------------------------------------------------------
       
    69  *
       
    70  *	scanner's state
       
    71  */
       
    72 
       
    73 static int                g_yyLineNr   = 1;
       
    74 static QCString           g_yyFileName;
       
    75 static FileDef           *g_yyFileDef;
       
    76 static FileDef           *g_inputFileDef;
       
    77 static int                g_ifcount    = 0;
       
    78 static QStrList          *g_pathList = 0;  
       
    79 static QStack<FileState>  g_includeStack;
       
    80 static QDict<int>        *g_argDict;
       
    81 static int                g_defArgs = -1;
       
    82 static QCString           g_defName;
       
    83 static QCString           g_defText;
       
    84 static QCString           g_defLitText;
       
    85 static QCString           g_defArgsStr;
       
    86 static bool               g_defVarArgs;
       
    87 static int                g_level;
       
    88 static int                g_lastCContext;
       
    89 static int                g_lastCPPContext;
       
    90 static QArray<int>        g_levelGuard;
       
    91 static BufStr            *g_inputBuf;
       
    92 static int                g_inputBufPos;
       
    93 static BufStr            *g_outputBuf;
       
    94 static int                g_roundCount;
       
    95 static bool               g_quoteArg;
       
    96 static DefineDict        *g_fileDefineDict = new DefineDict(10009);
       
    97 static DefineDict        *g_expandedDict;
       
    98 static int                g_findDefArgContext;
       
    99 static QCString           g_lastGuardName;
       
   100 static QCString           g_incName;
       
   101 static QCString           g_guardExpr;
       
   102 static int                g_curlyCount;
       
   103 static bool               g_nospaces; // add extra spaces during macro expansion
       
   104 
       
   105 static bool               g_macroExpansion; // from the configuration
       
   106 static bool               g_expandOnlyPredef; // from the configuration
       
   107 static int                g_commentCount;
       
   108 static bool               g_insideComment;
       
   109 static bool               g_isImported;
       
   110 static QCString           g_blockName;
       
   111 static int                g_condCtx;
       
   112 static bool               g_skip;
       
   113 static QStack<bool>       g_condStack;
       
   114 static bool               g_insideCS; // C# has simpler preprocessor
       
   115 
       
   116 static bool               g_lexInit = FALSE;
       
   117 
       
   118 DefineDict* getFileDefineDict() 
       
   119 {
       
   120   return g_fileDefineDict;
       
   121 }
       
   122 
       
   123 static void setFileName(const char *name)
       
   124 {
       
   125   bool ambig;
       
   126   QFileInfo fi(name);
       
   127   g_yyFileName=convertToQCString(fi.absFilePath());
       
   128   g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
       
   129   if (g_yyFileDef == 0 && Config_getBool("PREPROCESS_INCLUDES")) {
       
   130 		// Search again using Doxygen::includeNameDict
       
   131 	    // First insert the include file in the Doxygen::includeNameDict if
       
   132 	    // it is not there already. This can happen if the Doxygen::includeNameDict
       
   133 	    // has scanned .../inc but the #include "usr/usr.h"
       
   134 	    // The Doxygen::includeNameDict will not have usr.h in it so we poke it in.
       
   135 		if (!Doxygen::includeNameDict->find(g_yyFileName.data())) {
       
   136 			//Debug::print(Debug::IncludeGraph, 0, "pre.l setFileName() inserting in Doxygen::includeNameDict: %s\n", name);
       
   137 			FileDef  *fd=new FileDef(fi.dirPath()+"/", fi.fileName());
       
   138             FileName *fn=0;
       
   139             if (!fi.absFilePath().isEmpty() && (fn=(*Doxygen::includeNameDict)[name])) {
       
   140 				fn->append(fd);
       
   141             } else {
       
   142 				fn = new FileName(fi.absFilePath(), name);
       
   143 				fn->append(fd);
       
   144 				Doxygen::includeNameDict->insert(name, fn);
       
   145             }
       
   146 			g_yyFileDef = fd;
       
   147 		} else {
       
   148 			// Search the dictionary
       
   149 			FileName *fn = Doxygen::includeNameDict->find(g_yyFileName.data());
       
   150 			FileNameIterator fni(*fn);
       
   151 			FileDef *fd = 0;
       
   152 			for (fni.toFirst(); (fd=fni.current()); ++fni) {
       
   153 				if (fd && fd->absFilePath() == g_yyFileName) {
       
   154 					break;
       
   155 				}
       
   156 				fd = 0;
       
   157 			}
       
   158 			g_yyFileDef = fd;
       
   159 		}
       
   160 		//printf("pre.l setFileName() searching Doxygen::includeNameDict for %s, result=%p\n", name, g_yyFileDef);
       
   161 		//Debug::print(Debug::IncludeGraph, 0, "pre.l setFileName() searching Doxygen::includeNameDict for %s, result=%p\n", name, g_yyFileDef);
       
   162   }
       
   163   if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
       
   164   g_insideCS = g_yyFileName.right(3)==".cs";
       
   165 }
       
   166 
       
   167 static void incrLevel()
       
   168 {
       
   169   g_level++;
       
   170   g_levelGuard.resize(g_level);
       
   171   g_levelGuard[g_level-1]=FALSE;
       
   172   //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
       
   173 }
       
   174 
       
   175 static void decrLevel()
       
   176 {
       
   177   //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
       
   178   if (g_level > 0)
       
   179   {
       
   180     g_level--;
       
   181     g_levelGuard.resize(g_level);
       
   182   }
       
   183   else
       
   184   {
       
   185     err("%s:%d: Error: More #endif's than #if's found.\n",
       
   186 	g_yyFileName.data(),g_yyLineNr);
       
   187   }
       
   188 }
       
   189 
       
   190 static bool otherCaseDone()
       
   191 {
       
   192   if (g_level==0)
       
   193   {
       
   194     err("%s:%d: Error: Found an #else without a preceding #if.\n",
       
   195 	g_yyFileName.data(),g_yyLineNr);
       
   196     return TRUE;
       
   197   }
       
   198   else
       
   199   {
       
   200     return g_levelGuard[g_level-1];
       
   201   }
       
   202 }
       
   203 
       
   204 static void setCaseDone(bool value)
       
   205 {
       
   206   g_levelGuard[g_level-1]=value;
       
   207 }
       
   208 
       
   209 static Define *isDefined(const char *name)
       
   210 {
       
   211   if (name)
       
   212   {
       
   213     Define *def;
       
   214     //if ((def=fileDefineCache->findDefine(g_yyFileName,name)) && !def->undef) 
       
   215     //	return def;
       
   216     if ((def=g_fileDefineDict->find(name)) && !def->undef) return def; 
       
   217   }
       
   218   return 0;
       
   219 }
       
   220 
       
   221 static QDict<void> g_allIncludes(10009);
       
   222 
       
   223 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded)
       
   224 {
       
   225   alreadyIncluded = FALSE;
       
   226   FileState *fs = 0;
       
   227   //msg("checkAndOpenFile(%s)\n", fileName.data());
       
   228   QFileInfo fi(fileName);
       
   229   if (fi.exists() && fi.isFile())
       
   230   {
       
   231     QCString absName = convertToQCString(fi.absFilePath());
       
   232 	//msg("checkAndOpenFile() found: %s\n", absName.data());
       
   233     // global guard
       
   234     if (g_curlyCount==0) // not #include inside { ... }
       
   235     {
       
   236       if (g_allIncludes.find(absName)!=0)
       
   237       {
       
   238         alreadyIncluded = TRUE;
       
   239         //printf("  already included 1\n");
       
   240         if (!Config_getBool("PREPROCCESS_FULL_TU")) {
       
   241 			return 0; // already done
       
   242 		}
       
   243       } else {
       
   244 		g_allIncludes.insert(absName,(void *)0x8);
       
   245 	  }
       
   246     }
       
   247     // check include stack for absName
       
   248 	// This is equivelent to walking the stack and setting alreadyIncluded to
       
   249 	// TRUE if absName matches any filename
       
   250     QStack<FileState> tmpStack;
       
   251     g_includeStack.setAutoDelete(FALSE);
       
   252     while ((fs=g_includeStack.pop()))
       
   253     {
       
   254       if (fs->fileName==absName) alreadyIncluded=TRUE;
       
   255       tmpStack.push(fs);
       
   256     }
       
   257     while ((fs=tmpStack.pop()))
       
   258     {
       
   259       g_includeStack.push(fs);
       
   260     }
       
   261     g_includeStack.setAutoDelete(TRUE);
       
   262 
       
   263     if (alreadyIncluded)
       
   264     {
       
   265       //printf("  already included 2\n");
       
   266       return 0;
       
   267     }
       
   268     //printf("#include %s\n",absName.data());
       
   269 
       
   270     fs = new FileState(fi.size()+4096);
       
   271     alreadyIncluded = FALSE;
       
   272     if (!readInputFile(absName,fs->fileBuf))
       
   273     { // error
       
   274       //printf("  error reading\n");
       
   275       delete fs;
       
   276       fs=0;
       
   277     }
       
   278     else
       
   279     {
       
   280       fs->oldFileBuf    = g_inputBuf;
       
   281       fs->oldFileBufPos = g_inputBufPos;
       
   282     }
       
   283 
       
   284 #if 0
       
   285     QCString filterName = getFileFilter(absName);
       
   286     if (!filterName.isEmpty())
       
   287     {
       
   288       fs->isPlainFile = FALSE;
       
   289       QCString cmd = filterName+" \""+absName+"\"";
       
   290       fs->filePtr=portable_popen(cmd,"r");
       
   291       if (!fs->filePtr)
       
   292       {
       
   293         err("Error: could not execute filter %s, reason: %s\n",cmd.data(),
       
   294             strerror(errno));
       
   295       }
       
   296     }
       
   297     else
       
   298     {
       
   299       fs->isPlainFile = TRUE;
       
   300       fs->filePtr=fopen(absName,"r");
       
   301       if (!fs->filePtr)
       
   302       {
       
   303         err("Error: could not open file %s for reading, reason: %s \n",
       
   304             absName.data(),strerror(errno));
       
   305       }
       
   306     }
       
   307     if (!fs->filePtr) // error -> cleanup
       
   308     {
       
   309       delete fs;
       
   310       fs=0;
       
   311     }
       
   312     else
       
   313     {
       
   314       fs->oldYYin = preYYin;
       
   315     }
       
   316 #endif
       
   317 
       
   318   }
       
   319   return fs;
       
   320 }
       
   321 
       
   322 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded)
       
   323 {
       
   324   //msg("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data());
       
   325   if (localInclude && !g_yyFileName.isEmpty())
       
   326   {
       
   327     QFileInfo fi(g_yyFileName);
       
   328     if (fi.exists())
       
   329     {
       
   330       QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName;
       
   331       FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
       
   332       if (fs)
       
   333       {
       
   334 	setFileName(absName);
       
   335 	g_yyLineNr=1;
       
   336 	return fs;
       
   337       }
       
   338       else if (alreadyIncluded)
       
   339       {
       
   340 	return 0;
       
   341       }
       
   342     }
       
   343   }
       
   344   if (g_pathList==0) 
       
   345   {
       
   346     return 0;
       
   347   }
       
   348   char *s=g_pathList->first();
       
   349   while (s)
       
   350   {
       
   351     QCString absName = (QCString)s+"/"+fileName;
       
   352     FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
       
   353     if (fs)
       
   354     {
       
   355       setFileName(absName);
       
   356       g_yyLineNr=1;
       
   357       return fs;
       
   358     }
       
   359     else if (alreadyIncluded)
       
   360     {
       
   361       return 0;
       
   362     }
       
   363 
       
   364     s=g_pathList->next();
       
   365   } 
       
   366   return 0;
       
   367 }
       
   368 
       
   369 static QCString extractTrailingComment(const char *s)
       
   370 {
       
   371   if (s==0) return "";
       
   372   int i=strlen(s)-1;
       
   373   while (i>=0)
       
   374   {
       
   375     char c=s[i];
       
   376     switch (c)
       
   377     {
       
   378       case '/':
       
   379 	{
       
   380 	  i--;
       
   381 	  if (i>=0 && s[i]=='*') // end of a comment block
       
   382 	  {
       
   383 	    i--;
       
   384 	    while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
       
   385 	    if (i==0) return s; else return &s[i-1];
       
   386 	  }
       
   387 	  else
       
   388 	  {
       
   389 	    return "";
       
   390 	  }
       
   391 	} 
       
   392 	break;
       
   393 	// whitespace or line-continuation
       
   394       case ' ':
       
   395       case '\t': 
       
   396       case '\r':
       
   397       case '\n':
       
   398       case '\\':
       
   399 	break;
       
   400       default:
       
   401 	return "";
       
   402     }
       
   403     i--;
       
   404   }
       
   405   return "";
       
   406 }
       
   407 
       
   408 static int getNextChar(const QCString &expr,QCString *rest,uint &pos);
       
   409 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos);
       
   410 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c);
       
   411 static void expandExpression(QCString &expr,QCString *rest,int pos);
       
   412 
       
   413 static QCString stringize(const QCString &s)
       
   414 {
       
   415   QCString result;
       
   416   uint i=0;
       
   417   bool inString=FALSE;
       
   418   bool inChar=FALSE;
       
   419   char c,pc;
       
   420   while (i<s.length())
       
   421   {
       
   422     if (!inString && !inChar)
       
   423     {
       
   424       while (i<s.length() && !inString && !inChar)
       
   425       {
       
   426 	c=s.at(i++);
       
   427 	if (c=='"')
       
   428 	{
       
   429 	  result+="\\\"";
       
   430 	  inString=TRUE;
       
   431 	}
       
   432 	else if (c=='\'')
       
   433 	{
       
   434 	  result+=c;
       
   435 	  inChar=TRUE;
       
   436 	}
       
   437 	else
       
   438 	{
       
   439 	  result+=c;
       
   440 	}
       
   441       }
       
   442     }
       
   443     else if (inChar)
       
   444     {
       
   445       while (i<s.length() && inChar)
       
   446       {
       
   447 	c=s.at(i++);
       
   448 	if (c=='\'')
       
   449 	{
       
   450 	  result+='\'';
       
   451 	  inChar=FALSE;
       
   452 	}
       
   453 	else if (c=='\\')
       
   454 	{
       
   455 	  result+="\\\\";
       
   456 	}
       
   457 	else
       
   458 	{
       
   459 	  result+=c;
       
   460 	}
       
   461       }
       
   462     }
       
   463     else
       
   464     {
       
   465       pc=0;
       
   466       while (i<s.length() && inString)
       
   467       {
       
   468 	char c=s.at(i++);
       
   469 	if (c=='"') 
       
   470 	{
       
   471 	  result+="\\\"";
       
   472 	  inString= pc=='\\';
       
   473 	}
       
   474 	else if (c=='\\')
       
   475 	  result+="\\\\";
       
   476 	else
       
   477 	  result+=c;
       
   478 	pc=c;
       
   479       }
       
   480     }
       
   481   }
       
   482   //printf("stringize `%s'->`%s'\n",s.data(),result.data());
       
   483   return result;
       
   484 }
       
   485 
       
   486 /*! Execute all ## operators in expr. 
       
   487  * If the macro name before or after the operator contains a no-rescan 
       
   488  * marker (@-) then this is removed (before the concatenated macro name
       
   489  * may be expanded again.
       
   490  */
       
   491 static void processConcatOperators(QCString &expr)
       
   492 {
       
   493   //printf("processConcatOperators: in=`%s'\n",expr.data());
       
   494   QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); 
       
   495   int l,n,i=0;
       
   496   if (expr.isEmpty()) return;
       
   497   while ((n=r.match(expr,i,&l))!=-1)
       
   498   {
       
   499     //printf("Match: `%s'\n",expr.data()+i);
       
   500     if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
       
   501     {
       
   502       // remove no-rescan marker after ID
       
   503       l+=2;
       
   504     }
       
   505     //printf("found `%s'\n",expr.mid(n,l).data());
       
   506     // remove the ## operator and the surrounding whitespace
       
   507     expr=expr.left(n)+expr.right(expr.length()-n-l);
       
   508     int k=n-1;
       
   509     while (k>=0 && isId(expr.at(k))) k--; 
       
   510     if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
       
   511     {
       
   512       // remove no-rescan marker before ID
       
   513       expr=expr.left(k-1)+expr.right(expr.length()-k-1);
       
   514       n-=2;
       
   515     }
       
   516     i=n;
       
   517   }
       
   518   //printf("processConcatOperators: out=`%s'\n",expr.data());
       
   519 }
       
   520 
       
   521 static void yyunput (int c,char *buf_ptr  );
       
   522 static void returnCharToStream(char c)
       
   523 {
       
   524   unput(c);
       
   525 }
       
   526 
       
   527 static inline void addTillEndOfString(const QCString &expr,QCString *rest,
       
   528                                        uint &pos,char term,QCString &arg)
       
   529 {
       
   530   int cc;
       
   531   while ((cc=getNextChar(expr,rest,pos))!=EOF)
       
   532   {
       
   533     if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos);
       
   534     else if (cc==term) return;
       
   535     arg+=(char)cc;
       
   536   }
       
   537 }
       
   538 
       
   539 /*! replaces the function macro \a def whose argument list starts at
       
   540  * \a pos in expression \a expr. 
       
   541  * Notice that this routine may scan beyond the \a expr string if needed.
       
   542  * In that case the characters will be read from the input file.
       
   543  * The replacement string will be returned in \a result and the 
       
   544  * length of the (unexpanded) argument list is stored in \a len.
       
   545  */ 
       
   546 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result)
       
   547 {
       
   548   //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),g_level);
       
   549   uint j=pos;
       
   550   len=0;
       
   551   result.resize(0);
       
   552   int cc;
       
   553   while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc)) 
       
   554   { 
       
   555     len++; 
       
   556     getNextChar(expr,rest,j); 
       
   557   }
       
   558   if (cc!='(') 
       
   559   { 
       
   560     unputChar(expr,rest,j,' '); 
       
   561     return FALSE; 
       
   562   }
       
   563   getNextChar(expr,rest,j); // eat the `(' character
       
   564 
       
   565   QDict<QCString> argTable;  // list of arguments
       
   566   argTable.setAutoDelete(TRUE);
       
   567   QCString arg;
       
   568   int argCount=0;
       
   569   bool done=FALSE;
       
   570   
       
   571   // PHASE 1: read the macro arguments
       
   572   if (def->nargs==0)
       
   573   {
       
   574     while ((cc=getNextChar(expr,rest,j))!=EOF)
       
   575     {
       
   576       char c = (char)cc;
       
   577       if (c==')') break;
       
   578     }
       
   579   }
       
   580   else
       
   581   {
       
   582     while (!done && (argCount<def->nargs || def->varArgs) && 
       
   583 	((cc=getNextChar(expr,rest,j))!=EOF)
       
   584 	  )
       
   585     {
       
   586       char c=(char)cc;
       
   587       if (c=='(') // argument is a function => search for matching )
       
   588       {
       
   589 	int level=1;
       
   590 	arg+=c;
       
   591 	//char term='\0';
       
   592 	while ((cc=getNextChar(expr,rest,j))!=EOF)
       
   593 	{
       
   594 	  char c=(char)cc;
       
   595 	  //printf("processing %c: term=%c (%d)\n",c,term,term);
       
   596 	  if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
       
   597 	  {
       
   598 	    arg+=c;
       
   599 	    addTillEndOfString(expr,rest,j,c,arg);
       
   600 	  }
       
   601 	  if (c==')')
       
   602 	  {
       
   603 	    level--;
       
   604 	    arg+=c;
       
   605 	    if (level==0) break;
       
   606 	  }
       
   607 	  else if (c=='(')
       
   608 	  {
       
   609 	    level++;
       
   610 	    arg+=c;
       
   611 	  }
       
   612 	  else
       
   613 	    arg+=c;
       
   614 	}
       
   615       }
       
   616       else if (c==')' || c==',') // last or next argument found
       
   617       {
       
   618 	if (c==',' && argCount==def->nargs-1 && def->varArgs)
       
   619 	{
       
   620 	  arg=arg.stripWhiteSpace();
       
   621 	  arg+=',';
       
   622 	}
       
   623 	else
       
   624 	{
       
   625 	  QCString argKey;
       
   626 	  argKey.sprintf("@%d",argCount++); // key name
       
   627 	  arg=arg.stripWhiteSpace();
       
   628 	  // add argument to the lookup table
       
   629 	  argTable.insert(argKey, new QCString(arg));
       
   630 	  arg.resize(0);
       
   631 	  if (c==')') // end of the argument list
       
   632 	  {
       
   633 	    done=TRUE;
       
   634 	  }
       
   635 	}
       
   636       } 
       
   637       else if (c=='\"') // append literal strings
       
   638       {
       
   639 	arg+=c; 
       
   640 	bool found=FALSE;
       
   641 	while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
       
   642 	{
       
   643 	  found = cc=='"';
       
   644 	  if (cc=='\\')
       
   645 	  {
       
   646 	    c=(char)cc;	  
       
   647 	    arg+=c;
       
   648 	    if ((cc=getNextChar(expr,rest,j))==EOF) break;
       
   649 	  }
       
   650 	  c=(char)cc;	  
       
   651 	  arg+=c;
       
   652 	}
       
   653       }
       
   654       else if (c=='\'') // append literal characters
       
   655       {
       
   656 	arg+=c;
       
   657 	bool found=FALSE;
       
   658 	while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
       
   659 	{
       
   660 	  found = cc=='\'';
       
   661 	  if (cc=='\\')
       
   662 	  {
       
   663 	    c=(char)cc;	  
       
   664 	    arg+=c;
       
   665 	    if ((cc=getNextChar(expr,rest,j))==EOF) break;
       
   666 	  }
       
   667 	  c=(char)cc;
       
   668 	  arg+=c;
       
   669 	}
       
   670       }	    
       
   671       else // append other characters
       
   672       {
       
   673 	arg+=c;
       
   674       }
       
   675     }
       
   676   }
       
   677 
       
   678   // PHASE 2: apply the macro function
       
   679   if (argCount==def->nargs || 
       
   680       (argCount>def->nargs && def->varArgs)) // matching parameters lists
       
   681   {
       
   682     uint k=0;
       
   683     // substitution of all formal arguments
       
   684     QCString resExpr;
       
   685     const QCString d=def->definition.stripWhiteSpace();
       
   686     //printf("Macro definition: %s\n",d.data());
       
   687     bool inString=FALSE;
       
   688     while (k<d.length())
       
   689     {
       
   690       if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
       
   691       {
       
   692 	if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
       
   693 	{
       
   694 	  k+=2;
       
   695 	  resExpr+="@@"; // we unescape these later
       
   696 	}
       
   697 	else if (d.at(k+1)=='-') // no-rescan marker
       
   698 	{
       
   699 	  k+=2;
       
   700 	  resExpr+="@-";
       
   701 	}
       
   702 	else // argument marker => read the argument number
       
   703 	{
       
   704 	  QCString key="@";
       
   705 	  QCString *subst=0;
       
   706 	  bool hash=FALSE;
       
   707 	  int l=k-1;
       
   708 	  // search for ## backward
       
   709 	  if (l>=0 && d.at(l)=='"') l--;
       
   710 	  while (l>=0 && d.at(l)==' ') l--;
       
   711 	  if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
       
   712 	  k++;
       
   713 	  // scan the number
       
   714 	  while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
       
   715 	  if (!hash) 
       
   716 	  {
       
   717 	    // search for ## forward
       
   718 	    l=k;
       
   719 	    if (l<(int)d.length() && d.at(l)=='"') l++;
       
   720 	    while (l<(int)d.length() && d.at(l)==' ') l++;
       
   721 	    if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
       
   722 	  }
       
   723 	  //printf("request key %s result %s\n",key.data(),argTable[key]->data());
       
   724 	  if (key.length()>1 && (subst=argTable[key])) 
       
   725 	  {
       
   726 	    QCString substArg=*subst;
       
   727 	    //printf("substArg=`%s'\n",substArg.data());
       
   728 	    // only if no ## operator is before or after the argument
       
   729 	    // marker we do macro expansion.
       
   730 	    if (!hash) expandExpression(substArg,0,0);
       
   731 	    if (inString)
       
   732 	    {
       
   733 	      //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
       
   734 
       
   735 	      // if the marker is inside a string (because a # was put 
       
   736 	      // before the macro name) we must escape " and \ characters
       
   737 	      resExpr+=stringize(substArg);
       
   738 	    }
       
   739 	    else
       
   740 	    {
       
   741 	      if (hash && substArg.isEmpty())
       
   742 	      {
       
   743 		resExpr+="@E"; // empty argument will be remove later on
       
   744 	      }
       
   745 	      else if (g_nospaces)
       
   746 	      {
       
   747 	        resExpr+=substArg;
       
   748 	      }
       
   749 	      else
       
   750 	      {
       
   751 	        resExpr+=" "+substArg+" ";
       
   752 	      }
       
   753 	    }
       
   754 	  }
       
   755 	}
       
   756       }
       
   757       else // no marker, just copy
       
   758       {
       
   759 	if (!inString && d.at(k)=='\"') 
       
   760 	{
       
   761 	  inString=TRUE; // entering a literal string
       
   762 	}
       
   763 	else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
       
   764 	{
       
   765 	  inString=FALSE; // leaving a literal string
       
   766 	}
       
   767 	resExpr+=d.at(k++);
       
   768       }
       
   769     }
       
   770     len=j-pos;
       
   771     result=resExpr;
       
   772     //printf("result after substitution `%s' expr=`%s'\n",
       
   773     //       result.data(),expr.mid(pos,len).data());
       
   774     return TRUE;
       
   775   }
       
   776   return FALSE;
       
   777 }
       
   778 
       
   779 
       
   780 /*! returns the next identifier in string \a expr by starting at position \a p.
       
   781  * The position of the identifier is returned (or -1 if nothing is found)
       
   782  * and \a l is its length. Any quoted strings are skipping during the search.
       
   783  */
       
   784 static int getNextId(const QCString &expr,int p,int *l)
       
   785 {
       
   786   int n;
       
   787   while (p<(int)expr.length())
       
   788   {
       
   789     char c=expr.at(p++);
       
   790     if (isdigit(c)) // skip number
       
   791     {
       
   792       while (p<(int)expr.length() && isId(expr.at(p))) p++;
       
   793     }
       
   794     else if (isalpha(c) || c=='_') // read id
       
   795     {
       
   796       n=p-1;
       
   797       while (p<(int)expr.length() && isId(expr.at(p))) p++;
       
   798       *l=p-n;
       
   799       return n; 
       
   800     }
       
   801     else if (c=='"') // skip string
       
   802     {
       
   803       char ppc=0,pc=c;
       
   804       if (p<(int)expr.length()) c=expr.at(p);
       
   805       while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) 
       
   806 	// continue as long as no " is found, but ignoring \", but not \\"
       
   807       {
       
   808 	ppc=pc;
       
   809 	pc=c;
       
   810 	c=expr.at(p);
       
   811 	p++;
       
   812       }
       
   813       if (p<(int)expr.length()) ++p; // skip closing quote
       
   814     }
       
   815     else if (c=='/') // skip C Comment
       
   816     {
       
   817       char pc=c;
       
   818       if (p<(int)expr.length()) 
       
   819       {
       
   820 	c=expr.at(++p);
       
   821         if (c=='*')  // Start of C comment
       
   822         { 
       
   823   	  while (p<(int)expr.length() && !(pc=='*' && c=='/'))
       
   824 	  {
       
   825 	    pc=c;
       
   826 	    c=expr.at(++p);
       
   827 	  }
       
   828 	  p++;
       
   829         }
       
   830       }
       
   831     }
       
   832   }
       
   833   return -1;
       
   834 }
       
   835 
       
   836 /*! preforms recursive macro expansion on the string \a expr
       
   837  *  starting at position \a pos.
       
   838  *  May read additional characters from the input while re-scanning!
       
   839  *  If \a expandAll is \c TRUE then all macros in the expression are
       
   840  *  expanded, otherwise only the first is expanded.
       
   841  */
       
   842 static void expandExpression(QCString &expr,QCString *rest,int pos)
       
   843 {
       
   844   //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
       
   845   QCString macroName;
       
   846   QCString expMacro;
       
   847   bool definedTest=FALSE;
       
   848   int i=pos,l,p,len;
       
   849   while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
       
   850   {
       
   851     bool replaced=FALSE;
       
   852     macroName=expr.mid(p,l);
       
   853     if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
       
   854     {
       
   855       if (g_expandedDict->find(macroName)==0) // expand macro
       
   856       {
       
   857 	Define *def=isDefined(macroName);
       
   858 	if (definedTest) // macro name was found after defined 
       
   859 	{
       
   860 	  if (def) expMacro = " 1 "; else expMacro = " 0 ";
       
   861 	  replaced=TRUE;
       
   862 	  len=l;
       
   863 	  definedTest=FALSE;
       
   864 	}
       
   865 	else if (def && def->nargs==-1) // simple macro
       
   866 	{
       
   867 	  // substitute the definition of the macro
       
   868 	  //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
       
   869 	  if (g_nospaces)
       
   870 	  {
       
   871 	    expMacro=def->definition.stripWhiteSpace();
       
   872 	  }
       
   873 	  else
       
   874 	  {
       
   875 	    expMacro=" "+def->definition.stripWhiteSpace()+" ";
       
   876 	  }
       
   877 	  //expMacro=def->definition.stripWhiteSpace();
       
   878 	  replaced=TRUE;
       
   879 	  len=l;
       
   880 	  //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
       
   881 	}
       
   882 	else if (def && def->nargs>=0) // function macro
       
   883 	{
       
   884 	  replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
       
   885 	  len+=l;
       
   886 	}
       
   887         else if (macroName=="defined")
       
   888         {
       
   889   	  //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
       
   890 	  definedTest=TRUE;
       
   891         }
       
   892 
       
   893 	if (replaced) // expand the macro and rescan the expression
       
   894 	{
       
   895 	    
       
   896 	  //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
       
   897 	  QCString resultExpr=expMacro;
       
   898 	  QCString restExpr=expr.right(expr.length()-len-p);
       
   899 	  processConcatOperators(resultExpr);
       
   900 	  if (def && !def->nonRecursive)
       
   901 	  {
       
   902 	    g_expandedDict->insert(macroName,def);
       
   903 	    expandExpression(resultExpr,&restExpr,0);
       
   904 	    g_expandedDict->remove(macroName);
       
   905 	  }
       
   906 	  expr=expr.left(p)+resultExpr+restExpr;
       
   907 	  i=p;
       
   908 	  //printf("new expression: %s\n",expr.data());
       
   909 	}
       
   910 	else // move to the next macro name
       
   911 	{
       
   912 	  //printf("moving to the next macro old=%d new=%d\n",i,p+l);
       
   913 	  i=p+l;
       
   914 	}
       
   915       }
       
   916       else // move to the next macro name
       
   917       {
       
   918 	expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
       
   919 	//printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
       
   920 	i=p+l+2;
       
   921 	//i=p+l;
       
   922       }
       
   923     }
       
   924     else // no re-scan marker found, skip the macro name
       
   925     {
       
   926       //printf("skipping marked macro\n");
       
   927       i=p+l;
       
   928     }
       
   929   }
       
   930 }
       
   931 
       
   932 /*! replaces all occurrences of @@@@ in \a s by @@
       
   933  *  and removes all occurrences of @@E.
       
   934  *  All identifiers found are replaced by 0L
       
   935  */
       
   936 QCString removeIdsAndMarkers(const char *s)
       
   937 {
       
   938   //printf("removeIdsAndMarkers(%s)\n",s);
       
   939   const char *p=s;
       
   940   char c;
       
   941   bool inNum=FALSE;
       
   942   QCString result;
       
   943   if (p)
       
   944   {
       
   945     while ((c=*p))
       
   946     {
       
   947       if (c=='@') // replace @@ with @ and remove @E
       
   948       {
       
   949 	if (*(p+1)=='@')
       
   950 	{
       
   951 	  result+=c; 
       
   952 	}
       
   953 	else if (*(p+1)=='E')
       
   954 	{
       
   955 	  // skip
       
   956 	}
       
   957 	p+=2;
       
   958       }
       
   959       else if (isdigit(c)) // number
       
   960       {
       
   961 	result+=c;
       
   962 	p++;
       
   963         inNum=TRUE;	
       
   964       }
       
   965       else if (c=='d' && !inNum) // identifier starting with a `d'
       
   966       {
       
   967 	if (strncmp(p,"defined ",8)==0 || strncmp(p,"defined(",8)==0) 
       
   968 	           // defined keyword
       
   969 	{
       
   970 	  p+=7; // skip defined
       
   971 	}
       
   972 	else
       
   973 	{
       
   974 	  result+="0L";
       
   975 	  p++;
       
   976 	  while ((c=*p) && isId(c)) p++;
       
   977 	}
       
   978       }
       
   979       else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
       
   980       {
       
   981 	result+="0L";
       
   982 	p++;
       
   983 	while ((c=*p) && isId(c)) p++;
       
   984       }
       
   985       else if (c=='/') // skip C comments
       
   986       {
       
   987 	char pc=c;
       
   988 	c=*++p;
       
   989 	if (c=='*') // start of C comment
       
   990 	{ 
       
   991 	  while (*p && !(pc=='*' && c=='/')) // search end of comment
       
   992 	  {
       
   993 	    pc=c;
       
   994 	    c=*++p;
       
   995 	  }
       
   996 	  p++;
       
   997 	}
       
   998 	else // oops, not comment but division
       
   999 	{
       
  1000 	  result+=pc;
       
  1001 	  goto nextChar;
       
  1002 	}
       
  1003       }
       
  1004       else 
       
  1005       {
       
  1006 nextChar:
       
  1007 	result+=c;
       
  1008 	char lc=tolower(c);
       
  1009 	if (!isId(lc) && lc!='.' && lc!='-' && lc!='+') inNum=FALSE;
       
  1010 	p++;
       
  1011       }
       
  1012     }
       
  1013   }
       
  1014   //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
       
  1015   return result;
       
  1016 }
       
  1017 
       
  1018 /*! replaces all occurrences of @@ in \a s by @
       
  1019  *  \par assumption: 
       
  1020  *   \a s only contains pairs of @@'s
       
  1021  */
       
  1022 QCString removeMarkers(const char *s)
       
  1023 {
       
  1024   const char *p=s;
       
  1025   char c;
       
  1026   QCString result;
       
  1027   if (p)
       
  1028   {
       
  1029     while ((c=*p))
       
  1030     {
       
  1031       switch(c)
       
  1032       {
       
  1033 	case '@': // replace @@ with @
       
  1034 	  {
       
  1035 	    if (*(p+1)=='@')
       
  1036 	    {
       
  1037 	      result+=c; 
       
  1038 	    }
       
  1039 	    p+=2;
       
  1040 	  }
       
  1041 	  break;
       
  1042 	case '/': // skip C comments
       
  1043 	  {
       
  1044 	    result+=c;
       
  1045 	    char pc=c;
       
  1046 	    c=*++p;
       
  1047 	    if (c=='*') // start of C comment
       
  1048 	    { 
       
  1049 	      while (*p && !(pc=='*' && c=='/')) // search end of comment
       
  1050 	      {
       
  1051 		if (*p=='@' && *(p+1)=='@') 
       
  1052 		  result+=c,p++;
       
  1053 		else 
       
  1054 		  result+=c;
       
  1055 		pc=c;
       
  1056 		c=*++p;
       
  1057 	      }
       
  1058 	      if (*p)
       
  1059 	      {
       
  1060 	        result+=c;
       
  1061 	        p++;
       
  1062 	      }
       
  1063 	    }
       
  1064 	  }
       
  1065 	  break;
       
  1066 	case '"': // skip string literals
       
  1067 	  {
       
  1068 	    result+=c;
       
  1069 	    char pc=c;
       
  1070 	    c=*++p;
       
  1071 	    while (*p && (c!='"' || pc=='\\')) // no end quote
       
  1072 	    {
       
  1073 	      result+=c;
       
  1074 	      c=*++p;
       
  1075 	    }
       
  1076 	  }
       
  1077 	  break;
       
  1078 	case '\'': // skip char literals
       
  1079 	  {
       
  1080 	    result+=c;
       
  1081 	    char pc=c;
       
  1082 	    c=*++p;
       
  1083 	    while (*p && (c!='\'' || pc=='\\')) // no end quote
       
  1084 	    {
       
  1085 	      result+=c;
       
  1086 	      c=*++p;
       
  1087 	    }
       
  1088 	  }
       
  1089 	  break;
       
  1090 	default:
       
  1091 	  {
       
  1092 	    result+=c;
       
  1093 	    p++;
       
  1094 	  }
       
  1095 	  break;
       
  1096       }
       
  1097     }
       
  1098   }
       
  1099   //printf("RemoveMarkers(%s)=%s\n",s,result.data());
       
  1100   return result;
       
  1101 }
       
  1102 
       
  1103 /*! compute the value of the expression in string \a expr.
       
  1104  *  If needed the function may read additional characters from the input.
       
  1105  */
       
  1106 
       
  1107 bool computeExpression(const QCString &expr)
       
  1108 {
       
  1109   QCString e=expr;
       
  1110   expandExpression(e,0,0);
       
  1111   //printf("after expansion `%s'\n",e.data());
       
  1112   e = removeIdsAndMarkers(e);
       
  1113   if (e.isEmpty()) return FALSE;
       
  1114   //printf("parsing `%s'\n",e.data());
       
  1115   return parseCppExpression(g_yyFileName,g_yyLineNr,e);
       
  1116 }
       
  1117 
       
  1118 /*! expands the macro definition in \a name
       
  1119  *  If needed the function may read additional characters from the input
       
  1120  */
       
  1121 
       
  1122 QCString expandMacro(const QCString &name)
       
  1123 {
       
  1124   QCString n=name;
       
  1125   expandExpression(n,0,0);
       
  1126   n=removeMarkers(n);
       
  1127   //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
       
  1128   return n;
       
  1129 }
       
  1130 
       
  1131 Define *newDefine()
       
  1132 {
       
  1133   Define *def=new Define;
       
  1134   def->name = g_defName;
       
  1135   def->definition = g_defText.stripWhiteSpace();
       
  1136   def->nargs = g_defArgs;
       
  1137   def->fileName = g_yyFileName; 
       
  1138   def->lineNr = g_yyLineNr;
       
  1139   def->varArgs = g_defVarArgs;
       
  1140   //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
       
  1141   if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
       
  1142   {
       
  1143     def->isPredefined=TRUE;
       
  1144   }
       
  1145   return def;
       
  1146 }
       
  1147 
       
  1148 void addDefine()
       
  1149 {
       
  1150   if (g_skip) return; // do not add this define as it is inside a 
       
  1151                       // conditional section (cond command) that is disabled.
       
  1152   if (!Doxygen::gatherDefines) return;
       
  1153 
       
  1154   //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
       
  1155   //ArgumentList *al = new ArgumentList;
       
  1156   //stringToArgumentList(g_defArgsStr,al);
       
  1157   MemberDef *md=new MemberDef(
       
  1158       g_yyFileName,g_yyLineNr,
       
  1159       "#define",g_defName,g_defArgsStr,0,
       
  1160       Public,Normal,FALSE,Member,MemberDef::Define,0,0);
       
  1161   if (!g_defArgsStr.isEmpty())
       
  1162   {
       
  1163     ArgumentList *argList = new ArgumentList;
       
  1164     //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
       
  1165     stringToArgumentList(g_defArgsStr,argList);
       
  1166     md->setArgumentList(argList);
       
  1167   }
       
  1168   //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
       
  1169   int l=g_defLitText.find('\n');
       
  1170   if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
       
  1171   {
       
  1172     // strip first line if it only contains a slash
       
  1173     g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
       
  1174   }
       
  1175   else if (l>0)
       
  1176   {
       
  1177     // align the items on the first line with the items on the second line
       
  1178     int k=l+1;
       
  1179     const char *p=g_defLitText.data()+k;
       
  1180     char c;
       
  1181     while ((c=*p++) && (c==' ' || c=='\t')) k++;
       
  1182     g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
       
  1183   }
       
  1184   md->setInitializer(g_defLitText.stripWhiteSpace());
       
  1185 
       
  1186   md->setFileDef(g_inputFileDef);
       
  1187   md->setDefinition("#define "+g_defName);
       
  1188 
       
  1189   MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
       
  1190   if (mn==0)
       
  1191   {
       
  1192     mn = new MemberName(g_defName);
       
  1193     Doxygen::functionNameSDict->append(g_defName,mn);
       
  1194   }
       
  1195   mn->append(md);
       
  1196   if (g_yyFileDef) g_yyFileDef->insertMember(md);
       
  1197 
       
  1198   //Define *d;
       
  1199   //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); 
       
  1200 }
       
  1201 
       
  1202 static inline void outputChar(char c)
       
  1203 {
       
  1204 	if (Config_getBool("PREPROCESS_INCLUDES")) {
       
  1205 		g_outputBuf->addChar(c);
       
  1206 	} else {
       
  1207 		// Only output if the initial translation unit
       
  1208 		if (g_includeStack.isEmpty() || g_curlyCount>0) {
       
  1209 			g_outputBuf->addChar(c);
       
  1210 		}
       
  1211 	}
       
  1212 }
       
  1213 
       
  1214 static inline void outputArray(const char *a,int len)
       
  1215 {
       
  1216 	if (Config_getBool("PREPROCESS_INCLUDES")) {
       
  1217 		g_outputBuf->addArray(a,len);
       
  1218 	} else {
       
  1219 		// Only output if the initial translation unit
       
  1220 		if (g_includeStack.isEmpty() || g_curlyCount>0) {
       
  1221 			g_outputBuf->addArray(a,len);
       
  1222 		}
       
  1223 	}
       
  1224 }
       
  1225 
       
  1226 static void readIncludeFile(const QCString &inc)
       
  1227 {
       
  1228   if (!Config_getBool("SEARCH_INCLUDES")) return; // do not read include files
       
  1229   uint i=0;
       
  1230 
       
  1231   // find the start of the include file name
       
  1232   while (i<inc.length() &&
       
  1233          (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
       
  1234         ) i++;
       
  1235   uint s=i;
       
  1236 
       
  1237   // was it a local include?
       
  1238   bool localInclude = s>0 && inc.at(s-1)=='"';
       
  1239 
       
  1240   // find the end of the include file name
       
  1241   while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
       
  1242 
       
  1243   if (s<inc.length() && i>s) // valid include file name found
       
  1244   {
       
  1245     // extract include path+name
       
  1246     QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
       
  1247 
       
  1248     QCString oldFileName = g_yyFileName.copy();
       
  1249     FileDef *oldFileDef  = g_yyFileDef;
       
  1250     int oldLineNr        = g_yyLineNr;
       
  1251     //printf("Searching for `%s'\n",incFileName.data());
       
  1252 
       
  1253     // findFile will overwrite g_yyFileDef if found
       
  1254     FileState *fs;
       
  1255     bool alreadyIncluded = FALSE;
       
  1256     //printf("calling findFile(%s)\n",incFileName.data());
       
  1257     if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
       
  1258     {
       
  1259       //printf("Found include file!\n");
       
  1260       if (Debug::isFlagSet(Debug::Preprocessor))
       
  1261       {
       
  1262         for (i=0;i<g_includeStack.count();i++) msg("  ");
       
  1263         msg("#include %s: parsing...\n",incFileName.data());
       
  1264       }
       
  1265       if (oldFileDef)
       
  1266       {
       
  1267         // add include dependency to the file in which the #include was found
       
  1268 	    //Debug::print(Debug::IncludeGraph, 0, "pre.l readIncludeFile() adding dependency \"%s\" to \"%s\"\n", incFileName, oldFileDef->absFilePath().data());
       
  1269         oldFileDef->addIncludeDependency(g_yyFileDef,incFileName,localInclude,g_isImported);
       
  1270         // add included by dependency
       
  1271         if (g_yyFileDef)
       
  1272         {
       
  1273           //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
       
  1274           g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
       
  1275         }
       
  1276       }
       
  1277       fs->bufState=YY_CURRENT_BUFFER;
       
  1278       fs->lineNr=oldLineNr;
       
  1279       fs->fileName=oldFileName;
       
  1280       // push the state on the stack
       
  1281       g_includeStack.push(fs);
       
  1282       // set the scanner to the include file
       
  1283 
       
  1284       // Deal with file changes due to 
       
  1285       // #include's within { .. } blocks
       
  1286       QCString lineStr(g_yyFileName.length()+20);
       
  1287       lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
       
  1288       outputArray(lineStr.data(),lineStr.length());
       
  1289 
       
  1290       //fprintf(stderr,"Switching to include file %s\n",incFileName.data());
       
  1291       //preYYin=fs->filePtr;
       
  1292       //yy_switch_to_buffer(yy_create_buffer(preYYin, YY_BUF_SIZE));
       
  1293       g_inputBuf=&fs->fileBuf;
       
  1294       g_inputBufPos=0;
       
  1295       yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
       
  1296     }
       
  1297     else
       
  1298     {
       
  1299       //printf("  calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
       
  1300       if (oldFileDef)
       
  1301       {
       
  1302 	bool ambig;
       
  1303 	FileDef *fd = findFileDef(Doxygen::inputNameDict,incFileName,ambig);
       
  1304 	//printf("findFileDef(%s)=%p\n",incFileName.data(),fd);
       
  1305 	// add include dependency to the file in which the #include was found
       
  1306 	oldFileDef->addIncludeDependency(fd,incFileName,localInclude,g_isImported);
       
  1307 	// add included by dependency
       
  1308         if (fd)
       
  1309         {
       
  1310           //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
       
  1311           fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
       
  1312         }
       
  1313       }
       
  1314       if (Debug::isFlagSet(Debug::Preprocessor))
       
  1315       {
       
  1316         msg("#include %s: not found or already included! skipping...\n",incFileName.data());
       
  1317         //printf("Error: include file %s not found\n",yytext);
       
  1318       }
       
  1319       if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
       
  1320       {
       
  1321 	warn(g_yyFileName,g_yyLineNr,"Warning: include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
       
  1322       }
       
  1323     }
       
  1324   }
       
  1325 }
       
  1326 
       
  1327 /* ----------------------------------------------------------------- */
       
  1328 
       
  1329 static void startCondSection(const char *sectId)
       
  1330 {
       
  1331   g_condStack.push(new bool(g_skip));
       
  1332   if (Config_getList("ENABLED_SECTIONS").find(sectId)==-1)
       
  1333   {
       
  1334     g_skip=TRUE;
       
  1335   }
       
  1336 }
       
  1337 
       
  1338 static void endCondSection()
       
  1339 {
       
  1340   if (g_condStack.isEmpty())
       
  1341   {
       
  1342     g_skip=FALSE;
       
  1343   }
       
  1344   else
       
  1345   {
       
  1346     bool *ctx = g_condStack.pop();
       
  1347     g_skip=*ctx;
       
  1348   }
       
  1349 }
       
  1350 
       
  1351 static QCString escapeAt(const char *text)
       
  1352 {
       
  1353   QCString result;
       
  1354   if (text)
       
  1355   {
       
  1356     char c;
       
  1357     const char *p=text;
       
  1358     while ((c=*p++))
       
  1359     {
       
  1360       if (c=='@') result+="@@"; else result+=c;
       
  1361     }
       
  1362   }
       
  1363   return result;
       
  1364 }
       
  1365 
       
  1366 static char resolveTrigraph(char c)
       
  1367 {
       
  1368   switch (c)
       
  1369   {
       
  1370     case '=': return '#';
       
  1371     case '/': return '\\';
       
  1372     case '\'': return '^';
       
  1373     case '(': return '[';
       
  1374     case ')': return ']';
       
  1375     case '!': return '|';
       
  1376     case '<': return '{';
       
  1377     case '>': return '}';
       
  1378     case '-': return '~';
       
  1379   }
       
  1380   return '?';
       
  1381 }
       
  1382 
       
  1383 /* ----------------------------------------------------------------- */
       
  1384 
       
  1385 #undef  YY_INPUT
       
  1386 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
       
  1387 
       
  1388 static int yyread(char *buf,int max_size)
       
  1389 {
       
  1390 #if 0
       
  1391   int len = fread( buf, 1, max_size, preYYin );
       
  1392   if (len==0 && ferror( yyin ))
       
  1393   {
       
  1394     yy_fatal_error( "input in flex scanner failed" );
       
  1395     return len;
       
  1396   }
       
  1397   return filterCRLF(buf,len);
       
  1398 #endif
       
  1399 
       
  1400   int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
       
  1401   int bytesToCopy = QMIN(max_size,bytesInBuf);
       
  1402   memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
       
  1403   g_inputBufPos+=bytesToCopy;
       
  1404   return bytesToCopy;
       
  1405 }
       
  1406 
       
  1407 /* ----------------------------------------------------------------- */
       
  1408 
       
  1409 %}
       
  1410 
       
  1411 ID	[a-z_A-Z][a-z_A-Z0-9]*
       
  1412 B       [ \t]
       
  1413 BN	[ \t\r\n]
       
  1414 CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
       
  1415 
       
  1416 %option noyywrap
       
  1417 
       
  1418 %x      Start
       
  1419 %x	Command
       
  1420 %x	SkipCommand
       
  1421 %x	SkipLine
       
  1422 %x	CopyLine
       
  1423 %x	CopyString
       
  1424 %x      Include
       
  1425 %x      IncludeID
       
  1426 %x      EndImport
       
  1427 %x	DefName
       
  1428 %x	DefineArg
       
  1429 %x	DefineText
       
  1430 %x      SkipCPPBlock
       
  1431 %x      Ifdef
       
  1432 %x      Ifndef
       
  1433 %x	SkipCComment
       
  1434 %x	CopyCComment
       
  1435 %x	SkipVerbatim
       
  1436 %x	SkipCPPComment
       
  1437 %x	RemoveCComment
       
  1438 %x	RemoveCPPComment
       
  1439 %x	Guard
       
  1440 %x	DefinedExpr1
       
  1441 %x	DefinedExpr2
       
  1442 %x	SkipDoubleQuote
       
  1443 %x	SkipSingleQuote
       
  1444 %x	UndefName
       
  1445 %x	IgnoreLine
       
  1446 %x	FindDefineArgs
       
  1447 %x	ReadString
       
  1448 %x	CondLine
       
  1449 
       
  1450 %%
       
  1451 
       
  1452 <*>\x06					
       
  1453 <*>\x00
       
  1454 <*>\r
       
  1455 <*>"??"[=/'()!<>-]			{ // Trigraph
       
  1456   					  unput(resolveTrigraph(yytext[2]));
       
  1457   					}
       
  1458 <Start>^{B}*"#"				{ BEGIN(Command); }
       
  1459 <Start>^{B}*/[^#]			{
       
  1460  					  outputArray(yytext,yyleng); 
       
  1461   					  BEGIN(CopyLine); 
       
  1462 					}
       
  1463 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
       
  1464 					  int i;
       
  1465 					  for (i=yyleng-1;i>=0;i--)
       
  1466 					  {
       
  1467 					    unput(yytext[i]);
       
  1468 					  }
       
  1469 					  BEGIN(CopyLine);
       
  1470                                         }
       
  1471 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\(\)\n]*"("[^\)\n]*")"[^\)\n]*")"{B}*\n | // function list macro with one (...) argument, e.g. for K_GLOBAL_STATIC_WITH_ARGS
       
  1472 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"{B}*\n { // function like macro
       
  1473   					  static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
       
  1474 					  QCString name(yytext);
       
  1475 					  name=name.left(name.find('(')).stripWhiteSpace();
       
  1476 
       
  1477 					  Define *def=0;
       
  1478 					  if (skipFuncMacros && 
       
  1479 					      name!="Q_PROPERTY" &&
       
  1480 					      !(
       
  1481 					         (g_includeStack.isEmpty() || g_curlyCount>0) &&
       
  1482 					         g_macroExpansion &&
       
  1483 					         (def=g_fileDefineDict->find(name)) &&
       
  1484 					         (!g_expandOnlyPredef || def->isPredefined)
       
  1485 					       )
       
  1486 					     )
       
  1487 					  {
       
  1488 					    outputChar('\n');
       
  1489 					    g_yyLineNr++;
       
  1490 					  }
       
  1491 					  else // don't skip
       
  1492 					  {
       
  1493 					    int i;
       
  1494 					    for (i=yyleng-1;i>=0;i--)
       
  1495 					    {
       
  1496 					      unput(yytext[i]);
       
  1497 					    }
       
  1498 					    BEGIN(CopyLine);
       
  1499 					  }
       
  1500   					}
       
  1501 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{"	{
       
  1502                                           QCString text=yytext;
       
  1503   					  g_yyLineNr+=text.contains('\n');
       
  1504 					  outputArray(yytext,yyleng);
       
  1505   					}
       
  1506 <CopyLine>"{"				{ // count brackets inside the main file
       
  1507   					  if (g_includeStack.isEmpty()) 
       
  1508 					  {
       
  1509 					    g_curlyCount++;
       
  1510 					  }
       
  1511 					  outputChar(*yytext);
       
  1512   					}
       
  1513 <CopyLine>"}"				{ // count brackets inside the main file
       
  1514   					  if (g_includeStack.isEmpty() && g_curlyCount>0) 
       
  1515 					  {
       
  1516 					    g_curlyCount--;
       
  1517 					  }
       
  1518 					  outputChar(*yytext);
       
  1519   					}
       
  1520 <CopyLine>"'"\\[0-7]{1,3}"'"		{ 
       
  1521   					  outputArray(yytext,yyleng);
       
  1522 					}
       
  1523 <CopyLine>"'"\\."'"			{ 
       
  1524   					  outputArray(yytext,yyleng);
       
  1525 					}
       
  1526 <CopyLine>"'"."'"			{ 
       
  1527   					  outputArray(yytext,yyleng);
       
  1528 					}
       
  1529 <CopyLine>\"				{
       
  1530 					  outputChar(*yytext);
       
  1531 					  BEGIN( CopyString );
       
  1532 					}
       
  1533 <CopyString>[^\"\\\r\n]+		{
       
  1534   					  outputArray(yytext,yyleng);
       
  1535 					}
       
  1536 <CopyString>\\.				{
       
  1537 					  outputArray(yytext,yyleng);
       
  1538 					}
       
  1539 <CopyString>\"				{
       
  1540 					  outputChar(*yytext);
       
  1541 					  BEGIN( CopyLine );
       
  1542 					}
       
  1543 <CopyLine>{ID}/{BN}{0,80}"("			{
       
  1544   					  Define *def=0;
       
  1545 					  def=g_fileDefineDict->find(yytext);
       
  1546 					  //printf("Search for define %s found=%d g_includeStack.count()=%d "
       
  1547 					  //       "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
       
  1548 					  //	 "isPreDefined=%d tu=%d\n",yytext,def ? 1 : 0,
       
  1549 					  //	 g_includeStack.count(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
       
  1550 					  //	 def ? def->isPredefined : -1,
       
  1551 					  //	 Config_getBool("PREPROCCESS_FULL_TU")
       
  1552 					  //	);
       
  1553 					  if ((g_includeStack.isEmpty() || g_curlyCount>0 || Config_getBool("PREPROCCESS_FULL_TU")) &&
       
  1554 					      g_macroExpansion &&
       
  1555 					      (def=g_fileDefineDict->find(yytext)) &&
       
  1556 					      (!g_expandOnlyPredef || def->isPredefined || Config_getBool("PREPROCCESS_FULL_TU"))
       
  1557 					     )
       
  1558 					  {
       
  1559 					    //printf("Found it!\n");
       
  1560 					    g_roundCount=0;
       
  1561 					    g_defArgsStr=yytext;
       
  1562 					    if (def->nargs==-1) // no function macro
       
  1563 					    {
       
  1564 					      QCString result = expandMacro(g_defArgsStr);
       
  1565 					      outputArray(result,result.length());
       
  1566 					    }
       
  1567 					    else // zero or more arguments
       
  1568 					    {
       
  1569 					      g_findDefArgContext = CopyLine;
       
  1570 					      BEGIN(FindDefineArgs);
       
  1571 					    }
       
  1572 					  }
       
  1573 					  else
       
  1574 					  {
       
  1575 					    outputArray(yytext,yyleng);
       
  1576 					  }
       
  1577   					}
       
  1578 <CopyLine>{ID}				{
       
  1579                                           Define *def=0;
       
  1580 					  //printf("Search for define %s\n",yytext);
       
  1581   					  if ((g_includeStack.isEmpty() || g_curlyCount>0) && 
       
  1582 					      g_macroExpansion &&
       
  1583 					      (def=g_fileDefineDict->find(yytext)) &&
       
  1584 					      def->nargs==-1 &&
       
  1585 					      (!g_expandOnlyPredef || def->isPredefined)
       
  1586 					     )
       
  1587 					  {
       
  1588 					    //printf("Found it!\n");
       
  1589                                             QCString name=yytext;
       
  1590 					    QCString result=expandMacro(name); 
       
  1591 					    //printf("result=`%s'\n",result.data());
       
  1592 					    outputArray(result,result.length());
       
  1593 					  }
       
  1594 					  else
       
  1595 					  {
       
  1596 					    outputArray(yytext,yyleng);
       
  1597 					  }
       
  1598   					}
       
  1599 <CopyLine>"\\"\r?/\n			{ // strip line continuation characters
       
  1600   					}
       
  1601 <CopyLine>.				{
       
  1602   					  outputChar(*yytext);
       
  1603   					}
       
  1604 <CopyLine>\n				{
       
  1605   					  outputChar('\n');
       
  1606 					  BEGIN(Start);
       
  1607 					  g_yyLineNr++;
       
  1608   					}
       
  1609 <FindDefineArgs>"("			{
       
  1610   					  g_defArgsStr+='(';
       
  1611   					  g_roundCount++;
       
  1612   					}
       
  1613 <FindDefineArgs>")"			{
       
  1614   					  g_defArgsStr+=')';
       
  1615 					  g_roundCount--;
       
  1616 					  if (g_roundCount==0)
       
  1617 					  {
       
  1618 					    QCString result=expandMacro(g_defArgsStr);
       
  1619 					    //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
       
  1620 					    if (g_findDefArgContext==CopyLine)
       
  1621 					    {
       
  1622 					      outputArray(result,result.length());
       
  1623 					      BEGIN(g_findDefArgContext);
       
  1624 					    }
       
  1625 					    else // g_findDefArgContext==IncludeID
       
  1626 					    {
       
  1627 					      readIncludeFile(result);
       
  1628 					      g_nospaces=FALSE;
       
  1629 					      BEGIN(Start);
       
  1630 					    }
       
  1631 					  }
       
  1632   					}
       
  1633   /*
       
  1634 <FindDefineArgs>")"{B}*"("		{
       
  1635   					  g_defArgsStr+=yytext;
       
  1636   					}
       
  1637   */
       
  1638 <FindDefineArgs>{CHARLIT}		{
       
  1639   					  g_defArgsStr+=yytext;
       
  1640   					}
       
  1641 <FindDefineArgs>\"			{
       
  1642   					  g_defArgsStr+=*yytext;
       
  1643   					  BEGIN(ReadString);
       
  1644   					}
       
  1645 <FindDefineArgs>\n			{
       
  1646   					  g_yyLineNr++;
       
  1647 					  outputChar('\n');
       
  1648   					}
       
  1649 <FindDefineArgs>"@"			{
       
  1650   					  g_defArgsStr+="@@";
       
  1651   					}
       
  1652 <FindDefineArgs>.			{
       
  1653   					  g_defArgsStr+=*yytext;
       
  1654   					}
       
  1655 <ReadString>"\""			{
       
  1656   					  g_defArgsStr+=*yytext;
       
  1657 					  BEGIN(FindDefineArgs);
       
  1658   					}
       
  1659 <ReadString>"//"|"/*"			{
       
  1660   					  g_defArgsStr+=yytext;
       
  1661   					}
       
  1662 <ReadString>\\.				{
       
  1663   					  g_defArgsStr+=yytext;
       
  1664   					}
       
  1665 <ReadString>.				{
       
  1666   					  g_defArgsStr+=*yytext;
       
  1667   					}
       
  1668 <Command>("include"|"import"){B}+/{ID}	{
       
  1669   					  g_isImported = yytext[1]=='m';
       
  1670   					  if (g_macroExpansion) 
       
  1671 					    BEGIN(IncludeID);
       
  1672   					}
       
  1673 <Command>("include"|"import"){B}*[<"]	{ 
       
  1674   					  g_isImported = yytext[1]=='m';
       
  1675 					  char c[2];
       
  1676 					  c[0]=yytext[yyleng-1];c[1]='\0';
       
  1677 					  g_incName=c;
       
  1678   					  BEGIN(Include); 
       
  1679 					}
       
  1680 <Command>("cmake")?"define"{B}+		{ 
       
  1681   			                  //printf("!!!DefName\n"); 
       
  1682   					  BEGIN(DefName); 
       
  1683 					}
       
  1684 <Command>"ifdef"/{B}*"("		{
       
  1685   					  incrLevel();
       
  1686 					  g_guardExpr.resize(0);
       
  1687   					  BEGIN(DefinedExpr2);
       
  1688   					}
       
  1689 <Command>"ifdef"/{B}+			{
       
  1690   					  //printf("Pre.l: ifdef\n");
       
  1691   					  incrLevel();
       
  1692 					  g_guardExpr.resize(0);
       
  1693   					  BEGIN(DefinedExpr1);
       
  1694   					}
       
  1695 <Command>"ifndef"/{B}*"("		{
       
  1696   					  incrLevel();
       
  1697 					  g_guardExpr="! ";
       
  1698   					  BEGIN(DefinedExpr2);
       
  1699 					}
       
  1700 <Command>"ifndef"/{B}+			{
       
  1701   					  incrLevel();
       
  1702 					  g_guardExpr="! ";
       
  1703   					  BEGIN(DefinedExpr1);
       
  1704   					}
       
  1705 <Command>"if"/[ \t(!]			{
       
  1706   					  incrLevel();
       
  1707 					  g_guardExpr.resize(0);
       
  1708 					  BEGIN(Guard);
       
  1709 					}
       
  1710 <Command>("elif"|"else"{B}*"if")/[ \t(!]	{
       
  1711   					  if (!otherCaseDone())
       
  1712 					  {
       
  1713 					    g_guardExpr.resize(0);
       
  1714 					    BEGIN(Guard);  
       
  1715 					  }
       
  1716 					  else
       
  1717 					  {
       
  1718 					    g_ifcount=0;
       
  1719 					    BEGIN(SkipCPPBlock);
       
  1720 					  }
       
  1721   					}
       
  1722 <Command>"else"/[^a-z_A-Z0-9]		{
       
  1723 					  //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
       
  1724   					  if (otherCaseDone())
       
  1725 					  {
       
  1726 					    g_ifcount=0;
       
  1727 					    BEGIN(SkipCPPBlock);
       
  1728 					  }
       
  1729 					  else
       
  1730 					  {
       
  1731 					    setCaseDone(TRUE);
       
  1732 					    //g_levelGuard[g_level-1]=TRUE;
       
  1733 					  } 
       
  1734   					}
       
  1735 <Command>"undef"{B}+			{
       
  1736   					  BEGIN(UndefName);
       
  1737   					}
       
  1738 <Command>("elif"|"else"{B}*"if")/[ \t(!]	{
       
  1739   					  if (!otherCaseDone())
       
  1740 					  {
       
  1741 					    g_guardExpr.resize(0);
       
  1742   					    BEGIN(Guard);
       
  1743 					  }
       
  1744   					}
       
  1745 <Command>"endif"/[^a-z_A-Z0-9]		{
       
  1746   					  //printf("Pre.l: #endif\n");
       
  1747   					  decrLevel();
       
  1748   					}
       
  1749 <Command,IgnoreLine>\n			{
       
  1750   					  outputChar('\n');
       
  1751   					  BEGIN(Start);
       
  1752 					  g_yyLineNr++;
       
  1753   					}
       
  1754 <Command>{ID}				{ // unknown directive
       
  1755 					  BEGIN(IgnoreLine);
       
  1756 					}
       
  1757 <IgnoreLine>\\[\r]?\n			{
       
  1758   					  outputChar('\n');
       
  1759 					  g_yyLineNr++;
       
  1760 					}
       
  1761 <IgnoreLine>.
       
  1762 <Command>.
       
  1763 <UndefName>{ID}				{
       
  1764   					  Define *def;
       
  1765   					  if ((def=isDefined(yytext)) 
       
  1766 					      /*&& !def->isPredefined*/
       
  1767 					      && !def->nonRecursive
       
  1768 					     )
       
  1769 					  {
       
  1770 					    //printf("undefining %s\n",yytext);
       
  1771 					    def->undef=TRUE;
       
  1772 					  }
       
  1773 					  BEGIN(Start);
       
  1774   					}
       
  1775 <Guard>\\[\r]?\n			{
       
  1776   					  outputChar('\n');
       
  1777   					  g_guardExpr+=' ';
       
  1778 					  g_yyLineNr++;
       
  1779   					}
       
  1780 <Guard>"defined"/{B}*"("		{
       
  1781     					  BEGIN(DefinedExpr2);
       
  1782     					}
       
  1783 <Guard>"defined"/{B}+			{
       
  1784     					  BEGIN(DefinedExpr1);
       
  1785     					}
       
  1786 <Guard>{ID}				{ g_guardExpr+=yytext; }
       
  1787 <Guard>.				{ g_guardExpr+=*yytext; }
       
  1788 <Guard>\n				{
       
  1789   					  unput(*yytext);
       
  1790   					  //printf("Guard: `%s'\n",
       
  1791 					  //    g_guardExpr.data());
       
  1792 					  bool guard=computeExpression(g_guardExpr);
       
  1793 					  setCaseDone(guard);
       
  1794 					  //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
       
  1795 					  if (guard)
       
  1796 					  {
       
  1797 					    BEGIN(Start);
       
  1798 					  } 
       
  1799 					  else
       
  1800 					  {
       
  1801 					    g_ifcount=0;
       
  1802 					    BEGIN(SkipCPPBlock);
       
  1803 					  }
       
  1804   					}
       
  1805 <DefinedExpr1,DefinedExpr2>\\\n		{ g_yyLineNr++; outputChar('\n'); }
       
  1806 <DefinedExpr1>{ID}			{
       
  1807   					  if (isDefined(yytext))
       
  1808 					    g_guardExpr+=" 1L ";
       
  1809 					  else
       
  1810 					    g_guardExpr+=" 0L ";
       
  1811 					  g_lastGuardName=yytext;
       
  1812 					  BEGIN(Guard);
       
  1813   					}
       
  1814 <DefinedExpr2>{ID}			{
       
  1815   					  if (isDefined(yytext))
       
  1816 					    g_guardExpr+=" 1L ";
       
  1817 					  else
       
  1818 					    g_guardExpr+=" 0L ";
       
  1819 					  g_lastGuardName.resize(0);
       
  1820   					}
       
  1821 <DefinedExpr1,DefinedExpr2>\n		{ // should not happen, handle anyway
       
  1822                                           g_yyLineNr++;
       
  1823   					  g_ifcount=0;
       
  1824  					  BEGIN(SkipCPPBlock); 
       
  1825 					}
       
  1826 <DefinedExpr2>")"			{
       
  1827   					  BEGIN(Guard);
       
  1828   					}
       
  1829 <DefinedExpr1,DefinedExpr2>.
       
  1830 <SkipCPPBlock>^{B}*"#"			{ BEGIN(SkipCommand); }
       
  1831 <SkipCPPBlock>^{B}*/[^#]		{ BEGIN(SkipLine); }
       
  1832 <SkipCPPBlock>\n			{ g_yyLineNr++; outputChar('\n'); }
       
  1833 <SkipCPPBlock>.
       
  1834 <SkipCommand>"if"(("n")?("def"))?/[ \t(!]	{ 
       
  1835   					  incrLevel();
       
  1836                                           g_ifcount++; 
       
  1837   					  //printf("#if... depth=%d\n",g_ifcount);
       
  1838 					}
       
  1839 <SkipCommand>"else"			{
       
  1840 					  //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
       
  1841   					  if (g_ifcount==0 && !otherCaseDone())
       
  1842 					  {
       
  1843 					    setCaseDone(TRUE);
       
  1844   					    //outputChar('\n');
       
  1845 					    BEGIN(Start);
       
  1846 					  }
       
  1847   					}
       
  1848 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!]		{
       
  1849   					  if (g_ifcount==0) 
       
  1850 					  {
       
  1851   					    if (!otherCaseDone())
       
  1852 					    {
       
  1853 					      g_guardExpr.resize(0);
       
  1854 					      g_lastGuardName.resize(0);
       
  1855   					      BEGIN(Guard);
       
  1856 					    }
       
  1857 					    else
       
  1858 					    {
       
  1859 					      BEGIN(SkipCPPBlock);
       
  1860 					    }
       
  1861 					  }
       
  1862 					}
       
  1863 <SkipCommand>"endif"			{ 
       
  1864   					  decrLevel();
       
  1865   				          if (--g_ifcount<0)
       
  1866   					  {
       
  1867   					    //outputChar('\n');
       
  1868 					    BEGIN(Start);
       
  1869 					  }
       
  1870 					}
       
  1871 <SkipCommand>\n				{ 
       
  1872   					  outputChar('\n');
       
  1873   					  g_yyLineNr++; 
       
  1874 					  BEGIN(SkipCPPBlock);
       
  1875 					}
       
  1876 <SkipCommand>{ID}			{ // unknown directive 
       
  1877   					  BEGIN(SkipLine); 
       
  1878 					}
       
  1879 <SkipCommand>.
       
  1880 <SkipLine>[^/\n]+			
       
  1881 <SkipLine>.
       
  1882 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
       
  1883   					  g_lastCPPContext=YY_START;
       
  1884   					  BEGIN(RemoveCPPComment);
       
  1885 					}
       
  1886 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
       
  1887 					  g_lastCContext=YY_START;
       
  1888   					  BEGIN(RemoveCComment);
       
  1889   					}
       
  1890 <SkipLine>\n				{
       
  1891   					  outputChar('\n');
       
  1892 					  g_yyLineNr++;  
       
  1893 					  BEGIN(SkipCPPBlock);
       
  1894 					}
       
  1895 <IncludeID>{ID}{B}*/"("			{
       
  1896   					  g_nospaces=TRUE;
       
  1897 				          g_roundCount=0;
       
  1898 					  g_defArgsStr=yytext;
       
  1899 					  g_findDefArgContext = IncludeID;
       
  1900 					  BEGIN(FindDefineArgs);
       
  1901 					}
       
  1902 <IncludeID>{ID}				{
       
  1903   					  g_nospaces=TRUE;
       
  1904                                           readIncludeFile(expandMacro(yytext));
       
  1905 					  BEGIN(Start);
       
  1906   					}
       
  1907 <Include>[^\">\n]+[\">]			{ 
       
  1908 					  g_incName+=yytext;
       
  1909 					  readIncludeFile(g_incName);
       
  1910 					  if (g_isImported)
       
  1911 					  {
       
  1912 					    BEGIN(EndImport);
       
  1913 					  }
       
  1914 					  else
       
  1915 					  {
       
  1916 					    BEGIN(Start);
       
  1917 					  }
       
  1918   					}
       
  1919 <EndImport>[^\\\n]*/\n			{
       
  1920   					  BEGIN(Start);
       
  1921   					}
       
  1922 <EndImport>\\[\r]?"\n"			{ 
       
  1923 					  outputChar('\n');
       
  1924 					  g_yyLineNr++;
       
  1925 					}
       
  1926 <EndImport>.				{
       
  1927   					}
       
  1928 <DefName>{ID}/"("			{
       
  1929   					  //printf("Define() `%s'\n",yytext);
       
  1930 					  g_argDict = new QDict<int>(31);
       
  1931 					  g_argDict->setAutoDelete(TRUE);
       
  1932 					  g_defArgs = 0; 
       
  1933                                           g_defArgsStr.resize(0);
       
  1934 					  g_defText.resize(0);
       
  1935 					  g_defLitText.resize(0);
       
  1936 					  g_defName = yytext;
       
  1937 					  g_defVarArgs = FALSE;
       
  1938 					  BEGIN(DefineArg);
       
  1939   					}
       
  1940 <DefName>{ID}/{B}*			{
       
  1941   					  //printf("Define `%s'\n",yytext);
       
  1942   					  g_argDict = 0;
       
  1943 					  g_defArgs = -1;
       
  1944                                           g_defArgsStr.resize(0);
       
  1945 					  g_defText.resize(0);
       
  1946 					  g_defLitText.resize(0);
       
  1947 					  g_defName = yytext;
       
  1948 					  g_defVarArgs = FALSE;
       
  1949 					  QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
       
  1950 					  outputArray(tmp.data(),tmp.length());
       
  1951 					  g_quoteArg=FALSE;
       
  1952 					  g_insideComment=FALSE;
       
  1953 					  BEGIN(DefineText); 
       
  1954   					}
       
  1955 <DefName>{ID}/{B}*"\n"			{ // bare define
       
  1956   					  g_argDict = 0;
       
  1957 					  g_defArgs = -1;
       
  1958 					  g_defName = yytext;
       
  1959                                           g_defArgsStr.resize(0);
       
  1960 					  g_defText.resize(0);
       
  1961 					  g_defLitText.resize(0);
       
  1962 					  g_defVarArgs = FALSE;
       
  1963 					  if ( g_defName!=g_lastGuardName || Config_getBool("PREPROCCESS_FULL_TU"))
       
  1964 					  { // define may appear in the output
       
  1965 					    QCString tmp=(QCString)"#define "+g_defName;
       
  1966 					    outputArray(tmp.data(),tmp.length());
       
  1967 					    g_quoteArg=FALSE;
       
  1968 					    g_insideComment=FALSE;
       
  1969 					    if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
       
  1970 					    BEGIN(DefineText);
       
  1971 					  }
       
  1972 					  else // define is a guard => hide
       
  1973 					  {
       
  1974 					    //printf("Found a guard %s\n",yytext);
       
  1975 #if 0
       
  1976   					    Define *def=g_fileDefineDict->find(g_defName);
       
  1977 					    if (def==0) // new define name for this file
       
  1978 					    {
       
  1979 					      g_fileDefineDict->insert(g_defName,newDefine());
       
  1980 					    }
       
  1981 					    else // name already exists
       
  1982 					    {
       
  1983 					      if (def->undef) // undefined name
       
  1984 					      {
       
  1985 					        def->undef = FALSE;
       
  1986 					        def->name = g_defName;
       
  1987 					        def->definition = g_defText.stripWhiteSpace();
       
  1988 					        def->nargs = g_defArgs;
       
  1989 					        def->fileName = g_yyFileName.copy(); 
       
  1990 					        def->lineNr = g_yyLineNr;
       
  1991 					      }
       
  1992 					      else
       
  1993 					      {
       
  1994 					        //printf("Error: define %s is defined more than once!\n",g_defName.data());
       
  1995 					      }
       
  1996 					    }
       
  1997 #endif
       
  1998 					    g_lastGuardName.resize(0);
       
  1999 					    BEGIN(Start);
       
  2000 					  }
       
  2001   					}
       
  2002 <DefineArg>","{B}*			{ g_defArgsStr+=yytext; }
       
  2003 <DefineArg>"("{B}*                      { g_defArgsStr+=yytext; }
       
  2004 <DefineArg>{B}*")"{B}*			{
       
  2005                                           g_defArgsStr+=yytext; 
       
  2006 					  QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
       
  2007 					  outputArray(tmp.data(),tmp.length());
       
  2008 					  g_quoteArg=FALSE;
       
  2009 					  g_insideComment=FALSE;
       
  2010   					  BEGIN(DefineText);
       
  2011   					}
       
  2012 <DefineArg>"..."			{ // Variadic macro
       
  2013 					  g_defVarArgs = TRUE;
       
  2014 					  g_defArgsStr+=yytext;
       
  2015 					  g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
       
  2016 					  g_defArgs++;
       
  2017   					}
       
  2018 <DefineArg>{ID}{B}*("..."?)		{
       
  2019   					  //printf("Define addArg(%s)\n",yytext);
       
  2020   					  QCString argName=yytext;
       
  2021   					  g_defVarArgs = yytext[yyleng-1]=='.';
       
  2022 					  if (g_defVarArgs) // strip ellipsis
       
  2023 					  {
       
  2024 					    argName=argName.left(argName.length()-3);
       
  2025 					  }
       
  2026 					  argName = argName.stripWhiteSpace();
       
  2027                                           g_defArgsStr+=yytext;
       
  2028 					  g_argDict->insert(argName,new int(g_defArgs)); 
       
  2029 					  g_defArgs++;
       
  2030   					}
       
  2031   /*
       
  2032 <DefineText>"/ **"|"/ *!"			{
       
  2033   					  g_defText+=yytext;
       
  2034 					  g_defLitText+=yytext;
       
  2035 					  g_insideComment=TRUE;
       
  2036   					}
       
  2037 <DefineText>"* /"			{
       
  2038   					  g_defText+=yytext;
       
  2039 					  g_defLitText+=yytext;
       
  2040 					  g_insideComment=FALSE;
       
  2041   					}
       
  2042   */
       
  2043 <DefineText>"/*"			{
       
  2044 					  g_defText+=yytext;
       
  2045 					  g_defLitText+=yytext;
       
  2046 					  g_lastCContext=YY_START;
       
  2047 					  g_commentCount=1;
       
  2048   					  BEGIN(CopyCComment);
       
  2049   					}
       
  2050 <DefineText>"//"			{
       
  2051   				          outputChar('/');outputChar('/');
       
  2052   					  g_lastCPPContext=YY_START;
       
  2053 					  g_defLitText+=' ';
       
  2054   					  BEGIN(SkipCPPComment);
       
  2055   					}
       
  2056 <SkipCComment>[/]?"*/"			{
       
  2057   					  if (yytext[0]=='/') outputChar('/');
       
  2058   					  outputChar('*');outputChar('/');
       
  2059 					  if (--g_commentCount<=0)
       
  2060 					  {
       
  2061 					    if (g_lastCContext==Start) 
       
  2062 					      // small hack to make sure that ^... rule will
       
  2063 					      // match when going to Start... Example: "/*...*/ some stuff..."
       
  2064 					    {
       
  2065 					      YY_CURRENT_BUFFER->yy_at_bol=1;
       
  2066 					    }
       
  2067   					    BEGIN(g_lastCContext);  
       
  2068 					  }
       
  2069   					}
       
  2070 <SkipCComment>"//"("/")*		{
       
  2071   					  outputArray(yytext,yyleng);
       
  2072   					}
       
  2073 <SkipCComment>"/*"			{
       
  2074   					  outputChar('/');outputChar('*');
       
  2075 					  //g_commentCount++;
       
  2076   					}
       
  2077 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
       
  2078   					  outputArray(yytext,yyleng);
       
  2079   					}
       
  2080 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ {
       
  2081   					  outputArray(yytext,yyleng);
       
  2082   					  g_yyLineNr+=QCString(yytext).contains('\n');
       
  2083   					}
       
  2084 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+	{
       
  2085   					  outputArray(yytext,yyleng);
       
  2086   					  g_yyLineNr+=QCString(yytext).contains('\n');
       
  2087 					  if (yytext[1]=='f')
       
  2088 					  {
       
  2089 					    g_blockName="f";
       
  2090 					  }
       
  2091 					  else
       
  2092 					  {
       
  2093 					    g_blockName=QCString(&yytext[1]).stripWhiteSpace();
       
  2094 					  }
       
  2095 					  BEGIN(SkipVerbatim);
       
  2096   					}
       
  2097 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t]+	{ // conditional section
       
  2098   					  g_condCtx = YY_START;
       
  2099   					  outputArray(yytext,yyleng);
       
  2100   					  BEGIN(CondLine);
       
  2101   					}
       
  2102 <CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]*	{
       
  2103   				          startCondSection(yytext);
       
  2104   					  outputArray(yytext,yyleng);
       
  2105   					  BEGIN(g_condCtx);
       
  2106   					}
       
  2107 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*\n  |
       
  2108 <CondLine>.				{
       
  2109   					  outputArray(yytext,yyleng);
       
  2110   					  g_yyLineNr+=QCString(yytext).contains('\n');
       
  2111   					  startCondSection(" ");
       
  2112 					  if (YY_START==CondLine) BEGIN(g_condCtx);
       
  2113   					}
       
  2114 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9] {
       
  2115   					  outputArray(yytext,yyleng);
       
  2116   					  endCondSection();
       
  2117   					}
       
  2118 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
       
  2119   					  outputArray(yytext,yyleng);
       
  2120 					  if (yytext[1]=='f' && g_blockName=="f")
       
  2121 					  {
       
  2122 					    BEGIN(SkipCComment);
       
  2123 					  }
       
  2124 					  else if (&yytext[4]==g_blockName)
       
  2125 					  {
       
  2126 					    BEGIN(SkipCComment);
       
  2127 					  }
       
  2128   					}
       
  2129 <SkipVerbatim>"*/"|"/*"			{
       
  2130   					  outputArray(yytext,yyleng);
       
  2131   					}
       
  2132 <SkipCComment,SkipVerbatim>[^*\\@\x06\n\/]+ {
       
  2133   					  outputArray(yytext,yyleng);
       
  2134   					}
       
  2135 <SkipCComment,SkipVerbatim>\n		{ 
       
  2136   					  g_yyLineNr++;
       
  2137   					  outputChar('\n');
       
  2138   					}
       
  2139 <SkipCComment,SkipVerbatim>.		{
       
  2140   					  outputChar(*yytext);
       
  2141   					}
       
  2142 <CopyCComment>[^*a-z_A-Z\n]+		{
       
  2143 					  g_defLitText+=yytext;
       
  2144 					  g_defText+=escapeAt(yytext);
       
  2145   					}
       
  2146 <CopyCComment>"*/"			{
       
  2147 					  g_defLitText+=yytext;
       
  2148 					  g_defText+=yytext;
       
  2149   					  BEGIN(g_lastCContext);
       
  2150   					}
       
  2151 <CopyCComment>\n			{ 
       
  2152   					  g_yyLineNr++;
       
  2153 					  g_defLitText+=yytext;
       
  2154 					  g_defText+=' ';
       
  2155   					}
       
  2156 <RemoveCComment>"*/"		        { BEGIN(g_lastCContext); }
       
  2157 <RemoveCComment>"//"			
       
  2158 <RemoveCComment>"/*"
       
  2159 <RemoveCComment>[^*\x06\n]+
       
  2160 <RemoveCComment>\n			{ g_yyLineNr++; outputChar('\n'); }
       
  2161 <RemoveCComment>.			
       
  2162 <SkipCPPComment>[^\n\/\\@]+		{
       
  2163   					  outputArray(yytext,yyleng);
       
  2164   					}
       
  2165 <SkipCPPComment,RemoveCPPComment>\n	{
       
  2166   					  unput(*yytext);
       
  2167   					  BEGIN(g_lastCPPContext);
       
  2168   					}
       
  2169 <SkipCPPComment>"/*"			{
       
  2170   					  outputChar('/');outputChar('*');
       
  2171   					}
       
  2172 <SkipCPPComment>"//"			{
       
  2173   					  outputChar('/');outputChar('/');
       
  2174   					}
       
  2175 <SkipCPPComment>[^\x06\@\\\n]+		{
       
  2176   					  outputArray(yytext,yyleng);
       
  2177   					}
       
  2178 <SkipCPPComment>.			{
       
  2179   					  outputChar(*yytext);
       
  2180   					}
       
  2181 <RemoveCPPComment>"/*"
       
  2182 <RemoveCPPComment>"//"
       
  2183 <RemoveCPPComment>[^\x06\n]+
       
  2184 <RemoveCPPComment>.
       
  2185 <DefineText>"#"				{
       
  2186   					  g_quoteArg=TRUE;
       
  2187 					  g_defLitText+=yytext;
       
  2188   					}
       
  2189 <DefineText,CopyCComment>{ID}		{
       
  2190 					  g_defLitText+=yytext;
       
  2191   					  if (g_quoteArg)
       
  2192 					  {
       
  2193 					    g_defText+="\"";
       
  2194 					  }
       
  2195 					  if (g_defArgs>0)
       
  2196 					  {
       
  2197 					    int *n;
       
  2198 					    if ((n=(*g_argDict)[yytext]))
       
  2199 					    {
       
  2200 					      //if (!g_quoteArg) g_defText+=' ';
       
  2201 					      g_defText+='@';
       
  2202 					      QCString numStr;
       
  2203 					      numStr.sprintf("%d",*n);
       
  2204 					      g_defText+=numStr;
       
  2205 					      //if (!g_quoteArg) g_defText+=' ';
       
  2206 					    }
       
  2207 					    else
       
  2208 					    {
       
  2209 					      g_defText+=yytext;
       
  2210 					    }
       
  2211 					  }
       
  2212 					  else
       
  2213 					  {
       
  2214 					    g_defText+=yytext;
       
  2215 					  }
       
  2216 					  if (g_quoteArg)
       
  2217 					  {
       
  2218 					    g_defText+="\"";
       
  2219 					  }
       
  2220 					  g_quoteArg=FALSE;
       
  2221   					}
       
  2222 <CopyCComment>.				{
       
  2223 					  g_defLitText+=yytext;
       
  2224 					  g_defText+=yytext;
       
  2225   					}
       
  2226 <DefineText>\\[\r]?\n			{ 
       
  2227 					  g_defLitText+=yytext;
       
  2228 					  outputChar('\n');
       
  2229   					  g_defText += ' '; g_yyLineNr++; 
       
  2230 					}
       
  2231 <DefineText>\n				{
       
  2232 					  QCString comment=extractTrailingComment(g_defLitText);
       
  2233 					  g_defLitText+=yytext;
       
  2234 					  if (!comment.isEmpty())
       
  2235 					  {
       
  2236 					    outputArray(comment,comment.length());
       
  2237 					    g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
       
  2238 					  }
       
  2239   					  outputChar('\n');
       
  2240   					  Define *def=0;
       
  2241 					  //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
       
  2242 					  if (g_includeStack.isEmpty() || g_curlyCount>0) 
       
  2243 					  {
       
  2244 					    addDefine();
       
  2245 					  }
       
  2246 					  def=g_fileDefineDict->find(g_defName);
       
  2247 					  if (def==0) // new define
       
  2248 					  {
       
  2249 					    //printf("new define!\n");
       
  2250 					    g_fileDefineDict->insert(g_defName,newDefine());
       
  2251 					  }
       
  2252 					  else if (def)// name already exists
       
  2253 					  {
       
  2254 					    //printf("existing define!\n");
       
  2255 					    //printf("define found\n");
       
  2256 					    if (def->undef) // undefined name
       
  2257 					    {
       
  2258 					      def->undef = FALSE;
       
  2259 					      def->name = g_defName;
       
  2260 					      def->definition = g_defText.stripWhiteSpace();
       
  2261 					      def->nargs = g_defArgs;
       
  2262 					      def->fileName = g_yyFileName.copy(); 
       
  2263 					      def->lineNr = g_yyLineNr;
       
  2264 					    }
       
  2265 					    else
       
  2266 					    {
       
  2267 					      //printf("Error: define %s is defined more than once!\n",g_defName.data());
       
  2268 					    }
       
  2269 					  }
       
  2270 					  delete g_argDict; g_argDict=0;
       
  2271 					  g_yyLineNr++;
       
  2272 					  g_lastGuardName.resize(0);
       
  2273 					  BEGIN(Start);
       
  2274   					}
       
  2275 <DefineText>{B}*			{ g_defText += ' '; g_defLitText+=yytext; }
       
  2276 <DefineText>{B}*"##"{B}*		{ g_defText += "##"; g_defLitText+=yytext; }
       
  2277 <DefineText>"@"				{ g_defText += "@@"; g_defLitText+=yytext; }
       
  2278 <DefineText>\"				{ 
       
  2279                                           g_defText += *yytext; 
       
  2280   					  g_defLitText+=yytext; 
       
  2281 					  if (!g_insideComment)
       
  2282 					  {
       
  2283 					    BEGIN(SkipDoubleQuote);
       
  2284 					  }
       
  2285   					}
       
  2286 <DefineText>\'				{ g_defText += *yytext;
       
  2287   					  g_defLitText+=yytext; 
       
  2288 					  if (!g_insideComment)
       
  2289 					  {
       
  2290   					    BEGIN(SkipSingleQuote);
       
  2291 					  }
       
  2292 					}
       
  2293 <SkipDoubleQuote>"//"			{ g_defText += yytext; g_defLitText+=yytext; }
       
  2294 <SkipDoubleQuote>"/*"			{ g_defText += yytext; g_defLitText+=yytext; }
       
  2295 <SkipDoubleQuote>\"			{
       
  2296   					  g_defText += *yytext; g_defLitText+=yytext; 
       
  2297 					  BEGIN(DefineText);
       
  2298   					}
       
  2299 <SkipSingleQuote,SkipDoubleQuote>\\.	{
       
  2300   					  g_defText += yytext; g_defLitText+=yytext;
       
  2301 					}
       
  2302 <SkipSingleQuote>\'			{
       
  2303   					  g_defText += *yytext; g_defLitText+=yytext;
       
  2304 					  BEGIN(DefineText);
       
  2305   					}
       
  2306 <SkipDoubleQuote>.			{ g_defText += *yytext; g_defLitText+=yytext; }
       
  2307 <SkipSingleQuote>.			{ g_defText += *yytext; g_defLitText+=yytext; }
       
  2308 <DefineText>.				{ g_defText += *yytext; g_defLitText+=yytext; }
       
  2309 <<EOF>>					{
       
  2310                                           //fprintf(stderr,"End of include file\n");
       
  2311 					  //printf("Include stack depth=%d\n",g_includeStack.count());
       
  2312   					  if (g_includeStack.isEmpty())
       
  2313 					  {
       
  2314 					    //fprintf(stderr,"Terminating scanner!\n");
       
  2315 					    yyterminate();
       
  2316 					  }
       
  2317 					  else
       
  2318 					  {
       
  2319 					    FileState *fs=g_includeStack.pop();
       
  2320 					    //fileDefineCache->merge(g_yyFileName,fs->fileName);
       
  2321 #if 0
       
  2322 					    if (fs->isPlainFile)
       
  2323 					    {
       
  2324 					      if (fs->filePtr && fclose(fs->filePtr)!=0)
       
  2325 					      {
       
  2326 						err("Error: could not close file %s: %s\n",fs->fileName.data(),strerror(errno));
       
  2327 					      }
       
  2328 				              fs->filePtr=0;
       
  2329 					    }
       
  2330 					    else
       
  2331 					    {
       
  2332 					      if (fs->filePtr && portable_pclose(fs->filePtr)!=0)
       
  2333 					      {
       
  2334 						err("Error: could not close pipe: %s\n",strerror(errno));
       
  2335 					      }
       
  2336 				    	      fs->filePtr=0;
       
  2337 					    }
       
  2338 #endif
       
  2339 					    YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
       
  2340 					    yy_switch_to_buffer( fs->bufState );
       
  2341 					    yy_delete_buffer( oldBuf );
       
  2342 					    g_yyLineNr=fs->lineNr;
       
  2343                                             //preYYin = fs->oldYYin;
       
  2344                                             g_inputBuf = fs->oldFileBuf;
       
  2345 					    g_inputBufPos = fs->oldFileBufPos;
       
  2346 					    setFileName(fs->fileName.copy());
       
  2347 					    //fprintf(stderr,"######## FileName %s\n",g_yyFileName.data());
       
  2348 					    
       
  2349                                             // Deal with file changes due to 
       
  2350                                             // #include's within { .. } blocks
       
  2351                                             QCString lineStr(15+g_yyFileName.length());
       
  2352                                             lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
       
  2353                                             outputArray(lineStr.data(),lineStr.length());
       
  2354 					    
       
  2355 					    delete fs; fs=0;
       
  2356 					  }
       
  2357   					}
       
  2358 <*>"/*"/"*/"				|
       
  2359 <*>"/*"[*]?				{
       
  2360 					  outputArray(yytext,yyleng);
       
  2361   					  g_lastCContext=YY_START;
       
  2362 					  g_commentCount=1;
       
  2363 					  if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
       
  2364 					  BEGIN(SkipCComment);
       
  2365   					}
       
  2366 <*>"//"[/]?				{
       
  2367 					  outputArray(yytext,yyleng);
       
  2368   					  g_lastCPPContext=YY_START;
       
  2369 					  if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
       
  2370 					  BEGIN(SkipCPPComment);
       
  2371 					}
       
  2372 <*>\n					{ 
       
  2373   					  outputChar('\n');
       
  2374   					  g_yyLineNr++; 
       
  2375 					}
       
  2376 <*>.				        {
       
  2377   					  outputChar(*yytext);
       
  2378   					}
       
  2379 
       
  2380 %%
       
  2381 
       
  2382 /*@ ----------------------------------------------------------------------------
       
  2383  */
       
  2384 
       
  2385 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
       
  2386 {
       
  2387   //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
       
  2388   if (pos<expr.length())
       
  2389   {
       
  2390     //printf("%c=expr()\n",expr.at(pos));
       
  2391     return expr.at(pos++);
       
  2392   }
       
  2393   else if (rest && !rest->isEmpty())
       
  2394   {
       
  2395     int cc=rest->at(0);
       
  2396     *rest=rest->right(rest->length()-1);
       
  2397     //printf("%c=rest\n",cc);
       
  2398     return cc;
       
  2399   }
       
  2400   else
       
  2401   {
       
  2402     int cc=yyinput();
       
  2403     //printf("%c=yyinput()\n",cc);
       
  2404     return cc;
       
  2405   }
       
  2406 }
       
  2407  
       
  2408 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
       
  2409 {
       
  2410   //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
       
  2411   if (pos<expr.length())
       
  2412   {
       
  2413     //printf("%c=expr()\n",expr.at(pos));
       
  2414     return expr.at(pos);
       
  2415   }
       
  2416   else if (rest && !rest->isEmpty())
       
  2417   {
       
  2418     int cc=rest->at(0);
       
  2419     //printf("%c=rest\n",cc);
       
  2420     return cc;
       
  2421   }
       
  2422   else
       
  2423   {
       
  2424     int cc=yyinput();
       
  2425     returnCharToStream(cc);
       
  2426     //unput((char)cc);
       
  2427     //printf("%c=yyinput()\n",cc);
       
  2428     return cc;
       
  2429   }
       
  2430 }
       
  2431 
       
  2432 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
       
  2433 {
       
  2434   //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
       
  2435   if (pos<expr.length())
       
  2436   {
       
  2437     pos++;
       
  2438   }
       
  2439   else if (rest)
       
  2440   {
       
  2441     //printf("Prepending to rest!\n");
       
  2442     char cs[2];cs[0]=c;cs[1]='\0';
       
  2443     rest->prepend(cs);
       
  2444   }
       
  2445   else
       
  2446   {
       
  2447     //unput(c);
       
  2448     returnCharToStream(c);
       
  2449   }
       
  2450   //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
       
  2451 }
       
  2452 
       
  2453 void addSearchDir(const char *dir)
       
  2454 {
       
  2455   QFileInfo fi(dir);
       
  2456   if (fi.isDir()) g_pathList->append(fi.absFilePath());
       
  2457 } 
       
  2458 
       
  2459 void initPreprocessor()
       
  2460 {
       
  2461   g_pathList = new QStrList;
       
  2462   addSearchDir(".");
       
  2463   //defineNameList.setAutoDelete(TRUE);
       
  2464   //defineNameList.clear();
       
  2465   //defineDict.clear();
       
  2466   //fileDefineCache = new DefineCache(1009);
       
  2467   g_expandedDict = new DefineDict(17);
       
  2468   //g_fileDefineDict = new DefineDict(1009);
       
  2469 }
       
  2470 
       
  2471 void cleanUpPreprocessor()
       
  2472 {
       
  2473   //delete fileDefineCache;
       
  2474   //delete g_fileDefineDict; g_fileDefineDict=0;
       
  2475   delete g_expandedDict; g_expandedDict=0;
       
  2476   delete g_pathList; g_pathList=0;
       
  2477 }
       
  2478 
       
  2479 void dumpDefineDict(const DefineDict *theDefDict)
       
  2480 {
       
  2481 	if (Debug::isFlagSet(Debug::Preprocessor)) {
       
  2482 		// Make a map to sort the macros in alphbetical order
       
  2483 		typedef QMap<QString, Define*> DefineMapType;
       
  2484 		DefineMapType DefineMap;
       
  2485 		Define *def = 0;
       
  2486 		QDictIterator<Define> it(*theDefDict);
       
  2487 		while (it.current()) {
       
  2488 			def = it.current();
       
  2489 			DefineMap.insert(def->name, def);
       
  2490 			++it;
       
  2491 		}
       
  2492 		// Now write them out
       
  2493 		DefineMapType::Iterator mapIt;
       
  2494 		for (mapIt = DefineMap.begin(); mapIt != DefineMap.end(); ++mapIt) {
       
  2495 			def = mapIt.data();
       
  2496 			QString myDecl = def->name;
       
  2497 			if (def->nargs > 0) {
       
  2498 				myDecl.append("(");
       
  2499 				myDecl.append(def->args);
       
  2500 				myDecl.append(")");
       
  2501 			}
       
  2502 			printf("#define %s %s /* %s %d */\n",
       
  2503 				myDecl.data(),
       
  2504 				def->definition.data(),
       
  2505 				def->fileName.data(),
       
  2506 				def->lineNr
       
  2507 				);
       
  2508 		}
       
  2509 	}
       
  2510 }
       
  2511 
       
  2512 void dumpDefineDicts()
       
  2513 {
       
  2514 	if (Debug::isFlagSet(Debug::Preprocessor)) {
       
  2515 		printf("g_expandedDict:\n");
       
  2516 		dumpDefineDict(g_expandedDict);
       
  2517 		printf("g_fileDefineDict:\n");
       
  2518 		dumpDefineDict(g_fileDefineDict);
       
  2519 	}
       
  2520 }
       
  2521 
       
  2522 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
       
  2523 {
       
  2524   uint orgOffset=output.curPos();
       
  2525   //printf("##########################\n%s\n####################\n",
       
  2526   //    input.data());
       
  2527 
       
  2528   g_macroExpansion = Config_getBool("MACRO_EXPANSION");
       
  2529   g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
       
  2530   g_curlyCount=0;
       
  2531   g_nospaces=FALSE;
       
  2532   g_inputBuf=&input;
       
  2533   g_inputBufPos=0;
       
  2534   g_outputBuf=&output;
       
  2535   g_includeStack.setAutoDelete(TRUE);
       
  2536   g_includeStack.clear();
       
  2537   //g_fileDefineDict->setAutoDelete(TRUE);
       
  2538   //g_fileDefineDict->clear();
       
  2539   g_expandedDict->setAutoDelete(FALSE);
       
  2540   g_expandedDict->clear();
       
  2541   g_condStack.clear();
       
  2542   g_condStack.setAutoDelete(TRUE);
       
  2543   static bool firstTime=TRUE;
       
  2544   if (firstTime)
       
  2545   {
       
  2546     // add predefined macros
       
  2547     char *defStr;
       
  2548     QStrList &predefList = Config_getList("PREDEFINED");
       
  2549     QStrListIterator sli(predefList);
       
  2550     for (sli.toFirst();(defStr=sli.current());++sli)
       
  2551     {
       
  2552       QCString ds = defStr;
       
  2553       int i_equals=ds.find('=');
       
  2554       int i_obrace=ds.find('(');
       
  2555       int i_cbrace=ds.find(')');
       
  2556       bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
       
  2557 
       
  2558       if (i_obrace==0) continue; // no define name
       
  2559 
       
  2560       if (i_obrace<i_equals && i_cbrace<i_equals && 
       
  2561 	  i_obrace!=-1      && i_cbrace!=-1      && 
       
  2562 	  i_obrace<i_cbrace
       
  2563 	 ) // predefined function macro definition
       
  2564       {
       
  2565 	QRegExp reId("[a-z_A-Z][a-z_A-Z0-9]*"); // regexp matching an id
       
  2566 	QDict<int> argDict(17);
       
  2567 	argDict.setAutoDelete(TRUE);
       
  2568 	int i=i_obrace+1,p,l,count=0;
       
  2569 	// gather the formal arguments in a dictionary 
       
  2570 	while (i<i_cbrace && (p=reId.match(ds,i,&l)))
       
  2571 	{
       
  2572 	  argDict.insert(ds.mid(p,l),new int(count++));
       
  2573 	  i=p+l;
       
  2574 	}
       
  2575 	// strip definition part
       
  2576 	QCString tmp=ds.right(ds.length()-i_equals-1);
       
  2577 	QCString definition;
       
  2578 	i=0;
       
  2579 	// substitute all occurrences of formal arguments by their 
       
  2580 	// corresponding markers
       
  2581 	while ((p=reId.match(tmp,i,&l))!=-1)
       
  2582 	{
       
  2583 	  if (p>i) definition+=tmp.mid(i,p-i);
       
  2584 	  int *argIndex;
       
  2585 	  if ((argIndex=argDict[tmp.mid(p,l)])!=0)
       
  2586 	  {
       
  2587 	    QCString marker;
       
  2588 	    marker.sprintf(" @%d ",*argIndex);
       
  2589 	    definition+=marker;
       
  2590 	  }
       
  2591 	  else
       
  2592 	  {
       
  2593 	    definition+=tmp.mid(p,l);
       
  2594 	  }
       
  2595 	  i=p+l;
       
  2596 	}
       
  2597 	if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
       
  2598 
       
  2599 	// add define definition to the dictionary of defines for this file
       
  2600 	QCString dname = ds.left(i_obrace);
       
  2601 	if (!dname.isEmpty())
       
  2602 	{
       
  2603 	  Define *def = new Define;
       
  2604 	  def->name = dname;
       
  2605 	  def->definition = definition; 
       
  2606 	  def->nargs = count;
       
  2607 	  def->isPredefined = TRUE;
       
  2608 	  def->nonRecursive = nonRecursive;
       
  2609 	  g_fileDefineDict->insert(def->name,def);
       
  2610 	}
       
  2611 
       
  2612 	//printf("#define `%s' `%s' #nargs=%d\n",
       
  2613 	//  def->name.data(),def->definition.data(),def->nargs);
       
  2614       }
       
  2615       else if ((i_obrace==-1 || i_obrace>i_equals) &&
       
  2616 	  (i_cbrace==-1 || i_cbrace>i_equals) &&
       
  2617 	  !ds.isEmpty() && (int)ds.length()>i_equals
       
  2618 	  ) // predefined non-function macro definition
       
  2619       {
       
  2620 	Define *def = new Define;
       
  2621 	if (i_equals==-1) // simple define without argument
       
  2622 	{
       
  2623 	  def->name = ds;
       
  2624 	  def->definition = "1"; // substitute occurrences by 1 (true)
       
  2625 	}
       
  2626 	else // simple define with argument
       
  2627 	{
       
  2628 	  int ine=i_equals - (nonRecursive ? 1 : 0);
       
  2629 	  def->name = ds.left(ine);
       
  2630 	  def->definition = ds.right(ds.length()-i_equals-1);
       
  2631 	}
       
  2632 	if (!def->name.isEmpty())
       
  2633 	{
       
  2634 	  def->nargs = -1;
       
  2635 	  def->isPredefined = TRUE;
       
  2636 	  def->nonRecursive = nonRecursive;
       
  2637 	  g_fileDefineDict->insert(def->name,def);
       
  2638 	}
       
  2639 	else
       
  2640 	{
       
  2641 	  delete def;
       
  2642 	}
       
  2643 
       
  2644 	//printf("#define `%s' `%s' #nargs=%d\n",
       
  2645 	//  def->name.data(),def->definition.data(),def->nargs);
       
  2646       }
       
  2647     }
       
  2648     firstTime=FALSE;
       
  2649   }
       
  2650  
       
  2651 #if 0
       
  2652   QCString inputFilter = getFileFilter(fileName);
       
  2653   if (inputFilter.isEmpty())
       
  2654   {
       
  2655     preYYin = fopen(fileName,"r");
       
  2656     if (!preYYin)
       
  2657     {
       
  2658       err("Error: could not open file %s\n",fileName);
       
  2659       return;
       
  2660     }
       
  2661   }
       
  2662   else
       
  2663   {
       
  2664     QCString cmd = inputFilter+" \""+fileName+"\"";
       
  2665     Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
       
  2666     preYYin = portable_popen(cmd,"r");
       
  2667     if (!preYYin)
       
  2668     {
       
  2669       err("Error: could not execute filter %s\n",cmd.data());
       
  2670       return;
       
  2671     }
       
  2672   }
       
  2673 #endif
       
  2674   g_yyLineNr = 1;
       
  2675   g_level    = 0;
       
  2676   g_ifcount  = 0;
       
  2677   setFileName(fileName);
       
  2678   g_inputFileDef = g_yyFileDef;
       
  2679   BEGIN( Start );
       
  2680   
       
  2681   g_lastGuardName.resize(0);
       
  2682   g_guardExpr.resize(0);
       
  2683   
       
  2684   preYYlex();
       
  2685   g_lexInit=TRUE;
       
  2686 
       
  2687 #if 0
       
  2688   if (inputFilter.isEmpty())
       
  2689     fclose(preYYin);
       
  2690   else
       
  2691     portable_pclose(preYYin);
       
  2692 #endif
       
  2693   
       
  2694   if (Debug::isFlagSet(Debug::Preprocessor))
       
  2695   {
       
  2696 	printf("preprocessFile() dump from %d to %d\n", orgOffset, output.curPos());
       
  2697     char *orgPos=output.data()+orgOffset;
       
  2698     char *newPos=output.data()+output.curPos();
       
  2699     printf("Preprocessor output (size: %d bytes):\n",newPos-orgPos);
       
  2700     int line=1;
       
  2701     printf("---------\n00001 ");
       
  2702     while (orgPos<newPos) 
       
  2703     {
       
  2704       putchar(*orgPos);
       
  2705       if (*orgPos=='\n') printf("%05d ",++line);
       
  2706       orgPos++;
       
  2707     }
       
  2708     printf("\n---------\n");
       
  2709 	dumpDefineDicts();
       
  2710   }
       
  2711 }
       
  2712 
       
  2713 void preFreeScanner()
       
  2714 {
       
  2715 #if defined(YY_FLEX_SUBMINOR_VERSION) 
       
  2716   if (g_lexInit)
       
  2717   {
       
  2718     preYYlex_destroy();
       
  2719   }
       
  2720 #endif
       
  2721 }
       
  2722 
       
  2723 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
       
  2724 extern "C" { // some bogus code to keep the compiler happy
       
  2725 //  int  preYYwrap() { return 1 ; }
       
  2726   void preYYdummy() { yy_flex_realloc(0,0); } 
       
  2727 }
       
  2728 #endif
       
  2729