[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, &macroCorkIndex);
+				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