From 1919a8e0457925ff63d91a0227729340121d461e Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Sat, 9 Nov 2019 14:01:22 +0100 Subject: Make preprocess code reentrant --- src/doxygen.cpp | 10 +- src/doxygen.h | 2 + src/pre.h | 16 +- src/pre.l | 4689 ++++++++++++++++++++++++++++--------------------------- 4 files changed, 2383 insertions(+), 2334 deletions(-) diff --git a/src/doxygen.cpp b/src/doxygen.cpp index bf282b6..b0b3e67 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -171,6 +171,7 @@ bool Doxygen::generatingXmlOutput = FALSE; bool Doxygen::markdownSupport = TRUE; GenericsSDict *Doxygen::genericsDict; DocGroup Doxygen::docGroup; +Preprocessor *Doxygen::preprocessor = 0; // locally accessible globals static std::unordered_map< std::string, const Entry* > g_classEntries; @@ -9395,7 +9396,7 @@ static void parseFile(ParserInterface *parser, BufStr inBuf(fi.size()+4096); msg("Preprocessing %s...\n",fn); readInputFile(fileName,inBuf); - preprocessFile(fileName,inBuf,preBuf); + Doxygen::preprocessor->processFile(fileName,inBuf,preBuf); } else // no preprocessing { @@ -10078,7 +10079,7 @@ void initDoxygen() portable_correct_path(); Doxygen::runningTime.start(); - initPreprocessor(); + Doxygen::preprocessor = new Preprocessor(); Doxygen::parserManager = new ParserManager; Doxygen::parserManager->registerDefaultParser( new FileParser); @@ -10182,7 +10183,7 @@ void cleanUpDoxygen() delete Doxygen::globalScope; delete Doxygen::xrefLists; delete Doxygen::parserManager; - cleanUpPreprocessor(); + delete Doxygen::preprocessor; delete theTranslator; delete g_outputList; Mappers::freeMappers(); @@ -10662,7 +10663,7 @@ void adjustConfiguration() while (s) { QFileInfo fi(s); - addSearchDir(fi.absFilePath().utf8()); + Doxygen::preprocessor->addSearchDir(fi.absFilePath().utf8()); s=includePath.next(); } @@ -11266,7 +11267,6 @@ void parseInput() // we are done with input scanning now, so free up the buffers used by flex // (can be around 4MB) - preFreeScanner(); scanFreeScanner(); pyscanFreeScanner(); diff --git a/src/doxygen.h b/src/doxygen.h index c8eee7c..a23a678 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -60,6 +60,7 @@ class FormulaList; class FormulaDict; class FormulaNameDict; class SectionDict; +class Preprocessor; struct MemberGroupInfo; typedef QList StringList; @@ -152,6 +153,7 @@ class Doxygen static bool markdownSupport; static GenericsSDict *genericsDict; static DocGroup docGroup; + static Preprocessor *preprocessor; }; void initDoxygen(); diff --git a/src/pre.h b/src/pre.h index 190673f..193ab60 100644 --- a/src/pre.h +++ b/src/pre.h @@ -20,10 +20,16 @@ class BufStr; -void initPreprocessor(); -void cleanUpPreprocessor(); -void addSearchDir(const char *dir); -void preprocessFile(const char *fileName,BufStr &input,BufStr &output); -void preFreeScanner(); +class Preprocessor +{ + public: + Preprocessor(); + ~Preprocessor(); + void processFile(const char *fileName,BufStr &input,BufStr &output); + void addSearchDir(const char *dir); + private: + class Private; + Private *p; +}; #endif diff --git a/src/pre.l b/src/pre.l index 5e46110..0541b46 100644 --- a/src/pre.l +++ b/src/pre.l @@ -16,6 +16,8 @@ */ %option never-interactive %option prefix="preYY" +%option reentrant +%option extra-type="struct preYY_state *" %{ @@ -96,7 +98,8 @@ class DefineManager { public: /** Creates an empty container for defines */ - DefinesPerFile() : m_defines(257), m_includedFiles(17) + DefinesPerFile(DefineManager *parent) + : m_parent(parent), m_defines(257), m_includedFiles(17) { m_defines.setAutoDelete(TRUE); } @@ -126,24 +129,25 @@ class DefineManager } void collectDefines(DefineDict *dict,QDict &includeStack); private: + DefineManager *m_parent; DefineDict m_defines; QDict m_includedFiles; }; public: friend class DefinesPerFile; - /** Returns a reference to the singleton */ - static DefineManager &instance() + + /** Creates a new DefineManager object */ + DefineManager() : m_fileMap(1009), m_contextDefines(1009) { - if (theInstance==0) theInstance = new DefineManager; - return *theInstance; + m_fileMap.setAutoDelete(TRUE); } - /** Deletes the singleton */ - static void deleteInstance() + + /** Destroys the object */ + virtual ~DefineManager() { - delete theInstance; - theInstance = 0; } + /** Starts a context in which defines are collected. * Called at the start of a new file that is preprocessed. * @param fileName the name of the file to process. @@ -157,7 +161,7 @@ class DefineManager if (dpf==0) { //printf("New file!\n"); - dpf = new DefinesPerFile; + dpf = new DefinesPerFile(this); m_fileMap.insert(fileName,dpf); } } @@ -182,7 +186,7 @@ class DefineManager if (dpf==0) { //printf("New file!\n"); - dpf = new DefinesPerFile; + dpf = new DefinesPerFile(this); m_fileMap.insert(fileName,dpf); } else @@ -211,7 +215,7 @@ class DefineManager DefinesPerFile *dpf = m_fileMap.find(fileName); if (dpf==0) { - dpf = new DefinesPerFile; + dpf = new DefinesPerFile(this); m_fileMap.insert(fileName,dpf); } dpf->addDefine(def); @@ -228,7 +232,7 @@ class DefineManager DefinesPerFile *dpf = m_fileMap.find(fromFileName); if (dpf==0) { - dpf = new DefinesPerFile; + dpf = new DefinesPerFile(this); m_fileMap.insert(fromFileName,dpf); } dpf->addInclude(toFileName); @@ -248,9 +252,8 @@ class DefineManager { return m_contextDefines; } - private: - static DefineManager *theInstance; + private: /** Helper function to collect all define for a given file */ void collectDefinesForFile(const char *fileName,DefineDict *dict) { @@ -270,23 +273,10 @@ class DefineManager return m_fileMap.find(fileName); } - /** Creates a new DefineManager object */ - DefineManager() : m_fileMap(1009), m_contextDefines(1009) - { - m_fileMap.setAutoDelete(TRUE); - } - - /** Destroys the object */ - virtual ~DefineManager() - { - } - QDict m_fileMap; DefineDict m_contextDefines; }; -/** Singleton instance */ -DefineManager *DefineManager::theInstance = 0; /** Collects all defines for a file and all files that the file includes. * This function will recursively call itself for each file. @@ -304,7 +294,7 @@ void DefineManager::DefinesPerFile::collectDefines( for (di.toFirst();(di.current());++di) { QCString incFile = di.currentKey(); - DefinesPerFile *dpf = DefineManager::instance().find(incFile); + DefinesPerFile *dpf = m_parent->find(incFile); if (dpf && includeStack.find(incFile)==0) { //printf(" processing include %s\n",incFile.data()); @@ -334,1903 +324,560 @@ void DefineManager::DefinesPerFile::collectDefines( * scanner's state */ -static int g_yyLineNr = 1; -static int g_yyMLines = 1; -static int g_yyColNr = 1; -static QCString g_yyFileName; -static FileDef *g_yyFileDef; -static FileDef *g_inputFileDef; -static int g_ifcount = 0; -static QStrList *g_pathList = 0; -static QStack g_includeStack; -static QDict *g_argDict; -static int g_defArgs = -1; -static QCString g_defName; -static QCString g_defText; -static QCString g_defLitText; -static QCString g_defArgsStr; -static QCString g_defExtraSpacing; -static bool g_defVarArgs; -static int g_level; -static int g_lastCContext; -static int g_lastCPPContext; -static QArray g_levelGuard; -static BufStr *g_inputBuf; -static int g_inputBufPos; -static BufStr *g_outputBuf; -static int g_roundCount; -static bool g_quoteArg; -static DefineDict *g_expandedDict; -static int g_findDefArgContext; -static bool g_expectGuard; -static QCString g_guardName; -static QCString g_lastGuardName; -static QCString g_incName; -static QCString g_guardExpr; -static int g_curlyCount; -static bool g_nospaces; // add extra spaces during macro expansion - -static bool g_macroExpansion; // from the configuration -static bool g_expandOnlyPredef; // from the configuration -static int g_commentCount; -static bool g_insideComment; -static bool g_isImported; -static QCString g_blockName; -static int g_condCtx; -static bool g_skip; -static QStack g_condStack; -static bool g_insideCS; // C# has simpler preprocessor -static bool g_isSource; - -static bool g_lexInit = FALSE; -static int g_fenceSize = 0; -static bool g_ccomment; -static QCString g_delimiter; - -//DefineDict* getGlobalDefineDict() -//{ -// return g_globalDefineDict; -//} - -static void setFileName(const char *name) -{ - bool ambig; - QFileInfo fi(name); - g_yyFileName=fi.absFilePath().utf8(); - g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig); - if (g_yyFileDef==0) // if this is not an input file check if it is an - // include file - { - g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig); - } - //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n", - // name,g_yyFileName.data(),g_yyFileDef); - if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0; - g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp; - g_isSource = guessSection(g_yyFileName); -} - -static void incrLevel() -{ - g_level++; - g_levelGuard.resize(g_level); - g_levelGuard[g_level-1]=FALSE; - //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); -} - -static void decrLevel() +struct preYY_state { - //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); - if (g_level > 0) - { - g_level--; - g_levelGuard.resize(g_level); - } - else - { - warn(g_yyFileName,g_yyLineNr,"More #endif's than #if's found.\n"); - } -} - -static bool otherCaseDone() -{ - if (g_level==0) - { - warn(g_yyFileName,g_yyLineNr,"Found an #else without a preceding #if.\n"); - return TRUE; - } - else - { - return g_levelGuard[g_level-1]; - } -} + preYY_state() : allIncludes(10009) {} + int yyLineNr = 1; + int yyMLines = 1; + int yyColNr = 1; + QCString yyFileName; + FileDef *yyFileDef; + FileDef *inputFileDef; + int ifcount = 0; + QStrList *pathList = 0; + QStack includeStack; + QDict *argDict; + int defArgs = -1; + QCString defName; + QCString defText; + QCString defLitText; + QCString defArgsStr; + QCString defExtraSpacing; + bool defVarArgs; + int level; + int lastCContext; + int lastCPPContext; + QArray levelGuard; + BufStr *inputBuf; + int inputBufPos; + BufStr *outputBuf; + int roundCount; + bool quoteArg; + DefineDict *expandedDict; + int findDefArgContext; + bool expectGuard; + QCString guardName; + QCString lastGuardName; + QCString incName; + QCString guardExpr; + int curlyCount; + bool nospaces; // add extra spaces during macro expansion + + bool macroExpansion; // from the configuration + bool expandOnlyPredef; // from the configuration + int commentCount; + bool insideComment; + bool isImported; + QCString blockName; + int condCtx; + bool skip; + QStack condStack; + bool insideCS; // C# has simpler preprocessor + bool isSource; + + int fenceSize = 0; + bool ccomment; + QCString delimiter; + QDict allIncludes; + DefineManager defineManager; +}; -static void setCaseDone(bool value) -{ - g_levelGuard[g_level-1]=value; -} +// stateless functions +static QCString escapeAt(const char *text); +static QCString extractTrailingComment(const char *s); +static char resolveTrigraph(char c); + +// statefull functions +static inline void outputArray(yyscan_t yyscanner,const char *a,int len); +static inline void outputChar(yyscan_t yyscanner,char c); +static QCString expandMacro(yyscan_t yyscanner,const QCString &name); +static void readIncludeFile(yyscan_t yyscanner,const QCString &inc); +static void incrLevel(yyscan_t yyscanner); +static void decrLevel(yyscan_t yyscanner); +static void setCaseDone(yyscan_t yyscanner,bool value); +static bool otherCaseDone(yyscan_t yyscanner); +static bool computeExpression(yyscan_t yyscanner,const QCString &expr); +static void startCondSection(yyscan_t yyscanner,const char *sectId); +static void endCondSection(yyscan_t yyscanner); +static void addDefine(yyscan_t yyscanner); +static Define * newDefine(yyscan_t yyscanner); +static void setFileName(yyscan_t yyscanner,const char *name); +static int yyread(yyscan_t yyscanner,char *buf,int max_size); -static QDict g_allIncludes(10009); +/* ----------------------------------------------------------------- */ -static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded) -{ - alreadyIncluded = FALSE; - FileState *fs = 0; - //printf("checkAndOpenFile(%s)\n",fileName.data()); - QFileInfo fi(fileName); - if (fi.exists() && fi.isFile()) - { - static QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS); - if (patternMatch(fi,&exclPatterns)) return 0; +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); - QCString absName = fi.absFilePath().utf8(); +/* ----------------------------------------------------------------- */ - // global guard - if (g_curlyCount==0) // not #include inside { ... } - { - if (g_allIncludes.find(absName)!=0) - { - alreadyIncluded = TRUE; - //printf(" already included 1\n"); - return 0; // already done - } - g_allIncludes.insert(absName,(void *)0x8); - } - // check include stack for absName +%} - QStack tmpStack; - g_includeStack.setAutoDelete(FALSE); - while ((fs=g_includeStack.pop())) - { - if (fs->fileName==absName) alreadyIncluded=TRUE; - tmpStack.push(fs); - } - while ((fs=tmpStack.pop())) - { - g_includeStack.push(fs); - } - g_includeStack.setAutoDelete(TRUE); +ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* +B [ \t] +BN [ \t\r\n] +RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"(" +RAWEND ")"[^ \t\(\)\\]{0,16}\" +CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) - if (alreadyIncluded) - { - //printf(" already included 2\n"); - return 0; - } - //printf("#include %s\n",absName.data()); +%option noyywrap - fs = new FileState(fi.size()+4096); - alreadyIncluded = FALSE; - if (!readInputFile(absName,fs->fileBuf)) - { // error - //printf(" error reading\n"); - delete fs; - fs=0; - } - else - { - fs->oldFileBuf = g_inputBuf; - fs->oldFileBufPos = g_inputBufPos; - } - } - return fs; -} +%x Start +%x Command +%x SkipCommand +%x SkipLine +%x SkipString +%x CopyLine +%x CopyString +%x CopyStringCs +%x CopyStringFtn +%x CopyStringFtnDouble +%x CopyRawString +%x Include +%x IncludeID +%x EndImport +%x DefName +%x DefineArg +%x DefineText +%x SkipCPPBlock +%x Ifdef +%x Ifndef +%x SkipCComment +%x ArgCopyCComment +%x CopyCComment +%x SkipVerbatim +%x SkipCPPComment +%x RemoveCComment +%x RemoveCPPComment +%x Guard +%x DefinedExpr1 +%x DefinedExpr2 +%x SkipDoubleQuote +%x SkipSingleQuote +%x UndefName +%x IgnoreLine +%x FindDefineArgs +%x ReadString +%x CondLineC +%x CondLineCpp +%x SkipCond -static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded) -{ - //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data()); - if (portable_isAbsolutePath(fileName)) - { - FileState *fs = checkAndOpenFile(fileName,alreadyIncluded); - if (fs) - { - setFileName(fileName); - g_yyLineNr=1; - return fs; - } - else if (alreadyIncluded) - { - return 0; - } - } - if (localInclude && !g_yyFileName.isEmpty()) - { - QFileInfo fi(g_yyFileName); - if (fi.exists()) - { - QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName; - FileState *fs = checkAndOpenFile(absName,alreadyIncluded); - if (fs) - { - setFileName(absName); - g_yyLineNr=1; - return fs; - } - else if (alreadyIncluded) - { - return 0; - } - } - } - if (g_pathList==0) - { - return 0; - } - char *s=g_pathList->first(); - while (s) - { - QCString absName = (QCString)s+"/"+fileName; - //printf(" Looking for %s in %s\n",fileName,s); - FileState *fs = checkAndOpenFile(absName,alreadyIncluded); - if (fs) - { - setFileName(absName); - g_yyLineNr=1; - //printf(" -> found it\n"); - return fs; - } - else if (alreadyIncluded) - { - return 0; - } +%% - s=g_pathList->next(); - } - return 0; -} +<*>\x06 +<*>\x00 +<*>\r +<*>"??"[=/'()!<>-] { // Trigraph + unput(resolveTrigraph(yytext[2])); + } +^{B}*"#" { BEGIN(Command); yyextra->yyColNr+=yyleng; yyextra->yyMLines=0;} +^{B}*/[^#] { + outputArray(yyscanner,yytext,(int)yyleng); + BEGIN(CopyLine); + } +^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors? + int i; + for (i=(int)yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + BEGIN(CopyLine); + } +^{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 +^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro + bool skipFuncMacros = Config_getBool(SKIP_FUNCTION_MACROS); + QCString name(yytext); + name=name.left(name.find('(')).stripWhiteSpace(); -static QCString extractTrailingComment(const char *s) -{ - if (s==0) return ""; - int i=strlen(s)-1; - while (i>=0) - { - char c=s[i]; - switch (c) - { - case '/': - { - i--; - if (i>=0 && s[i]=='*') // end of a comment block - { - i--; - while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--; - if (i==0) - { - i++; - } - // only /*!< or /**< are treated as a comment for the macro name, - // otherwise the comment is treated as part of the macro definition - return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : ""; - } - else - { - return ""; - } - } - break; - // whitespace or line-continuation - case ' ': - case '\t': - case '\r': - case '\n': - case '\\': - break; - default: - return ""; - } - i--; - } - return ""; -} - -static int getNextChar(const QCString &expr,QCString *rest,uint &pos); -static int getCurrentChar(const QCString &expr,QCString *rest,uint pos); -static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c); -static void expandExpression(QCString &expr,QCString *rest,int pos); - -static QCString stringize(const QCString &s) -{ - QCString result; - uint i=0; - bool inString=FALSE; - bool inChar=FALSE; - char c,pc; - while (i'%s'\n",s.data(),result.data()); - return result; -} - -/*! Execute all ## operators in expr. - * If the macro name before or after the operator contains a no-rescan - * marker (@-) then this is removed (before the concatenated macro name - * may be expanded again. - */ -static void processConcatOperators(QCString &expr) -{ - //printf("processConcatOperators: in='%s'\n",expr.data()); - QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); - int l,n,i=0; - if (expr.isEmpty()) return; - while ((n=r.match(expr,i,&l))!=-1) - { - //printf("Match: '%s'\n",expr.data()+i); - if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-') - { - // remove no-rescan marker after ID - l+=2; - } - //printf("found '%s'\n",expr.mid(n,l).data()); - // remove the ## operator and the surrounding whitespace - expr=expr.left(n)+expr.right(expr.length()-n-l); - int k=n-1; - while (k>=0 && isId(expr.at(k))) k--; - if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@') - { - // remove no-rescan marker before ID - expr=expr.left(k-1)+expr.right(expr.length()-k-1); - n-=2; - } - i=n; - } - //printf("processConcatOperators: out='%s'\n",expr.data()); -} - -static void yyunput (int c,char *buf_ptr ); -static void returnCharToStream(char c) -{ - unput(c); -} - -static inline void addTillEndOfString(const QCString &expr,QCString *rest, - uint &pos,char term,QCString &arg) -{ - int cc; - while ((cc=getNextChar(expr,rest,pos))!=EOF && cc!=0) - { - if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos); - else if (cc==term) return; - arg+=(char)cc; - } -} - -/*! replaces the function macro \a def whose argument list starts at - * \a pos in expression \a expr. - * Notice that this routine may scan beyond the \a expr string if needed. - * In that case the characters will be read from the input file. - * The replacement string will be returned in \a result and the - * length of the (unexpanded) argument list is stored in \a len. - */ -static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result) -{ - //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); - uint j=pos; - len=0; - result.resize(0); - int cc; - while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc)) - { - len++; - getNextChar(expr,rest,j); - } - if (cc!='(') - { - unputChar(expr,rest,j,' '); - return FALSE; - } - getNextChar(expr,rest,j); // eat the '(' character - - QDict argTable; // list of arguments - argTable.setAutoDelete(TRUE); - QCString arg; - int argCount=0; - bool done=FALSE; - - // PHASE 1: read the macro arguments - if (def->nargs==0) - { - while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - { - char c = (char)cc; - if (c==')') break; - } - } - else - { - while (!done && (argCountnargs || def->varArgs) && - ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - ) - { - char c=(char)cc; - if (c=='(') // argument is a function => search for matching ) - { - int level=1; - arg+=c; - //char term='\0'; - while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - { - char c=(char)cc; - //printf("processing %c: term=%c (%d)\n",c,term,term); - if (c=='\'' || c=='\"') // skip ('s and )'s inside strings - { - arg+=c; - addTillEndOfString(expr,rest,j,c,arg); - } - if (c==')') - { - level--; - arg+=c; - if (level==0) break; - } - else if (c=='(') - { - level++; - arg+=c; - } - else - arg+=c; - } - } - else if (c==')' || c==',') // last or next argument found - { - if (c==',' && argCount==def->nargs-1 && def->varArgs) - { - arg=arg.stripWhiteSpace(); - arg+=','; - } - else - { - QCString argKey; - argKey.sprintf("@%d",argCount++); // key name - arg=arg.stripWhiteSpace(); - // add argument to the lookup table - argTable.insert(argKey, new QCString(arg)); - arg.resize(0); - if (c==')') // end of the argument list - { - done=TRUE; - } - } - } - else if (c=='\"') // append literal strings - { - arg+=c; - bool found=FALSE; - while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - { - found = cc=='"'; - if (cc=='\\') - { - c=(char)cc; - arg+=c; - if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break; - } - c=(char)cc; - arg+=c; - } - } - else if (c=='\'') // append literal characters - { - arg+=c; - bool found=FALSE; - while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - { - found = cc=='\''; - if (cc=='\\') - { - c=(char)cc; - arg+=c; - if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break; - } - c=(char)cc; - arg+=c; - } - } - else if (c=='/') // possible start of a comment - { - char prevChar = '\0'; - arg+=c; - if ((cc=getCurrentChar(expr,rest,j)) == '*') // we have a comment - { - while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0) - { - c=(char)cc; - arg+=c; - if (c == '/' && prevChar == '*') break; // we have an end of comment - prevChar = c; - } - } - } - else // append other characters - { - arg+=c; - } - } - } - - // PHASE 2: apply the macro function - if (argCount==def->nargs || // same number of arguments - (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many - // params as the non-variadic part (see bug731985) - { - uint k=0; - // substitution of all formal arguments - QCString resExpr; - const QCString d=def->definition.stripWhiteSpace(); - //printf("Macro definition: %s\n",d.data()); - bool inString=FALSE; - while (k copy it (is unescaped later) - { - k+=2; - resExpr+="@@"; // we unescape these later - } - else if (d.at(k+1)=='-') // no-rescan marker - { - k+=2; - resExpr+="@-"; - } - else // argument marker => read the argument number - { - QCString key="@"; - QCString *subst=0; - bool hash=FALSE; - int l=k-1; - // search for ## backward - if (l>=0 && d.at(l)=='"') l--; - while (l>=0 && d.at(l)==' ') l--; - if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE; - k++; - // scan the number - while (k='0' && d.at(k)<='9') key+=d.at(k++); - if (!hash) - { - // search for ## forward - l=k; - if (l<(int)d.length() && d.at(l)=='"') l++; - while (l<(int)d.length() && d.at(l)==' ') l++; - if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE; - } - //printf("request key %s result %s\n",key.data(),argTable[key]->data()); - if (key.length()>1 && (subst=argTable[key])) - { - QCString substArg=*subst; - //printf("substArg='%s'\n",substArg.data()); - // only if no ## operator is before or after the argument - // marker we do macro expansion. - if (!hash) expandExpression(substArg,0,0); - if (inString) - { - //printf("'%s'=stringize('%s')\n",stringize(*subst).data(),subst->data()); - - // if the marker is inside a string (because a # was put - // before the macro name) we must escape " and \ characters - resExpr+=stringize(substArg); - } - else - { - if (hash && substArg.isEmpty()) - { - resExpr+="@E"; // empty argument will be remove later on - } - else if (g_nospaces) - { - resExpr+=substArg; - } - else - { - resExpr+=" "+substArg+" "; - } - } - } - } - } - else // no marker, just copy - { - if (!inString && d.at(k)=='\"') - { - inString=TRUE; // entering a literal string - } - else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\')) - { - inString=FALSE; // leaving a literal string - } - resExpr+=d.at(k++); - } - } - len=j-pos; - result=resExpr; - //printf("result after substitution '%s' expr='%s'\n", - // result.data(),expr.mid(pos,len).data()); - return TRUE; - } - return FALSE; -} - - -/*! returns the next identifier in string \a expr by starting at position \a p. - * The position of the identifier is returned (or -1 if nothing is found) - * and \a l is its length. Any quoted strings are skipping during the search. - */ -static int getNextId(const QCString &expr,int p,int *l) -{ - int n; - while (p<(int)expr.length()) - { - char c=expr.at(p++); - if (isdigit(c)) // skip number - { - while (p<(int)expr.length() && isId(expr.at(p))) p++; - } - else if (isalpha(c) || c=='_') // read id - { - n=p-1; - while (p<(int)expr.length() && isId(expr.at(p))) p++; - *l=p-n; - return n; - } - else if (c=='"') // skip string - { - char ppc=0,pc=c; - if (p<(int)expr.length()) c=expr.at(p); - while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) - // continue as long as no " is found, but ignoring \", but not \\" - { - ppc=pc; - pc=c; - c=expr.at(p); - p++; - } - if (p<(int)expr.length()) ++p; // skip closing quote - } - else if (c=='/') // skip C Comment - { - //printf("Found C comment at p=%d\n",p); - char pc=c; - if (p<(int)expr.length()) - { - c=expr.at(p); - if (c=='*') // Start of C comment - { - p++; - while (p<(int)expr.length() && !(pc=='*' && c=='/')) - { - pc=c; - c=expr.at(p++); - } - } - } - //printf("Found end of C comment at p=%d\n",p); - } - } - return -1; -} - -/*! performs recursive macro expansion on the string \a expr - * starting at position \a pos. - * May read additional characters from the input while re-scanning! - * If \a expandAll is \c TRUE then all macros in the expression are - * expanded, otherwise only the first is expanded. - */ -static void expandExpression(QCString &expr,QCString *rest,int pos) -{ - //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0); - QCString macroName; - QCString expMacro; - bool definedTest=FALSE; - int i=pos,l,p,len; - while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name - { - bool replaced=FALSE; - macroName=expr.mid(p,l); - //printf("macroName=%s\n",macroName.data()); - if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker? - { - if (g_expandedDict->find(macroName)==0) // expand macro - { - Define *def=DefineManager::instance().isDefined(macroName); - if (macroName=="defined") - { - //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data()); - definedTest=TRUE; - } - else if (definedTest) // macro name was found after defined - { - if (def) expMacro = " 1 "; else expMacro = " 0 "; - replaced=TRUE; - len=l; - definedTest=FALSE; - } - else if (def && def->nargs==-1) // simple macro - { - // substitute the definition of the macro - //printf("macro '%s'->'%s'\n",macroName.data(),def->definition.data()); - if (g_nospaces) - { - expMacro=def->definition.stripWhiteSpace(); - } - else - { - expMacro=" "+def->definition.stripWhiteSpace()+" "; - } - //expMacro=def->definition.stripWhiteSpace(); - replaced=TRUE; - len=l; - //printf("simple macro expansion='%s'->'%s'\n",macroName.data(),expMacro.data()); - } - else if (def && def->nargs>=0) // function macro - { - replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro); - len+=l; - } - - if (replaced) // expand the macro and rescan the expression - { - //printf("replacing '%s'->'%s'\n",expr.mid(p,len).data(),expMacro.data()); - QCString resultExpr=expMacro; - QCString restExpr=expr.right(expr.length()-len-p); - processConcatOperators(resultExpr); - if (def && !def->nonRecursive) - { - g_expandedDict->insert(macroName,def); - expandExpression(resultExpr,&restExpr,0); - g_expandedDict->remove(macroName); - } - expr=expr.left(p)+resultExpr+restExpr; - i=p; - //printf("new expression: %s\n",expr.data()); - } - else // move to the next macro name - { - //printf("moving to the next macro old=%d new=%d\n",i,p+l); - i=p+l; - } - } - else // move to the next macro name - { - expr=expr.left(p)+"@-"+expr.right(expr.length()-p); - //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data()); - i=p+l+2; - //i=p+l; - } - } - else // no re-scan marker found, skip the macro name - { - //printf("skipping marked macro\n"); - i=p+l; - } - } -} - -/*! @brief Process string or character literal. - * - * \a inputStr should point to the start of a string or character literal. - * the routine will return a pointer to just after the end of the literal - * the character making up the literal will be added to \a result. - */ -const char *processUntilMatchingTerminator(const char *inputStr,QCString &result) -{ - if (inputStr==0) return inputStr; - char term = *inputStr; // capture start character of the literal - if (term!='\'' && term!='"') return inputStr; // not a valid literal - char c=term; - // output start character - result+=c; - inputStr++; - while ((c=*inputStr)) // while inside the literal - { - if (c==term) // found end marker of the literal - { - // output end character and stop - result+=c; - inputStr++; - break; - } - else if (c=='\\') // escaped character, process next character - // as well without checking for end marker. - { - result+=c; - inputStr++; - c=*inputStr; - if (c==0) break; // unexpected end of string after escape character - } - result+=c; - inputStr++; - } - return inputStr; -} - -/*! replaces all occurrences of @@@@ in \a s by @@ - * and removes all occurrences of @@E. - * All identifiers found are replaced by 0L - */ -QCString removeIdsAndMarkers(const char *s) -{ - //printf("removeIdsAndMarkers(%s)\n",s); - const char *p=s; - char c; - bool inNum=FALSE; - QCString result; - if (p) - { - while ((c=*p)) - { - if (c=='@') // replace @@ with @ and remove @E - { - if (*(p+1)=='@') - { - result+=c; - } - else if (*(p+1)=='E') - { - // skip - } - p+=2; - } - else if (isdigit(c)) // number - { - result+=c; - p++; - inNum=TRUE; - } - else if (c=='\'') // quoted character - { - p = processUntilMatchingTerminator(p,result); - } - else if (c=='d' && !inNum) // identifier starting with a 'd' - { - if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0) - // defined keyword - { - p+=7; // skip defined - } - else - { - result+="0L"; - p++; - while ((c=*p) && isId(c)) p++; - } - } - else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L - { - result+="0L"; - p++; - while ((c=*p) && isId(c)) p++; - while ((c=*p) && isspace((uchar)c)) p++; - if (*p=='(') // undefined function macro - { - p++; - int count=1; - while ((c=*p++)) - { - if (c=='(') count++; - else if (c==')') - { - count--; - if (count==0) break; - } - else if (c=='/') - { - char pc=c; - c=*++p; - if (c=='*') // start of C comment - { - while (*p && !(pc=='*' && c=='/')) // search end of comment - { - pc=c; - c=*++p; - } - p++; - } - } - } - } - } - else if (c=='/') // skip C comments - { - char pc=c; - c=*++p; - if (c=='*') // start of C comment - { - while (*p && !(pc=='*' && c=='/')) // search end of comment - { - pc=c; - c=*++p; - } - p++; - } - else // oops, not comment but division - { - result+=pc; - goto nextChar; - } - } - else - { -nextChar: - result+=c; - char lc=tolower(c); - if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE; - p++; - } - } - } - //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data()); - return result; -} - -/*! replaces all occurrences of @@ in \a s by @ - * \par assumption: - * \a s only contains pairs of @@'s - */ -QCString removeMarkers(const char *s) -{ - const char *p=s; - char c; - QCString result; - if (p) - { - while ((c=*p)) - { - switch(c) - { - case '@': // replace @@ with @ - { - if (*(p+1)=='@') - { - result+=c; - } - p+=2; - } - break; - case '/': // skip C comments - { - result+=c; - char pc=c; - c=*++p; - if (c=='*') // start of C comment - { - while (*p && !(pc=='*' && c=='/')) // search end of comment - { - if (*p=='@' && *(p+1)=='@') - result+=c,p++; - else - result+=c; - pc=c; - c=*++p; - } - if (*p) result+=c,p++; - } - } - break; - case '"': // skip string literals - case '\'': // skip char literals - p = processUntilMatchingTerminator(p,result); - break; - default: - { - result+=c; - p++; - } - break; - } - } - } - //printf("RemoveMarkers(%s)=%s\n",s,result.data()); - return result; -} - -/*! compute the value of the expression in string \a expr. - * If needed the function may read additional characters from the input. - */ - -bool computeExpression(const QCString &expr) -{ - QCString e=expr; - expandExpression(e,0,0); - //printf("after expansion '%s'\n",e.data()); - e = removeIdsAndMarkers(e); - if (e.isEmpty()) return FALSE; - //printf("parsing '%s'\n",e.data()); - return parseconstexp(g_yyFileName,g_yyLineNr,e); -} - -/*! expands the macro definition in \a name - * If needed the function may read additional characters from the input - */ - -QCString expandMacro(const QCString &name) -{ - QCString n=name; - expandExpression(n,0,0); - n=removeMarkers(n); - //printf("expandMacro '%s'->'%s'\n",name.data(),n.data()); - return n; -} - -Define *newDefine() -{ - Define *def=new Define; - def->name = g_defName; - def->definition = g_defText.stripWhiteSpace(); - def->nargs = g_defArgs; - def->fileName = g_yyFileName; - def->fileDef = g_yyFileDef; - def->lineNr = g_yyLineNr-g_yyMLines; - def->columnNr = g_yyColNr; - def->varArgs = g_defVarArgs; - //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(), - // def->fileDef ? def->fileDef->name().data() : def->fileName.data()); - //printf("newDefine: '%s'->'%s'\n",def->name.data(),def->definition.data()); - if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name]) - { - def->isPredefined=TRUE; - } - return def; -} - -void addDefine() -{ - if (g_skip) return; // do not add this define as it is inside a - // conditional section (cond command) that is disabled. - if (!Doxygen::gatherDefines) return; - - //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data()); - //ArgumentList *al = new ArgumentList; - //stringToArgumentList(g_defArgsStr,al); - MemberDef *md=createMemberDef( - g_yyFileName,g_yyLineNr-g_yyMLines,g_yyColNr, - "#define",g_defName,g_defArgsStr,0, - Public,Normal,FALSE,Member,MemberType_Define,ArgumentList(),ArgumentList(),""); - if (!g_defArgsStr.isEmpty()) - { - ArgumentList argList; - //printf("addDefine() g_defName='%s' g_defArgsStr='%s'\n",g_defName.data(),g_defArgsStr.data()); - stringToArgumentList(g_defArgsStr,argList); - md->setArgumentList(argList); - } - //printf("Setting initializer for '%s' to '%s'\n",g_defName.data(),g_defText.data()); - int l=g_defLitText.find('\n'); - if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\") - { - // strip first line if it only contains a slash - g_defLitText = g_defLitText.right(g_defLitText.length()-l-1); - } - else if (l>0) - { - // align the items on the first line with the items on the second line - int k=l+1; - const char *p=g_defLitText.data()+k; - char c; - while ((c=*p++) && (c==' ' || c=='\t')) k++; - g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace(); - } - md->setInitializer(g_defLitText.stripWhiteSpace()); - - //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef); - md->setFileDef(g_inputFileDef); - md->setDefinition("#define "+g_defName); - - MemberName *mn=Doxygen::functionNameSDict->find(g_defName); - if (mn==0) - { - mn = new MemberName(g_defName); - Doxygen::functionNameSDict->append(g_defName,mn); - } - mn->append(md); - if (g_yyFileDef) - { - g_yyFileDef->insertMember(md); - } - - //Define *d; - //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); -} - -static inline void outputChar(char c) -{ - if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c); -} - -static inline void outputArray(const char *a,int len) -{ - if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len); -} - -static void readIncludeFile(const QCString &inc) -{ - static bool searchIncludes = Config_getBool(SEARCH_INCLUDES); - uint i=0; - - // find the start of the include file name - while (i0 && inc.at(s-1)=='"'; - - // find the end of the include file name - while (is) // valid include file name found - { - // extract include path+name - QCString incFileName=inc.mid(s,i-s).stripWhiteSpace(); - - QCString dosExt = incFileName.right(4); - if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb") - { - // skip imported binary files (e.g. M$ type libraries) - return; - } - - QCString oldFileName = g_yyFileName; - FileDef *oldFileDef = g_yyFileDef; - int oldLineNr = g_yyLineNr; - //printf("Searching for '%s'\n",incFileName.data()); - - // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336) - QCString absIncFileName = incFileName; - { - QFileInfo fi(g_yyFileName); - if (fi.exists()) - { - QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName; - QFileInfo fi2(absName); - if (fi2.exists()) - { - absIncFileName=fi2.absFilePath().utf8(); - } - else if (searchIncludes) // search in INCLUDE_PATH as well - { - QStrList &includePath = Config_getList(INCLUDE_PATH); - char *s=includePath.first(); - while (s) - { - QFileInfo fi(s); - if (fi.exists() && fi.isDir()) - { - QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName; - //printf("trying absName=%s\n",absName.data()); - QFileInfo fi2(absName); - if (fi2.exists()) - { - absIncFileName=fi2.absFilePath().utf8(); - break; - } - //printf( "absIncFileName = %s\n", absIncFileName.data() ); - } - s=includePath.next(); - } - } - //printf( "absIncFileName = %s\n", absIncFileName.data() ); - } - } - DefineManager::instance().addInclude(g_yyFileName,absIncFileName); - DefineManager::instance().addFileToContext(absIncFileName); - - // findFile will overwrite g_yyFileDef if found - FileState *fs; - bool alreadyIncluded = FALSE; - //printf("calling findFile(%s)\n",incFileName.data()); - if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found - { - //printf("Found include file!\n"); - if (Debug::isFlagSet(Debug::Preprocessor)) - { - for (i=0;iaddIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE); - // add included by dependency - if (g_yyFileDef) - { - //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data()); - g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); - } - } - else if (g_inputFileDef) - { - g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE); - } - fs->bufState = YY_CURRENT_BUFFER; - fs->lineNr = oldLineNr; - fs->fileName = oldFileName; - fs->curlyCount = g_curlyCount; - g_curlyCount = 0; - // push the state on the stack - g_includeStack.push(fs); - // set the scanner to the include file - - // Deal with file changes due to - // #include's within { .. } blocks - QCString lineStr(g_yyFileName.length()+20); - lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data()); - outputArray(lineStr.data(),lineStr.length()); - - DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data())); - g_expectGuard=TRUE; - g_inputBuf = &fs->fileBuf; - g_inputBufPos=0; - yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE)); - } - else - { - //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded); - if (oldFileDef) - { - bool ambig; - //QCString absPath = incFileName; - //if (QDir::isRelativePath(incFileName)) - //{ - // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName); - // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data()); - //} - - // change to absolute name for bug 641336 - FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig); - //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd); - // add include dependency to the file in which the #include was found - oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE); - // add included by dependency - if (fd) - { - //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig); - fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); - } - } - else if (g_inputFileDef) - { - g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE); - } - if (Debug::isFlagSet(Debug::Preprocessor)) - { - if (alreadyIncluded) - { - Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",qPrint(incFileName)); - } - else - { - Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",qPrint(incFileName)); - } - //printf("error: include file %s not found\n",yytext); - } - if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... } - { - warn(g_yyFileName,g_yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data()); - } - } - } -} - -/* ----------------------------------------------------------------- */ - -static void startCondSection(const char *sectId) -{ - //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count()); - CondParser prs; - bool expResult = prs.parse(g_yyFileName,g_yyLineNr,sectId); - g_condStack.push(new CondCtx(g_yyLineNr,sectId,g_skip)); - if (!expResult) - { - g_skip=TRUE; - } - //printf(" expResult=%d skip=%d\n",expResult,g_skip); -} - -static void endCondSection() -{ - if (g_condStack.isEmpty()) - { - g_skip=FALSE; - } - else - { - CondCtx *ctx = g_condStack.pop(); - g_skip=ctx->skip; - delete ctx; - } - //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count()); -} - -static void forceEndCondSection() -{ - while (!g_condStack.isEmpty()) - { - delete g_condStack.pop(); - } - g_skip=FALSE; -} - -static QCString escapeAt(const char *text) -{ - QCString result; - if (text) - { - char c; - const char *p=text; - while ((c=*p++)) - { - if (c=='@') result+="@@"; else result+=c; - } - } - return result; -} - -static char resolveTrigraph(char c) -{ - switch (c) - { - case '=': return '#'; - case '/': return '\\'; - case '\'': return '^'; - case '(': return '['; - case ')': return ']'; - case '!': return '|'; - case '<': return '{'; - case '>': return '}'; - case '-': return '~'; - } - return '?'; -} - -/* ----------------------------------------------------------------- */ - -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); - -static int yyread(char *buf,int max_size) -{ - int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos; - int bytesToCopy = QMIN(max_size,bytesInBuf); - memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy); - g_inputBufPos+=bytesToCopy; - return bytesToCopy; -} - -/* ----------------------------------------------------------------- */ - -%} - -ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* -B [ \t] -BN [ \t\r\n] -RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"(" -RAWEND ")"[^ \t\(\)\\]{0,16}\" -CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) - -%option noyywrap - -%x Start -%x Command -%x SkipCommand -%x SkipLine -%x SkipString -%x CopyLine -%x CopyString -%x CopyStringCs -%x CopyStringFtn -%x CopyStringFtnDouble -%x CopyRawString -%x Include -%x IncludeID -%x EndImport -%x DefName -%x DefineArg -%x DefineText -%x SkipCPPBlock -%x Ifdef -%x Ifndef -%x SkipCComment -%x ArgCopyCComment -%x CopyCComment -%x SkipVerbatim -%x SkipCPPComment -%x RemoveCComment -%x RemoveCPPComment -%x Guard -%x DefinedExpr1 -%x DefinedExpr2 -%x SkipDoubleQuote -%x SkipSingleQuote -%x UndefName -%x IgnoreLine -%x FindDefineArgs -%x ReadString -%x CondLineC -%x CondLineCpp -%x SkipCond - -%% - -<*>\x06 -<*>\x00 -<*>\r -<*>"??"[=/'()!<>-] { // Trigraph - unput(resolveTrigraph(yytext[2])); - } -^{B}*"#" { BEGIN(Command); g_yyColNr+=yyleng; g_yyMLines=0;} -^{B}*/[^#] { - outputArray(yytext,(int)yyleng); - BEGIN(CopyLine); - } -^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors? - int i; - for (i=(int)yyleng-1;i>=0;i--) - { - unput(yytext[i]); - } - BEGIN(CopyLine); - } -^{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 -^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro - static bool skipFuncMacros = Config_getBool(SKIP_FUNCTION_MACROS); - QCString name(yytext); - name=name.left(name.find('(')).stripWhiteSpace(); - - Define *def=0; - if (skipFuncMacros && - name!="Q_PROPERTY" && - !( - (g_includeStack.isEmpty() || g_curlyCount>0) && - g_macroExpansion && - (def=DefineManager::instance().isDefined(name)) && - /*macroIsAccessible(def) &&*/ - (!g_expandOnlyPredef || def->isPredefined) - ) - ) - { - outputChar('\n'); - g_yyLineNr++; - } - else // don't skip - { - int i; - for (i=(int)yyleng-1;i>=0;i--) - { - unput(yytext[i]); - } - BEGIN(CopyLine); - } - } -"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" { - QCString text=yytext; - g_yyLineNr+=text.contains('\n'); - outputArray(yytext,(int)yyleng); - } -{RAWBEGIN} { - g_delimiter = yytext+2; - g_delimiter=g_delimiter.left(g_delimiter.length()-1); - outputArray(yytext,(int)yyleng); - BEGIN(CopyRawString); - } -"{" { // count brackets inside the main file - if (g_includeStack.isEmpty()) - { - g_curlyCount++; - } - outputChar(*yytext); - } -"}" { // count brackets inside the main file - if (g_includeStack.isEmpty() && g_curlyCount>0) - { - g_curlyCount--; - } - outputChar(*yytext); - } -"'"\\[0-7]{1,3}"'" { - outputArray(yytext,(int)yyleng); - } -"'"\\."'" { - outputArray(yytext,(int)yyleng); - } -"'"."'" { - outputArray(yytext,(int)yyleng); - } -@\" { - if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_CSharp) REJECT; - outputArray(yytext,(int)yyleng); - BEGIN( CopyStringCs ); - } -\" { - outputChar(*yytext); - if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) - { - BEGIN( CopyString ); - } - else - { - BEGIN( CopyStringFtnDouble ); - } - } -\' { - if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT; - outputChar(*yytext); - BEGIN( CopyStringFtn ); - } -[^\"\\\r\n]+ { - outputArray(yytext,(int)yyleng); - } -[^\"\r\n]+ { - outputArray(yytext,(int)yyleng); - } -\\. { - outputArray(yytext,(int)yyleng); - } -\" { - outputChar(*yytext); - BEGIN( CopyLine ); - } -[^\"\\\r\n]+ { - outputArray(yytext,(int)yyleng); - } -\\. { - outputArray(yytext,(int)yyleng); - } -\" { - outputChar(*yytext); - BEGIN( CopyLine ); - } -[^\'\\\r\n]+ { - outputArray(yytext,(int)yyleng); - } -\\. { - outputArray(yytext,(int)yyleng); - } -\' { - outputChar(*yytext); - BEGIN( CopyLine ); - } -{RAWEND} { - outputArray(yytext,(int)yyleng); - QCString delimiter = yytext+1; - delimiter=delimiter.left(delimiter.length()-1); - if (delimiter==g_delimiter) - { - BEGIN( CopyLine ); - } - } -[^)]+ { - outputArray(yytext,(int)yyleng); - } -. { - outputChar(*yytext); - } -{ID}/{BN}{0,80}"(" { - g_expectGuard = FALSE; - Define *def=0; - //def=g_globalDefineDict->find(yytext); - //def=DefineManager::instance().isDefined(yytext); - //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d " - // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d " - // "isPreDefined=%d\n",yytext,def ? 1 : 0, - // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef, - // def ? def->isPredefined : -1 - // ); - if ((g_includeStack.isEmpty() || g_curlyCount>0) && - g_macroExpansion && - (def=DefineManager::instance().isDefined(yytext)) && - /*(def->isPredefined || macroIsAccessible(def)) && */ - (!g_expandOnlyPredef || def->isPredefined) - ) - { - //printf("Found it! #args=%d\n",def->nargs); - g_roundCount=0; - g_defArgsStr=yytext; - if (def->nargs==-1) // no function macro - { - QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr); - outputArray(result,result.length()); - } - else // zero or more arguments - { - g_findDefArgContext = CopyLine; - BEGIN(FindDefineArgs); - } - } - else - { - outputArray(yytext,(int)yyleng); - } - } -{ID} { - Define *def=0; - if ((g_includeStack.isEmpty() || g_curlyCount>0) && - g_macroExpansion && - (def=DefineManager::instance().isDefined(yytext)) && - def->nargs==-1 && - /*(def->isPredefined || macroIsAccessible(def)) &&*/ - (!g_expandOnlyPredef || def->isPredefined) - ) - { - QCString result=def->isPredefined ? def->definition : expandMacro(yytext); - outputArray(result,result.length()); - } - else - { - outputArray(yytext,(int)yyleng); - } - } -"\\"\r?/\n { // strip line continuation characters - if (getLanguageFromFileName(g_yyFileName)==SrcLangExt_Fortran) outputChar(*yytext); - } -. { - outputChar(*yytext); - } -\n { - outputChar('\n'); - BEGIN(Start); - g_yyLineNr++; - g_yyColNr=1; - } -"(" { - g_defArgsStr+='('; - g_roundCount++; - } -")" { - g_defArgsStr+=')'; - g_roundCount--; - if (g_roundCount==0) - { - QCString result=expandMacro(g_defArgsStr); - //printf("g_defArgsStr='%s'->'%s'\n",g_defArgsStr.data(),result.data()); - if (g_findDefArgContext==CopyLine) - { - outputArray(result,result.length()); - BEGIN(g_findDefArgContext); - } - else // g_findDefArgContext==IncludeID - { - readIncludeFile(result); - g_nospaces=FALSE; - BEGIN(Start); - } - } - } - /* -")"{B}*"(" { - g_defArgsStr+=yytext; - } - */ -{CHARLIT} { - g_defArgsStr+=yytext; - } -"/*"[*]? { - g_defArgsStr+=yytext; - BEGIN(ArgCopyCComment); - } -\" { - g_defArgsStr+=*yytext; - BEGIN(ReadString); - } -' { - if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT; - g_defArgsStr+=*yytext; - BEGIN(ReadString); - } -\n { - g_defArgsStr+=' '; - g_yyLineNr++; - outputChar('\n'); - } -"@" { - g_defArgsStr+="@@"; - } -. { - g_defArgsStr+=*yytext; - } -[^*\n]+ { - g_defArgsStr+=yytext; - } -"*/" { - g_defArgsStr+=yytext; - BEGIN(FindDefineArgs); - } -\n { - g_defArgsStr+=' '; - g_yyLineNr++; - outputChar('\n'); - } -. { - g_defArgsStr+=yytext; - } -"\"" { - g_defArgsStr+=*yytext; - BEGIN(FindDefineArgs); - } -"'" { - if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT; - g_defArgsStr+=*yytext; - BEGIN(FindDefineArgs); - } + Define *def=0; + if (skipFuncMacros && + name!="Q_PROPERTY" && + !( + (yyextra->includeStack.isEmpty() || yyextra->curlyCount>0) && + yyextra->macroExpansion && + (def=yyextra->defineManager.isDefined(name)) && + /*macroIsAccessible(def) &&*/ + (!yyextra->expandOnlyPredef || def->isPredefined) + ) + ) + { + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; + } + else // don't skip + { + int i; + for (i=(int)yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + BEGIN(CopyLine); + } + } +"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" { + QCString text=yytext; + yyextra->yyLineNr+=text.contains('\n'); + outputArray(yyscanner,yytext,(int)yyleng); + } +{RAWBEGIN} { + yyextra->delimiter = yytext+2; + yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1); + outputArray(yyscanner,yytext,(int)yyleng); + BEGIN(CopyRawString); + } +"{" { // count brackets inside the main file + if (yyextra->includeStack.isEmpty()) + { + yyextra->curlyCount++; + } + outputChar(yyscanner,*yytext); + } +"}" { // count brackets inside the main file + if (yyextra->includeStack.isEmpty() && yyextra->curlyCount>0) + { + yyextra->curlyCount--; + } + outputChar(yyscanner,*yytext); + } +"'"\\[0-7]{1,3}"'" { + outputArray(yyscanner,yytext,(int)yyleng); + } +"'"\\."'" { + outputArray(yyscanner,yytext,(int)yyleng); + } +"'"."'" { + outputArray(yyscanner,yytext,(int)yyleng); + } +@\" { + if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_CSharp) REJECT; + outputArray(yyscanner,yytext,(int)yyleng); + BEGIN( CopyStringCs ); + } +\" { + outputChar(yyscanner,*yytext); + if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) + { + BEGIN( CopyString ); + } + else + { + BEGIN( CopyStringFtnDouble ); + } + } +\' { + if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT; + outputChar(yyscanner,*yytext); + BEGIN( CopyStringFtn ); + } +[^\"\\\r\n]+ { + outputArray(yyscanner,yytext,(int)yyleng); + } +[^\"\r\n]+ { + outputArray(yyscanner,yytext,(int)yyleng); + } +\\. { + outputArray(yyscanner,yytext,(int)yyleng); + } +\" { + outputChar(yyscanner,*yytext); + BEGIN( CopyLine ); + } +[^\"\\\r\n]+ { + outputArray(yyscanner,yytext,(int)yyleng); + } +\\. { + outputArray(yyscanner,yytext,(int)yyleng); + } +\" { + outputChar(yyscanner,*yytext); + BEGIN( CopyLine ); + } +[^\'\\\r\n]+ { + outputArray(yyscanner,yytext,(int)yyleng); + } +\\. { + outputArray(yyscanner,yytext,(int)yyleng); + } +\' { + outputChar(yyscanner,*yytext); + BEGIN( CopyLine ); + } +{RAWEND} { + outputArray(yyscanner,yytext,(int)yyleng); + QCString delimiter = yytext+1; + delimiter=delimiter.left(delimiter.length()-1); + if (delimiter==yyextra->delimiter) + { + BEGIN( CopyLine ); + } + } +[^)]+ { + outputArray(yyscanner,yytext,(int)yyleng); + } +. { + outputChar(yyscanner,*yytext); + } +{ID}/{BN}{0,80}"(" { + yyextra->expectGuard = FALSE; + Define *def=0; + //def=yyextra->globalDefineDict->find(yytext); + //def=yyextra->defineManager.isDefined(yytext); + //printf("Search for define %s found=%d yyextra->includeStack.isEmpty()=%d " + // "yyextra->curlyCount=%d yyextra->macroExpansion=%d yyextra->expandOnlyPredef=%d " + // "isPreDefined=%d\n",yytext,def ? 1 : 0, + // yyextra->includeStack.isEmpty(),yyextra->curlyCount,yyextra->macroExpansion,yyextra->expandOnlyPredef, + // def ? def->isPredefined : -1 + // ); + if ((yyextra->includeStack.isEmpty() || yyextra->curlyCount>0) && + yyextra->macroExpansion && + (def=yyextra->defineManager.isDefined(yytext)) && + /*(def->isPredefined || macroIsAccessible(def)) && */ + (!yyextra->expandOnlyPredef || def->isPredefined) + ) + { + //printf("Found it! #args=%d\n",def->nargs); + yyextra->roundCount=0; + yyextra->defArgsStr=yytext; + if (def->nargs==-1) // no function macro + { + QCString result = def->isPredefined ? def->definition : expandMacro(yyscanner,yyextra->defArgsStr); + outputArray(yyscanner,result,result.length()); + } + else // zero or more arguments + { + yyextra->findDefArgContext = CopyLine; + BEGIN(FindDefineArgs); + } + } + else + { + outputArray(yyscanner,yytext,(int)yyleng); + } + } +{ID} { + Define *def=0; + if ((yyextra->includeStack.isEmpty() || yyextra->curlyCount>0) && + yyextra->macroExpansion && + (def=yyextra->defineManager.isDefined(yytext)) && + def->nargs==-1 && + /*(def->isPredefined || macroIsAccessible(def)) &&*/ + (!yyextra->expandOnlyPredef || def->isPredefined) + ) + { + QCString result=def->isPredefined ? def->definition : expandMacro(yyscanner,yytext); + outputArray(yyscanner,result,result.length()); + } + else + { + outputArray(yyscanner,yytext,(int)yyleng); + } + } +"\\"\r?/\n { // strip line continuation characters + if (getLanguageFromFileName(yyextra->yyFileName)==SrcLangExt_Fortran) outputChar(yyscanner,*yytext); + } +. { + outputChar(yyscanner,*yytext); + } +\n { + outputChar(yyscanner,'\n'); + BEGIN(Start); + yyextra->yyLineNr++; + yyextra->yyColNr=1; + } +"(" { + yyextra->defArgsStr+='('; + yyextra->roundCount++; + } +")" { + yyextra->defArgsStr+=')'; + yyextra->roundCount--; + if (yyextra->roundCount==0) + { + QCString result=expandMacro(yyscanner,yyextra->defArgsStr); + //printf("yyextra->defArgsStr='%s'->'%s'\n",yyextra->defArgsStr.data(),result.data()); + if (yyextra->findDefArgContext==CopyLine) + { + outputArray(yyscanner,result,result.length()); + BEGIN(yyextra->findDefArgContext); + } + else // yyextra->findDefArgContext==IncludeID + { + readIncludeFile(yyscanner,result); + yyextra->nospaces=FALSE; + BEGIN(Start); + } + } + } + /* +")"{B}*"(" { + yyextra->defArgsStr+=yytext; + } + */ +{CHARLIT} { + yyextra->defArgsStr+=yytext; + } +"/*"[*]? { + yyextra->defArgsStr+=yytext; + BEGIN(ArgCopyCComment); + } +\" { + yyextra->defArgsStr+=*yytext; + BEGIN(ReadString); + } +' { + if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT; + yyextra->defArgsStr+=*yytext; + BEGIN(ReadString); + } +\n { + yyextra->defArgsStr+=' '; + yyextra->yyLineNr++; + outputChar(yyscanner,'\n'); + } +"@" { + yyextra->defArgsStr+="@@"; + } +. { + yyextra->defArgsStr+=*yytext; + } +[^*\n]+ { + yyextra->defArgsStr+=yytext; + } +"*/" { + yyextra->defArgsStr+=yytext; + BEGIN(FindDefineArgs); + } +\n { + yyextra->defArgsStr+=' '; + yyextra->yyLineNr++; + outputChar(yyscanner,'\n'); + } +. { + yyextra->defArgsStr+=yytext; + } +"\"" { + yyextra->defArgsStr+=*yytext; + BEGIN(FindDefineArgs); + } +"'" { + if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT; + yyextra->defArgsStr+=*yytext; + BEGIN(FindDefineArgs); + } "//"|"/*" { - g_defArgsStr+=yytext; + yyextra->defArgsStr+=yytext; } \\/\r?\n { // line continuation } \\. { - g_defArgsStr+=yytext; + yyextra->defArgsStr+=yytext; } . { - g_defArgsStr+=*yytext; + yyextra->defArgsStr+=*yytext; } ("include"|"import"){B}+/{ID} { - g_isImported = yytext[1]=='m'; - if (g_macroExpansion) + yyextra->isImported = yytext[1]=='m'; + if (yyextra->macroExpansion) BEGIN(IncludeID); } ("include"|"import"){B}*[<"] { - g_isImported = yytext[1]=='m'; + yyextra->isImported = yytext[1]=='m'; char c[2]; c[0]=yytext[yyleng-1];c[1]='\0'; - g_incName=c; + yyextra->incName=c; BEGIN(Include); } ("cmake")?"define"{B}+ { //printf("!!!DefName\n"); - g_yyColNr+=yyleng; + yyextra->yyColNr+=yyleng; BEGIN(DefName); } "ifdef"/{B}*"(" { - incrLevel(); - g_guardExpr.resize(0); + incrLevel(yyscanner); + yyextra->guardExpr.resize(0); BEGIN(DefinedExpr2); } "ifdef"/{B}+ { //printf("Pre.l: ifdef\n"); - incrLevel(); - g_guardExpr.resize(0); + incrLevel(yyscanner); + yyextra->guardExpr.resize(0); BEGIN(DefinedExpr1); } "ifndef"/{B}*"(" { - incrLevel(); - g_guardExpr="! "; + incrLevel(yyscanner); + yyextra->guardExpr="! "; BEGIN(DefinedExpr2); } "ifndef"/{B}+ { - incrLevel(); - g_guardExpr="! "; + incrLevel(yyscanner); + yyextra->guardExpr="! "; BEGIN(DefinedExpr1); } "if"/[ \t(!] { - incrLevel(); - g_guardExpr.resize(0); + incrLevel(yyscanner); + yyextra->guardExpr.resize(0); BEGIN(Guard); } ("elif"|"else"{B}*"if")/[ \t(!] { - if (!otherCaseDone()) + if (!otherCaseDone(yyscanner)) { - g_guardExpr.resize(0); + yyextra->guardExpr.resize(0); BEGIN(Guard); } else { - g_ifcount=0; + yyextra->ifcount=0; BEGIN(SkipCPPBlock); } } "else"/[^a-z_A-Z0-9\x80-\xFF] { - //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); - if (otherCaseDone()) + //printf("else yyextra->levelGuard[%d]=%d\n",yyextra->level-1,yyextra->levelGuard[yyextra->level-1]); + if (otherCaseDone(yyscanner)) { - g_ifcount=0; + yyextra->ifcount=0; BEGIN(SkipCPPBlock); } else { - setCaseDone(TRUE); - //g_levelGuard[g_level-1]=TRUE; + setCaseDone(yyscanner,TRUE); + //yyextra->levelGuard[yyextra->level-1]=TRUE; } } "undef"{B}+ { BEGIN(UndefName); } ("elif"|"else"{B}*"if")/[ \t(!] { - if (!otherCaseDone()) + if (!otherCaseDone(yyscanner)) { - g_guardExpr.resize(0); + yyextra->guardExpr.resize(0); BEGIN(Guard); } } "endif"/[^a-z_A-Z0-9\x80-\xFF] { //printf("Pre.l: #endif\n"); - decrLevel(); + decrLevel(yyscanner); } \n { - outputChar('\n'); + outputChar(yyscanner,'\n'); BEGIN(Start); - g_yyLineNr++; + yyextra->yyLineNr++; } "pragma"{B}+"once" { - g_expectGuard = FALSE; + yyextra->expectGuard = FALSE; } {ID} { // unknown directive BEGIN(IgnoreLine); } \\[\r]?\n { - outputChar('\n'); - g_yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; } . -. {g_yyColNr+=yyleng;} +. {yyextra->yyColNr+=yyleng;} {ID} { Define *def; - if ((def=DefineManager::instance().isDefined(yytext)) + if ((def=yyextra->defineManager.isDefined(yytext)) /*&& !def->isPredefined*/ && !def->nonRecursive ) @@ -2241,9 +888,9 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) BEGIN(Start); } \\[\r]?\n { - outputChar('\n'); - g_guardExpr+=' '; - g_yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->guardExpr+=' '; + yyextra->yyLineNr++; } "defined"/{B}*"(" { BEGIN(DefinedExpr2); @@ -2251,45 +898,45 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) "defined"/{B}+ { BEGIN(DefinedExpr1); } -{ID} { g_guardExpr+=yytext; } -"@" { g_guardExpr+="@@"; } -. { g_guardExpr+=*yytext; } +{ID} { yyextra->guardExpr+=yytext; } +"@" { yyextra->guardExpr+="@@"; } +. { yyextra->guardExpr+=*yytext; } \n { unput(*yytext); //printf("Guard: '%s'\n", - // g_guardExpr.data()); - bool guard=computeExpression(g_guardExpr); - setCaseDone(guard); - //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); + // yyextra->guardExpr.data()); + bool guard=computeExpression(yyscanner,yyextra->guardExpr); + setCaseDone(yyscanner,guard); + //printf("if yyextra->levelGuard[%d]=%d\n",yyextra->level-1,yyextra->levelGuard[yyextra->level-1]); if (guard) { BEGIN(Start); } else { - g_ifcount=0; + yyextra->ifcount=0; BEGIN(SkipCPPBlock); } } -\\\n { g_yyLineNr++; outputChar('\n'); } +\\\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); } {ID} { - if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext) - g_guardExpr+=" 1L "; + if (yyextra->defineManager.isDefined(yytext) || yyextra->guardName==yytext) + yyextra->guardExpr+=" 1L "; else - g_guardExpr+=" 0L "; - g_lastGuardName=yytext; + yyextra->guardExpr+=" 0L "; + yyextra->lastGuardName=yytext; BEGIN(Guard); } {ID} { - if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext) - g_guardExpr+=" 1L "; + if (yyextra->defineManager.isDefined(yytext) || yyextra->guardName==yytext) + yyextra->guardExpr+=" 1L "; else - g_guardExpr+=" 0L "; - g_lastGuardName=yytext; + yyextra->guardExpr+=" 0L "; + yyextra->lastGuardName=yytext; } \n { // should not happen, handle anyway - g_yyLineNr++; - g_ifcount=0; + yyextra->yyLineNr++; + yyextra->ifcount=0; BEGIN(SkipCPPBlock); } ")" { @@ -2298,29 +945,29 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) . ^{B}*"#" { BEGIN(SkipCommand); } ^{B}*/[^#] { BEGIN(SkipLine); } -\n { g_yyLineNr++; outputChar('\n'); } +\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); } . "if"(("n")?("def"))?/[ \t(!] { - incrLevel(); - g_ifcount++; - //printf("#if... depth=%d\n",g_ifcount); + incrLevel(yyscanner); + yyextra->ifcount++; + //printf("#if... depth=%d\n",yyextra->ifcount); } "else" { - //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone()); - if (g_ifcount==0 && !otherCaseDone()) + //printf("Else! yyextra->ifcount=%d otherCaseDone=%d\n",yyextra->ifcount,otherCaseDone()); + if (yyextra->ifcount==0 && !otherCaseDone(yyscanner)) { - setCaseDone(TRUE); - //outputChar('\n'); + setCaseDone(yyscanner,TRUE); + //outputChar(yyscanner,'\n'); BEGIN(Start); } } ("elif"|"else"{B}*"if")/[ \t(!] { - if (g_ifcount==0) + if (yyextra->ifcount==0) { - if (!otherCaseDone()) + if (!otherCaseDone(yyscanner)) { - g_guardExpr.resize(0); - g_lastGuardName.resize(0); + yyextra->guardExpr.resize(0); + yyextra->lastGuardName.resize(0); BEGIN(Guard); } else @@ -2330,17 +977,17 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) } } "endif" { - g_expectGuard = FALSE; - decrLevel(); - if (--g_ifcount<0) + yyextra->expectGuard = FALSE; + decrLevel(yyscanner); + if (--yyextra->ifcount<0) { - //outputChar('\n'); + //outputChar(yyscanner,'\n'); BEGIN(Start); } } \n { - outputChar('\n'); - g_yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; BEGIN(SkipCPPBlock); } {ID} { // unknown directive @@ -2356,18 +1003,18 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) "//"/[^\n]* { } "//"[^\n]* { - g_lastCPPContext=YY_START; + yyextra->lastCPPContext=YY_START; BEGIN(RemoveCPPComment); } "/*"/[^\n]* { } "/*"/[^\n]* { - g_lastCContext=YY_START; + yyextra->lastCContext=YY_START; BEGIN(RemoveCComment); } \n { - outputChar('\n'); - g_yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; BEGIN(SkipCPPBlock); } [^"\\\n]+ { } @@ -2377,21 +1024,21 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) } . { } {ID}{B}*/"(" { - g_nospaces=TRUE; - g_roundCount=0; - g_defArgsStr=yytext; - g_findDefArgContext = IncludeID; + yyextra->nospaces=TRUE; + yyextra->roundCount=0; + yyextra->defArgsStr=yytext; + yyextra->findDefArgContext = IncludeID; BEGIN(FindDefineArgs); } {ID} { - g_nospaces=TRUE; - readIncludeFile(expandMacro(yytext)); + yyextra->nospaces=TRUE; + readIncludeFile(yyscanner,expandMacro(yyscanner,yytext)); BEGIN(Start); } [^\">\n]+[\">] { - g_incName+=yytext; - readIncludeFile(g_incName); - if (g_isImported) + yyextra->incName+=yytext; + readIncludeFile(yyscanner,yyextra->incName); + if (yyextra->isImported) { BEGIN(EndImport); } @@ -2404,391 +1051,391 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) BEGIN(Start); } \\[\r]?"\n" { - outputChar('\n'); - g_yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; } . { } {ID}/("\\\n")*"(" { // define with argument //printf("Define() '%s'\n",yytext); - delete g_argDict; - g_argDict = new QDict(31); - g_argDict->setAutoDelete(TRUE); - g_defArgs = 0; - g_defArgsStr.resize(0); - g_defText.resize(0); - g_defLitText.resize(0); - g_defName = yytext; - g_defVarArgs = FALSE; - g_defExtraSpacing.resize(0); + delete yyextra->argDict; + yyextra->argDict = new QDict(31); + yyextra->argDict->setAutoDelete(TRUE); + yyextra->defArgs = 0; + yyextra->defArgsStr.resize(0); + yyextra->defText.resize(0); + yyextra->defLitText.resize(0); + yyextra->defName = yytext; + yyextra->defVarArgs = FALSE; + yyextra->defExtraSpacing.resize(0); BEGIN(DefineArg); } {ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard" //printf("Define '%s'\n",yytext); - delete g_argDict; g_argDict=0; - g_defArgs = -1; - g_defArgsStr.resize(0); - g_defName = yytext; - g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace(); - g_defVarArgs = FALSE; + delete yyextra->argDict; yyextra->argDict=0; + yyextra->defArgs = -1; + yyextra->defArgsStr.resize(0); + yyextra->defName = yytext; + yyextra->defName = yyextra->defName.left(yyextra->defName.length()-1).stripWhiteSpace(); + yyextra->defVarArgs = FALSE; //printf("Guard check: %s!=%s || %d\n", - // g_defName.data(),g_lastGuardName.data(),g_expectGuard); - if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard) + // yyextra->defName.data(),yyextra->lastGuardName.data(),yyextra->expectGuard); + if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard) { // define may appear in the output - QCString tmp=(QCString)"#define "+g_defName; - outputArray(tmp.data(),tmp.length()); - g_quoteArg=FALSE; - g_insideComment=FALSE; - g_lastGuardName.resize(0); - g_defText="1"; - g_defLitText="1"; + QCString tmp=(QCString)"#define "+yyextra->defName; + outputArray(yyscanner,tmp.data(),tmp.length()); + yyextra->quoteArg=FALSE; + yyextra->insideComment=FALSE; + yyextra->lastGuardName.resize(0); + yyextra->defText="1"; + yyextra->defLitText="1"; BEGIN(DefineText); } else // define is a guard => hide { //printf("Found a guard %s\n",yytext); - g_defText.resize(0); - g_defLitText.resize(0); + yyextra->defText.resize(0); + yyextra->defLitText.resize(0); BEGIN(Start); } - g_expectGuard=FALSE; + yyextra->expectGuard=FALSE; } {ID}/{B}*"\n" { // empty define - delete g_argDict; g_argDict=0; - g_defArgs = -1; - g_defName = yytext; - g_defArgsStr.resize(0); - g_defText.resize(0); - g_defLitText.resize(0); - g_defVarArgs = FALSE; + delete yyextra->argDict; yyextra->argDict=0; + yyextra->defArgs = -1; + yyextra->defName = yytext; + yyextra->defArgsStr.resize(0); + yyextra->defText.resize(0); + yyextra->defLitText.resize(0); + yyextra->defVarArgs = FALSE; //printf("Guard check: %s!=%s || %d\n", - // g_defName.data(),g_lastGuardName.data(),g_expectGuard); - if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard) + // yyextra->defName.data(),yyextra->lastGuardName.data(),yyextra->expectGuard); + if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard) { // define may appear in the output - QCString tmp=(QCString)"#define "+g_defName; - outputArray(tmp.data(),tmp.length()); - g_quoteArg=FALSE; - g_insideComment=FALSE; - if (g_insideCS) g_defText="1"; // for C#, use "1" as define text + QCString tmp=(QCString)"#define "+yyextra->defName; + outputArray(yyscanner,tmp.data(),tmp.length()); + yyextra->quoteArg=FALSE; + yyextra->insideComment=FALSE; + if (yyextra->insideCS) yyextra->defText="1"; // for C#, use "1" as define text BEGIN(DefineText); } else // define is a guard => hide { //printf("Found a guard %s\n",yytext); - g_guardName = yytext; - g_lastGuardName.resize(0); + yyextra->guardName = yytext; + yyextra->lastGuardName.resize(0); BEGIN(Start); } - g_expectGuard=FALSE; + yyextra->expectGuard=FALSE; } {ID}/{B}* { // define with content //printf("Define '%s'\n",yytext); - delete g_argDict; g_argDict=0; - g_defArgs = -1; - g_defArgsStr.resize(0); - g_defText.resize(0); - g_defLitText.resize(0); - g_defName = yytext; - g_defVarArgs = FALSE; - QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr; - outputArray(tmp.data(),tmp.length()); - g_quoteArg=FALSE; - g_insideComment=FALSE; + delete yyextra->argDict; yyextra->argDict=0; + yyextra->defArgs = -1; + yyextra->defArgsStr.resize(0); + yyextra->defText.resize(0); + yyextra->defLitText.resize(0); + yyextra->defName = yytext; + yyextra->defVarArgs = FALSE; + QCString tmp=(QCString)"#define "+yyextra->defName+yyextra->defArgsStr; + outputArray(yyscanner,tmp.data(),tmp.length()); + yyextra->quoteArg=FALSE; + yyextra->insideComment=FALSE; BEGIN(DefineText); } "\\\n" { - g_defExtraSpacing+="\n"; - g_yyLineNr++; + yyextra->defExtraSpacing+="\n"; + yyextra->yyLineNr++; } -","{B}* { g_defArgsStr+=yytext; } -"("{B}* { g_defArgsStr+=yytext; } +","{B}* { yyextra->defArgsStr+=yytext; } +"("{B}* { yyextra->defArgsStr+=yytext; } {B}*")"{B}* { - g_defArgsStr+=yytext; - QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing; - outputArray(tmp.data(),tmp.length()); - g_quoteArg=FALSE; - g_insideComment=FALSE; + yyextra->defArgsStr+=yytext; + QCString tmp=(QCString)"#define "+yyextra->defName+yyextra->defArgsStr+yyextra->defExtraSpacing; + outputArray(yyscanner,tmp.data(),tmp.length()); + yyextra->quoteArg=FALSE; + yyextra->insideComment=FALSE; BEGIN(DefineText); } "..." { // Variadic macro - g_defVarArgs = TRUE; - g_defArgsStr+=yytext; - g_argDict->insert("__VA_ARGS__",new int(g_defArgs)); - g_defArgs++; + yyextra->defVarArgs = TRUE; + yyextra->defArgsStr+=yytext; + yyextra->argDict->insert("__VA_ARGS__",new int(yyextra->defArgs)); + yyextra->defArgs++; } {ID}{B}*("..."?) { //printf("Define addArg(%s)\n",yytext); QCString argName=yytext; - g_defVarArgs = yytext[yyleng-1]=='.'; - if (g_defVarArgs) // strip ellipsis + yyextra->defVarArgs = yytext[yyleng-1]=='.'; + if (yyextra->defVarArgs) // strip ellipsis { argName=argName.left(argName.length()-3); } argName = argName.stripWhiteSpace(); - g_defArgsStr+=yytext; - g_argDict->insert(argName,new int(g_defArgs)); - g_defArgs++; + yyextra->defArgsStr+=yytext; + yyextra->argDict->insert(argName,new int(yyextra->defArgs)); + yyextra->defArgs++; } /* "/ **"|"/ *!" { - g_defText+=yytext; - g_defLitText+=yytext; - g_insideComment=TRUE; + yyextra->defText+=yytext; + yyextra->defLitText+=yytext; + yyextra->insideComment=TRUE; } "* /" { - g_defText+=yytext; - g_defLitText+=yytext; - g_insideComment=FALSE; + yyextra->defText+=yytext; + yyextra->defLitText+=yytext; + yyextra->insideComment=FALSE; } */ "/*"[!*]? { - g_defText+=yytext; - g_defLitText+=yytext; - g_lastCContext=YY_START; - g_commentCount=1; + yyextra->defText+=yytext; + yyextra->defLitText+=yytext; + yyextra->lastCContext=YY_START; + yyextra->commentCount=1; BEGIN(CopyCComment); } "//"[!/]? { - outputArray(yytext,(int)yyleng); - g_lastCPPContext=YY_START; - g_defLitText+=' '; + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->lastCPPContext=YY_START; + yyextra->defLitText+=' '; BEGIN(SkipCPPComment); } [/]?"*/" { - if (yytext[0]=='/') outputChar('/'); - outputChar('*');outputChar('/'); - if (--g_commentCount<=0) + if (yytext[0]=='/') outputChar(yyscanner,'/'); + outputChar(yyscanner,'*');outputChar(yyscanner,'/'); + if (--yyextra->commentCount<=0) { - if (g_lastCContext==Start) + if (yyextra->lastCContext==Start) // small hack to make sure that ^... rule will // match when going to Start... Example: "/*...*/ some stuff..." { YY_CURRENT_BUFFER->yy_at_bol=1; } - BEGIN(g_lastCContext); + BEGIN(yyextra->lastCContext); } } "//"("/")* { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } "/*" { - outputChar('/');outputChar('*'); - //g_commentCount++; + outputChar(yyscanner,'/');outputChar(yyscanner,'*'); + //yyextra->commentCount++; } [\\@][\\@]("f{"|"f$"|"f[") { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } ^({B}*"*"+)?{B}{0,3}"~~~"[~]* { - static bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT); + bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT); if (!markdownSupport) { REJECT; } else { - outputArray(yytext,(int)yyleng); - g_fenceSize=yyleng; + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->fenceSize=yyleng; BEGIN(SkipVerbatim); } } ^({B}*"*"+)?{B}{0,3}"```"[`]* { - static bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT); + bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT); if (!markdownSupport) { REJECT; } else { - outputArray(yytext,(int)yyleng); - g_fenceSize=yyleng; + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->fenceSize=yyleng; BEGIN(SkipVerbatim); } } [\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ { - outputArray(yytext,(int)yyleng); - g_yyLineNr+=QCString(yytext).contains('\n'); + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->yyLineNr+=QCString(yytext).contains('\n'); } [\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ { - outputArray(yytext,(int)yyleng); - g_yyLineNr+=QCString(yytext).contains('\n'); - g_fenceSize=0; + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->yyLineNr+=QCString(yytext).contains('\n'); + yyextra->fenceSize=0; if (yytext[1]=='f') { - g_blockName="f"; + yyextra->blockName="f"; } else { QCString bn=&yytext[1]; int i = bn.find('{'); // for \code{.c} if (i!=-1) bn=bn.left(i); - g_blockName=bn.stripWhiteSpace(); + yyextra->blockName=bn.stripWhiteSpace(); } BEGIN(SkipVerbatim); } [\\@][\\@]"cond"[ \t]+ { // escaped @cond - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } [\\@]"cond"[ \t]+ { // conditional section - g_ccomment=TRUE; - g_condCtx=YY_START; + yyextra->ccomment=TRUE; + yyextra->condCtx=YY_START; BEGIN(CondLineCpp); } [\\@]"cond"[ \t]+ { // conditional section - g_ccomment=FALSE; - g_condCtx=YY_START; + yyextra->ccomment=FALSE; + yyextra->condCtx=YY_START; BEGIN(CondLineC); } [!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ { - startCondSection(yytext); - if (g_skip) + startCondSection(yyscanner,yytext); + if (yyextra->skip) { if (YY_START==CondLineC) { // end C comment - outputArray("*/",2); - g_ccomment=TRUE; + outputArray(yyscanner,"*/",2); + yyextra->ccomment=TRUE; } else { - g_ccomment=FALSE; + yyextra->ccomment=FALSE; } BEGIN(SkipCond); } else { - BEGIN(g_condCtx); + BEGIN(yyextra->condCtx); } } . { // non-guard character unput(*yytext); - startCondSection(" "); - if (g_skip) + startCondSection(yyscanner," "); + if (yyextra->skip) { if (YY_START==CondLineC) { // end C comment - outputArray("*/",2); - g_ccomment=TRUE; + outputArray(yyscanner,"*/",2); + yyextra->ccomment=TRUE; } else { - g_ccomment=FALSE; + yyextra->ccomment=FALSE; } BEGIN(SkipCond); } else { - BEGIN(g_condCtx); + BEGIN(yyextra->condCtx); } } [\\@]"cond"[ \t\r]*/\n { // no guard if (YY_START==SkipCComment) { - g_ccomment=TRUE; + yyextra->ccomment=TRUE; // end C comment - outputArray("*/",2); + outputArray(yyscanner,"*/",2); } else { - g_ccomment=FALSE; + yyextra->ccomment=FALSE; } - g_condCtx=YY_START; - startCondSection(" "); + yyextra->condCtx=YY_START; + startCondSection(yyscanner," "); BEGIN(SkipCond); } -\n { g_yyLineNr++; outputChar('\n'); } +\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); } . { } [^\/\!*\\@\n]+ { } -"//"[/!] { g_ccomment=FALSE; } -"/*"[*!] { g_ccomment=TRUE; } +"//"[/!] { yyextra->ccomment=FALSE; } +"/*"[*!] { yyextra->ccomment=TRUE; } [\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] { - if (!g_skip) + if (!yyextra->skip) { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } } [\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] { - bool oldSkip = g_skip; - endCondSection(); - if (oldSkip && !g_skip) + bool oldSkip = yyextra->skip; + endCondSection(yyscanner); + if (oldSkip && !yyextra->skip) { - if (g_ccomment) + if (yyextra->ccomment) { - outputArray("/** ",4); + outputArray(yyscanner,"/** ",4); } - BEGIN(g_condCtx); + BEGIN(yyextra->condCtx); } } [\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] { - bool oldSkip = g_skip; - endCondSection(); - if (oldSkip && !g_skip) + bool oldSkip = yyextra->skip; + endCondSection(yyscanner); + if (oldSkip && !yyextra->skip) { - BEGIN(g_condCtx); + BEGIN(yyextra->condCtx); } } [\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */ - outputArray(yytext,(int)yyleng); - if (yytext[1]=='f' && g_blockName=="f") + outputArray(yyscanner,yytext,(int)yyleng); + if (yytext[1]=='f' && yyextra->blockName=="f") { BEGIN(SkipCComment); } - else if (&yytext[4]==g_blockName) + else if (&yytext[4]==yyextra->blockName) { BEGIN(SkipCComment); } } ^({B}*"*"+)?{B}{0,3}"~~~"[~]* { - outputArray(yytext,(int)yyleng); - if (g_fenceSize==yyleng) + outputArray(yyscanner,yytext,(int)yyleng); + if (yyextra->fenceSize==yyleng) { BEGIN(SkipCComment); } } ^({B}*"*"+)?{B}{0,3}"```"[`]* { - outputArray(yytext,(int)yyleng); - if (g_fenceSize==yyleng) + outputArray(yyscanner,yytext,(int)yyleng); + if (yyextra->fenceSize==yyleng) { BEGIN(SkipCComment); } } "*/"|"/*" { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } [^*\\@\x06~`\n\/]+ { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } \n { - g_yyLineNr++; - outputChar('\n'); + yyextra->yyLineNr++; + outputChar(yyscanner,'\n'); } . { - outputChar(*yytext); + outputChar(yyscanner,*yytext); } [^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] { - g_defLitText+=yytext; - g_defText+=escapeAt(yytext); + yyextra->defLitText+=yytext; + yyextra->defText+=escapeAt(yytext); } \\[\r]?\n { - g_defLitText+=yytext; - outputChar('\n'); - g_defText+=" "; - g_yyLineNr++; - g_yyMLines++; + yyextra->defLitText+=yytext; + outputChar(yyscanner,'\n'); + yyextra->defText+=" "; + yyextra->yyLineNr++; + yyextra->yyMLines++; } "*/" { - g_defLitText+=yytext; - g_defText+=yytext; - BEGIN(g_lastCContext); + yyextra->defLitText+=yytext; + yyextra->defText+=yytext; + BEGIN(yyextra->lastCContext); } \n { - g_yyLineNr++; - outputChar('\n'); - g_defLitText+=yytext; - g_defText+=' '; + yyextra->yyLineNr++; + outputChar(yyscanner,'\n'); + yyextra->defLitText+=yytext; + yyextra->defText+=' '; } "*/"{B}*"#" { // see bug 594021 for a usecase for this rule - if (g_lastCContext==SkipCPPBlock) + if (yyextra->lastCContext==SkipCPPBlock) { BEGIN(SkipCommand); } @@ -2797,246 +1444,1632 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) REJECT; } } -"*/" { BEGIN(g_lastCContext); } +"*/" { BEGIN(yyextra->lastCContext); } "//" "/*" [^*\x06\n]+ -\n { g_yyLineNr++; outputChar('\n'); } +\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); } . [^\n\/\\@]+ { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } \n { unput(*yytext); - BEGIN(g_lastCPPContext); + BEGIN(yyextra->lastCPPContext); } "/*" { - outputChar('/');outputChar('*'); + outputChar(yyscanner,'/');outputChar(yyscanner,'*'); } "//" { - outputChar('/');outputChar('/'); + outputChar(yyscanner,'/');outputChar(yyscanner,'/'); } [^\x06\@\\\n]+ { - outputArray(yytext,(int)yyleng); + outputArray(yyscanner,yytext,(int)yyleng); } . { - outputChar(*yytext); + outputChar(yyscanner,*yytext); } "/*" "//" [^\x06\n]+ . "#" { - g_quoteArg=TRUE; - g_defLitText+=yytext; + yyextra->quoteArg=TRUE; + yyextra->defLitText+=yytext; } {ID} { - g_defLitText+=yytext; - if (g_quoteArg) + yyextra->defLitText+=yytext; + if (yyextra->quoteArg) { - g_defText+="\""; + yyextra->defText+="\""; } - if (g_defArgs>0) + if (yyextra->defArgs>0) { int *n; - if ((n=(*g_argDict)[yytext])) + if ((n=(*yyextra->argDict)[yytext])) { - //if (!g_quoteArg) g_defText+=' '; - g_defText+='@'; + //if (!yyextra->quoteArg) yyextra->defText+=' '; + yyextra->defText+='@'; QCString numStr; numStr.sprintf("%d",*n); - g_defText+=numStr; - //if (!g_quoteArg) g_defText+=' '; + yyextra->defText+=numStr; + //if (!yyextra->quoteArg) yyextra->defText+=' '; } else { - g_defText+=yytext; + yyextra->defText+=yytext; } } else { - g_defText+=yytext; + yyextra->defText+=yytext; } - if (g_quoteArg) + if (yyextra->quoteArg) { - g_defText+="\""; + yyextra->defText+="\""; } - g_quoteArg=FALSE; + yyextra->quoteArg=FALSE; } . { - g_defLitText+=yytext; - g_defText+=yytext; + yyextra->defLitText+=yytext; + yyextra->defText+=yytext; } \\[\r]?\n { - g_defLitText+=yytext; - outputChar('\n'); - g_defText += ' '; - g_yyLineNr++; - g_yyMLines++; + yyextra->defLitText+=yytext; + outputChar(yyscanner,'\n'); + yyextra->defText += ' '; + yyextra->yyLineNr++; + yyextra->yyMLines++; + } +\n { + QCString comment=extractTrailingComment(yyextra->defLitText); + yyextra->defLitText+=yytext; + if (!comment.isEmpty()) + { + outputArray(yyscanner,comment,comment.length()); + yyextra->defLitText=yyextra->defLitText.left(yyextra->defLitText.length()-comment.length()-1); + } + outputChar(yyscanner,'\n'); + Define *def=0; + //printf("Define name='%s' text='%s' litTexti='%s'\n",yyextra->defName.data(),yyextra->defText.data(),yyextra->defLitText.data()); + if (yyextra->includeStack.isEmpty() || yyextra->curlyCount>0) + { + addDefine(yyscanner); + } + def=yyextra->defineManager.isDefined(yyextra->defName); + if (def==0) // new define + { + //printf("new define '%s'!\n",yyextra->defName.data()); + Define *nd = newDefine(yyscanner); + yyextra->defineManager.addDefine(yyextra->yyFileName,nd); + + // also add it to the local file list if it is a source file + //if (yyextra->isSource && yyextra->includeStack.isEmpty()) + //{ + // yyextra->fileDefineDict->insert(yyextra->defName,nd); + //} + } + else if (def /*&& macroIsAccessible(def)*/) + // name already exists + { + //printf("existing define!\n"); + //printf("define found\n"); + if (def->undef) // undefined name + { + def->undef = FALSE; + def->name = yyextra->defName; + def->definition = yyextra->defText.stripWhiteSpace(); + def->nargs = yyextra->defArgs; + def->fileName = yyextra->yyFileName.copy(); + def->lineNr = yyextra->yyLineNr-yyextra->yyMLines; + def->columnNr = yyextra->yyColNr; + } + else + { + //printf("error: define %s is defined more than once!\n",yyextra->defName.data()); + } + } + delete yyextra->argDict; yyextra->argDict=0; + yyextra->yyLineNr++; + yyextra->yyColNr=1; + yyextra->lastGuardName.resize(0); + BEGIN(Start); + } +{B}* { yyextra->defText += ' '; yyextra->defLitText+=yytext; } +{B}*"##"{B}* { yyextra->defText += "##"; yyextra->defLitText+=yytext; } +"@" { yyextra->defText += "@@"; yyextra->defLitText+=yytext; } +\" { + yyextra->defText += *yytext; + yyextra->defLitText+=yytext; + if (!yyextra->insideComment) + { + BEGIN(SkipDoubleQuote); + } + } +\' { yyextra->defText += *yytext; + yyextra->defLitText+=yytext; + if (!yyextra->insideComment) + { + BEGIN(SkipSingleQuote); + } + } +"//"[/]? { yyextra->defText += yytext; yyextra->defLitText+=yytext; } +"/*" { yyextra->defText += yytext; yyextra->defLitText+=yytext; } +\" { + yyextra->defText += *yytext; yyextra->defLitText+=yytext; + BEGIN(DefineText); + } +\\. { + yyextra->defText += yytext; yyextra->defLitText+=yytext; + } +\' { + yyextra->defText += *yytext; yyextra->defLitText+=yytext; + BEGIN(DefineText); + } +. { yyextra->defText += *yytext; yyextra->defLitText+=yytext; } +. { yyextra->defText += *yytext; yyextra->defLitText+=yytext; } +. { yyextra->defText += *yytext; yyextra->defLitText+=yytext; } +<> { + DBG_CTX((stderr,"End of include file\n")); + //printf("Include stack depth=%d\n",yyextra->includeStack.count()); + if (yyextra->includeStack.isEmpty()) + { + DBG_CTX((stderr,"Terminating scanner!\n")); + yyterminate(); + } + else + { + FileState *fs=yyextra->includeStack.pop(); + //fileDefineCache->merge(yyextra->yyFileName,fs->fileName); + YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; + yy_switch_to_buffer( fs->bufState, yyscanner ); + yy_delete_buffer( oldBuf, yyscanner ); + yyextra->yyLineNr = fs->lineNr; + //preYYin = fs->oldYYin; + yyextra->inputBuf = fs->oldFileBuf; + yyextra->inputBufPos = fs->oldFileBufPos; + yyextra->curlyCount = fs->curlyCount; + setFileName(yyscanner,fs->fileName); + DBG_CTX((stderr,"######## FileName %s\n",yyextra->yyFileName.data())); + + // Deal with file changes due to + // #include's within { .. } blocks + QCString lineStr(15+yyextra->yyFileName.length()); + lineStr.sprintf("# %d \"%s\" 2",yyextra->yyLineNr,yyextra->yyFileName.data()); + outputArray(yyscanner,lineStr.data(),lineStr.length()); + + delete fs; fs=0; + } + } +<*>"/*"/"*/" | +<*>"/*"[*]? { + if (YY_START==SkipVerbatim || YY_START==SkipCond) + { + REJECT; + } + else + { + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->lastCContext=YY_START; + yyextra->commentCount=1; + if (yyleng==3) yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented! + BEGIN(SkipCComment); + } + } +<*>"//"[/]? { + if (YY_START==SkipVerbatim || YY_START==SkipCond || getLanguageFromFileName(yyextra->yyFileName)==SrcLangExt_Fortran) + { + REJECT; + } + else + { + outputArray(yyscanner,yytext,(int)yyleng); + yyextra->lastCPPContext=YY_START; + if (yyleng==3) yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented! + BEGIN(SkipCPPComment); + } + } +<*>\n { + outputChar(yyscanner,'\n'); + yyextra->yyLineNr++; } -\n { - QCString comment=extractTrailingComment(g_defLitText); - g_defLitText+=yytext; - if (!comment.isEmpty()) - { - outputArray(comment,comment.length()); - g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1); - } - outputChar('\n'); - Define *def=0; - //printf("Define name='%s' text='%s' litTexti='%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data()); - if (g_includeStack.isEmpty() || g_curlyCount>0) - { - addDefine(); - } - def=DefineManager::instance().isDefined(g_defName); - if (def==0) // new define - { - //printf("new define '%s'!\n",g_defName.data()); - Define *nd = newDefine(); - DefineManager::instance().addDefine(g_yyFileName,nd); +<*>. { + yyextra->expectGuard = FALSE; + outputChar(yyscanner,*yytext); + } + +%% + +///////////////////////////////////////////////////////////////////////////////////// + +static int yyread(yyscan_t yyscanner,char *buf,int max_size) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + int bytesInBuf = state->inputBuf->curPos()-state->inputBufPos; + int bytesToCopy = QMIN(max_size,bytesInBuf); + memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy); + state->inputBufPos+=bytesToCopy; + return bytesToCopy; +} + +static void setFileName(yyscan_t yyscanner,const char *name) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + bool ambig; + QFileInfo fi(name); + state->yyFileName=fi.absFilePath().utf8(); + state->yyFileDef=findFileDef(Doxygen::inputNameDict,state->yyFileName,ambig); + if (state->yyFileDef==0) // if this is not an input file check if it is an + // include file + { + state->yyFileDef=findFileDef(Doxygen::includeNameDict,state->yyFileName,ambig); + } + //printf("setFileName(%s) state->yyFileName=%s state->yyFileDef=%p\n", + // name,state->yyFileName.data(),state->yyFileDef); + if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=0; + state->insideCS = getLanguageFromFileName(state->yyFileName)==SrcLangExt_CSharp; + state->isSource = guessSection(state->yyFileName); +} + +static void incrLevel(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + state->level++; + state->levelGuard.resize(state->level); + state->levelGuard[state->level-1]=FALSE; + //printf("%s line %d: incrLevel %d\n",yyextra->yyFileName.data(),yyextra->yyLineNr,yyextra->level); +} + +static void decrLevel(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + //printf("%s line %d: decrLevel %d\n",state->yyFileName.data(),state->yyLineNr,state->level); + if (state->level > 0) + { + state->level--; + state->levelGuard.resize(state->level); + } + else + { + warn(state->yyFileName,state->yyLineNr,"More #endif's than #if's found.\n"); + } +} + +static bool otherCaseDone(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + if (state->level==0) + { + warn(state->yyFileName,state->yyLineNr,"Found an #else without a preceding #if.\n"); + return TRUE; + } + else + { + return state->levelGuard[state->level-1]; + } +} + +static void setCaseDone(yyscan_t yyscanner,bool value) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + state->levelGuard[state->level-1]=value; +} + + +static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyIncluded) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + alreadyIncluded = FALSE; + FileState *fs = 0; + //printf("checkAndOpenFile(%s)\n",fileName.data()); + QFileInfo fi(fileName); + if (fi.exists() && fi.isFile()) + { + const QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS); + if (patternMatch(fi,&exclPatterns)) return 0; + + QCString absName = fi.absFilePath().utf8(); + + // global guard + if (state->curlyCount==0) // not #include inside { ... } + { + if (state->allIncludes.find(absName)!=0) + { + alreadyIncluded = TRUE; + //printf(" already included 1\n"); + return 0; // already done + } + state->allIncludes.insert(absName,(void *)0x8); + } + // check include stack for absName + + QStack tmpStack; + state->includeStack.setAutoDelete(FALSE); + while ((fs=state->includeStack.pop())) + { + if (fs->fileName==absName) alreadyIncluded=TRUE; + tmpStack.push(fs); + } + while ((fs=tmpStack.pop())) + { + state->includeStack.push(fs); + } + state->includeStack.setAutoDelete(TRUE); + + if (alreadyIncluded) + { + //printf(" already included 2\n"); + return 0; + } + //printf("#include %s\n",absName.data()); + + fs = new FileState(fi.size()+4096); + alreadyIncluded = FALSE; + if (!readInputFile(absName,fs->fileBuf)) + { // error + //printf(" error reading\n"); + delete fs; + fs=0; + } + else + { + fs->oldFileBuf = state->inputBuf; + fs->oldFileBufPos = state->inputBufPos; + } + } + return fs; +} + +static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localInclude,bool &alreadyIncluded) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + //printf("** findFile(%s,%d) state->yyFileName=%s\n",fileName,localInclude,state->yyFileName.data()); + if (portable_isAbsolutePath(fileName)) + { + FileState *fs = checkAndOpenFile(yyscanner,fileName,alreadyIncluded); + if (fs) + { + setFileName(yyscanner,fileName); + state->yyLineNr=1; + return fs; + } + else if (alreadyIncluded) + { + return 0; + } + } + if (localInclude && !state->yyFileName.isEmpty()) + { + QFileInfo fi(state->yyFileName); + if (fi.exists()) + { + QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName; + FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyIncluded); + if (fs) + { + setFileName(yyscanner,absName); + state->yyLineNr=1; + return fs; + } + else if (alreadyIncluded) + { + return 0; + } + } + } + if (state->pathList==0) + { + return 0; + } + char *s=state->pathList->first(); + while (s) + { + QCString absName = (QCString)s+"/"+fileName; + //printf(" Looking for %s in %s\n",fileName,s); + FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyIncluded); + if (fs) + { + setFileName(yyscanner,absName); + state->yyLineNr=1; + //printf(" -> found it\n"); + return fs; + } + else if (alreadyIncluded) + { + return 0; + } + + s=state->pathList->next(); + } + return 0; +} + +static QCString extractTrailingComment(const char *s) +{ + if (s==0) return ""; + int i=strlen(s)-1; + while (i>=0) + { + char c=s[i]; + switch (c) + { + case '/': + { + i--; + if (i>=0 && s[i]=='*') // end of a comment block + { + i--; + while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--; + if (i==0) + { + i++; + } + // only /*!< or /**< are treated as a comment for the macro name, + // otherwise the comment is treated as part of the macro definition + return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : ""; + } + else + { + return ""; + } + } + break; + // whitespace or line-continuation + case ' ': + case '\t': + case '\r': + case '\n': + case '\\': + break; + default: + return ""; + } + i--; + } + return ""; +} + +static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos); +static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint pos); +static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos,char c); +static void expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos); + +static QCString stringize(const QCString &s) +{ + QCString result; + uint i=0; + bool inString=FALSE; + bool inChar=FALSE; + char c,pc; + while (i'%s'\n",s.data(),result.data()); + return result; +} + +/*! Execute all ## operators in expr. + * If the macro name before or after the operator contains a no-rescan + * marker (@-) then this is removed (before the concatenated macro name + * may be expanded again. + */ +static void processConcatOperators(QCString &expr) +{ + //printf("processConcatOperators: in='%s'\n",expr.data()); + QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); + int l,n,i=0; + if (expr.isEmpty()) return; + while ((n=r.match(expr,i,&l))!=-1) + { + //printf("Match: '%s'\n",expr.data()+i); + if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-') + { + // remove no-rescan marker after ID + l+=2; + } + //printf("found '%s'\n",expr.mid(n,l).data()); + // remove the ## operator and the surrounding whitespace + expr=expr.left(n)+expr.right(expr.length()-n-l); + int k=n-1; + while (k>=0 && isId(expr.at(k))) k--; + if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@') + { + // remove no-rescan marker before ID + expr=expr.left(k-1)+expr.right(expr.length()-k-1); + n-=2; + } + i=n; + } + //printf("processConcatOperators: out='%s'\n",expr.data()); +} + +static void returnCharToStream(yyscan_t yyscanner,char c) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + unput(c); +} + +static inline void addTillEndOfString(yyscan_t yyscanner,const QCString &expr,QCString *rest, + uint &pos,char term,QCString &arg) +{ + int cc; + while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0) + { + if (cc=='\\') arg+=(char)cc,cc=getNextChar(yyscanner,expr,rest,pos); + else if (cc==term) return; + arg+=(char)cc; + } +} + +/*! replaces the function macro \a def whose argument list starts at + * \a pos in expression \a expr. + * Notice that this routine may scan beyond the \a expr string if needed. + * In that case the characters will be read from the input file. + * The replacement string will be returned in \a result and the + * length of the (unexpanded) argument list is stored in \a len. + */ +static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),state->level); + uint j=pos; + len=0; + result.resize(0); + int cc; + while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && isspace(cc)) + { + len++; + getNextChar(yyscanner,expr,rest,j); + } + if (cc!='(') + { + unputChar(yyscanner,expr,rest,j,' '); + return FALSE; + } + getNextChar(yyscanner,expr,rest,j); // eat the '(' character + + QDict argTable; // list of arguments + argTable.setAutoDelete(TRUE); + QCString arg; + int argCount=0; + bool done=FALSE; + + // PHASE 1: read the macro arguments + if (def->nargs==0) + { + while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + { + char c = (char)cc; + if (c==')') break; + } + } + else + { + while (!done && (argCountnargs || def->varArgs) && + ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + ) + { + char c=(char)cc; + if (c=='(') // argument is a function => search for matching ) + { + int level=1; + arg+=c; + //char term='\0'; + while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + { + char c=(char)cc; + //printf("processing %c: term=%c (%d)\n",c,term,term); + if (c=='\'' || c=='\"') // skip ('s and )'s inside strings + { + arg+=c; + addTillEndOfString(yyscanner,expr,rest,j,c,arg); + } + if (c==')') + { + level--; + arg+=c; + if (level==0) break; + } + else if (c=='(') + { + level++; + arg+=c; + } + else + arg+=c; + } + } + else if (c==')' || c==',') // last or next argument found + { + if (c==',' && argCount==def->nargs-1 && def->varArgs) + { + arg=arg.stripWhiteSpace(); + arg+=','; + } + else + { + QCString argKey; + argKey.sprintf("@%d",argCount++); // key name + arg=arg.stripWhiteSpace(); + // add argument to the lookup table + argTable.insert(argKey, new QCString(arg)); + arg.resize(0); + if (c==')') // end of the argument list + { + done=TRUE; + } + } + } + else if (c=='\"') // append literal strings + { + arg+=c; + bool found=FALSE; + while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + { + found = cc=='"'; + if (cc=='\\') + { + c=(char)cc; + arg+=c; + if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break; + } + c=(char)cc; + arg+=c; + } + } + else if (c=='\'') // append literal characters + { + arg+=c; + bool found=FALSE; + while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + { + found = cc=='\''; + if (cc=='\\') + { + c=(char)cc; + arg+=c; + if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break; + } + c=(char)cc; + arg+=c; + } + } + else if (c=='/') // possible start of a comment + { + char prevChar = '\0'; + arg+=c; + if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment + { + while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0) + { + c=(char)cc; + arg+=c; + if (c == '/' && prevChar == '*') break; // we have an end of comment + prevChar = c; + } + } + } + else // append other characters + { + arg+=c; + } + } + } + + // PHASE 2: apply the macro function + if (argCount==def->nargs || // same number of arguments + (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many + // params as the non-variadic part (see bug731985) + { + uint k=0; + // substitution of all formal arguments + QCString resExpr; + const QCString d=def->definition.stripWhiteSpace(); + //printf("Macro definition: %s\n",d.data()); + bool inString=FALSE; + while (k copy it (is unescaped later) + { + k+=2; + resExpr+="@@"; // we unescape these later + } + else if (d.at(k+1)=='-') // no-rescan marker + { + k+=2; + resExpr+="@-"; + } + else // argument marker => read the argument number + { + QCString key="@"; + QCString *subst=0; + bool hash=FALSE; + int l=k-1; + // search for ## backward + if (l>=0 && d.at(l)=='"') l--; + while (l>=0 && d.at(l)==' ') l--; + if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE; + k++; + // scan the number + while (k='0' && d.at(k)<='9') key+=d.at(k++); + if (!hash) + { + // search for ## forward + l=k; + if (l<(int)d.length() && d.at(l)=='"') l++; + while (l<(int)d.length() && d.at(l)==' ') l++; + if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE; + } + //printf("request key %s result %s\n",key.data(),argTable[key]->data()); + if (key.length()>1 && (subst=argTable[key])) + { + QCString substArg=*subst; + //printf("substArg='%s'\n",substArg.data()); + // only if no ## operator is before or after the argument + // marker we do macro expansion. + if (!hash) expandExpression(yyscanner,substArg,0,0); + if (inString) + { + //printf("'%s'=stringize('%s')\n",stringize(*subst).data(),subst->data()); + + // if the marker is inside a string (because a # was put + // before the macro name) we must escape " and \ characters + resExpr+=stringize(substArg); + } + else + { + if (hash && substArg.isEmpty()) + { + resExpr+="@E"; // empty argument will be remove later on + } + else if (state->nospaces) + { + resExpr+=substArg; + } + else + { + resExpr+=" "+substArg+" "; + } + } + } + } + } + else // no marker, just copy + { + if (!inString && d.at(k)=='\"') + { + inString=TRUE; // entering a literal string + } + else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\')) + { + inString=FALSE; // leaving a literal string + } + resExpr+=d.at(k++); + } + } + len=j-pos; + result=resExpr; + //printf("result after substitution '%s' expr='%s'\n", + // result.data(),expr.mid(pos,len).data()); + return TRUE; + } + return FALSE; +} + + +/*! returns the next identifier in string \a expr by starting at position \a p. + * The position of the identifier is returned (or -1 if nothing is found) + * and \a l is its length. Any quoted strings are skipping during the search. + */ +static int getNextId(const QCString &expr,int p,int *l) +{ + int n; + while (p<(int)expr.length()) + { + char c=expr.at(p++); + if (isdigit(c)) // skip number + { + while (p<(int)expr.length() && isId(expr.at(p))) p++; + } + else if (isalpha(c) || c=='_') // read id + { + n=p-1; + while (p<(int)expr.length() && isId(expr.at(p))) p++; + *l=p-n; + return n; + } + else if (c=='"') // skip string + { + char ppc=0,pc=c; + if (p<(int)expr.length()) c=expr.at(p); + while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) + // continue as long as no " is found, but ignoring \", but not \\" + { + ppc=pc; + pc=c; + c=expr.at(p); + p++; + } + if (p<(int)expr.length()) ++p; // skip closing quote + } + else if (c=='/') // skip C Comment + { + //printf("Found C comment at p=%d\n",p); + char pc=c; + if (p<(int)expr.length()) + { + c=expr.at(p); + if (c=='*') // Start of C comment + { + p++; + while (p<(int)expr.length() && !(pc=='*' && c=='/')) + { + pc=c; + c=expr.at(p++); + } + } + } + //printf("Found end of C comment at p=%d\n",p); + } + } + return -1; +} + +/*! performs recursive macro expansion on the string \a expr + * starting at position \a pos. + * May read additional characters from the input while re-scanning! + * If \a expandAll is \c TRUE then all macros in the expression are + * expanded, otherwise only the first is expanded. + */ +static void expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0); + QCString macroName; + QCString expMacro; + bool definedTest=FALSE; + int i=pos,l,p,len; + while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name + { + bool replaced=FALSE; + macroName=expr.mid(p,l); + //printf("macroName=%s\n",macroName.data()); + if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker? + { + if (state->expandedDict->find(macroName)==0) // expand macro + { + Define *def=state->defineManager.isDefined(macroName); + if (macroName=="defined") + { + //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data()); + definedTest=TRUE; + } + else if (definedTest) // macro name was found after defined + { + if (def) expMacro = " 1 "; else expMacro = " 0 "; + replaced=TRUE; + len=l; + definedTest=FALSE; + } + else if (def && def->nargs==-1) // simple macro + { + // substitute the definition of the macro + //printf("macro '%s'->'%s'\n",macroName.data(),def->definition.data()); + if (state->nospaces) + { + expMacro=def->definition.stripWhiteSpace(); + } + else + { + expMacro=" "+def->definition.stripWhiteSpace()+" "; + } + //expMacro=def->definition.stripWhiteSpace(); + replaced=TRUE; + len=l; + //printf("simple macro expansion='%s'->'%s'\n",macroName.data(),expMacro.data()); + } + else if (def && def->nargs>=0) // function macro + { + replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro); + len+=l; + } + + if (replaced) // expand the macro and rescan the expression + { + //printf("replacing '%s'->'%s'\n",expr.mid(p,len).data(),expMacro.data()); + QCString resultExpr=expMacro; + QCString restExpr=expr.right(expr.length()-len-p); + processConcatOperators(resultExpr); + if (def && !def->nonRecursive) + { + state->expandedDict->insert(macroName,def); + expandExpression(yyscanner,resultExpr,&restExpr,0); + state->expandedDict->remove(macroName); + } + expr=expr.left(p)+resultExpr+restExpr; + i=p; + //printf("new expression: %s\n",expr.data()); + } + else // move to the next macro name + { + //printf("moving to the next macro old=%d new=%d\n",i,p+l); + i=p+l; + } + } + else // move to the next macro name + { + expr=expr.left(p)+"@-"+expr.right(expr.length()-p); + //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data()); + i=p+l+2; + //i=p+l; + } + } + else // no re-scan marker found, skip the macro name + { + //printf("skipping marked macro\n"); + i=p+l; + } + } +} + +/*! @brief Process string or character literal. + * + * \a inputStr should point to the start of a string or character literal. + * the routine will return a pointer to just after the end of the literal + * the character making up the literal will be added to \a result. + */ +static const char *processUntilMatchingTerminator(const char *inputStr,QCString &result) +{ + if (inputStr==0) return inputStr; + char term = *inputStr; // capture start character of the literal + if (term!='\'' && term!='"') return inputStr; // not a valid literal + char c=term; + // output start character + result+=c; + inputStr++; + while ((c=*inputStr)) // while inside the literal + { + if (c==term) // found end marker of the literal + { + // output end character and stop + result+=c; + inputStr++; + break; + } + else if (c=='\\') // escaped character, process next character + // as well without checking for end marker. + { + result+=c; + inputStr++; + c=*inputStr; + if (c==0) break; // unexpected end of string after escape character + } + result+=c; + inputStr++; + } + return inputStr; +} + +/*! replaces all occurrences of @@@@ in \a s by @@ + * and removes all occurrences of @@E. + * All identifiers found are replaced by 0L + */ +static QCString removeIdsAndMarkers(const char *s) +{ + //printf("removeIdsAndMarkers(%s)\n",s); + const char *p=s; + char c; + bool inNum=FALSE; + QCString result; + if (p) + { + while ((c=*p)) + { + if (c=='@') // replace @@ with @ and remove @E + { + if (*(p+1)=='@') + { + result+=c; + } + else if (*(p+1)=='E') + { + // skip + } + p+=2; + } + else if (isdigit(c)) // number + { + result+=c; + p++; + inNum=TRUE; + } + else if (c=='\'') // quoted character + { + p = processUntilMatchingTerminator(p,result); + } + else if (c=='d' && !inNum) // identifier starting with a 'd' + { + if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0) + // defined keyword + { + p+=7; // skip defined + } + else + { + result+="0L"; + p++; + while ((c=*p) && isId(c)) p++; + } + } + else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L + { + result+="0L"; + p++; + while ((c=*p) && isId(c)) p++; + while ((c=*p) && isspace((uchar)c)) p++; + if (*p=='(') // undefined function macro + { + p++; + int count=1; + while ((c=*p++)) + { + if (c=='(') count++; + else if (c==')') + { + count--; + if (count==0) break; + } + else if (c=='/') + { + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + pc=c; + c=*++p; + } + p++; + } + } + } + } + } + else if (c=='/') // skip C comments + { + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + pc=c; + c=*++p; + } + p++; + } + else // oops, not comment but division + { + result+=pc; + goto nextChar; + } + } + else + { +nextChar: + result+=c; + char lc=tolower(c); + if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE; + p++; + } + } + } + //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data()); + return result; +} + +/*! replaces all occurrences of @@ in \a s by @ + * \par assumption: + * \a s only contains pairs of @@'s + */ +static QCString removeMarkers(const char *s) +{ + const char *p=s; + char c; + QCString result; + if (p) + { + while ((c=*p)) + { + switch(c) + { + case '@': // replace @@ with @ + { + if (*(p+1)=='@') + { + result+=c; + } + p+=2; + } + break; + case '/': // skip C comments + { + result+=c; + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + if (*p=='@' && *(p+1)=='@') + result+=c,p++; + else + result+=c; + pc=c; + c=*++p; + } + if (*p) result+=c,p++; + } + } + break; + case '"': // skip string literals + case '\'': // skip char literals + p = processUntilMatchingTerminator(p,result); + break; + default: + { + result+=c; + p++; + } + break; + } + } + } + //printf("RemoveMarkers(%s)=%s\n",s,result.data()); + return result; +} + +/*! compute the value of the expression in string \a expr. + * If needed the function may read additional characters from the input. + */ + +static bool computeExpression(yyscan_t yyscanner,const QCString &expr) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + QCString e=expr; + expandExpression(yyscanner,e,0,0); + //printf("after expansion '%s'\n",e.data()); + e = removeIdsAndMarkers(e); + if (e.isEmpty()) return FALSE; + //printf("parsing '%s'\n",e.data()); + return parseconstexp(state->yyFileName,state->yyLineNr,e); +} + +/*! expands the macro definition in \a name + * If needed the function may read additional characters from the input + */ + +static QCString expandMacro(yyscan_t yyscanner,const QCString &name) +{ + QCString n=name; + expandExpression(yyscanner,n,0,0); + n=removeMarkers(n); + //printf("expandMacro '%s'->'%s'\n",name.data(),n.data()); + return n; +} + +static Define *newDefine(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + Define *def=new Define; + def->name = state->defName; + def->definition = state->defText.stripWhiteSpace(); + def->nargs = state->defArgs; + def->fileName = state->yyFileName; + def->fileDef = state->yyFileDef; + def->lineNr = state->yyLineNr-state->yyMLines; + def->columnNr = state->yyColNr; + def->varArgs = state->defVarArgs; + //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(), + // def->fileDef ? def->fileDef->name().data() : def->fileName.data()); + //printf("newDefine: '%s'->'%s'\n",def->name.data(),def->definition.data()); + if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name]) + { + def->isPredefined=TRUE; + } + return def; +} + +static void addDefine(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + if (state->skip) return; // do not add this define as it is inside a + // conditional section (cond command) that is disabled. + if (!Doxygen::gatherDefines) return; + + //printf("addDefine %s %s\n",state->defName.data(),state->defArgsStr.data()); + //ArgumentList *al = new ArgumentList; + //stringToArgumentList(state->defArgsStr,al); + MemberDef *md=createMemberDef( + state->yyFileName,state->yyLineNr-state->yyMLines,state->yyColNr, + "#define",state->defName,state->defArgsStr,0, + Public,Normal,FALSE,Member,MemberType_Define,ArgumentList(),ArgumentList(),""); + if (!state->defArgsStr.isEmpty()) + { + ArgumentList argList; + //printf("addDefine() state->defName='%s' state->defArgsStr='%s'\n",state->defName.data(),state->defArgsStr.data()); + stringToArgumentList(state->defArgsStr,argList); + md->setArgumentList(argList); + } + //printf("Setting initializer for '%s' to '%s'\n",state->defName.data(),state->defText.data()); + int l=state->defLitText.find('\n'); + if (l>0 && state->defLitText.left(l).stripWhiteSpace()=="\\") + { + // strip first line if it only contains a slash + state->defLitText = state->defLitText.right(state->defLitText.length()-l-1); + } + else if (l>0) + { + // align the items on the first line with the items on the second line + int k=l+1; + const char *p=state->defLitText.data()+k; + char c; + while ((c=*p++) && (c==' ' || c=='\t')) k++; + state->defLitText=state->defLitText.mid(l+1,k-l-1)+state->defLitText.stripWhiteSpace(); + } + md->setInitializer(state->defLitText.stripWhiteSpace()); + + //printf("pre.l: md->setFileDef(%p)\n",state->inputFileDef); + md->setFileDef(state->inputFileDef); + md->setDefinition("#define "+state->defName); + + MemberName *mn=Doxygen::functionNameSDict->find(state->defName); + if (mn==0) + { + mn = new MemberName(state->defName); + Doxygen::functionNameSDict->append(state->defName,mn); + } + mn->append(md); + if (state->yyFileDef) + { + state->yyFileDef->insertMember(md); + } + + //Define *d; + //if ((d=defineDict[state->defName])==0) defineDict.insert(state->defName,newDefine()); +} + +static inline void outputChar(yyscan_t yyscanner,char c) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + if (state->includeStack.isEmpty() || state->curlyCount>0) state->outputBuf->addChar(c); +} + +static inline void outputArray(yyscan_t yyscanner,const char *a,int len) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + if (state->includeStack.isEmpty() || state->curlyCount>0) state->outputBuf->addArray(a,len); +} + +static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + static bool searchIncludes = Config_getBool(SEARCH_INCLUDES); + uint i=0; + + // find the start of the include file name + while (i0 && inc.at(s-1)=='"'; + + // find the end of the include file name + while (is) // valid include file name found + { + // extract include path+name + QCString incFileName=inc.mid(s,i-s).stripWhiteSpace(); + + QCString dosExt = incFileName.right(4); + if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb") + { + // skip imported binary files (e.g. M$ type libraries) + return; + } + + QCString oldFileName = state->yyFileName; + FileDef *oldFileDef = state->yyFileDef; + int oldLineNr = state->yyLineNr; + //printf("Searching for '%s'\n",incFileName.data()); + + // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336) + QCString absIncFileName = incFileName; + { + QFileInfo fi(state->yyFileName); + if (fi.exists()) + { + QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName; + QFileInfo fi2(absName); + if (fi2.exists()) + { + absIncFileName=fi2.absFilePath().utf8(); + } + else if (searchIncludes) // search in INCLUDE_PATH as well + { + QStrList &includePath = Config_getList(INCLUDE_PATH); + char *s=includePath.first(); + while (s) + { + QFileInfo fi(s); + if (fi.exists() && fi.isDir()) + { + QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName; + //printf("trying absName=%s\n",absName.data()); + QFileInfo fi2(absName); + if (fi2.exists()) + { + absIncFileName=fi2.absFilePath().utf8(); + break; + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + s=includePath.next(); + } + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + } + state->defineManager.addInclude(state->yyFileName,absIncFileName); + state->defineManager.addFileToContext(absIncFileName); - // also add it to the local file list if it is a source file - //if (g_isSource && g_includeStack.isEmpty()) - //{ - // g_fileDefineDict->insert(g_defName,nd); - //} - } - else if (def /*&& macroIsAccessible(def)*/) - // name already exists - { - //printf("existing define!\n"); - //printf("define found\n"); - if (def->undef) // undefined name - { - def->undef = FALSE; - def->name = g_defName; - def->definition = g_defText.stripWhiteSpace(); - def->nargs = g_defArgs; - def->fileName = g_yyFileName.copy(); - def->lineNr = g_yyLineNr-g_yyMLines; - def->columnNr = g_yyColNr; - } - else - { - //printf("error: define %s is defined more than once!\n",g_defName.data()); - } - } - delete g_argDict; g_argDict=0; - g_yyLineNr++; - g_yyColNr=1; - g_lastGuardName.resize(0); - BEGIN(Start); - } -{B}* { g_defText += ' '; g_defLitText+=yytext; } -{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; } -"@" { g_defText += "@@"; g_defLitText+=yytext; } -\" { - g_defText += *yytext; - g_defLitText+=yytext; - if (!g_insideComment) - { - BEGIN(SkipDoubleQuote); - } - } -\' { g_defText += *yytext; - g_defLitText+=yytext; - if (!g_insideComment) - { - BEGIN(SkipSingleQuote); - } - } -"//"[/]? { g_defText += yytext; g_defLitText+=yytext; } -"/*" { g_defText += yytext; g_defLitText+=yytext; } -\" { - g_defText += *yytext; g_defLitText+=yytext; - BEGIN(DefineText); - } -\\. { - g_defText += yytext; g_defLitText+=yytext; - } -\' { - g_defText += *yytext; g_defLitText+=yytext; - BEGIN(DefineText); - } -. { g_defText += *yytext; g_defLitText+=yytext; } -. { g_defText += *yytext; g_defLitText+=yytext; } -. { g_defText += *yytext; g_defLitText+=yytext; } -<> { - DBG_CTX((stderr,"End of include file\n")); - //printf("Include stack depth=%d\n",g_includeStack.count()); - if (g_includeStack.isEmpty()) - { - DBG_CTX((stderr,"Terminating scanner!\n")); - yyterminate(); - } - else - { - FileState *fs=g_includeStack.pop(); - //fileDefineCache->merge(g_yyFileName,fs->fileName); - YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; - yy_switch_to_buffer( fs->bufState ); - yy_delete_buffer( oldBuf ); - g_yyLineNr = fs->lineNr; - //preYYin = fs->oldYYin; - g_inputBuf = fs->oldFileBuf; - g_inputBufPos = fs->oldFileBufPos; - g_curlyCount = fs->curlyCount; - setFileName(fs->fileName); - DBG_CTX((stderr,"######## FileName %s\n",g_yyFileName.data())); - - // Deal with file changes due to - // #include's within { .. } blocks - QCString lineStr(15+g_yyFileName.length()); - lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data()); - outputArray(lineStr.data(),lineStr.length()); - - delete fs; fs=0; - } - } -<*>"/*"/"*/" | -<*>"/*"[*]? { - if (YY_START==SkipVerbatim || YY_START==SkipCond) - { - REJECT; - } - else - { - outputArray(yytext,(int)yyleng); - g_lastCContext=YY_START; - g_commentCount=1; - if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! - BEGIN(SkipCComment); - } - } -<*>"//"[/]? { - if (YY_START==SkipVerbatim || YY_START==SkipCond || getLanguageFromFileName(g_yyFileName)==SrcLangExt_Fortran) - { - REJECT; - } - else - { - outputArray(yytext,(int)yyleng); - g_lastCPPContext=YY_START; - if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! - BEGIN(SkipCPPComment); - } - } -<*>\n { - outputChar('\n'); - g_yyLineNr++; - } -<*>. { - g_expectGuard = FALSE; - outputChar(*yytext); - } + // findFile will overwrite state->yyFileDef if found + FileState *fs; + bool alreadyIncluded = FALSE; + //printf("calling findFile(%s)\n",incFileName.data()); + if ((fs=findFile(yyscanner,incFileName,localInclude,alreadyIncluded))) // see if the include file can be found + { + //printf("Found include file!\n"); + if (Debug::isFlagSet(Debug::Preprocessor)) + { + for (i=0;iincludeStack.count();i++) + { + Debug::print(Debug::Preprocessor,0," "); + } + //msg("#include %s: parsing...\n",incFileName.data()); + } + if (oldFileDef) + { + // add include dependency to the file in which the #include was found + bool ambig; + // change to absolute name for bug 641336 + FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig); + oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,state->isImported,FALSE); + // add included by dependency + if (state->yyFileDef) + { + //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data()); + state->yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,state->isImported); + } + } + else if (state->inputFileDef) + { + state->inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,state->isImported,TRUE); + } + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + fs->bufState = YY_CURRENT_BUFFER; + fs->lineNr = oldLineNr; + fs->fileName = oldFileName; + fs->curlyCount = state->curlyCount; + state->curlyCount = 0; + // push the state on the stack + state->includeStack.push(fs); + // set the scanner to the include file -%% + // Deal with file changes due to + // #include's within { .. } blocks + QCString lineStr(state->yyFileName.length()+20); + lineStr.sprintf("# 1 \"%s\" 1\n",state->yyFileName.data()); + outputArray(yyscanner,lineStr.data(),lineStr.length()); + + DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data())); + state->expectGuard=TRUE; + state->inputBuf = &fs->fileBuf; + state->inputBufPos=0; + yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner); + } + else + { + //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded); + if (oldFileDef) + { + bool ambig; + //QCString absPath = incFileName; + //if (QDir::isRelativePath(incFileName)) + //{ + // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName); + // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data()); + //} + + // change to absolute name for bug 641336 + FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig); + //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd); + // add include dependency to the file in which the #include was found + oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,state->isImported,FALSE); + // add included by dependency + if (fd) + { + //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig); + fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,state->isImported); + } + } + else if (state->inputFileDef) + { + state->inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,state->isImported,TRUE); + } + if (Debug::isFlagSet(Debug::Preprocessor)) + { + if (alreadyIncluded) + { + Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",qPrint(incFileName)); + } + else + { + Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",qPrint(incFileName)); + } + //printf("error: include file %s not found\n",yytext); + } + if (state->curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... } + { + warn(state->yyFileName,state->yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data()); + } + } + } +} + +/* ----------------------------------------------------------------- */ + +static void startCondSection(yyscan_t yyscanner,const char *sectId) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count()); + CondParser prs; + bool expResult = prs.parse(state->yyFileName,state->yyLineNr,sectId); + state->condStack.push(new CondCtx(state->yyLineNr,sectId,state->skip)); + if (!expResult) + { + state->skip=TRUE; + } + //printf(" expResult=%d skip=%d\n",expResult,state->skip); +} + +static void endCondSection(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + if (state->condStack.isEmpty()) + { + state->skip=FALSE; + } + else + { + CondCtx *ctx = state->condStack.pop(); + state->skip=ctx->skip; + delete ctx; + } + //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count()); +} + +static void forceEndCondSection(yyscan_t yyscanner) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + while (!state->condStack.isEmpty()) + { + delete state->condStack.pop(); + } + state->skip=FALSE; +} + +static QCString escapeAt(const char *text) +{ + QCString result; + if (text) + { + char c; + const char *p=text; + while ((c=*p++)) + { + if (c=='@') result+="@@"; else result+=c; + } + } + return result; +} + +static char resolveTrigraph(char c) +{ + switch (c) + { + case '=': return '#'; + case '/': return '\\'; + case '\'': return '^'; + case '(': return '['; + case ')': return ']'; + case '!': return '|'; + case '<': return '{'; + case '>': return '}'; + case '-': return '~'; + } + return '?'; +} /*@ ---------------------------------------------------------------------------- */ -static int getNextChar(const QCString &expr,QCString *rest,uint &pos) +static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos) { //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); if (posdata() : 0,pos); if (posdata() : 0,pos,c); if (posdata() : 0,pos,c); } -void addSearchDir(const char *dir) +/////////////////////////////////////////////////////////////////////////////////////////////// + +struct Preprocessor::Private +{ + yyscan_t yyscanner; + preYY_state state; + bool firstTime = FALSE; +}; + +void Preprocessor::addSearchDir(const char *dir) { + YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner); QFileInfo fi(dir); - if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8()); + if (fi.isDir()) state->pathList->append(fi.absFilePath().utf8()); } -void initPreprocessor() +Preprocessor::Preprocessor() { - g_pathList = new QStrList; + p = new Private; + preYYlex_init_extra(&p->state,&p->yyscanner); + YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner); + state->pathList = new QStrList; addSearchDir("."); - g_expandedDict = new DefineDict(17); + state->expandedDict = new DefineDict(17); } -void cleanUpPreprocessor() +Preprocessor::~Preprocessor() { - delete g_expandedDict; g_expandedDict=0; - delete g_pathList; g_pathList=0; - DefineManager::deleteInstance(); + YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner); + delete state->expandedDict; + state->expandedDict=0; + delete state->pathList; + state->pathList=0; + preYYlex_destroy(p->yyscanner); + delete p; } - -void preprocessFile(const char *fileName,BufStr &input,BufStr &output) +void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output) { + yyscan_t yyscanner = p->yyscanner; + YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner); + struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; printlex(yy_flex_debug, TRUE, __FILE__, fileName); uint orgOffset=output.curPos(); //printf("##########################\n%s\n####################\n", // input.data()); - g_macroExpansion = Config_getBool(MACRO_EXPANSION); - g_expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF); - g_skip=FALSE; - g_curlyCount=0; - g_nospaces=FALSE; - g_inputBuf=&input; - g_inputBufPos=0; - g_outputBuf=&output; - g_includeStack.setAutoDelete(TRUE); - g_includeStack.clear(); - g_expandedDict->setAutoDelete(FALSE); - g_expandedDict->clear(); - g_condStack.setAutoDelete(TRUE); - g_condStack.clear(); - //g_fileDefineDict->clear(); - - setFileName(fileName); - g_inputFileDef = g_yyFileDef; - DefineManager::instance().startContext(g_yyFileName); + state->macroExpansion = Config_getBool(MACRO_EXPANSION); + state->expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF); + state->skip=FALSE; + state->curlyCount=0; + state->nospaces=FALSE; + state->inputBuf=&input; + state->inputBufPos=0; + state->outputBuf=&output; + state->includeStack.setAutoDelete(TRUE); + state->includeStack.clear(); + state->expandedDict->setAutoDelete(FALSE); + state->expandedDict->clear(); + state->condStack.setAutoDelete(TRUE); + state->condStack.clear(); + //state->fileDefineDict->clear(); + + setFileName(yyscanner,fileName); + state->inputFileDef = state->yyFileDef; + state->defineManager.startContext(state->yyFileName); - static bool firstTime=TRUE; - if (firstTime) + p->firstTime=TRUE; + if (p->firstTime) { // add predefined macros char *defStr; @@ -3226,9 +3278,9 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) def->nargs = count; def->isPredefined = TRUE; def->nonRecursive = nonRecursive; - def->fileDef = g_yyFileDef; + def->fileDef = state->yyFileDef; def->fileName = fileName; - DefineManager::instance().addDefine(g_yyFileName,def); + state->defineManager.addDefine(state->yyFileName,def); } //printf("#define '%s' '%s' #nargs=%d\n", @@ -3257,9 +3309,9 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) def->nargs = -1; def->isPredefined = TRUE; def->nonRecursive = nonRecursive; - def->fileDef = g_yyFileDef; + def->fileDef = state->yyFileDef; def->fileName = fileName; - DefineManager::instance().addDefine(g_yyFileName,def); + state->defineManager.addDefine(state->yyFileName,def); } else { @@ -3273,24 +3325,23 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) //firstTime=FALSE; } - g_yyLineNr = 1; - g_yyColNr = 1; - g_level = 0; - g_ifcount = 0; + state->yyLineNr = 1; + state->yyColNr = 1; + state->level = 0; + state->ifcount = 0; BEGIN( Start ); - g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC; - g_guardName.resize(0); - g_lastGuardName.resize(0); - g_guardExpr.resize(0); + state->expectGuard = guessSection(fileName)==Entry::HEADER_SEC; + state->guardName.resize(0); + state->lastGuardName.resize(0); + state->guardExpr.resize(0); - preYYlex(); - g_lexInit=TRUE; + preYYlex(yyscanner); - while (!g_condStack.isEmpty()) + while (!state->condStack.isEmpty()) { - CondCtx *ctx = g_condStack.pop(); + CondCtx *ctx = state->condStack.pop(); QCString sectionInfo = " "; if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx->sectionId.stripWhiteSpace().data()); warn(fileName,ctx->lineNr,"Conditional section%sdoes not have " @@ -3298,18 +3349,18 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) delete ctx; } // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829) - forceEndCondSection(); + forceEndCondSection(yyscanner); // remove locally defined macros so they can be redefined in another source file - //if (g_fileDefineDict->count()>0) + //if (state->fileDefineDict->count()>0) //{ - // QDictIterator di(*g_fileDefineDict); + // QDictIterator di(*state->fileDefineDict); // Define *d; // for (di.toFirst();(d=di.current());++di) // { - // g_globalDefineDict->remove(di.currentKey()); + // state->globalDefineDict->remove(di.currentKey()); // } - // g_fileDefineDict->clear(); + // state->fileDefineDict->clear(); //} if (Debug::isFlagSet(Debug::Preprocessor)) @@ -3326,11 +3377,11 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) orgPos++; } Debug::print(Debug::Preprocessor,0,"\n---------\n"); - if (DefineManager::instance().defineContext().count()>0) + if (state->defineManager.defineContext().count()>0) { Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n"); Debug::print(Debug::Preprocessor,0,"---------\n"); - QDictIterator di(DefineManager::instance().defineContext()); + QDictIterator di(state->defineManager.defineContext()); Define *def; for (di.toFirst();(def=di.current());++di) { @@ -3343,20 +3394,10 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output) Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n"); } } - DefineManager::instance().endContext(); + state->defineManager.endContext(); printlex(yy_flex_debug, FALSE, __FILE__, fileName); } -void preFreeScanner() -{ -#if defined(YY_FLEX_SUBMINOR_VERSION) - if (g_lexInit) - { - preYYlex_destroy(); - } -#endif -} - #if !defined(YY_FLEX_SUBMINOR_VERSION) extern "C" { // some bogus code to keep the compiler happy // int preYYwrap() { return 1 ; } -- cgit v0.12