RE: [Doxygen-users] Documenting #included files
Brought to you by:
dimitri
From: Jac G. <ja...@ma...> - 2001-05-02 23:49:15
|
>Thanks for your reply. If your {} trick works, it might be helpful, >although I'd rather not split the class tag from the guts of the class. I think it's possible to trick doxygen into it in another way: #ifdef DOXYGEN { #endif #include "your_file_with_complete_class_definition_here" #ifdef DOXYGEN } // balance the braces #endif If you want to do it in a legitimate way, you can also use namespaces, but I doubt if they are useful in your case because they are probably not documented by all compilers. >Anyway, it sounds like you agree on the usefulness of telling Doxygen to >document #included files. Do you have any proposed syntax? The syntax I had in mind was (replace the @ by any other character if you want): //@scaninclude This command directs doxygen to scan the file that is mentioned in the next #include command. //@dontscaninclude This command directs doxygen to NOT scan the file that is mentioned in the next #include command, not even if it contains @ifinclude commands that would make doxygen scan the code otherwise //@ifinclude[d] [[operator] value] This command directs doxygen to scan the code that follows if the include-stack's depth corresponds to the specified operator and value. <operator> can be < or > or <= or >= or == or !=, if you don't mention the operator, == is used. The value is 0 if the file is being scanned as base file, 1 if it is included from the base file etc. I included the patch in which these commands are implemented (and some other little goodies :-). It works partly: it will let Doxygen scan the included files as it's told to, and it will generate documentation for the classes and methods in the included file as it's supposed to. However it does NOT work 100%!!! - doxygen does not generate code fragments for methods in included files - doxygen does not generate hotlinks to code ("Definition in line %d of file %s") in included files - the graphs are not generated correctly for my special case (where class definitions are divided over include files, yuck!). If I would know what to do with the database in scanner.l when the preprocessor changes to a different sourcefile, those problems would be fixed. By the way, in my opinion, it shouldn't be necessary to patch doxygen this way: doxygen should scan the code in the same way that a C/C++ preprocessor does. A while ago someone posted a message containing a link to a website where someone patched the gcc preprocessor so it generates an XML document from which a clever XML parser should be able to generate a database that can be used by doxygen. > If you don't >have time to finish your patch for this, I could do it myself. (I had >already assumed I'd have to add it if I wanted it.) Go ahead if you want (just mention me as the original inventor, ok? :-) I'm sorry, I don't have time to comment this patch right now... ===Jac cvs diff -u # irrelevant lines and files truncated Index: src/config.l =================================================================== RCS file: /u/kp3softd/cvsroot/src/config.l,v retrieving revision 1.54 diff -u -r1.54 config.l --- src/config.l 2001/04/08 19:19:30 1.54 +++ src/config.l 2001/05/02 23:37:44 @@ -14,6 +14,8 @@ %{ +//#define YY_USER_ACTION printf("<%d>%s", __LINE__ -2, yytext); + /* * includes */ @@ -323,8 +325,9 @@ <*>\0x0d <Start,GetString,GetStrList,GetBool,SkipInvalid>"#" { BEGIN(SkipComment); } -<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()- 1).stripWhiteSpace(); +<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*("="|"+=") { QCString cmd=yytext; + bool add=(cmd.right(2)=="+= "); + cmd=cmd.left(cmd.length()- (1+(int)add)).stripWhiteSpace(); ConfigOption *option = config->get(cmd); if (option==0) // oops not known { @@ -334,6 +337,11 @@ } else // known tag { + if (add && option->kind()!= ConfigOption::O_List) + { + err("Warning: '+=' cannot be used with option %s at line %d, file %s; using '='\n", + cmd.data(), yyLineNr, yyFileName.data()); + } switch(option->kind()) { case ConfigOption::O_Info: @@ -342,7 +350,7 @@ break; case ConfigOption::O_List: l = ((ConfigList *)option)->valueRef(); - l->clear(); + if (!add) l->clear(); elemStr=""; BEGIN(GetStrList); break; @@ -365,39 +373,6 @@ b = ((ConfigBool *)option)->valueRef(); BEGIN(GetBool); break; - } - } - } -<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()- 2).stripWhiteSpace(); - ConfigOption *option = config->get(cmd); - if (option==0) // oops not known - { - err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n", - yytext,yyLineNr,yyFileName.data()); - BEGIN(SkipInvalid); - } - else // known tag - { - switch(option->kind()) - { - case ConfigOption::O_Info: - // shouldn't get here! - BEGIN(SkipInvalid); - break; - case ConfigOption::O_List: - l = ((ConfigList *)option)->valueRef(); - elemStr=""; - BEGIN(GetStrList); - break; - case ConfigOption::O_Enum: - case ConfigOption::O_String: - case ConfigOption::O_Int: - case ConfigOption::O_Bool: - err("Warning: operator += not supported for `%s'. Ignoring line at line %d, file %s\n", - yytext,yyLineNr,yyFileName.data()); - BEGIN(SkipInvalid); - break; } } } Index: src/doxygen.cpp =================================================================== RCS file: /u/kp3softd/cvsroot/src/doxygen.cpp,v retrieving revision 1.66 diff -u -r1.66 doxygen.cpp --- src/doxygen.cpp 2001/04/30 17:28:32 1.66 +++ src/doxygen.cpp 2001/05/02 23:37:45 @@ -2818,9 +2818,9 @@ { warn( root->fileName,root->startLine, - "Warning: member %s belongs to two different groups. The second " - "one found here will be ignored.", - md->name().data() + "Warning: member %s belongs to two different groups.\n" + "The one that will be used is at %s:%d", + md->name().data(), md->getDefFileName().data(), md-> getDefLine() ); } } @@ -5493,16 +5493,6 @@ { QCString fileName=*s; - int fileNameSize=fileName.length(); - - // add begin filename marker - output.addChar(0x06); - // copy filename - output.addArray(fileName.data(),fileNameSize); - - // add end filename marker - output.addChar(0x06); - output.addChar('\n'); if (Config_getBool("ENABLE_PREPROCESSING")) { msg("Preprocessing %s...\n",s->data()); @@ -5510,6 +5500,18 @@ } else { + // add begin filename marker + output.addChar(0x06); + // copy filename + output.addArray(fileName.data(),fileName.length()); + + // add line number + output.addChar(0x06); + output.addChar('1'); + + // add end filename marker + output.addChar(0x06); + msg("Reading %s...\n",s->data()); copyAndFilterFile(fileName,output); } Index: src/message.cpp =================================================================== RCS file: /u/kp3softd/cvsroot/src/message.cpp,v retrieving revision 1.25 diff -u -r1.25 message.cpp --- src/message.cpp 2001/04/22 19:01:52 1.25 +++ src/message.cpp 2001/05/02 23:37:45 @@ -142,7 +142,7 @@ { if (Config_getBool("WARN_IF_UNDOCUMENTED")) { - if (file==0) file="<unknwon>"; + if (file==0) file="<unknown>"; char text[4096]; va_list args; va_start(args, fmt); Index: src/pre.l =================================================================== RCS file: /u/kp3softd/cvsroot/src/pre.l,v retrieving revision 1.39 diff -u -r1.39 pre.l --- src/pre.l 2001/04/08 19:19:31 1.39 +++ src/pre.l 2001/05/02 23:37:46 @@ -17,6 +17,8 @@ %{ +//#define YY_USER_ACTION printf("<%d>%s", __LINE__ -2, yytext); + /* * includes */ @@ -53,15 +55,71 @@ #define YY_NEVER_INTERACTIVE 1 - +typedef enum +{ + ScanIncNA, // we're not including (this is the base file) + ScanIncNone, // no commands active + ScanIncYes, // scaninclude given + ScanIncNo // dontscaninclude given +} ScanInclude; + +typedef enum +{ + IfIncNone, // no ifinclude given + IfIncEQ, // ifinclude == or = + IfIncNE, // ifinclude != or <> + IfIncLT, // ifinclude < + IfIncLE, // ifinclude <= + IfIncGT, // ifinclude > + IfIncGE // ifinclude >= +} IfIncComp; + +typedef enum +{ + PreNone, // no preprocessor command found + PreScanInclude, // scaninclude found + PreDontScanInclude, // dontscaninclude found + PreIfInclude // if[not]include[d]/endifinclude[d] found +} PreProcessorCmd; + struct FileState { - int lineNr; - FILE *filePtr; - YY_BUFFER_STATE bufState; - QCString fileName; + int lineNr; + FILE *filePtr; + YY_BUFFER_STATE bufState; + QCString fileName; + QCString bareFileName; + int pathListIndex; + ScanInclude parentScanInclude; + uint ifIncDepth; + IfIncComp ifIncComp; }; +// Extended version of QStack, which includes a next() operation. +template<class type> class WalkableStack : private QGList +{ +public: + WalkableStack() {} + WalkableStack( const WalkableStack<type> &s ) : QGList(s) {} + ~WalkableStack() { clear(); } + WalkableStack<type> &operator=(const WalkableStack<type> &s) + { return (WalkableStack<type>&)QGList::operator=(s); } + bool autoDelete() const { return QCollection::autoDelete(); } + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + void push( const type *d ) { QGList::insertAt(0,Item(d)); } + type *pop() { return (type *)QGList::takeFirst(); } + bool remove() { return QGList::removeFirst(); } + void clear() { QGList::clear(); } + type *top() const { return (type *)QGList::cfirst(); } + operator type *() const { return (type *)QGList::cfirst(); } + type *current() const { return (type *)QGList::cfirst(); } + type *next() { return (type *)QGList::next(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + /* ----------------------------------------------------------------- * * scanner's state @@ -69,10 +127,12 @@ static int g_yyLineNr = 1; static QCString g_yyFileName; +static QCString g_bareFileName; static FileDef *g_yyFileDef; static int g_ifcount = 0; static QStrList *g_pathList = 0; -static QStack<FileState> g_includeStack; +static WalkableStack<FileState> g_includeStack; +static int g_currentPathListIndex = -1; static QDict<int> *g_argDict; static int g_defArgs = -1; static QCString g_defName; @@ -83,6 +143,7 @@ static int g_level; static int g_lastCContext; static int g_lastCPPContext; +static int g_nextCommentContext; static QArray<int> g_levelGuard; static BufStr *g_outputBuf; static int g_roundCount; @@ -92,10 +153,18 @@ static int g_findDefArgContext; static QCString g_lastGuardName; static QCString g_incName; +static bool g_incNext; static QCString g_guardExpr; static int g_curlyCount; static bool g_nospaces; // add extra spaces during macro expansion - +static PreProcessorCmd g_doxyCmd; +static ScanInclude g_parentScanInclude; +static ScanInclude g_scanInclude; +static IfIncComp g_ifIncComp; +static uint g_ifIncDepth; +static bool g_scanEnabledCache=true; +static bool g_scanEnabledCacheChanged=true; +static bool g_fileNeedsMark=false; static bool g_macroExpansion; // from the configuration static bool g_expandOnlyPredef; // from the configuration @@ -103,8 +172,21 @@ static void setFileName(const char *name) { bool ambig; + Debug::print(Debug::Preprocessor,0,"opening %s\n",name); g_yyFileName=name; g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig); + g_fileNeedsMark=true; +} + +static void outputFileMarker(void) +{ + g_outputBuf->addChar('\x06'); + g_outputBuf->addArray(g_yyFileName.data(),g_yyFileName.length()); + g_outputBuf->addChar('\x06'); + QCString lineno;lineno.setNum(g_yyLineNr); + g_outputBuf->addArray(lineno.data(),lineno.length()); + g_outputBuf->addChar('\x06'); + g_fileNeedsMark=false; } static void incrLevel() @@ -161,7 +243,7 @@ return 0; } -static FILE *checkAndOpenFile(const QCString &absName) +static FILE *checkAndOpenFile(const QCString &absName, const QCString &bareName, int pathListIndex) { FILE *f = 0; QFileInfo fi(absName); @@ -178,20 +260,30 @@ f=fopen(absName,"r"); if (!f) err("Error: could not open file %s for reading\ n",absName.data()); } + if (f) + { + setFileName(absName); + g_yyLineNr=1; + g_parentScanInclude=g_scanInclude; + g_scanInclude=ScanIncNone; + g_ifIncComp=IfIncNone; + g_scanEnabledCacheChanged=true; + g_bareFileName=bareName; + g_currentPathListIndex=pathListIndex; + yy_switch_to_buffer(yy_create_buffer((preYYin=f), YY_BUF_SIZE)); + } } return f; } -static FILE *findFile(const char *fileName,bool localInclude) +static FILE *findFile(const QCString &fileName,bool localInclude) { if (localInclude && g_yyFileDef) { - QCString absName = g_yyFileDef->getPath()+"/"+fileName; - FILE *f = checkAndOpenFile(absName); + QCString absName = g_yyFileDef->getPath()+fileName; + FILE *f = checkAndOpenFile(absName, fileName, g_currentPathListIndex); if (f) { - setFileName(absName); - g_yyLineNr=1; return f; } } @@ -200,17 +292,30 @@ return 0; } char *s=g_pathList->first(); + + int foundPathListIndex=0; + int startingIndex=0; + if (g_incNext && !strcmp(g_bareFileName.data(), fileName.data())) + { + // Get the current include-path index and search from there. + // Note that for the base filename, the current path list index is + // set to -1, so the search starts at 0. + startingIndex=g_currentPathListIndex+1; + } + while (s) { - QCString absName = (QCString)s+"/"+fileName; - FILE *f = checkAndOpenFile(absName); - if (f) + if (foundPathListIndex>=startingIndex) { - setFileName(absName); - g_yyLineNr=1; - return f; - } + QCString absName = (QCString)s+"/"+fileName; + FILE *f = checkAndOpenFile(absName, fileName, foundPathListIndex); + if (f) + { + return f; + } + } + foundPathListIndex++; s=g_pathList->next(); } return 0; @@ -880,19 +985,123 @@ //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); } +static inline bool scanEnabled(void) +{ + if (g_scanEnabledCacheChanged) + { + // by defrault, scanning is enabled + bool b=true; + + // check for dontscaninclude override + if (g_parentScanInclude==ScanIncNo) + { + // parent disallows scanning + b=false; + } + else + { + // we're not in an include or the parent allows/mandates scanning + uint depth=g_includeStack.count(); + + // check for ifinclude override + switch (g_ifIncComp) + { + case IfIncNone: + // No ifinclude present. Check if parent mandates scanning + b=((depth==0) || + (g_parentScanInclude==ScanIncYes) || + ((depth!=0) && (g_curlyCount>0))); + break; + case IfIncEQ: + // include level must be equal to given number + b=(depth==g_ifIncDepth); + break; + case IfIncNE: + // include level must be unequal to given number + b=(depth!=g_ifIncDepth); + break; + case IfIncLT: + // include level must be less than given number + b=(depth<g_ifIncDepth); + break; + case IfIncLE: + // include level must be less or equal to given number + b=(depth<g_ifIncDepth); + break; + case IfIncGT: + // include level must be greater than given number + b=(depth>g_ifIncDepth); + break; + case IfIncGE: + // include level must be greater or equal to given number + b=(depth>=g_ifIncDepth); + break; + } + } + + // copy local to global + g_scanEnabledCache=b; + + // if scanning is enabled, mark the current position + if (g_scanEnabledCache && g_fileNeedsMark) + { + outputFileMarker(); + } + g_scanEnabledCacheChanged=false; + } + return g_scanEnabledCache; +} + static inline void outputChar(char c) { - if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf-> addChar(c); + if (scanEnabled()) 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); + if (scanEnabled()) g_outputBuf->addArray(a,len); } +/*! this is called at the end of each source line and at the end of each + * C comment, to execute any preprocessor commands that were found. + * Note: We need to postpone processing the command until after the + * comment ends, because if scanning is enable or disabled by the command, + * the scanner would otherwise end up with an unclosed or unopened comment. + * We CAN postpone processing until the end of the comment because + * preprocessor commands need to be right after the beginning of + * the comment, so there can never be more than one command per comment. + */ +static void execPreProcCmd(void) +{ + switch (g_doxyCmd) + { + case PreScanInclude: + g_scanInclude=ScanIncYes; + g_scanEnabledCacheChanged=true; + break; + case PreDontScanInclude: + g_scanInclude=ScanIncNo; + g_scanEnabledCacheChanged=true; + break; + case PreIfInclude: + g_scanEnabledCacheChanged=true; + break; + case PreNone: + default: + ; // Nothing to do + } + + // reset the command, just in case + g_doxyCmd=PreNone; +} + static void readIncludeFile(const QCString &inc) { - if (!Config_getBool("SEARCH_INCLUDES")) return; // do not read include files + if (!Config_getBool("SEARCH_INCLUDES")) + { + Debug::print(Debug::Preprocessor,0,"SEARCH_INCLUDES is false; not including %s\n",inc.data()); + return; // do not read include files + } uint i=0; // find the start of the include file name @@ -913,16 +1122,26 @@ QCString incFileName=inc.mid(s,i-s).stripWhiteSpace(); FILE *f; - QCString oldFileName = g_yyFileName.copy(); FileDef *oldFileDef = g_yyFileDef; - int oldLineNr = g_yyLineNr; + + // store the state of the old file + FileState *fs=new FileState; + fs->bufState=YY_CURRENT_BUFFER; + fs->lineNr=g_yyLineNr; + fs->fileName=g_yyFileName.copy(); + fs->bareFileName=g_bareFileName; + fs->pathListIndex=g_currentPathListIndex; + fs->parentScanInclude=g_parentScanInclude; + fs->ifIncDepth=g_ifIncDepth; + fs->ifIncComp=g_ifIncComp; + //printf("Searching for `%s'\n",incFileName.data()); if ((f=findFile(incFileName,localInclude))) // see if the include file can be found { if (Debug::isFlagSet(Debug::Preprocessor)) { - for (i=0;i<g_includeStack.count();i++) msg(" "); - msg("#include %s: parsing...\n",incFileName.data()); + for (i=0;i<=g_includeStack.count();i++) msg(" "); + msg("#include%s %s: parsing...\n", g_incNext?"_next":"", incFileName.data()); } if (oldFileDef) { @@ -934,26 +1153,19 @@ g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef-> name(),localInclude); } } - FileState *fs=new FileState; - fs->bufState=YY_CURRENT_BUFFER; - fs->lineNr=oldLineNr; - fs->fileName=oldFileName; fs->filePtr=f; // push the state on the stack g_includeStack.push(fs); - // set the scanner to the include file // TODO: Enable this to deal with file changes due to // #include's within { .. } blocks //QCString lineStr; //lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data()); //outputArray(lineStr.data(),lineStr.length()); - - preYYin=f; - yy_switch_to_buffer(yy_create_buffer(preYYin, YY_BUF_SIZE)); } else { + delete fs; // delete unused data if (oldFileDef) { bool ambig; @@ -966,9 +1178,17 @@ fd->addIncludedByDependency(oldFileDef,oldFileDef-> name(),localInclude); } } - if (Debug::isFlagSet(Debug::Preprocessor)) - { - msg("#include %s: not found! skipping...\ n",incFileName.data()); + // failing #include_next's are apparently not reported by gcc, + // so we won't complain about failed #include_next's either + if (!g_incNext) + { + warn(g_yyFileName.data(), g_yyLineNr, "#include %s: not found! skipping...", incFileName.data()); + FileState *fs=g_includeStack.top(); + while (fs) + { + warn_cont(" included from: %s:%d\n", fs->fileName.data(), fs->lineNr); + fs=g_includeStack.next(); + } //printf("Error: include file %s not found\n",yytext); } } @@ -977,11 +1197,14 @@ /* ----------------------------------------------------------------- * / +#define DO_LINEFEED do { outputChar('\n'); g_yyLineNr++; execPreProcCmd(); } while(0) + %} ID [a-z_A-Z][a-z_A-Z0-9]* B [ \t] BN [ \t\r\n] +CMD [@] %option noyywrap @@ -999,6 +1222,8 @@ %x SkipCPPBlock %x Ifdef %x Ifndef +%x DoxyCommand +%x IfIncludeParm %x SkipCComment %x SkipCPPComment %x RemoveCComment @@ -1044,12 +1269,18 @@ <CopyLine>"{" { // count brackets inside the main file if (g_includeStack.isEmpty()) + { g_curlyCount++; + g_scanEnabledCacheChanged=true; + } outputChar(*yytext); } <CopyLine>"}" { // count brackets inside the main file if (g_includeStack.isEmpty()) + { g_curlyCount--; + g_scanEnabledCacheChanged=true; + } outputChar(*yytext); // This should hold otherwise the preprocessor is confused //ASSERT(g_curlyCount>=0); @@ -1132,9 +1363,8 @@ outputChar(*yytext); } <CopyLine>\n { - outputChar('\n'); + DO_LINEFEED; BEGIN(Start); - g_yyLineNr++; } <FindDefineArgs>"(" { g_defArgsStr+='('; @@ -1170,8 +1400,7 @@ BEGIN(ReadString); } <FindDefineArgs>\n { - g_yyLineNr++; - outputChar('\n'); + DO_LINEFEED; } <FindDefineArgs>"@" { g_defArgsStr+="@@"; @@ -1192,7 +1421,20 @@ <ReadString>. { g_defArgsStr+=*yytext; } +<Command>"include_next"{B}+/{ID} { + g_incNext=true; + if (g_macroExpansion) + BEGIN(IncludeID); + } +<Command>"include_next"{B}*[<"] { + char c[2]; + c[0]=yytext[yyleng-1];c[1]='\0'; + g_incName=c; + g_incNext=true; + BEGIN(Include); + } <Command>"include"{B}+/{ID} { + g_incNext=false; if (g_macroExpansion) BEGIN(IncludeID); } @@ -1200,6 +1442,7 @@ char c[2]; c[0]=yytext[yyleng-1];c[1]='\0'; g_incName=c; + g_incNext=false; BEGIN(Include); } <Command>"define"{B}+ { @@ -1272,16 +1515,15 @@ decrLevel(); } <Command,IgnoreLine>\n { - outputChar('\n'); + + DO_LINEFEED; BEGIN(Start); - g_yyLineNr++; } <Command>{ID} { // unknown directive BEGIN(IgnoreLine); } <IgnoreLine>\\[\r]?\n { - outputChar('\n'); - g_yyLineNr++; + DO_LINEFEED; } <IgnoreLine>. <Command>. @@ -1295,9 +1537,8 @@ BEGIN(Start); } <Guard>\\[\r]?\n { - outputChar('\n'); + DO_LINEFEED; g_guardExpr+=' '; - g_yyLineNr++; } <Guard>"defined"/{B}*"(" { BEGIN(DefinedExpr2); @@ -1307,8 +1548,7 @@ } <Guard>. { g_guardExpr+=*yytext; } <Guard>\n { - outputChar('\n'); - g_yyLineNr++; + DO_LINEFEED; //printf("Guard: `%s'\n", // g_guardExpr.data()); bool guard=computeExpression(g_guardExpr); @@ -1324,7 +1564,7 @@ BEGIN(SkipCPPBlock); } } -<DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\ n'); } +<DefinedExpr1,DefinedExpr2>\\\n { DO_LINEFEED; } <DefinedExpr1>{ID} { if (isDefined(yytext)) g_guardExpr+=" 1L "; @@ -1389,8 +1629,7 @@ } } <SkipCommand>\n { - outputChar('\n'); - g_yyLineNr++; + DO_LINEFEED; BEGIN(SkipCPPBlock); } <SkipCommand>{ID} { // unknown directive @@ -1408,8 +1647,7 @@ BEGIN(RemoveCComment); } <SkipLine>\n { - outputChar('\n'); - g_yyLineNr++; + DO_LINEFEED; BEGIN(SkipCPPBlock); } <IncludeID>{ID}{B}*/"(" { @@ -1530,16 +1768,99 @@ g_defText+=' '; g_defLitText+=' '; g_lastCContext=YY_START; - BEGIN(SkipCComment); + g_nextCommentContext=SkipCComment; + BEGIN(DoxyCommand); } <DefineText>"//" { outputChar('/');outputChar('/'); g_lastCPPContext=YY_START; g_defLitText+=' '; - BEGIN(SkipCPPComment); + g_nextCommentContext=SkipCPPComment; + BEGIN(DoxyCommand); } +<DoxyCommand>{B}*{CMD}"scaninclude" { + g_doxyCmd=PreScanInclude; + BEGIN(g_nextCommentContext); + } +<DoxyCommand>{B}*{CMD}"dontscaninclude" { + g_doxyCmd= PreDontScanInclude; + BEGIN(g_nextCommentContext); + } +<DoxyCommand>{B}*{CMD}"ifinclude"[d]{B}* { + g_doxyCmd=PreIfInclude; + g_ifIncDepth=0; + g_ifIncComp=IfIncGT; + BEGIN(IfIncludeParm); + } +<IfIncludeParm>("<="|"<"|"="|"=="|"!="|"<>"|">"|">="){B}*/[0-9] { + switch (yytext[0]) + { + case '<': + switch (yytext[1]) + { + case '=': + g_ifIncComp=IfIncLE; + break; + case '>': + g_ifIncComp=IfIncNE; + break; + default: + g_ifIncComp=IfIncLT; + } + break; + case '=': // '=' or '==' + g_ifIncComp=IfIncEQ; + break; + case '!': + g_ifIncComp=IfIncNE; + break; + case '>': + switch (yytext[1]) + { + case '=': + g_ifIncComp=IfIncGE; + break; + default: + g_ifIncComp=IfIncGT; + } + break; + default: + ; // never happens + } + } +<IfIncludeParm>[0-9]+ { + g_ifIncDepth=0; + int i=0; + while (yytext[i]) + { + g_ifIncDepth=g_ifIncDepth*10+(yytext[i]-'0'); + i++; + } + BEGIN(g_nextCommentContext); + } +<IfIncludeParm>"//"|"/*"|.|\n { + yyless(0); + BEGIN(g_nextCommentContext); + } +<DoxyCommand>{B}*{CMD}"ifnotinclude"[d] { + g_doxyCmd=PreIfInclude; + g_ifIncDepth=0; + g_ifIncComp=IfIncEQ; + BEGIN(g_nextCommentContext); + } +<DoxyCommand>{B}*{CMD}"endifinclude"[d] { + g_doxyCmd=PreIfInclude; + g_ifIncComp=IfIncNone; + BEGIN(g_nextCommentContext); + } +<DoxyCommand>"//"|"/*"|.|\n { + g_doxyCmd=PreNone; + yyless(0); + BEGIN(g_nextCommentContext); + } <SkipCComment>"*/" { outputChar('*');outputChar('/'); + execPreProcCmd(); BEGIN(g_lastCContext); } <SkipCComment>"//" { @@ -1552,8 +1873,7 @@ outputArray(yytext,yyleng); } <SkipCComment>\n { - g_yyLineNr++; - outputChar('\n'); + DO_LINEFEED; } <SkipCComment>. { outputChar(*yytext); @@ -1562,7 +1882,7 @@ <RemoveCComment>"//" <RemoveCComment>"/*" <RemoveCComment>[^*\n]+ -<RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); } +<RemoveCComment>\n { DO_LINEFEED; } <RemoveCComment>. <SkipCPPComment,RemoveCPPComment>\n { unput(*yytext); @@ -1623,12 +1943,11 @@ } <DefineText>\\[\r]?\n { g_defLitText+=yytext; - outputChar('\n'); - g_defText += ' '; g_yyLineNr++; + DO_LINEFEED; + g_defText += ' '; } <DefineText>\n { g_defLitText+=yytext; - 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) @@ -1660,7 +1979,7 @@ } } delete g_argDict; g_argDict=0; - g_yyLineNr++; + DO_LINEFEED; g_lastGuardName.resize(0); BEGIN(Start); } @@ -1712,6 +2031,13 @@ yy_delete_buffer( oldBuf ); g_yyLineNr=fs->lineNr; setFileName(fs->fileName.copy()); + g_currentPathListIndex=fs->pathListIndex; + g_scanInclude=ScanIncNone; // Reset, don't use fs->scanInclude! + g_parentScanInclude=fs->parentScanInclude; + g_ifIncDepth=fs->ifIncDepth; + g_ifIncComp=fs->ifIncComp; + g_scanEnabledCacheChanged= true; + g_bareFileName=fs-> bareFileName; //printf("######## FileName %s\ n",g_yyFileName.data()); // TODO: Enable this to deal with file changes due to @@ -1728,16 +2054,17 @@ <*>"/*" { outputChar('/');outputChar('*'); g_lastCContext=YY_START; - BEGIN(SkipCComment); + g_nextCommentContext=SkipCComment; + BEGIN(DoxyCommand); } <*>"//" { outputChar('/');outputChar('/'); g_lastCPPContext=YY_START; - BEGIN(SkipCPPComment); + g_nextCommentContext=SkipCPPComment; + BEGIN(DoxyCommand); } <*>\n { - outputChar('\n'); - g_yyLineNr++; + DO_LINEFEED; } <*>. { outputChar(*yytext); @@ -1971,10 +2298,17 @@ return; } } - g_yyLineNr = 1; g_level = 0; g_ifcount = 0; + g_currentPathListIndex=-1; + g_parentScanInclude=ScanIncNA; + g_scanInclude=ScanIncNone; + g_ifIncComp=IfIncNone; + g_scanEnabledCacheChanged=true; + g_yyLineNr = 0; // indicate to scanner that this is a base file setFileName(fileName); + outputFileMarker(); + g_yyLineNr = 1; BEGIN( Start ); g_lastGuardName.resize(0); @@ -1993,10 +2327,19 @@ msg("Preprocessor output (size: %d bytes):\n",newPos-orgPos); int line=1; msg("---------\n00001 "); + int markercount=0; while (orgPos<newPos) { + if (*orgPos==6) + { + if (++markercount==3) + markercount=0; + } + else if (markercount==0) + { putchar(*orgPos); if (*orgPos=='\n') printf("%05d ",++line); + } orgPos++; } msg("\n---------\n"); Index: src/scanner.l =================================================================== RCS file: /u/kp3softd/cvsroot/src/scanner.l,v retrieving revision 1.62 diff -u -r1.62 scanner.l --- src/scanner.l 2001/04/30 17:28:33 1.62 +++ src/scanner.l 2001/05/02 23:37:47 @@ -17,6 +17,8 @@ %{ +//#define YY_USER_ACTION printf("<%d>%s", __LINE__ -2, yytext); + /* * includes */ @@ -101,6 +103,7 @@ static int anonCount = 0 ; static char yyFileName[4096] ; static int lastMemberGroupLine; +static QCString lastMemberGroupFile; static MethodTypes mtype; static bool gstat; static bool removeSlashes; @@ -532,31 +535,32 @@ %% -<*>\x06[^\x06]*\x06 { // new file - if (memberGroupId!=NOGROUP) - { - warn(yyFileName,yyLineNr,"Warning: Missing // @}"); - memberGroupId=NOGROUP; - } - yyLineNr= 0 ; // there is always an extra newline at the start of the file +<*>\x06[^\x06]*\x06[0-9]+\x06 { // new file int i; for( i = 0 ; yytext[i+1] != 6 ; i++ ) yyFileName[i] = yytext[i+1] ; yyFileName[i] = 0 ; setContext(); - msg("Parsing file %s...\n",yyFileName); - current_root = global_root ; - initParser(); - current->reset(); - int sec=guessSection(yyFileName); - if (sec) - { - current->name = yyFileName; - current->section = sec; - current_root->addSubEntry(current); - current = new Entry; + // parse line number + for (yyLineNr=0, i++;yytext[i+1]!=6;i++) + yyLineNr=yyLineNr*10+(yytext[i+1]-'0'); + if (yyLineNr==0) // start of a new base file + { + yyLineNr=1; + msg("Parsing file %s ...\n",yyFileName); + current_root = global_root ; + initParser(); + current->reset(); + int sec=guessSection(yyFileName); + if (sec) + { + current->name = yyFileName; + current->section = sec; + current_root->addSubEntry(current); + current = new Entry; + } + BEGIN( FindMembers ); } - BEGIN( FindMembers ); } <*>\x0d <NextSemi>"{" { @@ -705,6 +709,9 @@ <PackageName>";" { BEGIN(FindMembers); } +<FindMembers>{B}*"friend"{BN}+[^;]*";" { // ignore friend declarations (TODO: parse these and generate references for them) + lineCount(); + } <FindMembers>{B}*"static"{BN}+ { //current->type += " static "; current->stat = TRUE; lineCount(); @@ -3252,6 +3259,7 @@ memberGroupId = newMemberGroupId(); current->mGrpId = memberGroupId; lastMemberGroupLine = yyLineNr; + lastMemberGroupFile = yyFileName; } else { @@ -3744,7 +3752,7 @@ if (memberGroupId!=NOGROUP) { warn(yyFileName,yyLineNr,"Warning: ignoring nested member group. " - "Previous command was found at line %d.",lastMemberGroupLine); + "Previous command was found at file %s line %d.",lastMemberGroupFile.data(),lastMemberGroupLine); } else if (!lastDefGroup.isEmpty()) { @@ -3763,6 +3771,7 @@ memberGroupId = newMemberGroupId(); current->mGrpId = memberGroupId; lastMemberGroupLine = yyLineNr; + lastMemberGroupFile = yyFileName; } } |