[geany/geany] 353cef: Various parser updates to make them compatible with latest ctags main
Jiří Techet
git-noreply at xxxxx
Sun Feb 7 21:31:58 UTC 2021
Branch: refs/heads/master
Author: Jiří Techet <techet at gmail.com>
Committer: Jiří Techet <techet at gmail.com>
Date: Wed, 18 Nov 2020 23:13:15 UTC
Commit: 353ceff30518ea0291a1f8cae279d66dd0a1c469
https://github.com/geany/geany/commit/353ceff30518ea0291a1f8cae279d66dd0a1c469
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).
More information about the Commits
mailing list