SF.net SVN: geany: [544] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Sun Jul 9 14:42:17 UTC 2006


Revision: 544
Author:   eht16
Date:     2006-07-09 07:41:53 -0700 (Sun, 09 Jul 2006)
ViewCVS:  http://svn.sourceforge.net/geany/?rev=544&view=rev

Log Message:
-----------
Added new filetype D(patch by Christop Berg, thanks).

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/src/build.c
    trunk/src/filetypes.c
    trunk/src/filetypes.h
    trunk/src/highlighting.c
    trunk/src/highlighting.h
    trunk/src/templates.c
    trunk/src/templates.h
    trunk/src/utils.c
    trunk/tagmanager/Makefile.am
    trunk/tagmanager/parsers.h

Added Paths:
-----------
    trunk/data/filetypes.d
    trunk/tagmanager/d.c
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/ChangeLog	2006-07-09 14:41:53 UTC (rev 544)
@@ -1,3 +1,11 @@
+2006-07-09  Enrico Tröger  <enrico.troeger at uvena.de>
+
+ * tagmanager/d.c, tagmanager/Makefile.am, tagmanager/parsers.h,
+   src/filetypes.c, src/highlighting.c, src/utils.c, src/build.c,
+   src/templates.c, data/filetypes.d:
+   Added new filetype D(patch by Christop Berg, thanks).
+
+
 2006-07-08  Nick Treleaven  <nick.treleaven at btinternet.com>
 
  * src/keyfile.c: Fix saving the terminal tool on quitting.

Added: trunk/data/filetypes.d
===================================================================
--- trunk/data/filetypes.d	                        (rev 0)
+++ trunk/data/filetypes.d	2006-07-09 14:41:53 UTC (rev 544)
@@ -0,0 +1,67 @@
+# For complete documentation of this file, please see Geany's main documentation
+[styling]
+# foreground;background;bold;italic
+default=0x000000;0xffffff;false;false
+comment=0x0000ff;0xffffff;false;false
+commentline=0x0000ff;0xffffff;false;false
+commentdoc=0x0000ff;0xffffff;false;false
+number=0x007f00;0xffffff;false;false
+word=0x991111;0xffffff;true;false
+word2=0x00007F;0xffffff;true;false
+string=0x1E90FF;0xffffff;false;false
+character=0x1E90FF;0xffffff;false;false
+uuid=0x804040;0xffffff;false;false
+preprocessor=0x7F7F00;0xffffff;false;false
+operator=0x101030;0xffffff;false;false
+identifier=0x100000;0xffffff;false;false
+stringeol=0x000000;0xe0c0e0;false;false
+verbatim=0x101030;0xffffff;false;false
+regex=0x905010;0xffffff;false;false
+commentlinedoc=0x0000ff;0xffffff;true;false
+commentdockeyword=0x0000ff;0xffffff;true;true
+globalclass=0xbb1111;0xffffff;true;false
+# whether arguments of preprocessor commands should be styled (only first argument is used)
+# 1 to enable, 0 to disable
+styling_within_preprocessor=1;0;false;false
+
+[keywords]
+# all items must be in one line
+primary=__FILE__ __LINE__ __DATA__ __TIME__ __TIMESTAMP__ abstract alias align asm assert auto body bool break byte case cast catch cdouble cent cfloat char class const continue creal dchar debug default delegate delete deprecated do double else enum export extern false final finally float for foreach function goto idouble if ifloat import in inout int interface invariant ireal is long mixin module new null out override package pragma private protected public real return scope short static struct super switch synchronized template this throw true try typedef typeof ubyte ucent uint ulong union unittest ushort version void volatile wchar while with
+docComment=TODO FIXME
+
+[settings]
+# the following characters are these which a "word" can contains, see documentation
+wordchars=_#&abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
+
+# if only single comment char is supported like # in this file, leave comment_close blank
+comment_open=//
+comment_close=
+# this is an alternative way, so multiline comments are used
+#comment_open=/*
+#comment_close=*/
+# this is alternative way, so multiline comments are used
+#comment_open=/+
+#comment_close=+/
+
+# set to false if a comment character/string should start a column 0 of a line, true uses any
+# indention of the line, e.g. setting to true causes the following on pressing CTRL+d
+	#command_example();
+# setting to false would generate this
+#	command_example();
+# This setting works only for single line comments
+comment_use_indent=true
+
+[build_settings]
+# %f will be replaced by the complete filename
+# %e will be replaced by the filename without extension
+# (use only one of it at one time)
+compiler=dmd -w -c "%f"
+# the -of option is automatically added by Geany
+linker=dmd -w "%f"
+# you can also use the gdc compiler, please use the "gdmd" wrapper script(included with gdc)
+#compiler=gdmd -w -c "%f"
+#linker=gdmd -w "%f"
+
+run_cmd="./%e"
+
+

Modified: trunk/src/build.c
===================================================================
--- trunk/src/build.c	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/build.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -209,12 +209,26 @@
 		}
 	}
 
-	argv = g_new0(gchar *, 4);
-	argv[0] = g_strdup(doc_list[idx].file_type->programs->linker);
-	argv[1] = g_strdup("-o");
-	argv[2] = g_path_get_basename(executable);
-	argv[3] = NULL;
+	if (doc_list[idx].file_type->id == GEANY_FILETYPES_D)
+	{	// the dmd compiler needs -of instead of -o and it accepts no whitespace after -of
+		gchar *tmp = g_path_get_basename(executable);
 
+		argv = g_new0(gchar *, 3);
+		argv[0] = g_strdup(doc_list[idx].file_type->programs->linker);
+		argv[1] = g_strconcat("-of", tmp, NULL);
+		argv[2] = NULL;
+
+		g_free(tmp);
+	}
+	else
+	{
+		argv = g_new0(gchar *, 4);
+		argv[0] = g_strdup(doc_list[idx].file_type->programs->linker);
+		argv[1] = g_strdup("-o");
+		argv[2] = g_path_get_basename(executable);
+		argv[3] = NULL;
+	}
+
 	g_free(executable);
 	g_free(object_file);
 	g_free(locale_filename);

Modified: trunk/src/filetypes.c
===================================================================
--- trunk/src/filetypes.c	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/filetypes.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -432,6 +432,25 @@
 	filetypes_init_build_programs(filetypes[GEANY_FILETYPES_TCL]);
 	filetypes_create_menu_item(filetype_menu, filetypes[GEANY_FILETYPES_TCL]->title, filetypes[GEANY_FILETYPES_TCL]);
 
+#define D
+	filetypes[GEANY_FILETYPES_D] = g_new0(filetype, 1);
+	filetypes[GEANY_FILETYPES_D]->id = GEANY_FILETYPES_D;
+	filetypes[GEANY_FILETYPES_D]->lang = 17;
+	filetypes[GEANY_FILETYPES_D]->name = g_strdup("D");
+	filetypes[GEANY_FILETYPES_D]->has_tags = TRUE;
+	filetypes[GEANY_FILETYPES_D]->title = g_strdup(_("D source file"));
+	filetypes[GEANY_FILETYPES_D]->extension = g_strdup("d");
+	filetypes[GEANY_FILETYPES_D]->pattern = g_new0(gchar*, 3);
+	filetypes[GEANY_FILETYPES_D]->pattern[0] = g_strdup("*.d");
+	filetypes[GEANY_FILETYPES_D]->pattern[1] = g_strdup("*.di");
+	filetypes[GEANY_FILETYPES_D]->pattern[2] = NULL;
+	filetypes[GEANY_FILETYPES_D]->comment_open = g_strdup("//");
+	filetypes[GEANY_FILETYPES_D]->comment_close = NULL;
+	filetypes[GEANY_FILETYPES_D]->style_func_ptr = styleset_d;
+	filetypes_init_build_programs(filetypes[GEANY_FILETYPES_D]);
+	filetypes_create_menu_item(filetype_menu, filetypes[GEANY_FILETYPES_D]->title, filetypes[GEANY_FILETYPES_D]);
+	filetypes_create_newmenu_item(template_menu, filetypes[GEANY_FILETYPES_D]->title, filetypes[GEANY_FILETYPES_D]);
+
 #define ALL
 	filetypes[GEANY_FILETYPES_ALL] = g_new0(filetype, 1);
 	filetypes[GEANY_FILETYPES_ALL]->id = GEANY_FILETYPES_ALL;
@@ -587,6 +606,8 @@
 			return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_PASCAL); break;
 		case GEANY_FILETYPES_RUBY:
 			return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_RUBY); break;
+		case GEANY_FILETYPES_D:
+			return templates_get_template_generic(GEANY_TEMPLATE_FILETYPE_D); break;
 		default: return NULL;
 	}
 }

Modified: trunk/src/filetypes.h
===================================================================
--- trunk/src/filetypes.h	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/filetypes.h	2006-07-09 14:41:53 UTC (rev 544)
@@ -47,8 +47,9 @@
 	GEANY_FILETYPES_OMS,		// 17
 	GEANY_FILETYPES_RUBY,		// 18
 	GEANY_FILETYPES_TCL,		// 19
-	GEANY_FILETYPES_ALL,		// 20
-	GEANY_MAX_FILE_TYPES		// 21
+	GEANY_FILETYPES_D,			// 20
+	GEANY_FILETYPES_ALL,		// 21
+	GEANY_MAX_FILE_TYPES		// 22
 };
 
 struct build_menu_items

Modified: trunk/src/highlighting.c
===================================================================
--- trunk/src/highlighting.c	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/highlighting.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -2246,5 +2246,125 @@
 	SSM(sci, SCI_SETWHITESPACEFORE, 1, invert(0xc0c0c0));
 }
 
