diff --git a/main/parse.c b/main/parse.c index 75e3640947..a81544a267 100644 --- a/main/parse.c +++ b/main/parse.c @@ -4030,7 +4030,8 @@ static unsigned int parserCorkFlags (parserDefinition *parser) return r; } -static void setupLanguageSubparsersInUse (const langType language) +/* NOTE: Exported only for CPreProcessor */ +extern void setupLanguageSubparsersInUse (const langType language) { subparser *tmp; @@ -4044,7 +4045,8 @@ static void setupLanguageSubparsersInUse (const langType language) } } -static subparser* teardownLanguageSubparsersInUse (const langType language) +/* NOTE: Exported only for CPreProcessor */ +extern subparser* teardownLanguageSubparsersInUse (const langType language) { subparser *tmp; diff --git a/parsers/cpreprocessor.c b/parsers/cpreprocessor.c index a06144a7fd..a25adf39c6 100644 --- a/parsers/cpreprocessor.c +++ b/parsers/cpreprocessor.c @@ -14,6 +14,7 @@ #include "general.h" /* must always come first */ #include +#include #include "debug.h" #include "entry.h" @@ -30,6 +31,12 @@ #include "cxx/cxx_debug.h" +/* Ideally these two should be private in "main" part. + * Because the CPreProcessor parser is imperfect as a base parser, the + * parser must call them directly. */ +extern subparser* teardownLanguageSubparsersInUse (const langType language); +extern void setupLanguageSubparsersInUse (const langType language); + /* * MACROS */ @@ -296,6 +303,9 @@ static void cppInitCommon(langType clientLang, t = getNamedLanguage ("CPreProcessor", 0); initializeParser (t); } + pushLanguage(Cpp.lang); + setupLanguageSubparsersInUse (Cpp.lang); + popLanguage(); Cpp.clientLang = clientLang; Cpp.ungetBuffer = NULL; @@ -439,6 +449,9 @@ extern void cppTerminate (void) hashTableDelete (Cpp.fileMacroTable); Cpp.fileMacroTable = NULL; } + pushLanguage(Cpp.lang); + teardownLanguageSubparsersInUse (Cpp.lang); + popLanguage(); } extern void cppBeginStatement (void) @@ -1243,30 +1256,135 @@ static Comment isComment (void) return comment; } +static cPreProcessorSubparser *notifyLineToSubparsers (cPreProcessorSubparser *sub, + char firstchar, + vString *line, + bool *sentThe1stLine) +{ + if (sub == NULL && *sentThe1stLine == true) + return NULL; + + if (!*sentThe1stLine) + { + Assert (sub == NULL); + + subparser *s; + + *sentThe1stLine = true; + + pushLanguage (Cpp.lang); + foreachSubparser(s, false) + { + bool b = false; + cPreProcessorSubparser *cpp = (cPreProcessorSubparser *)s; + enterSubparser(s); + if (cpp->firstLineNotify) + b = cpp->firstLineNotify (cpp, firstchar, vStringValue(line)); + leaveSubparser(); + + if (b) + { + sub = cpp; + break; + } + } + popLanguage (); + return sub; + } + + enterSubparser(&sub->subparser); + if (sub->restLineNotify) + sub->restLineNotify (sub, vStringValue(line)); + leaveSubparser(); + return sub; +} + +static void notifyEndOfComment (cPreProcessorSubparser *cpp) +{ + enterSubparser(&cpp->subparser); + if (cpp->endOfCommentNotify) + cpp->endOfCommentNotify(cpp); + leaveSubparser(); +} + +static bool isDocCommentStarter(int c) +{ + return c == '*'; +} + +static bool isWhitespaceOnly (vString *line) +{ + const char *c = vStringValue(line); + + while (*c) + { + if (!isspace((unsigned char) *c) + && !isDocCommentStarter(*c)) + return false; + c++; + } + return true; +} + /* Skips over a C style comment. According to ANSI specification a comment * is treated as white space, so we perform this substitution. + * + * As side effects, running subparsers interested in comments. */ static int cppSkipOverCComment (void) { int c = cppGetcFromUngetBufferOrFile (); + int c0 = 0; + vString *line = NULL; + bool sentThe1stLine = false; + cPreProcessorSubparser *sub = NULL; + + + if (isDocCommentStarter (c)) + { + c0 = c; + c = cppGetcFromUngetBufferOrFile (); + if (c0 == '*' && c == '/') + return SPACE; + cppUngetc (c); + c = c0; + line = vStringNew (); + } while (c != EOF) { - if (c != '*') - c = cppGetcFromUngetBufferOrFile (); - else + if (c == '*') { const int next = cppGetcFromUngetBufferOrFile (); - if (next != '/') - c = next; - else + if (next == '/') { c = SPACE; /* replace comment with space */ break; } + cppUngetc (next); } + + if (line) + { + vStringPut (line, c); + if (c == '\n') + { + if (sub || !isWhitespaceOnly (line)) + sub = notifyLineToSubparsers (sub, c0, line, &sentThe1stLine); + vStringClear (line); + } + } + c = cppGetcFromUngetBufferOrFile (); } + + if (line && !vStringIsEmpty(line) && (sub || !isWhitespaceOnly (line))) + sub = notifyLineToSubparsers (sub, c0, line, &sentThe1stLine); + + if (sub) + notifyEndOfComment (sub); + + vStringDelete (line); /* NULL is acceptable */ return c; } diff --git a/parsers/cpreprocessor.h b/parsers/cpreprocessor.h index 5ae1b7483e..fd58bb9aff 100644 --- a/parsers/cpreprocessor.h +++ b/parsers/cpreprocessor.h @@ -17,6 +17,8 @@ #include "types.h" #include "vstring.h" +#include "subparser.h" + /* * MACROS */ @@ -144,4 +146,15 @@ extern void cppBuildMacroReplacementWithPtrArrayAndUngetResult( cppMacroInfo * macro, const ptrArray * args); +/* Running a parser inside comments. */ +typedef struct sCPreProcessorSubparser cPreProcessorSubparser; + +struct sCPreProcessorSubparser { + subparser subparser; + + bool (* firstLineNotify) (cPreProcessorSubparser *s, char firstchar, const char *line); + void (* restLineNotify) (cPreProcessorSubparser *s, const char *line); + void (* endOfCommentNotify) (cPreProcessorSubparser *s); +}; + #endif /* CTAGS_MAIN_GET_H */