Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Wed, 18 Nov 2020 23:13:15 UTC Commit: 353ceff30518ea0291a1f8cae279d66dd0a1c469 https://github.com/geany/geany/commit/353ceff30518ea0291a1f8cae279d66dd0a1c4...
Log Message: ----------- Various parser updates to make them compatible with latest ctags main
Modified Paths: -------------- ctags/parsers/c.c ctags/parsers/erlang.c ctags/parsers/go.c ctags/parsers/haxe.c ctags/parsers/lcpp.c ctags/parsers/lcpp.h ctags/parsers/make.c ctags/parsers/nsis.c ctags/parsers/objc.c ctags/parsers/pascal.c ctags/parsers/perl.c ctags/parsers/powershell.c ctags/parsers/python.c ctags/parsers/r.c ctags/parsers/ruby.c ctags/parsers/rust.c ctags/parsers/sql.c
Modified: ctags/parsers/c.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -1224,7 +1224,7 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type, if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken)) && (0 != strcmp(vStringValue(st->firstToken->name), tag->name))) { - tag->extensionFields.varType = getVarType(st, nameToken); + tag->extensionFields.typeRef[1] = getVarType(st, nameToken); } } } @@ -1726,7 +1726,7 @@ static void analyzeIdentifier (tokenInfo *const token) bool parensToo = false;
if (isInputLanguage (Lang_java) || - ! isIgnoreToken (name, &parensToo, &replacement)) + ! cppIsIgnoreToken (name, &parensToo, &replacement)) { if (replacement != NULL) token->keyword = analyzeKeyword (replacement);
Modified: ctags/parsers/erlang.c 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -18,6 +18,7 @@ #include "entry.h" #include "options.h" #include "read.h" +#include "parse.h" #include "routines.h" #include "vstring.h"
Modified: ctags/parsers/go.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -10,7 +10,7 @@ #include "entry.h" #include "keyword.h" #include "read.h" -#include "main.h" +#include "parse.h" #include "routines.h" #include "vstring.h" #include "options.h" @@ -531,7 +531,7 @@ static void makeTag (tokenInfo *const token, const goKind kind, if (argList) e.extensionFields.signature = argList; if (varType) - e.extensionFields.varType = varType; + e.extensionFields.typeRef[1] = varType;
if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL) {
Modified: ctags/parsers/haxe.c 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -17,7 +17,6 @@ #include <stdio.h> #endif #include <string.h> -#include "main.h" #include "entry.h" #include "keyword.h" #include "parse.h"
Modified: ctags/parsers/lcpp.c 1086 lines changed, 1086 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,1086 @@ +/* +* Copyright (c) 1996-2002, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* This module contains the high level input read functions (preprocessor +* directives are handled within this level). +*/ + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ + +#include <string.h> + +#include "debug.h" +#include "entry.h" +#include "lcpp.h" +#include "kind.h" +#include "options_p.h" +#include "read.h" +#include "vstring.h" +#include "parse.h" +#include "xtag.h" + +/* +* MACROS +*/ +#define stringMatch(s1,s2) (strcmp (s1,s2) == 0) +#define isspacetab(c) ((c) == SPACE || (c) == TAB) + +/* +* DATA DECLARATIONS +*/ +typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS, COMMENT_D } Comment; + +enum eCppLimits { + MaxCppNestingLevel = 20, + MaxDirectiveName = 10 +}; + +/* Defines the one nesting level of a preprocessor conditional. + */ +typedef struct sConditionalInfo { + bool ignoreAllBranches; /* ignoring parent conditional branch */ + bool singleBranch; /* choose only one branch */ + bool branchChosen; /* branch already selected */ + bool ignoring; /* current ignore state */ +} conditionalInfo; + +enum eState { + DRCTV_NONE, /* no known directive - ignore to end of line */ + DRCTV_DEFINE, /* "#define" encountered */ + DRCTV_HASH, /* initial '#' read; determine directive */ + DRCTV_IF, /* "#if" or "#ifdef" encountered */ + DRCTV_PRAGMA, /* #pragma encountered */ + DRCTV_UNDEF /* "#undef" encountered */ +}; + +/* Defines the current state of the pre-processor. + */ +typedef struct sCppState { + int ungetch, ungetch2; /* ungotten characters, if any */ + bool resolveRequired; /* must resolve if/else/elif/endif branch */ + bool hasAtLiteralStrings; /* supports @"c:" strings */ + bool hasCxxRawLiteralStrings; /* supports R"xxx(...)xxx" strings */ + int defineMacroKindIndex; + struct sDirective { + enum eState state; /* current directive being processed */ + bool accept; /* is a directive syntactically permitted? */ + vString * name; /* macro name */ + unsigned int nestLevel; /* level 0 is not used */ + conditionalInfo ifdef [MaxCppNestingLevel]; + } directive; +} cppState; + +/* +* DATA DEFINITIONS +*/ + +static vString *signature = NULL; +static bool collectingSignature = false; + +/* Use brace formatting to detect end of block. + */ +static bool BraceFormat = false; + +static cppState Cpp = { + '\0', '\0', /* ungetch characters */ + false, /* resolveRequired */ + false, /* hasAtLiteralStrings */ + false, /* hasCxxRawLiteralStrings */ + -1, /* defineMacroKindIndex */ + { + DRCTV_NONE, /* state */ + false, /* accept */ + NULL, /* tag name */ + 0, /* nestLevel */ + { {false,false,false,false} } /* ifdef array */ + } /* directive */ +}; + +/* +* FUNCTION DEFINITIONS +*/ + +extern bool cppIsBraceFormat (void) +{ + return BraceFormat; +} + +extern unsigned int cppGetDirectiveNestLevel (void) +{ + return Cpp.directive.nestLevel; +} + +extern void cppInit (const bool state, const bool hasAtLiteralStrings, + const bool hasCxxRawLiteralStrings, + int defineMacroKindIndex) +{ + BraceFormat = state; + + Cpp.ungetch = '\0'; + Cpp.ungetch2 = '\0'; + Cpp.resolveRequired = false; + Cpp.hasAtLiteralStrings = hasAtLiteralStrings; + Cpp.hasCxxRawLiteralStrings = hasCxxRawLiteralStrings; + Cpp.defineMacroKindIndex = defineMacroKindIndex; + + Cpp.directive.state = DRCTV_NONE; + Cpp.directive.accept = true; + Cpp.directive.nestLevel = 0; + + Cpp.directive.ifdef [0].ignoreAllBranches = false; + Cpp.directive.ifdef [0].singleBranch = false; + Cpp.directive.ifdef [0].branchChosen = false; + Cpp.directive.ifdef [0].ignoring = false; + + Cpp.directive.name = vStringNewOrClear (Cpp.directive.name); +} + +extern void cppTerminate (void) +{ + if (Cpp.directive.name != NULL) + { + vStringDelete (Cpp.directive.name); + Cpp.directive.name = NULL; + } +} + +extern void cppBeginStatement (void) +{ + Cpp.resolveRequired = true; +} + +extern void cppEndStatement (void) +{ + Cpp.resolveRequired = false; +} + +/* +* Scanning functions +* +* This section handles preprocessor directives. It strips out all +* directives and may emit a tag for #define directives. +*/ + +/* This puts a character back into the input queue for the input File. + * Up to two characters may be ungotten. + */ +extern void cppUngetc (const int c) +{ + Assert (Cpp.ungetch2 == '\0'); + Cpp.ungetch2 = Cpp.ungetch; + Cpp.ungetch = c; + if (collectingSignature) + vStringChop (signature); +} + +static inline int getcAndCollect (void) +{ + int c = getcFromInputFile (); + if (collectingSignature && c != EOF) + vStringPut (signature, c); + return c; +} + +static inline void ungetcAndCollect (int c) +{ + ungetcToInputFile (c); + if (collectingSignature) + vStringChop (signature); +} + +/* Reads a directive, whose first character is given by "c", into "name". + */ +static bool readDirective (int c, char *const name, unsigned int maxLength) +{ + unsigned int i; + + for (i = 0 ; i < maxLength - 1 ; ++i) + { + if (i > 0) + { + c = getcAndCollect (); + if (c == EOF || ! isalpha (c)) + { + ungetcAndCollect (c); + break; + } + } + name [i] = c; + } + name [i] = '\0'; /* null terminate */ + + return (bool) isspacetab (c); +} + +/* Reads an identifier, whose first character is given by "c", into "tag", + * together with the file location and corresponding line number. + */ +static void readIdentifier (int c, vString *const name) +{ + vStringClear (name); + do + { + vStringPut (name, c); + c = getcAndCollect (); + } while (c != EOF && cppIsident (c)); + ungetcAndCollect (c); +} + +static conditionalInfo *currentConditional (void) +{ + return &Cpp.directive.ifdef [Cpp.directive.nestLevel]; +} + +static bool isIgnore (void) +{ + return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring; +} + +static bool setIgnore (const bool ignore) +{ + return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore; +} + +static bool isIgnoreBranch (void) +{ + conditionalInfo *const ifdef = currentConditional (); + + /* Force a single branch if an incomplete statement is discovered + * en route. This may have allowed earlier branches containing complete + * statements to be followed, but we must follow no further branches. + */ + if (Cpp.resolveRequired && ! BraceFormat) + ifdef->singleBranch = true; + + /* We will ignore this branch in the following cases: + * + * 1. We are ignoring all branches (conditional was within an ignored + * branch of the parent conditional) + * 2. A branch has already been chosen and either of: + * a. A statement was incomplete upon entering the conditional + * b. A statement is incomplete upon encountering a branch + */ + return (bool) (ifdef->ignoreAllBranches || + (ifdef->branchChosen && ifdef->singleBranch)); +} + +static void chooseBranch (void) +{ + if (! BraceFormat) + { + conditionalInfo *const ifdef = currentConditional (); + + ifdef->branchChosen = (bool) (ifdef->singleBranch || + Cpp.resolveRequired); + } +} + +/* Pushes one nesting level for an #if directive, indicating whether or not + * the branch should be ignored and whether a branch has already been chosen. + */ +static bool pushConditional (const bool firstBranchChosen) +{ + const bool ignoreAllBranches = isIgnore (); /* current ignore */ + bool ignoreBranch = false; + + if (Cpp.directive.nestLevel < (unsigned int) MaxCppNestingLevel - 1) + { + conditionalInfo *ifdef; + + ++Cpp.directive.nestLevel; + ifdef = currentConditional (); + + /* We take a snapshot of whether there is an incomplete statement in + * progress upon encountering the preprocessor conditional. If so, + * then we will flag that only a single branch of the conditional + * should be followed. + */ + ifdef->ignoreAllBranches = ignoreAllBranches; + ifdef->singleBranch = Cpp.resolveRequired; + ifdef->branchChosen = firstBranchChosen; + ifdef->ignoring = (bool) (ignoreAllBranches || ( + ! firstBranchChosen && ! BraceFormat)); + ignoreBranch = ifdef->ignoring; + } + return ignoreBranch; +} + +/* Pops one nesting level for an #endif directive. + */ +static bool popConditional (void) +{ + if (Cpp.directive.nestLevel > 0) + --Cpp.directive.nestLevel; + + return isIgnore (); +} + +static int makeDefineTag (const char *const name, bool parameterized, bool undef) +{ + const bool isFileScope = (bool) (! isInputHeaderFile ()); + + if (Cpp.defineMacroKindIndex == -1) + return CORK_NIL; + if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE)) + return CORK_NIL; + + if ( /* condition for definition tag */ + ((!undef) && isLanguageKindEnabled (getInputLanguage(), Cpp.defineMacroKindIndex)) + || /* condition for reference tag */ + (undef && isXtagEnabled(XTAG_REFERENCE_TAGS))) + { + tagEntryInfo e; + + initTagEntry (&e, name, Cpp.defineMacroKindIndex); + e.lineNumberEntry = (bool) (Option.locate == EX_LINENUM); + e.isFileScope = isFileScope; + e.truncateLineAfterTag = true; + if (parameterized) + e.extensionFields.signature = cppGetSignature (); + makeTagEntry (&e); + if (parameterized) + eFree((char *) e.extensionFields.signature); + } + return CORK_NIL; +} + +static int directiveDefine (const int c, bool undef) +{ + int r = CORK_NIL; + + if (cppIsident1 (c)) + { + bool parameterized; + int nc; + + readIdentifier (c, Cpp.directive.name); + nc = getcAndCollect (); + parameterized = (nc == '('); + if (parameterized) + { + cppStartCollectingSignature (); + while (nc != EOF) + { + int lastC = nc; + nc = getcAndCollect (); + if (nc == '\n' && lastC != '\') + break; + } + cppStopCollectingSignature (); + } + ungetcAndCollect (nc); + if (! isIgnore ()) + makeDefineTag (vStringValue (Cpp.directive.name), parameterized, undef); + } + Cpp.directive.state = DRCTV_NONE; + return r; +} + +static void directiveUndef (const int c) +{ + if (isXtagEnabled (XTAG_REFERENCE_TAGS)) + { + directiveDefine (c, true); + } + else + { + Cpp.directive.state = DRCTV_NONE; + } +} + +static void directivePragma (int c) +{ + if (cppIsident1 (c)) + { + readIdentifier (c, Cpp.directive.name); + if (stringMatch (vStringValue (Cpp.directive.name), "weak")) + { + /* generate macro tag for weak name */ + do + { + c = getcAndCollect (); + } while (c == SPACE); + if (cppIsident1 (c)) + { + readIdentifier (c, Cpp.directive.name); + makeDefineTag (vStringValue (Cpp.directive.name), NULL, false); + } + } + } + Cpp.directive.state = DRCTV_NONE; +} + +static bool directiveIf (const int c) +{ + const bool ignore = pushConditional ((bool) (c != '0')); + + Cpp.directive.state = DRCTV_NONE; + + return ignore; +} + +static bool directiveHash (const int c) +{ + bool ignore = false; + char directive [MaxDirectiveName]; + DebugStatement ( const bool ignore0 = isIgnore (); ) + + readDirective (c, directive, MaxDirectiveName); + if (stringMatch (directive, "define")) + Cpp.directive.state = DRCTV_DEFINE; + else if (stringMatch (directive, "undef")) + Cpp.directive.state = DRCTV_UNDEF; + else if (strncmp (directive, "if", (size_t) 2) == 0) + Cpp.directive.state = DRCTV_IF; + else if (stringMatch (directive, "elif") || + stringMatch (directive, "else")) + { + ignore = setIgnore (isIgnoreBranch ()); + if (! ignore && stringMatch (directive, "else")) + chooseBranch (); + Cpp.directive.state = DRCTV_NONE; + DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); ) + } + else if (stringMatch (directive, "endif")) + { + DebugStatement ( debugCppNest (false, Cpp.directive.nestLevel); ) + ignore = popConditional (); + Cpp.directive.state = DRCTV_NONE; + DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); ) + } + else if (stringMatch (directive, "pragma")) + Cpp.directive.state = DRCTV_PRAGMA; + else + Cpp.directive.state = DRCTV_NONE; + + return ignore; +} + +/* Handles a pre-processor directive whose first character is given by "c". + */ +static bool handleDirective (const int c, int *macroCorkIndex) +{ + bool ignore = isIgnore (); + + switch (Cpp.directive.state) + { + case DRCTV_NONE: ignore = isIgnore (); break; + case DRCTV_DEFINE: + *macroCorkIndex = directiveDefine (c, false); + break; + case DRCTV_HASH: ignore = directiveHash (c); break; + case DRCTV_IF: ignore = directiveIf (c); break; + case DRCTV_PRAGMA: directivePragma (c); break; + case DRCTV_UNDEF: directiveUndef (c); break; + } + return ignore; +} + +/* Called upon reading of a slash ('/') characters, determines whether a + * comment is encountered, and its type. + */ +static Comment isComment (void) +{ + Comment comment; + const int next = getcAndCollect (); + + if (next == '*') + comment = COMMENT_C; + else if (next == '/') + comment = COMMENT_CPLUS; + else if (next == '+') + comment = COMMENT_D; + else + { + ungetcAndCollect (next); + comment = COMMENT_NONE; + } + return comment; +} + +/* Skips over a C style comment. According to ANSI specification a comment + * is treated as white space, so we perform this substitution. + */ +int cppSkipOverCComment (void) +{ + int c = getcAndCollect (); + + while (c != EOF) + { + if (c != '*') + c = getcAndCollect (); + else + { + const int next = getcAndCollect (); + + if (next != '/') + c = next; + else + { + c = SPACE; /* replace comment with space */ + break; + } + } + } + return c; +} + +/* Skips over a C++ style comment. + */ +static int skipOverCplusComment (void) +{ + int c; + + while ((c = getcAndCollect ()) != EOF) + { + if (c == BACKSLASH) + getcAndCollect (); /* throw away next character, too */ + else if (c == NEWLINE) + break; + } + return c; +} + +/* Skips over a D style comment. + * Really we should match nested /+ comments. At least they're less common. + */ +static int skipOverDComment (void) +{ + int c = getcAndCollect (); + + while (c != EOF) + { + if (c != '+') + c = getcAndCollect (); + else + { + const int next = getcAndCollect (); + + if (next != '/') + c = next; + else + { + c = SPACE; /* replace comment with space */ + break; + } + } + } + return c; +} + +/* Skips to the end of a string, returning a special character to + * symbolically represent a generic string. + */ +static int skipToEndOfString (bool ignoreBackslash) +{ + int c; + + while ((c = getcAndCollect ()) != EOF) + { + if (c == BACKSLASH && ! ignoreBackslash) + getcAndCollect (); /* throw away next character, too */ + else if (c == DOUBLE_QUOTE) + break; + } + return STRING_SYMBOL; /* symbolic representation of string */ +} + +static int isCxxRawLiteralDelimiterChar (int c) +{ + return (c != ' ' && c != '\f' && c != '\n' && c != '\r' && c != '\t' && c != '\v' && + c != '(' && c != ')' && c != '\'); +} + +static int skipToEndOfCxxRawLiteralString (void) +{ + int c = getcAndCollect (); + + if (c != '(' && ! isCxxRawLiteralDelimiterChar (c)) + { + ungetcAndCollect (c); + c = skipToEndOfString (false); + } + else + { + char delim[16]; + unsigned int delimLen = 0; + bool collectDelim = true; + + do + { + if (collectDelim) + { + if (isCxxRawLiteralDelimiterChar (c) && + delimLen < (sizeof delim / sizeof *delim)) + delim[delimLen++] = c; + else + collectDelim = false; + } + else if (c == ')') + { + unsigned int i = 0; + + while ((c = getcAndCollect ()) != EOF && i < delimLen && delim[i] == c) + i++; + if (i == delimLen && c == DOUBLE_QUOTE) + break; + else + ungetcAndCollect (c); + } + } + while ((c = getcAndCollect ()) != EOF); + c = STRING_SYMBOL; + } + return c; +} + +/* Skips to the end of the three (possibly four) 'c' sequence, returning a + * special character to symbolically represent a generic character. + */ +static int skipToEndOfChar (void) +{ + int c; + int count = 0; + + while ((c = getcAndCollect ()) != EOF) + { + ++count; + if (c == BACKSLASH) + getcAndCollect (); /* throw away next character, too */ + else if (c == SINGLE_QUOTE) + break; + else if (c == NEWLINE) + { + ungetcAndCollect (c); + break; + } + } + return CHAR_SYMBOL; /* symbolic representation of character */ +} + +/* This function returns the next character, stripping out comments, + * C pre-processor directives, and the contents of single and double + * quoted strings. In short, strip anything which places a burden upon + * the tokenizer. + */ +extern int cppGetc (void) +{ + bool directive = false; + bool ignore = false; + int c; + int macroCorkIndex = CORK_NIL; + + if (Cpp.ungetch != '\0') + { + c = Cpp.ungetch; + Cpp.ungetch = Cpp.ungetch2; + Cpp.ungetch2 = '\0'; + if (collectingSignature) + vStringPut (signature, c); + return c; /* return here to avoid re-calling debugPutc () */ + } + else do + { +start_loop: + c = getcAndCollect (); +process: + switch (c) + { + case EOF: + ignore = false; + directive = false; + macroCorkIndex = CORK_NIL; + break; + + case TAB: + case SPACE: + break; /* ignore most white space */ + + case NEWLINE: + if (directive && ! ignore) + { + macroCorkIndex = CORK_NIL; + directive = false; + } + Cpp.directive.accept = true; + break; + + case DOUBLE_QUOTE: + Cpp.directive.accept = false; + c = skipToEndOfString (false); + break; + + case '#': + if (Cpp.directive.accept) + { + directive = true; + Cpp.directive.state = DRCTV_HASH; + Cpp.directive.accept = false; + } + break; + + case SINGLE_QUOTE: + Cpp.directive.accept = false; + c = skipToEndOfChar (); + break; + + case '/': + { + const Comment comment = isComment (); + + if (comment == COMMENT_C) + c = cppSkipOverCComment (); + else if (comment == COMMENT_CPLUS) + { + c = skipOverCplusComment (); + if (c == NEWLINE) + ungetcAndCollect (c); + } + else if (comment == COMMENT_D) + c = skipOverDComment (); + else + Cpp.directive.accept = false; + break; + } + + case BACKSLASH: + { + int next = getcAndCollect (); + + if (next == NEWLINE) + goto start_loop; + else + ungetcAndCollect (next); + break; + } + + case '?': + { + int next = getcAndCollect (); + if (next != '?') + ungetcAndCollect (next); + else + { + next = getcAndCollect (); + switch (next) + { + case '(': c = '['; break; + case ')': c = ']'; break; + case '<': c = '{'; break; + case '>': c = '}'; break; + case '/': c = BACKSLASH; goto process; + case '!': c = '|'; break; + case SINGLE_QUOTE: c = '^'; break; + case '-': c = '~'; break; + case '=': c = '#'; goto process; + default: + ungetcAndCollect ('?'); + ungetcAndCollect (next); + break; + } + } + } break; + + /* digraphs: + * input: <: :> <% %> %: %:%: + * output: [ ] { } # ## + */ + case '<': + { + int next = getcAndCollect (); + switch (next) + { + case ':': c = '['; break; + case '%': c = '{'; break; + default: ungetcAndCollect (next); + } + goto enter; + } + case ':': + { + int next = getcAndCollect (); + if (next == '>') + c = ']'; + else + ungetcAndCollect (next); + goto enter; + } + case '%': + { + int next = getcAndCollect (); + switch (next) + { + case '>': c = '}'; break; + case ':': c = '#'; goto process; + default: ungetcAndCollect (next); + } + goto enter; + } + + default: + if (c == '@' && Cpp.hasAtLiteralStrings) + { + int next = getcAndCollect (); + if (next == DOUBLE_QUOTE) + { + Cpp.directive.accept = false; + c = skipToEndOfString (true); + break; + } + else + ungetcAndCollect (next); + } + else if (c == 'R' && Cpp.hasCxxRawLiteralStrings) + { + /* OMG!11 HACK!!11 Get the previous character. + * + * We need to know whether the previous character was an identifier or not, + * because "R" has to be on its own, not part of an identifier. This allows + * for constructs like: + * + * #define FOUR "4" + * const char *p = FOUR"5"; + * + * which is not a raw literal, but a preprocessor concatenation. + * + * FIXME: handle + * + * const char *p = R\ + * "xxx(raw)xxx"; + * + * which is perfectly valid (yet probably very unlikely). */ + int prev = getNthPrevCFromInputFile (1, '\0'); + int prev2 = getNthPrevCFromInputFile (2, '\0'); + int prev3 = getNthPrevCFromInputFile (3, '\0'); + + if (! cppIsident (prev) || + (! cppIsident (prev2) && (prev == 'L' || prev == 'u' || prev == 'U')) || + (! cppIsident (prev3) && (prev2 == 'u' && prev == '8'))) + { + int next = getcAndCollect (); + if (next != DOUBLE_QUOTE) + ungetcAndCollect (next); + else + { + Cpp.directive.accept = false; + c = skipToEndOfCxxRawLiteralString (); + break; + } + } + } + enter: + Cpp.directive.accept = false; + if (directive) + ignore = handleDirective (c, ¯oCorkIndex); + break; + } + } while (directive || ignore); + + DebugStatement ( debugPutc (DEBUG_CPP, c); ) + DebugStatement ( if (c == NEWLINE) + debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); ) + + return c; +} + +typedef enum +{ + st_none_t, + st_escape_t, + st_c_comment_t, + st_cpp_comment_t, + st_double_quote_t, + st_single_quote_t +} ParseState; + +static void stripCodeBuffer(char *buf) +{ + int i = 0, pos = 0; + ParseState state = st_none_t, prev_state = st_none_t; + + while (buf[i] != '\0') + { + switch(buf[i]) + { + case '/': + if (st_none_t == state) + { + /* Check if this is the start of a comment */ + if (buf[i+1] == '*') /* C comment */ + state = st_c_comment_t; + else if (buf[i+1] == '/') /* C++ comment */ + state = st_cpp_comment_t; + else /* Normal character */ + buf[pos++] = '/'; + } + else if (st_c_comment_t == state) + { + /* Check if this is the end of a C comment */ + if (buf[i-1] == '*') + { + if ((pos > 0) && (buf[pos-1] != ' ')) + buf[pos++] = ' '; + state = st_none_t; + } + } + break; + case '"': + if (st_none_t == state) + state = st_double_quote_t; + else if (st_double_quote_t == state) + state = st_none_t; + break; + case ''': + if (st_none_t == state) + state = st_single_quote_t; + else if (st_single_quote_t == state) + state = st_none_t; + break; + default: + if ((buf[i] == '\') && (st_escape_t != state)) + { + prev_state = state; + state = st_escape_t; + } + else if (st_escape_t == state) + { + state = prev_state; + prev_state = st_none_t; + } + else if ((buf[i] == '\n') && (st_cpp_comment_t == state)) + { + if ((pos > 0) && (buf[pos-1] != ' ')) + buf[pos++] = ' '; + state = st_none_t; + } + else if (st_none_t == state) + { + if (isspace(buf[i])) + { + if ((pos > 0) && (buf[pos-1] != ' ')) + buf[pos++] = ' '; + } + else + buf[pos++] = buf[i]; + } + break; + } + ++i; + } + buf[pos] = '\0'; + return; +} + +extern char *cppGetSignature(void) +{ + char *start, *end; + int level; + + if (NULL == signature || vStringLength (signature) < 2) + return NULL; + + start = eStrdup (vStringValue (signature)); + stripCodeBuffer(start); + for (level = 1, end = start + 1; level > 0; ++end) + { + if ('\0' == *end) + break; + else if ('(' == *end) + ++ level; + else if (')' == *end) + -- level; + } + *end = '\0'; + return start; +} + +extern void cppStartCollectingSignature (void) +{ + signature = vStringNewOrClear (signature); + vStringPut (signature, '('); + collectingSignature = true; +} + +extern void cppStopCollectingSignature (void) +{ + collectingSignature = false; +} + +extern void cppClearSignature (void) +{ + signature = vStringNewOrClear (signature); + collectingSignature = false; +} + +/* tags_ignore is a NULL-terminated array of strings, read from ~/.config/geany/ignore.tags. + * This file contains a space or newline separated list of symbols which should be ignored + * by the C/C++ parser, see -I command line option of ctags for details. */ +char **c_tags_ignore = NULL; + +/* Determines whether or not "name" should be ignored, per the ignore list. + */ +extern bool cppIsIgnoreToken (const char *const name, + bool *const pIgnoreParens, + const char **const replacement) +{ + bool result = false; + + if (c_tags_ignore != NULL) + { + const size_t nameLen = strlen (name); + unsigned int i; + unsigned int len = 0; + vString *token = vStringNew(); + + while (c_tags_ignore[len]) + len++; + + if (pIgnoreParens != NULL) + *pIgnoreParens = false; + + for (i = 0 ; i < len ; ++i) + { + size_t tokenLen; + + vStringCopyS (token, c_tags_ignore[i]); + tokenLen = vStringLength (token); + + if (tokenLen >= 2 && vStringChar (token, tokenLen - 1) == '*' && + strncmp (vStringValue (token), name, tokenLen - 1) == 0) + { + result = true; + break; + } + if (strncmp (vStringValue (token), name, nameLen) == 0) + { + if (nameLen == tokenLen) + { + result = true; + break; + } + else if (tokenLen == nameLen + 1 && + vStringChar (token, tokenLen - 1) == '+') + { + result = true; + if (pIgnoreParens != NULL) + *pIgnoreParens = true; + break; + } + else if (vStringChar (token, nameLen) == '=') + { + if (replacement != NULL) + *replacement = vStringValue (token) + nameLen + 1; + break; + } + } + } + vStringDelete (token); + } + return result; +}
Modified: ctags/parsers/lcpp.h 84 lines changed, 84 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,84 @@ +/* +* Copyright (c) 1998-2002, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* External interface to get.c +*/ +#ifndef CTAGS_MAIN_GET_H +#define CTAGS_MAIN_GET_H + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ +#include "types.h" + +/* +* MACROS +*/ +/* Is the character valid as a character of a C identifier? + * VMS allows '$' in identifiers. + */ +#define cppIsident(c) (isalnum(c) || (c) == '_' || (c) == '$') + +/* Is the character valid as the first character of a C identifier? + * C++ allows '~' in destructors. + * VMS allows '$' in identifiers. + * Vala allows '@' in identifiers. + */ +#define cppIsident1(c) ( ((c >= 0) && (c < 0x80) && isalpha(c)) \ + || (c) == '_' || (c) == '~' || (c) == '$' || (c) == '@') +/* NOTE about isident1 profitability + + Doing the same as isascii before passing value to isalpha + ---------------------------------------------------------- + cppGetc() can return the value out of range of char. + cppGetc calls skipToEndOfString and skipToEndOfString can + return STRING_SYMBOL(== 338). + + Depending on the platform, isalpha(338) returns different value . + As far as Fedora22, it returns 0. On Windows 2010, it returns 1. + + man page on Fedora 22 says: + + These functions check whether c, which must have the value of an + unsigned char or EOF, falls into a certain character class + according to the specified locale. + + isascii is for suitable to verify the range of input. However, it + is not portable enough. */ + +#define RoleTemplateUndef { true, "undef", "undefined" } + +#define RoleTemplateSystem { true, "system", "system header" } +#define RoleTemplateLocal { true, "local", "local header" } + +/* +* FUNCTION PROTOTYPES +*/ +extern bool cppIsBraceFormat (void); +extern unsigned int cppGetDirectiveNestLevel (void); + +extern void cppInit (const bool state, + const bool hasAtLiteralStrings, + const bool hasCxxRawLiteralStrings, + int defineMacroKindIndex); +extern void cppTerminate (void); +extern void cppBeginStatement (void); +extern void cppEndStatement (void); +extern void cppUngetc (const int c); +extern int cppGetc (void); +extern int cppSkipOverCComment (void); + +extern char *cppGetSignature (void); +extern void cppStartCollectingSignature (void); +extern void cppStopCollectingSignature (void); +extern void cppClearSignature (void); + +extern bool cppIsIgnoreToken (const char *const name, + bool *const pIgnoreParens, + const char **const replacement); + +#endif /* CTAGS_MAIN_GET_H */
Modified: ctags/parsers/make.c 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -20,6 +20,7 @@ #include "parse.h" #include "read.h" #include "routines.h" +#include "strlist.h" #include "vstring.h" #include "xtag.h"
Modified: ctags/parsers/nsis.c 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -17,7 +17,6 @@
#include "parse.h" #include "read.h" -#include "main.h" #include "vstring.h" #include "routines.h"
Modified: ctags/parsers/objc.c 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -17,6 +17,7 @@
#include "keyword.h" #include "entry.h" +#include "parse.h" #include "options.h" #include "read.h" #include "routines.h" @@ -1109,7 +1110,7 @@ static void objcInitialize (const langType language) extern parserDefinition *ObjcParser (void) { static const char *const extensions[] = { "m", "h", NULL }; - parserDefinition *def = parserNewFull ("ObjectiveC", KIND_FILE_ALT); + parserDefinition *def = parserNew ("ObjectiveC"); def->kindTable = ObjcKinds; def->kindCount = ARRAY_SIZE (ObjcKinds); def->extensions = extensions;
Modified: ctags/parsers/pascal.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -46,7 +46,7 @@ static void createPascalTag (tagEntryInfo* const tag, initTagEntry (tag, vStringValue (name), kind);
tag->extensionFields.signature = arglist; - tag->extensionFields.varType = vartype; + tag->extensionFields.typeRef[1] = vartype; } else {
Modified: ctags/parsers/perl.c 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -17,6 +17,7 @@ #include <string.h>
#include "entry.h" +#include "promise.h" #include "options.h" #include "read.h" #include "routines.h"
Modified: ctags/parsers/powershell.c 1 lines changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -15,7 +15,6 @@ */ #include "general.h" /* must always come first */ #include "debug.h" -#include "main.h" #include "parse.h" #include "read.h" #include "vstring.h"
Modified: ctags/parsers/python.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -18,7 +18,7 @@ #include "nestlevel.h" #include "options.h" #include "read.h" -#include "main.h" +#include "parse.h" #include "vstring.h" #include "routines.h" #include "debug.h"
Modified: ctags/parsers/r.c 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -19,6 +19,7 @@
#include "debug.h" #include "entry.h" +#include "parse.h" #include "read.h" #include "vstring.h" #include "routines.h"
Modified: ctags/parsers/ruby.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -554,7 +554,7 @@ static void findRubyTags (void) extern parserDefinition* RubyParser (void) { static const char *const extensions [] = { "rb", "ruby", NULL }; - parserDefinition* def = parserNewFull ("Ruby", KIND_FILE_ALT); + parserDefinition* def = parserNew ("Ruby"); def->kindTable = RubyKinds; def->kindCount = ARRAY_SIZE (RubyKinds); def->extensions = extensions;
Modified: ctags/parsers/rust.c 5 lines changed, 2 insertions(+), 3 deletions(-) =================================================================== @@ -10,7 +10,6 @@ * INCLUDE FILES */ #include "general.h" /* must always come first */ -#include "main.h"
#include <string.h>
@@ -446,7 +445,7 @@ static void addTag (vString* ident, const char* type, const char* arg_list, int tag.sourceFileName = getInputFileName();
tag.extensionFields.signature = arg_list; - tag.extensionFields.varType = type; + tag.extensionFields.typeRef[1] = type; if (parent_kind != K_NONE) { tag.extensionFields.scopeKindIndex = parent_kind; @@ -973,7 +972,7 @@ static void findRustTags (void) extern parserDefinition *RustParser (void) { static const char *const extensions[] = { "rs", NULL }; - parserDefinition *def = parserNewFull ("Rust", KIND_FILE_ALT); + parserDefinition *def = parserNew ("Rust"); def->kindTable = rustKinds; def->kindCount = ARRAY_SIZE (rustKinds); def->extensions = extensions;
Modified: ctags/parsers/sql.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -2338,7 +2338,7 @@ static void findSqlTags (void) extern parserDefinition* SqlParser (void) { static const char *const extensions [] = { "sql", NULL }; - parserDefinition* def = parserNewFull ("SQL", KIND_FILE_ALT); + parserDefinition* def = parserNew ("SQL"); def->kindTable = SqlKinds; def->kindCount = ARRAY_SIZE (SqlKinds); def->extensions = extensions;
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).