+static void styleset_d_init(void)
+{
+	GKeyFile *config = g_key_file_new();
+	GKeyFile *config_home = g_key_file_new();
+	gchar *f = g_strconcat(app->configdir, G_DIR_SEPARATOR_S GEANY_FILEDEFS_SUBDIR G_DIR_SEPARATOR_S, "filetypes.d", NULL);
 
+	styleset_load_file(config, GEANY_DATA_DIR G_DIR_SEPARATOR_S "filetypes.d", G_KEY_FILE_KEEP_COMMENTS, NULL);
+	g_key_file_load_from_file(config_home, f, G_KEY_FILE_KEEP_COMMENTS, NULL);
 
+	types[GEANY_FILETYPES_D] = g_new(style_set, 1);
+	styleset_get_hex(config, config_home, "styling", "default", "0x000000", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[0]);
+	styleset_get_hex(config, config_home, "styling", "comment", "0x0000ff", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[1]);
+	styleset_get_hex(config, config_home, "styling", "commentline", "0x0000ff", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[2]);
+	styleset_get_hex(config, config_home, "styling", "commentdoc", "0x0000ff", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[3]);
+	styleset_get_hex(config, config_home, "styling", "number", "0x007f00", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[4]);
+	styleset_get_hex(config, config_home, "styling", "word", "0x991111", "0xffffff", "true", types[GEANY_FILETYPES_D]->styling[5]);
+	styleset_get_hex(config, config_home, "styling", "word2", "0x00007F", "0xffffff", "true", types[GEANY_FILETYPES_D]->styling[6]);
+	styleset_get_hex(config, config_home, "styling", "string", "0x1E90FF", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[7]);
+	styleset_get_hex(config, config_home, "styling", "character", "0x1E90FF", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[8]);
+	styleset_get_hex(config, config_home, "styling", "uuid", "0x804040", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[9]);
+	styleset_get_hex(config, config_home, "styling", "preprocessor", "0x7F7F00", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[10]);
+	styleset_get_hex(config, config_home, "styling", "operator", "0x101030", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[11]);
+	styleset_get_hex(config, config_home, "styling", "identifier", "0x100000", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[12]);
+	styleset_get_hex(config, config_home, "styling", "stringeol", "0x000000", "0xe0c0e0", "false", types[GEANY_FILETYPES_D]->styling[13]);
+	styleset_get_hex(config, config_home, "styling", "verbatim", "0x101030", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[14]);
+	styleset_get_hex(config, config_home, "styling", "regex", "0x101030", "0xffffff", "false", types[GEANY_FILETYPES_D]->styling[15]);
+	styleset_get_hex(config, config_home, "styling", "commentlinedoc", "0x0000ff", "0xffffff", "true", types[GEANY_FILETYPES_D]->styling[16]);
+	styleset_get_hex(config, config_home, "styling", "commentdockeyword", "0x0000ff", "0xffffff", "true", types[GEANY_FILETYPES_D]->styling[17]);
+	styleset_get_hex(config, config_home, "styling", "globalclass", "0xbb1111", "0xffffff", "true", types[GEANY_FILETYPES_D]->styling[18]);
+	styleset_get_int(config, config_home, "styling", "styling_within_preprocessor", 1, 0, types[GEANY_FILETYPES_D]->styling[19]);
+
+	types[GEANY_FILETYPES_D]->keywords = g_new(gchar*, 3);
+	styleset_get_keywords(config, config_home, "keywords", "primary", GEANY_FILETYPES_D, 0, "__FILE__ __LINE__ __DATA__ __TIME__ __TIMESTAMP__ abstract alias align asm assert auto body bool break byte case cast catch cdouble cent cfloat char class const continue creal dchar debug default delegate delete deprecated do double else enum export extern false final finally float for foreach function goto idouble if ifloat import in inout int interface invariant ireal is long mixin module new null out override package pragma private protected public real return scope short static struct super switch synchronized template this throw true try typedef typeof ubyte ucent uint ulong union unittest ushort version void volatile wchar while with");
+	styleset_get_keywords(config, config_home, "keywords", "docComment", GEANY_FILETYPES_D, 1, "TODO FIXME");
+	types[GEANY_FILETYPES_D]->keywords[2] = NULL;
+
+	styleset_get_wordchars(config, config_home, GEANY_FILETYPES_D, GEANY_WORDCHARS);
+	filetypes_get_config(config, config_home, GEANY_FILETYPES_D);
+
+	g_key_file_free(config);
+	g_key_file_free(config_home);
+	g_free(f);
+
+	// load global tags file for C autocompletion
+	if (! app->ignore_global_tags && ! global_c_tags_loaded)
+	{
+		// 0 is the langType used in TagManager (see the table in tagmanager/parsers.h)
+		// C++ is a special case, here we use 0 to have C global tags in C++, too
+		tm_workspace_load_global_tags(GEANY_DATA_DIR G_DIR_SEPARATOR_S "global.tags", 0);
+		global_c_tags_loaded = TRUE;
+	}
+}
+
+
+void styleset_d(ScintillaObject *sci)
+{
+	if (types[GEANY_FILETYPES_D] == NULL) styleset_d_init();
+
+	styleset_common(sci, 5);
+
+
+	/* Assign global keywords */
+	if ((app->tm_workspace) && (app->tm_workspace->global_tags))
+	{
+		guint j;
+		GPtrArray *g_typedefs = tm_tags_extract(app->tm_workspace->global_tags, tm_tag_typedef_t | tm_tag_struct_t | tm_tag_class_t);
+		if ((g_typedefs) && (g_typedefs->len > 0))
+		{
+			GString *s = g_string_sized_new(g_typedefs->len * 10);
+			for (j = 0; j < g_typedefs->len; ++j)
+			{
+				if (!(TM_TAG(g_typedefs->pdata[j])->atts.entry.scope))
+				{
+					g_string_append(s, TM_TAG(g_typedefs->pdata[j])->name);
+					g_string_append_c(s, ' ');
+				}
+			}
+			SSM(sci, SCI_SETKEYWORDS, 1, (sptr_t) s->str);
+			g_string_free(s, TRUE);
+		}
+		g_ptr_array_free(g_typedefs, TRUE);
+	}
+
+	SSM(sci, SCI_SETWORDCHARS, 0, (sptr_t) types[GEANY_FILETYPES_D]->wordchars);
+	SSM(sci, SCI_AUTOCSETMAXHEIGHT, 8, 0);
+
+	SSM(sci, SCI_SETLEXER, SCLEX_CPP, 0);
+
+	//SSM(sci, SCI_SETCONTROLCHARSYMBOL, 32, 0);
+
+	SSM(sci, SCI_SETKEYWORDS, 0, (sptr_t) types[GEANY_FILETYPES_D]->keywords[0]);
+	SSM(sci, SCI_SETKEYWORDS, 2, (sptr_t) types[GEANY_FILETYPES_D]->keywords[1]);
+
+	styleset_set_style(sci, SCE_C_DEFAULT, GEANY_FILETYPES_D, 0);
+	styleset_set_style(sci, SCE_C_COMMENT, GEANY_FILETYPES_D, 1);
+	styleset_set_style(sci, SCE_C_COMMENTLINE, GEANY_FILETYPES_D, 2);
+	styleset_set_style(sci, SCE_C_COMMENTDOC, GEANY_FILETYPES_D, 3);
+	styleset_set_style(sci, SCE_C_NUMBER, GEANY_FILETYPES_D, 4);
+	styleset_set_style(sci, SCE_C_WORD, GEANY_FILETYPES_D, 5);
+	styleset_set_style(sci, SCE_C_WORD2, GEANY_FILETYPES_D, 6);
+	styleset_set_style(sci, SCE_C_STRING, GEANY_FILETYPES_D, 7);
+	styleset_set_style(sci, SCE_C_CHARACTER, GEANY_FILETYPES_D, 8);
+	styleset_set_style(sci, SCE_C_UUID, GEANY_FILETYPES_D, 9);
+	styleset_set_style(sci, SCE_C_PREPROCESSOR, GEANY_FILETYPES_D, 10);
+	styleset_set_style(sci, SCE_C_OPERATOR, GEANY_FILETYPES_D, 11);
+	styleset_set_style(sci, SCE_C_IDENTIFIER, GEANY_FILETYPES_D, 12);
+	styleset_set_style(sci, SCE_C_STRINGEOL, GEANY_FILETYPES_D, 13);
+	styleset_set_style(sci, SCE_C_VERBATIM, GEANY_FILETYPES_D, 14);
+	styleset_set_style(sci, SCE_C_REGEX, GEANY_FILETYPES_D, 15);
+	styleset_set_style(sci, SCE_C_COMMENTLINEDOC, GEANY_FILETYPES_D, 16);
+	styleset_set_style(sci, SCE_C_COMMENTDOCKEYWORD, GEANY_FILETYPES_D, 17);
+
+	SSM(sci, SCI_STYLESETFORE, SCE_C_COMMENTDOCKEYWORDERROR, invert(0x0000ff));
+	SSM(sci, SCI_STYLESETBACK, SCE_C_COMMENTDOCKEYWORDERROR, invert(0xffffff));
+	SSM(sci, SCI_STYLESETITALIC, SCE_C_COMMENTDOCKEYWORDERROR, TRUE);
+
+	// is used for local structs and typedefs
+	styleset_set_style(sci, SCE_C_GLOBALCLASS, GEANY_FILETYPES_D, 18);
+
+	SSM(sci, SCI_SETWHITESPACEFORE, 1, invert(0xc0c0c0));
+}
+

Modified: trunk/src/highlighting.h
===================================================================
--- trunk/src/highlighting.h	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/highlighting.h	2006-07-09 14:41:53 UTC (rev 544)
@@ -81,4 +81,6 @@
 
 void styleset_tcl(ScintillaObject *sci);
 
+void styleset_d(ScintillaObject *sci);
+
 #endif

Modified: trunk/src/templates.c
===================================================================
--- trunk/src/templates.c	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/templates.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -58,6 +58,7 @@
 	gchar *template_filename_filetype_none = templates_get_filename("template.filetype.none");
 	gchar *template_filename_filetype_c = templates_get_filename("template.filetype.c");
 	gchar *template_filename_filetype_cpp = templates_get_filename("template.filetype.cpp");
+	gchar *template_filename_filetype_d = templates_get_filename("template.filetype.d");
 	gchar *template_filename_filetype_java = templates_get_filename("template.filetype.java");
 	gchar *template_filename_filetype_pascal = templates_get_filename("template.filetype.pascal");
 	gchar *template_filename_filetype_php = templates_get_filename("template.filetype.php");
@@ -86,6 +87,7 @@
 	templates_create_file(template_filename_filetype_none, templates_filetype_none);
 	templates_create_file(template_filename_filetype_c, templates_filetype_c);
 	templates_create_file(template_filename_filetype_cpp, templates_filetype_cpp);
+	templates_create_file(template_filename_filetype_d, templates_filetype_d);
 	templates_create_file(template_filename_filetype_java, templates_filetype_java);
 	templates_create_file(template_filename_filetype_pascal, templates_filetype_pascal);
 	templates_create_file(template_filename_filetype_php, templates_filetype_php);
@@ -138,6 +140,9 @@
 	templates_read_file(template_filename_filetype_c, &templates[GEANY_TEMPLATE_FILETYPE_C]);
 	templates[GEANY_TEMPLATE_FILETYPE_C] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_C], year, date);
 
+	templates_read_file(template_filename_filetype_d, &templates[GEANY_TEMPLATE_FILETYPE_D]);
+	templates[GEANY_TEMPLATE_FILETYPE_D] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_D], year, date);
+
 	templates_read_file(template_filename_filetype_cpp, &templates[GEANY_TEMPLATE_FILETYPE_CPP]);
 	templates[GEANY_TEMPLATE_FILETYPE_CPP] = templates_replace_all(templates[GEANY_TEMPLATE_FILETYPE_CPP], year, date);
 
@@ -173,6 +178,7 @@
 	g_free(template_filename_filetype_none);
 	g_free(template_filename_filetype_c);
 	g_free(template_filename_filetype_cpp);
+	g_free(template_filename_filetype_d);
 	g_free(template_filename_filetype_java);
 	g_free(template_filename_filetype_php);
 	g_free(template_filename_filetype_pascal);

Modified: trunk/src/templates.h
===================================================================
--- trunk/src/templates.h	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/templates.h	2006-07-09 14:41:53 UTC (rev 544)
@@ -62,6 +62,7 @@
 	GEANY_TEMPLATE_FILETYPE_PHP,
 	GEANY_TEMPLATE_FILETYPE_PASCAL,
 	GEANY_TEMPLATE_FILETYPE_RUBY,
+	GEANY_TEMPLATE_FILETYPE_D,
 
 	GEANY_MAX_TEMPLATES
 };
@@ -207,6 +208,16 @@
 }\n\
 ";
 
+static const gchar templates_filetype_d[] = "\n\
+import std.stdio;\n\
+\n\
+int main(char[][] args)\n\
+{\n\
+\n\
+	return 0;\n\
+}\n\
+";
+
 static const gchar templates_filetype_php[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
   \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\

Modified: trunk/src/utils.c
===================================================================
--- trunk/src/utils.c	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/src/utils.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -2436,13 +2436,21 @@
 		case GEANY_FILETYPES_PASCAL:
 		{
 			// bandit.pas(149,3) Fatal: Syntax error, ";" expected but "ELSE" found
-			// still untested with other files than the opened
 			pattern = "(";
 			field_min_len = 2;
 			field_idx_line = 1;
 			field_idx_file = 0;
 			break;
 		}
+		case GEANY_FILETYPES_D:
+		{
+			// warning - pi.d(118): implicit conversion of expression (digit) of type int ...
+			pattern = " (";
+			field_min_len = 4;
+			field_idx_line = 3;
+			field_idx_file = 2;
+			break;
+		}
 		default: return;
 	}
 

Modified: trunk/tagmanager/Makefile.am
===================================================================
--- trunk/tagmanager/Makefile.am	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/tagmanager/Makefile.am	2006-07-09 14:41:53 UTC (rev 544)
@@ -27,6 +27,7 @@
 	args.c\
 	args.h\
 	c.c\
+	d.c\
 	conf.c\
 	css.c\
 	docbook.c\

Added: trunk/tagmanager/d.c
===================================================================
--- trunk/tagmanager/d.c	                        (rev 0)
+++ trunk/tagmanager/d.c	2006-07-09 14:41:53 UTC (rev 544)
@@ -0,0 +1,2303 @@
+/*
+*
+*   Copyright (c) 1996-2001, Darren Hiebert
+*   Copyright (c) 2006, Enrico Tröger
+*
+*   This source code is released for free distribution under the terms of the
+*   GNU General Public License.
+*
+*   This module contains functions for parsing and scanning D source files(based on c.c).
+*/
+
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"	/* must always come first */
+
+#include <string.h>
+#include <setjmp.h>
+//#include <glib.h>
+
+#include "entry.h"
+#include "get.h"
+#include "keyword.h"
+#include "main.h"
+#include "parse.h"
+#include "read.h"
+#include "options.h"
+
+/*
+*   MACROS
+*/
+#define MaxFields   6
+
+#define stringValue(a)		#a
+#define activeToken(st)		((st)->token [(int) (st)->tokenIndex])
+#define parentDecl(st)		((st)->parent == NULL ? \
+				DECL_NONE : (st)->parent->declaration)
+#define isType(token,t)		(boolean) ((token)->type == (t))
+#define insideEnumBody(st)	(boolean) ((st)->parent == NULL ? FALSE : \
+				    ((st)->parent->declaration == DECL_ENUM))
+#define isExternCDecl(st,c)	(boolean) ((c) == STRING_SYMBOL  && \
+		    ! (st)->haveQualifyingName  && (st)->scope == SCOPE_EXTERN)
+
+#define isOneOf(c,s)		(boolean) (strchr ((s), (c)) != NULL)
+
+/*
+*   DATA DECLARATIONS
+*/
+
+enum { NumTokens = 3 };
+
+typedef enum eException {
+    ExceptionNone, ExceptionEOF, ExceptionFormattingError,
+    ExceptionBraceFormattingError
+} exception_t;
+
+/*  Used to specify type of keyword.
+ */
+typedef enum eKeywordId {
+    KEYWORD_NONE,
+    KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
+    KEYWORD_BOOLEAN, KEYWORD_BYTE,
+    KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
+    KEYWORD_DOUBLE,
+    KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN, KEYWORD_EXTENDS,
+    KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FRIEND,
+    KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
+    KEYWORD_INTERFACE,
+    KEYWORD_LONG,
+    KEYWORD_MUTABLE,
+    KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NATIVE,
+    KEYWORD_OPERATOR, KEYWORD_OVERLOAD,
+    KEYWORD_PACKAGE, KEYWORD_PRIVATE, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
+    KEYWORD_REGISTER,
+    KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRUCT,
+    KEYWORD_SYNCHRONIZED,
+    KEYWORD_TEMPLATE, KEYWORD_THROW, KEYWORD_THROWS, KEYWORD_TRANSIENT,
+    KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
+    KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USING,
+    KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
+    KEYWORD_WCHAR_T
+} keywordId;
+
+/*  Used to determine whether keyword is valid for the current language and
+ *  what its ID is.
+ */
+typedef struct sKeywordDesc {
+    const char *name;
+    keywordId id;
+    short isValid [3]; /* indicates languages for which kw is valid */
+} keywordDesc;
+
+/*  Used for reporting the type of object parsed by nextToken ().
+ */
+typedef enum eTokenType {
+    TOKEN_NONE,		/* none */
+    TOKEN_ARGS,		/* a parenthetical pair and its contents */
+    TOKEN_BRACE_CLOSE,
+    TOKEN_BRACE_OPEN,
+    TOKEN_COMMA,		/* the comma character */
+    TOKEN_DOUBLE_COLON,	/* double colon indicates nested-name-specifier */
+    TOKEN_KEYWORD,
+    TOKEN_NAME,		/* an unknown name */
+    TOKEN_PACKAGE,	/* a Java package name */
+    TOKEN_PAREN_NAME,	/* a single name in parentheses */
+    TOKEN_SEMICOLON,	/* the semicolon character */
+    TOKEN_SPEC,		/* a storage class specifier, qualifier, type, etc. */
+    TOKEN_COUNT
+} tokenType;
+
+/*  This describes the scoping of the current statement.
+ */
+typedef enum eTagScope {
+    SCOPE_GLOBAL,		/* no storage class specified */
+    SCOPE_STATIC,		/* static storage class */
+    SCOPE_EXTERN,		/* external storage class */
+    SCOPE_FRIEND,		/* declares access only */
+    SCOPE_TYPEDEF,		/* scoping depends upon context */
+    SCOPE_COUNT
+} tagScope;
+
+typedef enum eDeclaration {
+    DECL_NONE,
+    DECL_BASE,			/* base type (default) */
+    DECL_CLASS,
+    DECL_ENUM,
+    DECL_FUNCTION,
+    DECL_IGNORE,		/* non-taggable "declaration" */
+    DECL_INTERFACE,
+    DECL_NAMESPACE,
+    DECL_NOMANGLE,		/* C++ name demangling block */
+    DECL_PACKAGE,
+    DECL_STRUCT,
+    DECL_UNION,
+    DECL_COUNT
+} declType;
+
+typedef enum eVisibilityType {
+    ACCESS_UNDEFINED,
+    ACCESS_PRIVATE,
+    ACCESS_PROTECTED,
+    ACCESS_PUBLIC,
+    ACCESS_COUNT
+} accessType;
+
+/*  Information about the parent class of a member (if any).
+ */
+typedef struct sMemberInfo {
+    accessType	access;		/* access of current statement */
+    accessType	accessDefault;	/* access default for current statement */
+} memberInfo;
+
+typedef struct sTokenInfo {
+    tokenType     type;
+    keywordId     keyword;
+    vString*      name;		/* the name of the token */
+    unsigned long lineNumber;	/* line number of tag */
+    fpos_t        filePosition;	/* file position of line containing name */
+} tokenInfo;
+
+
+typedef enum eImplementation {
+    IMP_DEFAULT,
+    IMP_ABSTRACT,
+    IMP_VIRTUAL,
+    IMP_PURE_VIRTUAL,
+    IMP_COUNT
+} impType;
+
+/*  Describes the statement currently undergoing analysis.
+ */
+typedef struct sStatementInfo {
+    tagScope	scope;
+    declType	declaration;	/* specifier associated with TOKEN_SPEC */
+    boolean	gotName;	/* was a name parsed yet? */
+    boolean	haveQualifyingName;  /* do we have a name we are considering? */
+    boolean	gotParenName;	/* was a name inside parentheses parsed yet? */
+    boolean	gotArgs;	/* was a list of parameters parsed yet? */
+    boolean	isPointer;	/* is 'name' a pointer? */
+    impType	implementation;	/* abstract or concrete implementation? */
+    unsigned int tokenIndex;	/* currently active token */
+    tokenInfo*	token [(int) NumTokens];
+    tokenInfo*	context;	/* accumulated scope of current statement */
+    tokenInfo*	blockName;	/* name of current block */
+    memberInfo	member;		/* information regarding parent class/struct */
+    vString*	parentClasses;	/* parent classes */
+    struct sStatementInfo *parent;  /* statement we are nested within */
+	long argEndPosition; /* Position where argument list ended */
+	tokenInfo* firstToken; /* First token in the statement */
+} statementInfo;
+
+/*  Describes the type of tag being generated.
+ */
+typedef enum eTagType {
+    TAG_UNDEFINED,
+    TAG_CLASS,			/* class name */
+    TAG_ENUM,			/* enumeration name */
+    TAG_ENUMERATOR,		/* enumerator (enumeration value) */
+    TAG_FIELD,			/* field (Java) */
+    TAG_FUNCTION,		/* function definition */
+    TAG_INTERFACE,		/* interface declaration */
+    TAG_MEMBER,			/* structure, class or interface member */
+    TAG_METHOD,			/* method declaration */
+    TAG_NAMESPACE,		/* namespace name */
+    TAG_PACKAGE,		/* package name */
+    TAG_PROTOTYPE,		/* function prototype or declaration */
+    TAG_STRUCT,			/* structure name */
+    TAG_TYPEDEF,		/* typedef name */
+    TAG_UNION,			/* union name */
+    TAG_VARIABLE,		/* variable definition */
+    TAG_EXTERN_VAR,		/* external variable declaration */
+	TAG_MACRO,			/* #define s */
+    TAG_COUNT			/* must be last */
+} tagType;
+
+typedef struct sParenInfo {
+    boolean isPointer;
+    boolean isParamList;
+    boolean isKnrParamList;
+    boolean isNameCandidate;
+    boolean invalidContents;
+    boolean nestedArgs;
+    unsigned int parameterCount;
+} parenInfo;
+
+/*
+*   DATA DEFINITIONS
+*/
+
+static jmp_buf Exception;
+
+static langType Lang_d;
+
+/* Used to index into the DKinds table. */
+typedef enum {
+    CK_UNDEFINED = -1,
+    CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
+    CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
+    CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
+    CK_EXTERN_VARIABLE
+} cKind;
+
+static kindOption DKinds [] = {
+    { TRUE,  'c', "class",      "classes"},
+    { TRUE,  'd', "macro",      "macro definitions"},
+    { TRUE,  'e', "enumerator", "enumerators (values inside an enumeration)"},
+    { TRUE,  'f', "function",   "function definitions"},
+    { TRUE,  'g', "enum",       "enumeration names"},
+    { TRUE,  'm', "member",     "class, struct, and union members"},
+    { TRUE,  'n', "namespace",  "namespaces"},
+    { FALSE, 'p', "prototype",  "function prototypes"},
+    { TRUE,  's', "struct",     "structure names"},
+    { TRUE,  't', "typedef",    "typedefs"},
+    { TRUE,  'u', "union",      "union names"},
+    { TRUE,  'v', "variable",   "variable definitions"},
+    { FALSE, 'x', "externvar",  "external variable declarations"},
+};
+
+static const keywordDesc KeywordTable [] = {
+    /* 						    C++		*/
+    /* 					     ANSI C  |  Java	*/
+    /* keyword		keyword ID		 \   |   /  	*/
+    { "__attribute__",	KEYWORD_ATTRIBUTE,	{ 1, 1, 0 } },
+    { "abstract",	KEYWORD_ABSTRACT,	{ 0, 0, 1 } },
+    { "boolean",	KEYWORD_BOOLEAN,	{ 0, 0, 1 } },
+    { "byte",		KEYWORD_BYTE,		{ 0, 0, 1 } },
+    { "catch",		KEYWORD_CATCH,		{ 0, 1, 0 } },
+    { "char",		KEYWORD_CHAR,		{ 1, 1, 1 } },
+    { "class",		KEYWORD_CLASS,		{ 0, 1, 1 } },
+    { "const",		KEYWORD_CONST,		{ 1, 1, 1 } },
+    { "double",		KEYWORD_DOUBLE,		{ 1, 1, 1 } },
+    { "enum",		KEYWORD_ENUM,		{ 1, 1, 0 } },
+    { "explicit",	KEYWORD_EXPLICIT,	{ 0, 1, 0 } },
+    { "extends",	KEYWORD_EXTENDS,	{ 0, 0, 1 } },
+    { "extern",		KEYWORD_EXTERN,		{ 1, 1, 0 } },
+    { "final",		KEYWORD_FINAL,		{ 0, 0, 1 } },
+    { "float",		KEYWORD_FLOAT,		{ 1, 1, 1 } },
+    { "friend",		KEYWORD_FRIEND,		{ 0, 1, 0 } },
+    { "implements",	KEYWORD_IMPLEMENTS,	{ 0, 0, 1 } },
+    { "import",		KEYWORD_IMPORT,		{ 0, 0, 1 } },
+    { "inline",		KEYWORD_INLINE,		{ 0, 1, 0 } },
+    { "int",		KEYWORD_INT,		{ 1, 1, 1 } },
+    { "interface",	KEYWORD_INTERFACE,	{ 0, 0, 1 } },
+    { "long",		KEYWORD_LONG,		{ 1, 1, 1 } },
+    { "mutable",	KEYWORD_MUTABLE,	{ 0, 1, 0 } },
+    { "namespace",	KEYWORD_NAMESPACE,	{ 0, 1, 0 } },
+    { "native",		KEYWORD_NATIVE,		{ 0, 0, 1 } },
+    { "new",		KEYWORD_NEW,		{ 0, 1, 1 } },
+    { "operator",	KEYWORD_OPERATOR,	{ 0, 1, 0 } },
+    { "overload",	KEYWORD_OVERLOAD,	{ 0, 1, 0 } },
+    { "package",	KEYWORD_PACKAGE,	{ 0, 0, 1 } },
+    { "private",	KEYWORD_PRIVATE,	{ 0, 1, 1 } },
+    { "protected",	KEYWORD_PROTECTED,	{ 0, 1, 1 } },
+    { "public",		KEYWORD_PUBLIC,		{ 0, 1, 1 } },
+    { "register",	KEYWORD_REGISTER,	{ 1, 1, 0 } },
+    { "short",		KEYWORD_SHORT,		{ 1, 1, 1 } },
+    { "signed",		KEYWORD_SIGNED,		{ 1, 1, 0 } },
+    { "static",		KEYWORD_STATIC,		{ 1, 1, 1 } },
+    { "struct",		KEYWORD_STRUCT,		{ 1, 1, 0 } },
+    { "synchronized",	KEYWORD_SYNCHRONIZED,	{ 0, 0, 1 } },
+    { "template",	KEYWORD_TEMPLATE,	{ 0, 1, 0 } },
+    { "throw",		KEYWORD_THROW,		{ 0, 1, 1 } },
+    { "throws",		KEYWORD_THROWS,		{ 0, 0, 1 } },
+    { "transient",	KEYWORD_TRANSIENT,	{ 0, 0, 1 } },
+    { "try",		KEYWORD_TRY,		{ 0, 1, 0 } },
+    { "typedef",	KEYWORD_TYPEDEF,	{ 1, 1, 0 } },
+    { "typename",	KEYWORD_TYPENAME,	{ 0, 1, 0 } },
+    { "union",		KEYWORD_UNION,		{ 1, 1, 0 } },
+    { "unsigned",	KEYWORD_UNSIGNED,	{ 1, 1, 0 } },
+    { "using",		KEYWORD_USING,		{ 0, 1, 0 } },
+    { "virtual",	KEYWORD_VIRTUAL,	{ 0, 1, 0 } },
+    { "void",		KEYWORD_VOID,		{ 1, 1, 1 } },
+    { "volatile",	KEYWORD_VOLATILE,	{ 1, 1, 1 } },
+    { "wchar_t",	KEYWORD_WCHAR_T,	{ 1, 1, 0 } }
+};
+
+/*
+*   FUNCTION PROTOTYPES
+*/
+static void createTags (const unsigned int nestLevel, statementInfo *const parent);
+
+/*
+*   FUNCTION DEFINITIONS
+*/
+
+/* Debugging functions added by Biswa */
+#if DEBUG_C
+static char *tokenTypeName[] = {
+    "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
+    "package", "paren-name", "';'",	"spec", "count"
+};
+
+static char *tagScopeNames[] = {
+	"global", "static", "extern", "friend", "typedef", "count"};
+
+static char *declTypeNames[] = {
+	"none", "base", "class", "enum", "function", "ignore", "interface",
+	"namespace", "nomangle", "package", "struct", "union", "count"};
+
+static char *impTypeNames[] = {
+	"default", "abstract", "virtual", "pure-virtual", "count"};
+
+void printToken(const tokenInfo *const token)
+{
+	fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
+	  token->keyword, vStringValue(token->name));
+}
+
+void printTagEntry(const tagEntryInfo *tag)
+{
+	fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
+	tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
+	tag->extensionFields.varType);
+}
+
+void printStatement(const statementInfo *const statement)
+{
+	int i;
+	statementInfo *st = (statementInfo *) statement;
+	while (NULL != st)
+	{
+		fprintf(stderr, "Statement Info:\n------------------------\n");
+		fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope]
+		, declTypeNames[st->declaration], impTypeNames[st->implementation]);
+		for (i=0; i < NumTokens; ++i)
+		{
+			fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
+			printToken(st->token[i]);
+		}
+		fprintf(stderr, "Context: ");
+		printToken(st->context);
+		fprintf(stderr, "Block: ");
+		printToken(st->blockName);
+		fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
+		fprintf(stderr, "First token: ");
+		printToken(st->firstToken);
+		if (NULL != st->parent)
+			fprintf(stderr, "Printing Parent:\n");
+		st = st->parent;
+	}
+	fprintf(stderr, "-----------------------------------------------\n");
+}
+#endif
+
+/* Checks if the token is a base data type (int/log/float/void/etc) */
+static boolean isBaseDataType(const char *name)
+{
+	return (boolean) ((0 == strcmp(name, "int")) || (0 == strcmp(name, "char")) ||
+	  (0 == strcmp(name, "long")) || (0 == strcmp(name, "float")) ||
+	  (0 == strcmp(name, "double")) || (0 == strcmp(name, "short")) ||
+	  (0 == strcmp(name, "void")) || (0 == strcmp(name, "bool")));
+}
+
+/*extern boolean includingDefineTags (void)
+{
+    return DKinds [CK_DEFINE].enabled;
+}
+*/
+/*
+*   Token management
+*/
+
+static void initToken (tokenInfo* const token)
+{
+    token->type		= TOKEN_NONE;
+    token->keyword	= KEYWORD_NONE;
+    token->lineNumber	= getSourceLineNumber ();
+    token->filePosition	= getInputFilePosition ();
+    vStringClear (token->name);
+}
+
+static void advanceToken (statementInfo* const st)
+{
+    if (st->tokenIndex >= (unsigned int) NumTokens - 1)
+	st->tokenIndex = 0;
+    else
+	++st->tokenIndex;
+    initToken (st->token [st->tokenIndex]);
+}
+
+static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
+{
+    unsigned int tokenIndex;
+    unsigned int num = (unsigned int) NumTokens;
+    Assert (n < num);
+    tokenIndex = (st->tokenIndex + num - n) % num;
+    return st->token [tokenIndex];
+}
+
+static void setToken (statementInfo *const st, const tokenType type)
+{
+    tokenInfo *token;
+    token = activeToken (st);
+    initToken (token);
+    token->type = type;
+}
+
+static void retardToken (statementInfo *const st)
+{
+    if (st->tokenIndex == 0)
+	st->tokenIndex = (unsigned int) NumTokens - 1;
+    else
+	--st->tokenIndex;
+    setToken (st, TOKEN_NONE);
+}
+
+static tokenInfo *newToken (void)
+{
+    tokenInfo *const token = xMalloc (1, tokenInfo);
+    token->name = vStringNew ();
+    initToken (token);
+    return token;
+}
+
+static void deleteToken (tokenInfo *const token)
+{
+    if (token != NULL)
+    {
+	vStringDelete (token->name);
+	eFree (token);
+    }
+}
+
+static const char *accessString (const accessType access)
+{
+    static const char *const names [] ={
+	"?", "private", "protected", "public", "default"
+    };
+    Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
+    Assert ((int) access < ACCESS_COUNT);
+    return names [(int) access];
+}
+
+static const char *implementationString (const impType imp)
+{
+    static const char *const names [] ={
+	"?", "abstract", "virtual", "pure virtual"
+    };
+    Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
+    Assert ((int) imp < IMP_COUNT);
+    return names [(int) imp];
+}
+
+/*
+*   Debugging functions
+*/
+
+#ifdef TM_DEBUG
+
+#define boolString(c)   ((c) ? "TRUE" : "FALSE")
+
+static const char *tokenString (const tokenType type)
+{
+    static const char *const names [] = {
+	"none", "args", "}", "{", "comma", "double colon", "keyword", "name",
+	"package", "paren-name", "semicolon", "specifier"
+    };
+    Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
+    Assert ((int) type < TOKEN_COUNT);
+    return names [(int) type];
+}
+
+static const char *scopeString (const tagScope scope)
+{
+    static const char *const names [] = {
+	"global", "static", "extern", "friend", "typedef"
+    };
+    Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
+    Assert ((int) scope < SCOPE_COUNT);
+    return names [(int) scope];
+}
+
+static const char *declString (const declType declaration)
+{
+    static const char *const names [] = {
+	"?", "base", "class", "enum", "function", "ignore", "interface",
+	"namespace", "no mangle", "package", "struct", "union",
+    };
+    Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
+    Assert ((int) declaration < DECL_COUNT);
+    return names [(int) declaration];
+}
+
+static const char *keywordString (const keywordId keyword)
+{
+    const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
+    const char *name = "none";
+    size_t i;
+    for (i = 0  ;  i < count  ;  ++i)
+    {
+	const keywordDesc *p = &KeywordTable [i];
+
+	if (p->id == keyword)
+	{
+	    name = p->name;
+	    break;
+	}
+    }
+    return name;
+}
+
+static void __unused__ pt (tokenInfo *const token)
+{
+    if (isType (token, TOKEN_NAME))
+	printf ("type: %-12s: %-13s   line: %lu\n",
+	       tokenString (token->type), vStringValue (token->name),
+	       token->lineNumber);
+    else if (isType (token, TOKEN_KEYWORD))
+	printf ("type: %-12s: %-13s   line: %lu\n",
+	       tokenString (token->type), keywordString (token->keyword),
+	       token->lineNumber);
+    else
+	printf ("type: %-12s                  line: %lu\n",
+	       tokenString (token->type), token->lineNumber);
+}
+
+static void __unused__ ps (statementInfo *const st)
+{
+    unsigned int i;
+    printf ("scope: %s   decl: %s   gotName: %s   gotParenName: %s\n",
+	   scopeString (st->scope), declString (st->declaration),
+	   boolString (st->gotName), boolString (st->gotParenName));
+    printf ("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
+    printf ("access: %s   default: %s\n", accessString (st->member.access),
+	   accessString (st->member.accessDefault));
+    printf ("token  : ");
+    pt (activeToken (st));
+    for (i = 1  ;  i < (unsigned int) NumTokens  ;  ++i)
+    {
+	printf ("prev %u : ", i);
+	pt (prevToken (st, i));
+    }
+    printf ("context: ");
+    pt (st->context);
+}
+
+#endif
+
+/*
+*   Statement management
+*/
+
+static boolean isContextualKeyword (const tokenInfo *const token)
+{
+    boolean result;
+    switch (token->keyword)
+    {
+	case KEYWORD_CLASS:
+	case KEYWORD_ENUM:
+	case KEYWORD_INTERFACE:
+	case KEYWORD_NAMESPACE:
+	case KEYWORD_STRUCT:
+	case KEYWORD_UNION:
+	    result = TRUE;
+	    break;
+
+	default: result = FALSE; break;
+    }
+    return result;
+}
+
+static boolean isContextualStatement (const statementInfo *const st)
+{
+    boolean result = FALSE;
+    if (st != NULL) switch (st->declaration)
+    {
+	case DECL_CLASS:
+	case DECL_ENUM:
+	case DECL_INTERFACE:
+	case DECL_NAMESPACE:
+	case DECL_STRUCT:
+	case DECL_UNION:
+	    result = TRUE;
+	    break;
+
+	default: result = FALSE; break;
+    }
+    return result;
+}
+
+static boolean isMember (const statementInfo *const st)
+{
+    boolean result;
+    if (isType (st->context, TOKEN_NAME))
+	result = TRUE;
+    else
+	result = isContextualStatement (st->parent);
+    return result;
+}
+
+static void initMemberInfo (statementInfo *const st)
+{
+    accessType accessDefault = ACCESS_UNDEFINED;
+
+    if (st->parent != NULL) switch (st->parent->declaration)
+    {
+	case DECL_ENUM:
+	case DECL_NAMESPACE:
+	case DECL_UNION:
+	    accessDefault = ACCESS_UNDEFINED;
+	    break;
+
+	case DECL_CLASS:
+		accessDefault = ACCESS_PRIVATE;
+	    break;
+
+	case DECL_INTERFACE:
+	case DECL_STRUCT:
+	    accessDefault = ACCESS_PUBLIC;
+	    break;
+
+	default: break;
+    }
+    st->member.accessDefault = accessDefault;
+    st->member.access	     = accessDefault;
+}
+
+static void reinitStatement (statementInfo *const st, const boolean partial)
+{
+    unsigned int i;
+
+    if (! partial)
+    {
+	st->scope = SCOPE_GLOBAL;
+	if (isContextualStatement (st->parent))
+	    st->declaration = DECL_BASE;
+	else
+	    st->declaration = DECL_NONE;
+    }
+    st->gotParenName	= FALSE;
+    st->isPointer	= FALSE;
+    st->implementation	= IMP_DEFAULT;
+    st->gotArgs		= FALSE;
+    st->gotName		= FALSE;
+    st->haveQualifyingName = FALSE;
+    st->tokenIndex	= 0;
+	st->argEndPosition = 0;
+
+    for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
+	initToken (st->token [i]);
+
+    initToken (st->context);
+    initToken (st->blockName);
+    vStringClear (st->parentClasses);
+
+    /*  Init member info.
+     */
+    if (! partial)
+	st->member.access = st->member.accessDefault;
+
+	/* Init first token */
+	if (!partial)
+	initToken(st->firstToken);
+}
+
+static void initStatement (statementInfo *const st, statementInfo *const parent)
+{
+    st->parent = parent;
+    initMemberInfo (st);
+    reinitStatement (st, FALSE);
+}
+
+/*
+*   Tag generation functions
+*/
+static cKind dTagKind (const tagType type)
+{
+    cKind result = CK_UNDEFINED;
+    switch (type)
+    {
+	case TAG_CLASS:      result = CK_CLASS;           break;
+	case TAG_ENUM:       result = CK_ENUMERATION;     break;
+	case TAG_ENUMERATOR: result = CK_ENUMERATOR;      break;
+	case TAG_FUNCTION:   result = CK_FUNCTION;        break;
+	case TAG_MEMBER:     result = CK_MEMBER;          break;
+	case TAG_NAMESPACE:  result = CK_NAMESPACE;       break;
+	case TAG_PROTOTYPE:  result = CK_PROTOTYPE;       break;
+	case TAG_STRUCT:     result = CK_STRUCT;          break;
+	case TAG_TYPEDEF:    result = CK_TYPEDEF;         break;
+	case TAG_UNION:      result = CK_UNION;           break;
+	case TAG_VARIABLE:   result = CK_VARIABLE;        break;
+	case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
+
+	default: Assert ("Bad C tag type" == NULL); break;
+    }
+    return result;
+}
+
+static const char *tagName (const tagType type)
+{
+    return DKinds [dTagKind (type)].name;
+}
+
+static int tagLetter (const tagType type)
+{
+    return DKinds [dTagKind (type)].letter;
+}
+
+/*
+static boolean includeTag (const tagType type, const boolean isFileScope)
+{
+    boolean result;
+    if (isFileScope  &&  ! Option.include.fileScope)
+	result = FALSE;
+    else if (isLanguage (Lang_java))
+	result = JavaKinds [javaTagKind (type)].enabled;
+    else
+	result = CKinds [cTagKind (type)].enabled;
+    return result;
+}
+*/
+
+static tagType declToTagType (const declType declaration)
+{
+    tagType type = TAG_UNDEFINED;
+
+    switch (declaration)
+    {
+	case DECL_CLASS:	type = TAG_CLASS;	break;
+	case DECL_ENUM:		type = TAG_ENUM;	break;
+	case DECL_FUNCTION:	type = TAG_FUNCTION;	break;
+	case DECL_INTERFACE:	type = TAG_INTERFACE;	break;
+	case DECL_NAMESPACE:	type = TAG_NAMESPACE;	break;
+	case DECL_STRUCT:	type = TAG_STRUCT;	break;
+	case DECL_UNION:	type = TAG_UNION;	break;
+
+	default: Assert ("Unexpected declaration" == NULL); break;
+    }
+    return type;
+}
+
+static const char* accessField (const statementInfo *const st)
+{
+    const char* result = NULL;
+    if (st->scope == SCOPE_FRIEND)
+	result = "friend";
+    else if (st->member.access != ACCESS_UNDEFINED)
+	result = accessString (st->member.access);
+    return result;
+}
+
+static void addOtherFields (tagEntryInfo* const tag, const tagType type,
+			    const statementInfo *const st, vString *const scope)
+{
+    /*  For selected tag types, append an extension flag designating the
+     *  parent object in which the tag is defined.
+     */
+    switch (type)
+    {
+	default: break;
+
+	case TAG_CLASS:
+	case TAG_ENUM:
+	case TAG_ENUMERATOR:
+	case TAG_FIELD:
+	case TAG_FUNCTION:
+	case TAG_INTERFACE:
+	case TAG_MEMBER:
+	case TAG_METHOD:
+	case TAG_PROTOTYPE:
+	case TAG_STRUCT:
+	case TAG_TYPEDEF:
+	case TAG_UNION:
+	    if (isMember (st) &&
+		! (type == TAG_ENUMERATOR  &&  vStringLength (scope) == 0))
+	    {
+		if (isType (st->context, TOKEN_NAME))
+		    tag->extensionFields.scope [0] = tagName (TAG_CLASS);
+		else
+		    tag->extensionFields.scope [0] =
+			tagName (declToTagType (parentDecl (st)));
+		tag->extensionFields.scope [1] = vStringValue (scope);
+	    }
+	    if ((type == TAG_CLASS  ||  type == TAG_INTERFACE  ||
+		 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
+	    {
+
+		tag->extensionFields.inheritance =
+			vStringValue (st->parentClasses);
+	    }
+		tag->extensionFields.implementation =
+			implementationString (st->implementation);
+	    if (isMember (st))
+	    {
+		tag->extensionFields.access = accessField (st);
+	    }
+	    break;
+    }
+
+	if ((TAG_FIELD == tag->type) || (TAG_MEMBER == tag->type) ||
+		(TAG_EXTERN_VAR == tag->type) || (TAG_TYPEDEF == tag->type) ||
+		(TAG_VARIABLE == tag->type) || (TAG_METHOD == tag->type) ||
+		(TAG_PROTOTYPE == tag->type) || (TAG_FUNCTION == tag->type))
+	{
+		if (((TOKEN_NAME == st->firstToken->type) || ((TOKEN_KEYWORD == st->firstToken->type)
+			  && isBaseDataType(st->firstToken->name->buffer)))
+			  && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
+				tag->extensionFields.varType = vStringValue(st->firstToken->name);
+	}
+}
+
+static void addContextSeparator (vString *const scope)
+{
+	vStringCatS (scope, "::");
+}
+
+static void findScopeHierarchy (vString *const string,
+				const statementInfo *const st)
+{
+    const char* const anon = "<anonymous>";
+    boolean nonAnonPresent = FALSE;
+
+    vStringClear (string);
+    if (isType (st->context, TOKEN_NAME))
+    {
+	vStringCopy (string, st->context->name);
+	nonAnonPresent = TRUE;
+    }
+    if (st->parent != NULL)
+    {
+	vString *temp = vStringNew ();
+	const statementInfo *s;
+
+	for (s = st->parent  ;  s != NULL  ;  s = s->parent)
+	{
+	    if (isContextualStatement (s))
+	    {
+		vStringCopy (temp, string);
+		vStringClear (string);
+		if (isType (s->blockName, TOKEN_NAME))
+		{
+		    if (isType (s->context, TOKEN_NAME) &&
+			vStringLength (s->context->name) > 0)
+		    {
+			vStringCat (string, s->context->name);
+			addContextSeparator (string);
+		    }
+		    vStringCat (string, s->blockName->name);
+		    nonAnonPresent = TRUE;
+		}
+		else
+		    vStringCopyS (string, anon);
+		if (vStringLength (temp) > 0)
+		    addContextSeparator (string);
+		vStringCat (string, temp);
+	    }
+	}
+	vStringDelete (temp);
+
+	if (! nonAnonPresent)
+	    vStringClear (string);
+    }
+}
+
+static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
+			       vString *const scope)
+{
+    if (0  &&
+	scope != NULL  &&  vStringLength (scope) > 0)
+    {
+	vString *const scopedName = vStringNew ();
+
+	if (type != TAG_ENUMERATOR)
+	    vStringCopy (scopedName, scope);
+	else
+	{
+	    /* remove last component (i.e. enumeration name) from scope */
+	    const char* const sc = vStringValue (scope);
+	    const char* colon = strrchr (sc, ':');
+	    if (colon != NULL)
+	    {
+		while (*colon == ':'  &&  colon > sc)
+		    --colon;
+		vStringNCopy (scopedName, scope, colon + 1 - sc);
+	    }
+	}
+	if (vStringLength (scopedName) > 0)
+	{
+	    addContextSeparator (scopedName);
+	    vStringCatS (scopedName, e->name);
+	    e->name = vStringValue (scopedName);
+	    makeTagEntry (e);
+	}
+	vStringDelete (scopedName);
+    }
+}
+
+static void makeTag (const tokenInfo *const token,
+		     const statementInfo *const st,
+		     boolean isFileScope, const tagType type)
+{
+#ifdef DEBUG_C
+	printToken(token);
+	fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
+	printStatement(st);
+#endif
+    /*  Nothing is really of file scope when it appears in a header file.
+     */
+    isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
+
+    if (isType (token, TOKEN_NAME)  &&  vStringLength (token->name) > 0  /* &&
+	includeTag (type, isFileScope) */)
+    {
+	vString *scope = vStringNew ();
+	tagEntryInfo e;
+
+	initTagEntry (&e, vStringValue (token->name));
+
+	e.lineNumber	= token->lineNumber;
+	e.filePosition	= token->filePosition;
+	e.isFileScope	= isFileScope;
+	e.kindName	= tagName (type);
+	e.kind		= tagLetter (type);
+	e.type = type;
+
+	findScopeHierarchy (scope, st);
+	addOtherFields (&e, type, st, scope);
+
+#ifdef DEBUG_C
+	printTagEntry(&e);
+#endif
+	makeTagEntry (&e);
+	if (NULL != TagEntryFunction)
+		makeExtraTagEntry (type, &e, scope);
+	vStringDelete (scope);
+	if (NULL != e.extensionFields.arglist)
+		free((char *) e.extensionFields.arglist);
+    }
+}
+
+static boolean isValidTypeSpecifier (const declType declaration)
+{
+    boolean result;
+    switch (declaration)
+    {
+	case DECL_BASE:
+	case DECL_CLASS:
+	case DECL_ENUM:
+	case DECL_STRUCT:
+	case DECL_UNION:
+	    result = TRUE;
+	    break;
+
+	default:
+	    result = FALSE;
+	    break;
+    }
+    return result;
+}
+
+static void qualifyEnumeratorTag (const statementInfo *const st,
+				  const tokenInfo *const nameToken)
+{
+    if (isType (nameToken, TOKEN_NAME))
+	makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
+}
+
+static void qualifyFunctionTag (const statementInfo *const st,
+				const tokenInfo *const nameToken)
+{
+    if (isType (nameToken, TOKEN_NAME))
+    {
+	const tagType type = TAG_FUNCTION;
+	const boolean isFileScope =
+			(boolean) (st->member.access == ACCESS_PRIVATE ||
+			(!isMember (st)  &&  st->scope == SCOPE_STATIC));
+
+	makeTag (nameToken, st, isFileScope, type);
+    }
+}
+
+static void qualifyFunctionDeclTag (const statementInfo *const st,
+				    const tokenInfo *const nameToken)
+{
+    if (! isType (nameToken, TOKEN_NAME))
+	;
+    else if (st->scope == SCOPE_TYPEDEF)
+	makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
+    else if (isValidTypeSpecifier (st->declaration))
+	makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
+}
+
+static void qualifyCompoundTag (const statementInfo *const st,
+				const tokenInfo *const nameToken)
+{
+    if (isType (nameToken, TOKEN_NAME))
+    {
+	const tagType type = declToTagType (st->declaration);
+
+	if (type != TAG_UNDEFINED)
+	    makeTag (nameToken, st, TRUE, type);
+    }
+}
+
+static void qualifyBlockTag (statementInfo *const st,
+			     const tokenInfo *const nameToken)
+{
+    switch (st->declaration)
+    {
+	case DECL_CLASS:
+	case DECL_ENUM:
+	case DECL_INTERFACE:
+	case DECL_NAMESPACE:
+	case DECL_STRUCT:
+	case DECL_UNION:
+	    qualifyCompoundTag (st, nameToken);
+	    break;
+	default: break;
+    }
+}
+
+static void qualifyVariableTag (const statementInfo *const st,
+				const tokenInfo *const nameToken)
+{
+    /*	We have to watch that we do not interpret a declaration of the
+     *	form "struct tag;" as a variable definition. In such a case, the
+     *	token preceding the name will be a keyword.
+     */
+    if (! isType (nameToken, TOKEN_NAME))
+	;
+    else if (st->declaration == DECL_IGNORE)
+	;
+    else if (st->scope == SCOPE_TYPEDEF)
+	makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
+    else if (st->declaration == DECL_PACKAGE)
+	makeTag (nameToken, st, FALSE, TAG_PACKAGE);
+    else if (isValidTypeSpecifier (st->declaration))
+    {
+	if (isMember (st))
+	{
+	    if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_STATIC)
+		makeTag (nameToken, st, TRUE, TAG_MEMBER);
+	}
+	else
+	{
+	    if (st->scope == SCOPE_EXTERN  ||  ! st->haveQualifyingName)
+		makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
+	    else
+		makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
+			TAG_VARIABLE);
+	}
+    }
+}
+
+/*
+*   Parsing functions
+*/
+
+/*  Skip to the next non-white character.
+ */
+static int skipToNonWhite (void)
+{
+    int c;
+
+    do
+	c = cppGetc ();
+    while (isspace (c));
+
+    return c;
+}
+
+/*  Skips to the next brace in column 1. This is intended for cases where
+ *  preprocessor constructs result in unbalanced braces.
+ */
+static void skipToFormattedBraceMatch (void)
+{
+    int c, next;
+
+    c = cppGetc ();
+    next = cppGetc ();
+    while (c != EOF  &&  (c != '\n'  ||  next != '}'))
+    {
+	c = next;
+	next = cppGetc ();
+    }
+}
+
+/*  Skip to the matching character indicated by the pair string. If skipping
+ *  to a matching brace and any brace is found within a different level of a
+ *  #if conditional statement while brace formatting is in effect, we skip to
+ *  the brace matched by its formatting. It is assumed that we have already
+ *  read the character which starts the group (i.e. the first character of
+ *  "pair").
+ */
+static void skipToMatch (const char *const pair)
+{
+    const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
+    const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
+    const unsigned int initialLevel = getDirectiveNestLevel ();
+    const int begin = pair [0], end = pair [1];
+    const unsigned long inputLineNumber = getInputLineNumber ();
+    int matchLevel = 1;
+    int c = '\0';
+    while (matchLevel > 0  &&  (c = cppGetc ()) != EOF)
+    {
+	if (c == begin)
+	{
+	    ++matchLevel;
+	    if (braceFormatting  &&  getDirectiveNestLevel () != initialLevel)
+	    {
+		skipToFormattedBraceMatch ();
+		break;
+	    }
+	}
+	else if (c == end)
+	{
+	    --matchLevel;
+	    if (braceFormatting  &&  getDirectiveNestLevel () != initialLevel)
+	    {
+		skipToFormattedBraceMatch ();
+		break;
+	    }
+	}
+    }
+    if (c == EOF)
+    {
+		verbose ("%s: failed to find match for '%c' at line %lu\n",	getInputFileName (), begin, inputLineNumber);
+	if (braceMatching)
+	    longjmp (Exception, (int) ExceptionBraceFormattingError);
+	else
+	    longjmp (Exception, (int) ExceptionFormattingError);
+    }
+}
+
+static void skipParens (void)
+{
+    const int c = skipToNonWhite ();
+
+    if (c == '(')
+	skipToMatch ("()");
+    else
+	cppUngetc (c);
+}
+
+static void skipBraces (void)
+{
+    const int c = skipToNonWhite ();
+
+    if (c == '{')
+	skipToMatch ("{}");
+    else
+	cppUngetc (c);
+}
+
+static keywordId analyzeKeyword (const char *const name)
+{
+    const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
+    return id;
+}
+
+static void analyzeIdentifier (tokenInfo *const token)
+{
+    char *const name = vStringValue (token->name);
+    const char *replacement = NULL;
+    boolean parensToo = FALSE;
+
+    if (! isIgnoreToken (name, &parensToo, &replacement))
+    {
+	if (replacement != NULL)
+	    token->keyword = analyzeKeyword (replacement);
+	else
+	    token->keyword = analyzeKeyword (vStringValue (token->name));
+
+	if (token->keyword == KEYWORD_NONE)
+	    token->type = TOKEN_NAME;
+	else
+	    token->type = TOKEN_KEYWORD;
+    }
+    else
+    {
+	initToken (token);
+	if (parensToo)
+	{
+	    int c = skipToNonWhite ();
+
+	    if (c == '(')
+		skipToMatch ("()");
+	}
+    }
+}
+
+static void readIdentifier (tokenInfo *const token, const int firstChar)
+{
+    vString *const name = token->name;
+    int c = firstChar;
+
+    initToken (token);
+
+    do
+    {
+	vStringPut (name, c);
+	c = cppGetc ();
+    } while (isident (c));
+    vStringTerminate (name);
+    cppUngetc (c);		/* unget non-identifier character */
+
+    analyzeIdentifier (token);
+}
+
+static void readPackageName (tokenInfo *const token, const int firstChar)
+{
+    vString *const name = token->name;
+    int c = firstChar;
+
+    initToken (token);
+
+    while (isident (c)  ||  c == '.')
+    {
+	vStringPut (name, c);
+	c = cppGetc ();
+    }
+    vStringTerminate (name);
+    cppUngetc (c);		/* unget non-package character */
+}
+
+static void readPackage (statementInfo *const st)
+{
+    tokenInfo *const token = activeToken (st);
+    Assert (isType (token, TOKEN_KEYWORD));
+    readPackageName (token, skipToNonWhite ());
+    token->type = TOKEN_NAME;
+    st->declaration = DECL_PACKAGE;
+    st->gotName = TRUE;
+    st->haveQualifyingName = TRUE;
+}
+
+static void processName (statementInfo *const st)
+{
+    Assert (isType (activeToken (st), TOKEN_NAME));
+    if (st->gotName  &&  st->declaration == DECL_NONE)
+	st->declaration = DECL_BASE;
+    st->gotName = TRUE;
+    st->haveQualifyingName = TRUE;
+}
+
+static void readOperator (statementInfo *const st)
+{
+    const char *const acceptable = "+-*/%^&|~!=<>,[]";
+    const tokenInfo* const prev = prevToken (st,1);
+    tokenInfo *const token = activeToken (st);
+    vString *const name = token->name;
+    int c = skipToNonWhite ();
+
+    /*  When we arrive here, we have the keyword "operator" in 'name'.
+     */
+    if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
+	 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
+	;	/* ignore "operator" keyword if preceded by these keywords */
+    else if (c == '(')
+    {
+	/*  Verify whether this is a valid function call (i.e. "()") operator.
+	 */
+	if (cppGetc () == ')')
+	{
+	    vStringPut (name, ' ');  /* always separate operator from keyword */
+	    c = skipToNonWhite ();
+	    if (c == '(')
+		vStringCatS (name, "()");
+	}
+	else
+	{
+	    skipToMatch ("()");
+	    c = cppGetc ();
+	}
+    }
+    else if (isident1 (c))
+    {
+	/*  Handle "new" and "delete" operators, and conversion functions
+	 *  (per 13.3.1.1.2 [2] of the C++ spec).
+	 */
+	boolean whiteSpace = TRUE;	/* default causes insertion of space */
+	do
+	{
+	    if (isspace (c))
+		whiteSpace = TRUE;
+	    else
+	    {
+		if (whiteSpace)
+		{
+		    vStringPut (name, ' ');
+		    whiteSpace = FALSE;
+		}
+		vStringPut (name, c);
+	    }
+	    c = cppGetc ();
+	} while (! isOneOf (c, "(;")  &&  c != EOF);
+	vStringTerminate (name);
+    }
+    else if (isOneOf (c, acceptable))
+    {
+	vStringPut (name, ' ');	/* always separate operator from keyword */
+	do
+	{
+	    vStringPut (name, c);
+	    c = cppGetc ();
+	} while (isOneOf (c, acceptable));
+	vStringTerminate (name);
+    }
+
+    cppUngetc (c);
+
+    token->type	= TOKEN_NAME;
+    token->keyword = KEYWORD_NONE;
+    processName (st);
+}
+
+static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
+{
+    dest->type         = src->type;
+    dest->keyword      = src->keyword;
+    dest->filePosition = src->filePosition;
+    dest->lineNumber   = src->lineNumber;
+    vStringCopy (dest->name, src->name);
+}
+
+static void setAccess (statementInfo *const st, const accessType access)
+{
+    if (isMember (st))
+    {
+    int c = skipToNonWhite ();
+
+    if (c == ':')
+	reinitStatement (st, FALSE);
+    else
+	cppUngetc (c);
+
+    st->member.accessDefault = access;
+	st->member.access = access;
+    }
+}
+
+static void discardTypeList (tokenInfo *const token)
+{
+    int c = skipToNonWhite ();
+    while (isident1 (c))
+    {
+	readIdentifier (token, c);
+	c = skipToNonWhite ();
+	if (c == '.'  ||  c == ',')
+	    c = skipToNonWhite ();
+    }
+    cppUngetc (c);
+}
+
+static void addParentClass (statementInfo *const st, tokenInfo *const token)
+{
+    if (vStringLength (token->name) > 0  &&
+	vStringLength (st->parentClasses) > 0)
+    {
+	vStringPut (st->parentClasses, ',');
+    }
+    vStringCat (st->parentClasses, token->name);
+}
+
+static void readParents (statementInfo *const st, const int qualifier)
+{
+    tokenInfo *const token = newToken ();
+    tokenInfo *const parent = newToken ();
+    int c;
+
+    do
+    {
+	c = skipToNonWhite ();
+	if (isident1 (c))
+	{
+	    readIdentifier (token, c);
+	    if (isType (token, TOKEN_NAME))
+		vStringCat (parent->name, token->name);
+	    else
+	    {
+		addParentClass (st, parent);
+		initToken (parent);
+	    }
+	}
+	else if (c == qualifier)
+	    vStringPut (parent->name, c);
+	else if (c == '<')
+	    skipToMatch ("<>");
+	else if (isType (token, TOKEN_NAME))
+	{
+	    addParentClass (st, parent);
+	    initToken (parent);
+	}
+    } while (c != '{'  &&  c != EOF);
+    cppUngetc (c);
+    deleteToken (parent);
+    deleteToken (token);
+}
+
+static void processToken (tokenInfo *const token, statementInfo *const st)
+{
+    switch (token->keyword)		/* is it a reserved word? */
+    {
+	default: break;
+
+	case KEYWORD_NONE:	processName (st); break;
+	case KEYWORD_ABSTRACT:	st->implementation = IMP_ABSTRACT;	break;
+	case KEYWORD_ATTRIBUTE:	skipParens (); initToken (token);	break;
+	case KEYWORD_CATCH:	skipParens (); skipBraces ();		break;
+	case KEYWORD_CHAR:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_CLASS:	st->declaration = DECL_CLASS;		break;
+	case KEYWORD_CONST:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_DOUBLE:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_ENUM:	st->declaration = DECL_ENUM;		break;
+	case KEYWORD_EXTENDS:	readParents (st, '.');
+				setToken (st, TOKEN_NONE);		break;
+	case KEYWORD_FLOAT:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_FRIEND:	st->scope	= SCOPE_FRIEND;		break;
+	case KEYWORD_IMPLEMENTS:readParents (st, '.');
+				setToken (st, TOKEN_NONE);		break;
+	case KEYWORD_IMPORT:	st->declaration = DECL_IGNORE;		break;
+	case KEYWORD_INT:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE;	break;
+	case KEYWORD_LONG:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_NAMESPACE: st->declaration = DECL_NAMESPACE;	break;
+	case KEYWORD_OPERATOR:	readOperator (st);			break;
+	case KEYWORD_PACKAGE:	readPackage (st);			break;
+	case KEYWORD_PRIVATE:	setAccess (st, ACCESS_PRIVATE);		break;
+	case KEYWORD_PROTECTED:	setAccess (st, ACCESS_PROTECTED);	break;
+	case KEYWORD_PUBLIC:	setAccess (st, ACCESS_PUBLIC);		break;
+	case KEYWORD_SHORT:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_SIGNED:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_STRUCT:	st->declaration = DECL_STRUCT;		break;
+	case KEYWORD_THROWS:	discardTypeList (token);		break;
+	case KEYWORD_TYPEDEF:	st->scope	= SCOPE_TYPEDEF;	break;
+	case KEYWORD_UNION:	st->declaration = DECL_UNION;		break;
+	case KEYWORD_UNSIGNED:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_USING:	st->declaration = DECL_IGNORE;		break;
+	case KEYWORD_VOID:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_VOLATILE:	st->declaration = DECL_BASE;		break;
+	case KEYWORD_VIRTUAL:	st->implementation = IMP_VIRTUAL;	break;
+
+	case KEYWORD_EXTERN:
+	    st->scope = SCOPE_EXTERN;
+	    st->declaration = DECL_BASE;
+	    break;
+
+	case KEYWORD_STATIC:
+		st->scope = SCOPE_STATIC;
+	    st->declaration = DECL_BASE;
+	    break;
+    }
+}
+
+/*
+*   Parenthesis handling functions
+*/
+
+static void restartStatement (statementInfo *const st)
+{
+    tokenInfo *const save = newToken ();
+    tokenInfo *token = activeToken (st);
+
+    copyToken (save, token);
+    reinitStatement (st, FALSE);
+    token = activeToken (st);
+    copyToken (token, save);
+    deleteToken (save);
+    processToken (token, st);
+}
+
+/*  Skips over a the mem-initializer-list of a ctor-initializer, defined as:
+ *
+ *  mem-initializer-list:
+ *    mem-initializer, mem-initializer-list
+ *
+ *  mem-initializer:
+ *    [::] [nested-name-spec] class-name (...)
+ *    identifier
+ */
+static void skipMemIntializerList (tokenInfo *const token)
+{
+    int c;
+
+    do
+    {
+	c = skipToNonWhite ();
+	while (isident1 (c)  ||  c == ':')
+	{
+	    if (c != ':')
+		readIdentifier (token, c);
+	    c = skipToNonWhite ();
+	}
+	if (c == '<')
+	{
+	    skipToMatch ("<>");
+	    c = skipToNonWhite ();
+	}
+	if (c == '(')
+	{
+	    skipToMatch ("()");
+	    c = skipToNonWhite ();
+	}
+    } while (c == ',');
+    cppUngetc (c);
+}
+
+static void skipMacro (statementInfo *const st)
+{
+    tokenInfo *const prev2 = prevToken (st, 2);
+
+    if (isType (prev2, TOKEN_NAME))
+	retardToken (st);
+    skipToMatch ("()");
+}
+
+/*  Skips over characters following the parameter list. This will be either
+ *  non-ANSI style function declarations or C++ stuff. Our choices:
+ *
+ *  C (K&R):
+ *    int func ();
+ *    int func (one, two) int one; float two; {...}
+ *  C (ANSI):
+ *    int func (int one, float two);
+ *    int func (int one, float two) {...}
+ *  C++:
+ *    int foo (...) [const|volatile] [throw (...)];
+ *    int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
+ *    int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
+ *        catch (...) {...}
+ */
+static boolean skipPostArgumentStuff (statementInfo *const st,
+				      parenInfo *const info)
+{
+    tokenInfo *const token = activeToken (st);
+    unsigned int parameters = info->parameterCount;
+    unsigned int elementCount = 0;
+    boolean restart = FALSE;
+    boolean end = FALSE;
+    int c = skipToNonWhite ();
+
+    do
+    {
+	switch (c)
+	{
+	case ')':				break;
+	case ':': skipMemIntializerList (token);break;	/* ctor-initializer */
+	case '[': skipToMatch ("[]");		break;
+	case '=': cppUngetc (c); end = TRUE;	break;
+	case '{': cppUngetc (c); end = TRUE;	break;
+	case '}': cppUngetc (c); end = TRUE;	break;
+
+	case '(':
+	    if (elementCount > 0)
+		++elementCount;
+	    skipToMatch ("()");
+	    break;
+
+	case ';':
+	    if (parameters == 0  ||  elementCount < 2)
+	    {
+		cppUngetc (c);
+		end = TRUE;
+	    }
+	    else if (--parameters == 0)
+		end = TRUE;
+	    break;
+
+	default:
+	    if (isident1 (c))
+	    {
+		readIdentifier (token, c);
+		switch (token->keyword)
+		{
+		case KEYWORD_ATTRIBUTE:	skipParens ();	break;
+		case KEYWORD_THROW:	skipParens ();	break;
+		case KEYWORD_CONST:			break;
+		case KEYWORD_TRY:			break;
+		case KEYWORD_VOLATILE:		break;
+		case KEYWORD_WCHAR_T:		st->declaration = DECL_BASE; break;
+
+		case KEYWORD_CATCH:	case KEYWORD_CLASS:
+		case KEYWORD_EXPLICIT:	case KEYWORD_EXTERN:
+		case KEYWORD_FRIEND:	case KEYWORD_INLINE:
+		case KEYWORD_MUTABLE:	case KEYWORD_NAMESPACE:
+		case KEYWORD_NEW:	case KEYWORD_OPERATOR:
+		case KEYWORD_OVERLOAD:	case KEYWORD_PRIVATE:
+		case KEYWORD_PROTECTED:	case KEYWORD_PUBLIC:
+		case KEYWORD_STATIC:	case KEYWORD_TEMPLATE:
+		case KEYWORD_TYPEDEF:	case KEYWORD_TYPENAME:
+		case KEYWORD_USING:	case KEYWORD_VIRTUAL:
+		    /*  Never allowed within parameter declarations.
+		     */
+		    restart = TRUE;
+		    end = TRUE;
+		    break;
+
+		default:
+		    if (isType (token, TOKEN_NONE))
+			;
+		    else if (info->isKnrParamList  &&  info->parameterCount > 0)
+			++elementCount;
+		    else
+		    {
+			/*  If we encounter any other identifier immediately
+			 *  following an empty parameter list, this is almost
+			 *  certainly one of those Microsoft macro "thingies"
+			 *  that the automatic source code generation sticks
+			 *  in. Terminate the current statement.
+			 */
+			restart = TRUE;
+			end = TRUE;
+		    }
+		    break;
+		}
+	    }
+	}
+	if (! end)
+	{
+	    c = skipToNonWhite ();
+	    if (c == EOF)
+		end = TRUE;
+	}
+    } while (! end);
+
+    if (restart)
+	restartStatement (st);
+    else
+	setToken (st, TOKEN_NONE);
+    return (boolean) (c != EOF);
+}
+
+static void analyzePostParens (statementInfo *const st, parenInfo *const info)
+{
+    const unsigned long inputLineNumber = getInputLineNumber ();
+    int c = skipToNonWhite ();
+
+    cppUngetc (c);
+    if (isOneOf (c, "{;,="))
+	;
+    else
+    {
+	if (! skipPostArgumentStuff (st, info))
+	{
+	    verbose (
+		"%s: confusing argument declarations beginning at line %lu\n",
+		getInputFileName (), inputLineNumber);
+	    longjmp (Exception, (int) ExceptionFormattingError);
+	}
+    }
+}
+
+static int parseParens (statementInfo *const st, parenInfo *const info)
+{
+    tokenInfo *const token = activeToken (st);
+    unsigned int identifierCount = 0;
+    unsigned int depth = 1;
+    boolean firstChar = TRUE;
+    int nextChar = '\0';
+
+    info->parameterCount = 1;
+    do
+    {
+	int c = skipToNonWhite ();
+	switch (c)
+	{
+	    case '&':
+	    case '*':
+		info->isPointer = TRUE;
+		info->isKnrParamList = FALSE;
+		if (identifierCount == 0)
+		    info->isParamList = FALSE;
+		initToken (token);
+		break;
+
+	    case ':':
+		info->isKnrParamList = FALSE;
+		break;
+
+	    case '.':
+		info->isNameCandidate = FALSE;
+		info->isKnrParamList = FALSE;
+		break;
+
+	    case ',':
+		info->isNameCandidate = FALSE;
+		if (info->isKnrParamList)
+		{
+		    ++info->parameterCount;
+		    identifierCount = 0;
+		}
+		break;
+
+	    case '=':
+		info->isKnrParamList = FALSE;
+		info->isNameCandidate = FALSE;
+		if (firstChar)
+		{
+		    info->isParamList = FALSE;
+		    skipMacro (st);
+		    depth = 0;
+		}
+		break;
+
+	    case '[':
+		info->isKnrParamList = FALSE;
+		skipToMatch ("[]");
+		break;
+
+	    case '<':
+		info->isKnrParamList = FALSE;
+		skipToMatch ("<>");
+		break;
+
+	    case ')':
+		if (firstChar)
+		    info->parameterCount = 0;
+		--depth;
+		break;
+
+	    case '(':
+		info->isKnrParamList = FALSE;
+		if (firstChar)
+		{
+		    info->isNameCandidate = FALSE;
+		    cppUngetc (c);
+		    skipMacro (st);
+		    depth = 0;
+		}
+		else if (isType (token, TOKEN_PAREN_NAME))
+		{
+		    c = skipToNonWhite ();
+		    if (c == '*')	/* check for function pointer */
+		    {
+			skipToMatch ("()");
+			c = skipToNonWhite ();
+			if (c == '(')
+			    skipToMatch ("()");
+		    }
+		    else
+		    {
+			cppUngetc (c);
+			cppUngetc ('(');
+			info->nestedArgs = TRUE;
+		    }
+		}
+		else
+		    ++depth;
+		break;
+
+	    default:
+		if (isident1 (c))
+		{
+		    if (++identifierCount > 1)
+			info->isKnrParamList = FALSE;
+		    readIdentifier (token, c);
+		    if (isType (token, TOKEN_NAME)  &&  info->isNameCandidate)
+			token->type = TOKEN_PAREN_NAME;
+		    else if (isType (token, TOKEN_KEYWORD))
+		    {
+			info->isKnrParamList = FALSE;
+			info->isNameCandidate = FALSE;
+		    }
+		}
+		else
+		{
+		    info->isParamList     = FALSE;
+		    info->isKnrParamList  = FALSE;
+		    info->isNameCandidate = FALSE;
+		    info->invalidContents = TRUE;
+		}
+		break;
+	}
+	firstChar = FALSE;
+    } while (! info->nestedArgs  &&  depth > 0  &&
+	     (info->isKnrParamList  ||  info->isNameCandidate));
+
+    if (! info->nestedArgs) while (depth > 0)
+    {
+	skipToMatch ("()");
+	--depth;
+    }
+	if (st->argEndPosition == 0)
+		st->argEndPosition = ftell(File.fp);
+
+    if (! info->isNameCandidate)
+	initToken (token);
+
+    return nextChar;
+}
+
+static void initParenInfo (parenInfo *const info)
+{
+    info->isPointer		= FALSE;
+    info->isParamList		= TRUE;
+    info->isKnrParamList	= TRUE;
+    info->isNameCandidate	= TRUE;
+    info->invalidContents	= FALSE;
+    info->nestedArgs		= FALSE;
+    info->parameterCount	= 0;
+}
+
+static void analyzeParens (statementInfo *const st)
+{
+    tokenInfo *const prev = prevToken (st, 1);
+
+    if (! isType (prev, TOKEN_NONE))    /* in case of ignored enclosing macros */
+    {
+	tokenInfo *const token = activeToken (st);
+	parenInfo info;
+	int c;
+
+	initParenInfo (&info);
+	parseParens (st, &info);
+	c = skipToNonWhite ();
+	cppUngetc (c);
+	if (info.invalidContents)
+	    reinitStatement (st, FALSE);
+	else if (info.isNameCandidate  &&  isType (token, TOKEN_PAREN_NAME)  &&
+		 ! st->gotParenName  &&
+		 (! info.isParamList || ! st->haveQualifyingName  ||
+		  c == '('  ||
+		  (c == '='  &&  st->implementation != IMP_VIRTUAL) ||
+		  (st->declaration == DECL_NONE  &&  isOneOf (c, ",;"))))
+	{
+	    token->type = TOKEN_NAME;
+	    processName (st);
+	    st->gotParenName = TRUE;
+	    if (! (c == '('  &&  info.nestedArgs))
+		st->isPointer = info.isPointer;
+	}
+	else if (! st->gotArgs  &&  info.isParamList)
+	{
+	    st->gotArgs = TRUE;
+	    setToken (st, TOKEN_ARGS);
+	    advanceToken (st);
+	    analyzePostParens (st, &info);
+	}
+	else
+	    setToken (st, TOKEN_NONE);
+    }
+}
+
+/*
+*   Token parsing functions
+*/
+
+static void addContext (statementInfo *const st, const tokenInfo* const token)
+{
+    if (isType (token, TOKEN_NAME))
+    {
+	if (vStringLength (st->context->name) > 0)
+	{
+	    vStringCatS (st->context->name, "::");
+	}
+	vStringCat (st->context->name, token->name);
+	st->context->type = TOKEN_NAME;
+    }
+}
+
+static void processColon (statementInfo *const st)
+{
+    const int c = skipToNonWhite ();
+    const boolean doubleColon = (boolean) (c == ':');
+
+    if (doubleColon)
+    {
+	setToken (st, TOKEN_DOUBLE_COLON);
+	st->haveQualifyingName = FALSE;
+    }
+    else
+    {
+	cppUngetc (c);
+	if (st->declaration == DECL_CLASS  ||  st->declaration == DECL_STRUCT)
+	{
+	    readParents (st, ':');
+	}
+    }
+}
+
+/*  Skips over any initializing value which may follow an '=' character in a
+ *  variable definition.
+ */
+static int skipInitializer (statementInfo *const st)
+{
+    boolean done = FALSE;
+    int c;
+
+    while (! done)
+    {
+	c = skipToNonWhite ();
+
+	if (c == EOF)
+	    longjmp (Exception, (int) ExceptionFormattingError);
+	else switch (c)
+	{
+	    case ',':
+	    case ';': done = TRUE; break;
+
+	    case '0':
+		if (st->implementation == IMP_VIRTUAL)
+		    st->implementation = IMP_PURE_VIRTUAL;
+		break;
+
+	    case '[': skipToMatch ("[]"); break;
+	    case '(': skipToMatch ("()"); break;
+	    case '{': skipToMatch ("{}"); break;
+
+	    case '}':
+		if (insideEnumBody (st))
+		    done = TRUE;
+		else if (! isBraceFormat ())
+		{
+		    verbose ("%s: unexpected closing brace at line %lu\n",
+			    getInputFileName (), getInputLineNumber ());
+		    longjmp (Exception, (int) ExceptionBraceFormattingError);
+		}
+		break;
+
+	    default: break;
+	}
+    }
+    return c;
+}
+
+static void processInitializer (statementInfo *const st)
+{
+    const boolean inEnumBody = insideEnumBody (st);
+    const int c = skipInitializer (st);
+
+    if (c == ';')
+	setToken (st, TOKEN_SEMICOLON);
+    else if (c == ',')
+	setToken (st, TOKEN_COMMA);
+    else if ('}'  &&  inEnumBody)
+    {
+	cppUngetc (c);
+	setToken (st, TOKEN_COMMA);
+    }
+    if (st->scope == SCOPE_EXTERN)
+	st->scope = SCOPE_GLOBAL;
+}
+
+static void parseIdentifier (statementInfo *const st, const int c)
+{
+    tokenInfo *const token = activeToken (st);
+
+    readIdentifier (token, c);
+    if (! isType (token, TOKEN_NONE))
+	processToken (token, st);
+}
+
+static void parseGeneralToken (statementInfo *const st, const int c)
+{
+    const tokenInfo *const prev = prevToken (st, 1);
+
+    if (isident1(c))
+    {
+	parseIdentifier (st, c);
+	if (isType (st->context, TOKEN_NAME) &&
+	    isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
+	{
+	    initToken (st->context);
+	}
+    }
+    else if (isExternCDecl (st, c))
+    {
+	st->declaration = DECL_NOMANGLE;
+	st->scope = SCOPE_GLOBAL;
+    }
+}
+
+/*  Reads characters from the pre-processor and assembles tokens, setting
+ *  the current statement state.
+ */
+static void nextToken (statementInfo *const st)
+{
+    tokenInfo *token = activeToken (st);
+    do
+    {
+
+	int c = skipToNonWhite ();
+
+	switch (c)
+	{
+	    case EOF: longjmp (Exception, (int) ExceptionEOF);		break;
+	    case '(': analyzeParens (st); token = activeToken (st); break;
+	    case '*': st->haveQualifyingName = FALSE;			break;
+	    case ',': setToken (st, TOKEN_COMMA);			break;
+	    case ':': processColon (st);					break;
+	    case ';': setToken (st, TOKEN_SEMICOLON);			break;
+	    case '<': skipToMatch ("<>");				break;
+	    case '=': processInitializer (st);				break;
+	    case '[': skipToMatch ("[]");				break;
+	    case '{': setToken (st, TOKEN_BRACE_OPEN);			break;
+	    case '}': setToken (st, TOKEN_BRACE_CLOSE);			break;
+	    default:  parseGeneralToken (st, c);				break;
+	}
+    } while (isType (token, TOKEN_NONE));
+
+	/* We want to know about non-keyword variable types */
+	if (TOKEN_NONE == st->firstToken->type)
+	{
+		if ((TOKEN_NAME == token->type) || ((TOKEN_KEYWORD == token->type)
+			&& (isBaseDataType(token->name->buffer))))
+			copyToken(st->firstToken, token);
+	}
+}
+
+/*
+*   Scanning support functions
+*/
+
+static statementInfo *CurrentStatement = NULL;
+
+static statementInfo *newStatement (statementInfo *const parent)
+{
+    statementInfo *const st = xMalloc (1, statementInfo);
+    unsigned int i;
+
+    for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
+	st->token [i] = newToken ();
+
+    st->context = newToken ();
+    st->blockName = newToken ();
+    st->parentClasses = vStringNew ();
+	st->firstToken = newToken();
+
+    initStatement (st, parent);
+    CurrentStatement = st;
+
+    return st;
+}
+
+static void deleteStatement (void)
+{
+    statementInfo *const st = CurrentStatement;
+    statementInfo *const parent = st->parent;
+    unsigned int i;
+
+    for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
+    {
+	deleteToken (st->token [i]);        st->token [i] = NULL;
+    }
+    deleteToken (st->blockName);           st->blockName = NULL;
+    deleteToken (st->context);             st->context = NULL;
+    vStringDelete (st->parentClasses);     st->parentClasses = NULL;
+	deleteToken(st->firstToken);
+    eFree (st);
+    CurrentStatement = parent;
+}
+
+static void deleteAllStatements (void)
+{
+    while (CurrentStatement != NULL)
+	deleteStatement ();
+}
+
+static boolean isStatementEnd (const statementInfo *const st)
+{
+    const tokenInfo *const token = activeToken (st);
+    boolean isEnd;
+
+    if (isType (token, TOKEN_SEMICOLON))
+	isEnd = TRUE;
+    else if (isType (token, TOKEN_BRACE_CLOSE))
+	isEnd = (boolean) ! isContextualStatement (st);
+    else
+	isEnd = FALSE;
+
+    return isEnd;
+}
+
+static void checkStatementEnd (statementInfo *const st)
+{
+    const tokenInfo *const token = activeToken (st);
+
+    if (isType (token, TOKEN_COMMA))
+	reinitStatement (st, TRUE);
+    else if (isStatementEnd (st))
+    {
+	reinitStatement (st, FALSE);
+	cppEndStatement ();
+    }
+    else
+    {
+	cppBeginStatement ();
+	advanceToken (st);
+    }
+}
+
+static void nest (statementInfo *const st, const unsigned int nestLevel)
+{
+    switch (st->declaration)
+    {
+	case DECL_CLASS:
+	case DECL_ENUM:
+	case DECL_INTERFACE:
+	case DECL_NAMESPACE:
+	case DECL_NOMANGLE:
+	case DECL_STRUCT:
+	case DECL_UNION:
+	    createTags (nestLevel, st);
+	    break;
+	default:
+	    skipToMatch ("{}");
+	    break;
+    }
+    advanceToken (st);
+    setToken (st, TOKEN_BRACE_CLOSE);
+}
+
+static void tagCheck (statementInfo *const st)
+{
+    const tokenInfo *const token = activeToken (st);
+    const tokenInfo *const prev  = prevToken (st, 1);
+    const tokenInfo *const prev2 = prevToken (st, 2);
+
+    switch (token->type)
+    {
+	case TOKEN_NAME:
+	    if (insideEnumBody (st))
+		qualifyEnumeratorTag (st, token);
+	    break;
+#if 0
+	case TOKEN_PACKAGE:
+	    if (st->haveQualifyingName)
+		makeTag (token, st, FALSE, TAG_PACKAGE);
+	    break;
+#endif
+	case TOKEN_BRACE_OPEN:
+	    if (isType (prev, TOKEN_ARGS))
+	    {
+		if (st->haveQualifyingName)
+		{
+		    st->declaration = DECL_FUNCTION;
+		    if (isType (prev2, TOKEN_NAME))
+			copyToken (st->blockName, prev2);
+		    qualifyFunctionTag (st, prev2);
+		}
+	    }
+	    else if (isContextualStatement (st))
+	    {
+		if (isType (prev, TOKEN_NAME))
+		    copyToken (st->blockName, prev);
+		qualifyBlockTag (st, prev);
+	    }
+	    break;
+
+	case TOKEN_SEMICOLON:
+	case TOKEN_COMMA:
+	    if (insideEnumBody (st))
+		;
+	    else if (isType (prev, TOKEN_NAME))
+	    {
+		if (isContextualKeyword (prev2))
+		    st->scope = SCOPE_EXTERN;
+		else
+			qualifyVariableTag (st, prev);
+	    }
+	    else if (isType (prev, TOKEN_ARGS)  &&  isType (prev2, TOKEN_NAME))
+	    {
+		if (st->isPointer)
+		    qualifyVariableTag (st, prev2);
+		else
+		    qualifyFunctionDeclTag (st, prev2);
+	    }
+	    break;
+
+	default: break;
+    }
+}
+
+/*  Parses the current file and decides whether to write out and tags that
+ *  are discovered.
+ */
+static void createTags (const unsigned int nestLevel,
+			statementInfo *const parent)
+{
+    statementInfo *const st = newStatement (parent);
+
+    while (TRUE)
+    {
+	tokenInfo *token;
+
+	nextToken (st);
+	token = activeToken (st);
+	if (isType (token, TOKEN_BRACE_CLOSE))
+	{
+	    if (nestLevel > 0)
+		break;
+	    else
+	    {
+		verbose ("%s: unexpected closing brace at line %lu\n",
+			getInputFileName (), getInputLineNumber ());
+		longjmp (Exception, (int) ExceptionBraceFormattingError);
+	    }
+	}
+	else if (isType (token, TOKEN_DOUBLE_COLON))
+	{
+	    addContext (st, prevToken (st, 1));
+	    advanceToken (st);
+	}
+	else
+	{
+	    tagCheck (st);
+	    if (isType (token, TOKEN_BRACE_OPEN))
+		nest (st, nestLevel + 1);
+	    checkStatementEnd (st);
+	}
+    }
+    deleteStatement ();
+}
+
+static boolean findDTags (const unsigned int passCount)
+{
+    exception_t exception;
+    boolean retry;
+
+    Assert (passCount < 3);
+    cppInit ((boolean) (passCount > 1));
+
+    exception = (exception_t) setjmp (Exception);
+    retry = FALSE;
+    if (exception == ExceptionNone)
+	createTags (0, NULL);
+    else
+    {
+	deleteAllStatements ();
+	if (exception == ExceptionBraceFormattingError  &&  passCount == 1)
+	{
+	    retry = TRUE;
+	   verbose ("%s: retrying file with fallback brace matching algorithm\n",
+		    getInputFileName ());
+	}
+    }
+    cppTerminate ();
+    return retry;
+}
+
+static void buildKeywordHash (const langType language, unsigned int idx)
+{
+    const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
+    size_t i;
+    for (i = 0  ;  i < count  ;  ++i)
+    {
+	const keywordDesc* const p = &KeywordTable [i];
+	if (p->isValid [idx])
+	    addKeyword (p->name, language, (int) p->id);
+    }
+}
+
+static void initializeDParser (const langType language)
+{
+    Lang_d = language;
+    buildKeywordHash (language, 17);
+}
+
+
+extern parserDefinition* DParser (void)
+{
+    static const char *const extensions [] = { "d", "di", NULL };
+    parserDefinition* def = parserNew ("D");
+    def->kinds      = DKinds;
+    def->kindCount  = KIND_COUNT (DKinds);
+    def->extensions = extensions;
+    def->parser2    = findDTags;
+    def->initialize = initializeDParser;
+    return def;
+}
+
+
+/* vi:set tabstop=8 shiftwidth=4: */

Modified: trunk/tagmanager/parsers.h
===================================================================
--- trunk/tagmanager/parsers.h	2006-07-08 18:23:20 UTC (rev 543)
+++ trunk/tagmanager/parsers.h	2006-07-09 14:41:53 UTC (rev 544)
@@ -31,7 +31,8 @@
     CssParser, \
     RubyParser, \
     TclParser, \
-    ShParser
+    ShParser, \
+    DParser
 
 /*
 langType of each parser
@@ -52,6 +53,7 @@
 14	RubyParser
 15	TclParser
 16	ShParser
+17	DParser
 */
 #endif	/* _PARSERS_H */
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Commits mailing list