[anjuta] symbol-db: anjuta-tags updated to ctags-5.8 version.



commit df8cfa55a04adbbe4249cc6ded6ca64485891da2
Author: Massimo Corà <mcora src gnome org>
Date:   Sun Jul 12 14:34:13 2009 +0200

    symbol-db: anjuta-tags updated to ctags-5.8 version.
    
    Updated some files and added ocaml.c.

 plugins/symbol-db/anjuta-tags/Makefile.am |    1 +
 plugins/symbol-db/anjuta-tags/ant.c       |   84 +-
 plugins/symbol-db/anjuta-tags/asp.c       |  123 +-
 plugins/symbol-db/anjuta-tags/dosbatch.c  |    6 +-
 plugins/symbol-db/anjuta-tags/flex.c      | 4487 ++++++++++++++---------------
 plugins/symbol-db/anjuta-tags/keyword.c   |    5 +-
 plugins/symbol-db/anjuta-tags/lisp.c      |    4 +-
 plugins/symbol-db/anjuta-tags/matlab.c    |    6 +-
 plugins/symbol-db/anjuta-tags/ocaml.c     | 1842 ++++++++++++
 plugins/symbol-db/anjuta-tags/parsers.h   |    3 +-
 plugins/symbol-db/anjuta-tags/php.c       |   22 +-
 plugins/symbol-db/anjuta-tags/python.c    |  245 ++-
 plugins/symbol-db/anjuta-tags/read.c      |    4 +-
 plugins/symbol-db/anjuta-tags/tex.c       |    4 +-
 plugins/symbol-db/anjuta-tags/vstring.h   |    3 +-
 plugins/symbol-db/symbol-db-engine-core.c |    2 +-
 16 files changed, 4457 insertions(+), 2384 deletions(-)
---
diff --git a/plugins/symbol-db/anjuta-tags/Makefile.am b/plugins/symbol-db/anjuta-tags/Makefile.am
index eea7d23..62ec5a2 100644
--- a/plugins/symbol-db/anjuta-tags/Makefile.am
+++ b/plugins/symbol-db/anjuta-tags/Makefile.am
@@ -58,6 +58,7 @@ anjuta_tags_SOURCES = \
 	make.c        \
 	Makefile.am        \
 	matlab.c        \
+  ocaml.c \
 	options.c        \
 	options.h        \
 	parse.c        \
diff --git a/plugins/symbol-db/anjuta-tags/ant.c b/plugins/symbol-db/anjuta-tags/ant.c
index e729276..eedfcec 100644
--- a/plugins/symbol-db/anjuta-tags/ant.c
+++ b/plugins/symbol-db/anjuta-tags/ant.c
@@ -1,42 +1,42 @@
-/*
-*   $Id: yacc.c 443 2006-05-30 04:37:13Z darren $
-*
-*   Copyright (c) 2001-2002, Nick Hibma <n_hibma van-laarhoven org>
-*
-*   This source code is released for free distribution under the terms of the
-*   GNU General Public License.
-*
-*   This module contains functions for generating tags for YACC language files.
-*/
-
-/*
-*   INCLUDE FILES
-*/
-#include "general.h"  /* must always come first */
-
-#include <string.h>
-#include "parse.h"
-
-/*
-*   FUNCTION DEFINITIONS
-*/
-
-static void installAntRegex (const langType language)
-{
-	addTagRegex (language,
-		"^[ \t]*<[ \t]*project.*name=\"([^\"]+)\".*", "\\1", "p,project,projects", NULL);
-	addTagRegex (language,
-		"^[ \t]*<[ \t]*target.*name=\"([^\"]+)\".*", "\\1", "t,target,targets", NULL);
-}
-
-extern parserDefinition* AntParser ()
-{
-	static const char *const extensions [] = { "build.xml", NULL };
-	parserDefinition* const def = parserNew ("Ant");
-	def->extensions = extensions;
-	def->initialize = installAntRegex;
-	def->regex      = TRUE;
-	return def;
-}
-
-/* vi:set tabstop=4 shiftwidth=4: */
+/*
+*   $Id$
+*
+*   Copyright (c) 2008, David Fishburn
+*
+*   This source code is released for free distribution under the terms of the
+*   GNU General Public License.
+*
+*   This module contains functions for generating tags for Ant language files.
+*/
+
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"  /* must always come first */
+
+#include <string.h>
+#include "parse.h"
+
+/*
+*   FUNCTION DEFINITIONS
+*/
+
+static void installAntRegex (const langType language)
+{
+	addTagRegex (language,
+		"^[ \t]*<[ \t]*project.*name=\"([^\"]+)\".*", "\\1", "p,project,projects", NULL);
+	addTagRegex (language,
+		"^[ \t]*<[ \t]*target.*name=\"([^\"]+)\".*", "\\1", "t,target,targets", NULL);
+}
+
+extern parserDefinition* AntParser ()
+{
+	static const char *const extensions [] = { "build.xml", NULL };
+	parserDefinition* const def = parserNew ("Ant");
+	def->extensions = extensions;
+	def->initialize = installAntRegex;
+	def->regex      = TRUE;
+	return def;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
diff --git a/plugins/symbol-db/anjuta-tags/asp.c b/plugins/symbol-db/anjuta-tags/asp.c
index 27e8474..7290ad8 100644
--- a/plugins/symbol-db/anjuta-tags/asp.c
+++ b/plugins/symbol-db/anjuta-tags/asp.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: asp.c 443 2006-05-30 04:37:13Z darren $
+*   $Id: asp.c 711 2009-07-04 16:52:11Z dhiebert $
 *
 *   Copyright (c) 2000, Patrick Dehne <patrick steidle net>
 *
@@ -25,11 +25,12 @@
 *   DATA DEFINITIONS
 */
 typedef enum {
-	K_CONST, K_FUNCTION, K_SUB, K_DIM
+	K_CONST, K_CLASS, K_FUNCTION, K_SUB, K_DIM
 } aspKind;
 
 static kindOption AspKinds [] = {
-	{ TRUE, 'c', "constant",   "constants"},
+	{ TRUE, 'd', "constant",   "constants"},
+	{ TRUE, 'c', "class",      "classes"}, 
 	{ TRUE, 'f', "function",   "functions"},
 	{ TRUE, 's', "subroutine", "subroutines"},
 	{ TRUE, 'v', "variable",   "variables"}
@@ -112,6 +113,102 @@ static void findAspTags (void)
 				}
 			}
 
+			/* class member? */
+			else if (strncasecmp ((const char*) cp, "public", (size_t) 6) == 0)
+			{
+				cp += 6;
+				if (isspace ((int) *cp))
+				{
+					while (isspace ((int) *cp))
+						++cp;
+					if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
+					{
+						cp+=8;
+					    while (isspace ((int) *cp))
+						    ++cp;
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_FUNCTION);
+					    vStringClear (name);
+					}
+					else if (strncasecmp ((const char*) cp, "sub", (size_t) 3) == 0)
+					{
+						cp+=3;
+					    while (isspace ((int) *cp))
+						    ++cp;
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_SUB);
+					    vStringClear (name);
+					}
+					else {
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_DIM);
+					    vStringClear (name);
+					}
+				}
+			}
+			else if (strncasecmp ((const char*) cp, "private", (size_t) 7) == 0)
+			{
+				cp += 7;
+				if (isspace ((int) *cp))
+				{
+					while (isspace ((int) *cp))
+						++cp;
+					if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
+					{
+						cp+=8;
+					    while (isspace ((int) *cp))
+						    ++cp;
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_FUNCTION);
+					    vStringClear (name);
+					}
+					else if (strncasecmp ((const char*) cp, "sub", (size_t) 3) == 0)
+					{
+						cp+=3;
+					    while (isspace ((int) *cp))
+						    ++cp;
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_SUB);
+					    vStringClear (name);
+					}
+					else {
+					    while (isalnum ((int) *cp)  ||  *cp == '_')
+					    {
+						    vStringPut (name, (int) *cp);
+						    ++cp;
+					    }
+					    vStringTerminate (name);
+					    makeSimpleTag (name, AspKinds, K_DIM);
+					    vStringClear (name);
+					}
+				}
+			}
+
 			/* function? */
 			else if (strncasecmp ((const char*) cp, "function", (size_t) 8) == 0)
 			{
@@ -170,6 +267,25 @@ static void findAspTags (void)
 				}
 			}
 
+			/* class declaration? */
+			else if (strncasecmp ((const char*) cp, "class", (size_t) 5) == 0)
+			{
+				cp += 5;
+				if (isspace ((int) *cp))
+				{
+					while (isspace ((int) *cp))
+						++cp;
+					while (isalnum ((int) *cp)  ||  *cp == '_')
+					{
+						vStringPut (name, (int) *cp);
+						++cp;
+					}
+					vStringTerminate (name);
+					makeSimpleTag (name, AspKinds, K_CLASS);
+					vStringClear (name);
+				}
+			}
+
 			/* const declaration? */
 			else if (strncasecmp ((const char*) cp, "const", (size_t) 5) == 0)
 			{
@@ -209,3 +325,4 @@ extern parserDefinition* AspParser (void)
 }
 
 /* vi:set tabstop=4 shiftwidth=4: */
+
diff --git a/plugins/symbol-db/anjuta-tags/dosbatch.c b/plugins/symbol-db/anjuta-tags/dosbatch.c
index f137657..c165183 100644
--- a/plugins/symbol-db/anjuta-tags/dosbatch.c
+++ b/plugins/symbol-db/anjuta-tags/dosbatch.c
@@ -1,12 +1,12 @@
 /*
-*   $Id: yacc.c 443 2006-05-30 04:37:13Z darren $
+*   $Id$
 *
-*   Copyright (c) 2001-2002, Nick Hibma <n_hibma van-laarhoven org>
+*   Copyright (c) 2009, David Fishburn
 *
 *   This source code is released for free distribution under the terms of the
 *   GNU General Public License.
 *
-*   This module contains functions for generating tags for YACC language files.
+*   This module contains functions for generating tags for DOS Batch language files.
 */
 
 /*
diff --git a/plugins/symbol-db/anjuta-tags/flex.c b/plugins/symbol-db/anjuta-tags/flex.c
index 7fb6977..06ca243 100644
--- a/plugins/symbol-db/anjuta-tags/flex.c
+++ b/plugins/symbol-db/anjuta-tags/flex.c
@@ -1,2244 +1,2243 @@
-/*
- *	 $Id: flex.c 666 2008-05-15 17:47:31Z dfishburn $
- *
- *	 Copyright (c) 2003, Darren Hiebert
- *
- *	 This source code is released for free distribution under the terms of the
- *	 GNU General Public License.
- *
- *	 This module contains functions for generating tags for Adobe languages.
- *	 There are a number of different ones, but this will begin with:
- *	     Flex
- *	         MXML files (*.mMacromedia XML)
- *	         ActionScript files (*.as)
- *	 
- *
- *	 Flex 3 language reference
- *		 http://livedocs.adobe.com/flex/3/langref/index.html
- */
-
-/*
- *	 INCLUDE FILES
- */
-#include "general.h"	/* must always come first */
-#include <ctype.h>	/* to define isalpha () */
-#include <setjmp.h>
-#ifdef DEBUG
-#include <stdio.h>
-#endif
-
-#include "debug.h"
-#include "entry.h"
-#include "keyword.h"
-#include "parse.h"
-#include "read.h"
-#include "routines.h"
-#include "vstring.h"
-
-/*
- *	 MACROS
- */
-#define isType(token,t)		(boolean) ((token)->type == (t))
-#define isKeyword(token,k)	(boolean) ((token)->keyword == (k))
-
-/*
- *	 DATA DECLARATIONS
- */
-
-typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
-
-/*
- * Tracks class and function names already created
- */
-static stringList *ClassNames;
-static stringList *FunctionNames;
-
-/*	Used to specify type of keyword.
-*/
-typedef enum eKeywordId {
-	KEYWORD_NONE = -1,
-	KEYWORD_function,
-	KEYWORD_capital_function,
-	KEYWORD_object,
-	KEYWORD_capital_object,
-	KEYWORD_prototype,
-	KEYWORD_var,
-	KEYWORD_new,
-	KEYWORD_this,
-	KEYWORD_for,
-	KEYWORD_while,
-	KEYWORD_do,
-	KEYWORD_if,
-	KEYWORD_else,
-	KEYWORD_switch,
-	KEYWORD_try,
-	KEYWORD_catch,
-	KEYWORD_finally,
-	KEYWORD_public,
-	KEYWORD_private,
-	KEYWORD_static,
-	KEYWORD_class,
-	KEYWORD_id,
-	KEYWORD_script,
-	KEYWORD_cdata,
-	KEYWORD_mx
-} keywordId;
-
-/*	Used to determine whether keyword is valid for the token language and
- *	what its ID is.
- */
-typedef struct sKeywordDesc {
-	const char *name;
-	keywordId id;
-} keywordDesc;
-
-typedef enum eTokenType {
-	TOKEN_UNDEFINED,
-	TOKEN_CHARACTER,
-	TOKEN_CLOSE_PAREN,
-	TOKEN_SEMICOLON,
-	TOKEN_COLON,
-	TOKEN_COMMA,
-	TOKEN_KEYWORD,
-	TOKEN_OPEN_PAREN,
-	TOKEN_OPERATOR,
-	TOKEN_IDENTIFIER,
-	TOKEN_STRING,
-	TOKEN_PERIOD,
-	TOKEN_OPEN_CURLY,
-	TOKEN_CLOSE_CURLY,
-	TOKEN_EQUAL_SIGN,
-	TOKEN_EXCLAMATION,
-	TOKEN_FORWARD_SLASH,
-	TOKEN_OPEN_SQUARE,
-	TOKEN_CLOSE_SQUARE,
-	TOKEN_OPEN_MXML,
-	TOKEN_CLOSE_MXML,
-	TOKEN_CLOSE_SGML,
-	TOKEN_LESS_THAN,
-	TOKEN_GREATER_THAN,
-	TOKEN_QUESTION_MARK
-} tokenType;
-
-typedef struct sTokenInfo {
-	tokenType		type;
-	keywordId		keyword;
-	vString *		string;
-	vString *		scope;
-	unsigned long 	lineNumber;
-	fpos_t 			filePosition;
-	int				nestLevel;
-	boolean			ignoreTag;
-	boolean			isClass;
-} tokenInfo;
-
-/*
- *	DATA DEFINITIONS
- */
-
-static langType Lang_js;
-
-static jmp_buf Exception;
-
-typedef enum {
-	FLEXTAG_FUNCTION,
-	FLEXTAG_CLASS,
-	FLEXTAG_METHOD,
-	FLEXTAG_PROPERTY,
-	FLEXTAG_VARIABLE,
-	FLEXTAG_MXTAG,
-	FLEXTAG_COUNT
-} flexKind;
-
-static kindOption FlexKinds [] = {
-	{ TRUE,  'f', "function",	  "functions"		   },
-	{ TRUE,  'c', "class",		  "classes"			   },
-	{ TRUE,  'm', "method",		  "methods"			   },
-	{ TRUE,  'p', "property",	  "properties"		   },
-	{ TRUE,  'v', "variable",	  "global variables"   },
-	{ TRUE,  'x', "mxtag",		  "mxtags" 			   }
-};
-
-static const keywordDesc FlexKeywordTable [] = {
-	/* keyword		keyword ID */
-	{ "function",	KEYWORD_function			},
-	{ "Function",	KEYWORD_capital_function	},
-	{ "object",		KEYWORD_object				},
-	{ "Object",		KEYWORD_capital_object		},
-	{ "prototype",	KEYWORD_prototype			},
-	{ "var",		KEYWORD_var					},
-	{ "new",		KEYWORD_new					},
-	{ "this",		KEYWORD_this				},
-	{ "for",		KEYWORD_for					},
-	{ "while",		KEYWORD_while				},
-	{ "do",			KEYWORD_do					},
-	{ "if",			KEYWORD_if					},
-	{ "else",		KEYWORD_else				},
-	{ "switch",		KEYWORD_switch				},
-	{ "try",		KEYWORD_try					},
-	{ "catch",		KEYWORD_catch				},
-	{ "finally",	KEYWORD_finally				},
-	{ "public",		KEYWORD_public				},
-	{ "private",	KEYWORD_private				},
-	{ "static",		KEYWORD_static				},
-	{ "class",		KEYWORD_class				},
-	{ "id",			KEYWORD_id					},
-	{ "script",		KEYWORD_script				},
-	{ "cdata",		KEYWORD_cdata				},
-	{ "mx",			KEYWORD_mx					}
-};
-
-/*
- *	 FUNCTION DEFINITIONS
- */
-
-/* Recursive functions */
-static void parseFunction (tokenInfo *const token);
-static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent);
-static boolean parseLine (tokenInfo *const token);
-static boolean parseActionScript (tokenInfo *const token);
-
-static boolean isIdentChar (const int c)
-{
-	return (boolean)
-		(isalpha (c) || isdigit (c) || c == '$' || 
-		 c == '@' || c == '_' || c == '#');
-}
-
-static void buildFlexKeywordHash (void)
-{
-	const size_t count = sizeof (FlexKeywordTable) /
-		sizeof (FlexKeywordTable [0]);
-	size_t i;
-	for (i = 0	;  i < count  ;  ++i)
-	{
-		const keywordDesc* const p = &FlexKeywordTable [i];
-		addKeyword (p->name, Lang_js, (int) p->id);
-	}
-}
-
-static tokenInfo *newToken (void)
-{
-	tokenInfo *const token = xMalloc (1, tokenInfo);
-
-	token->type			= TOKEN_UNDEFINED;
-	token->keyword		= KEYWORD_NONE;
-	token->string		= vStringNew ();
-	token->scope		= vStringNew ();
-	token->nestLevel	= 0;
-	token->isClass		= FALSE;
-	token->ignoreTag	= FALSE;
-	token->lineNumber   = getSourceLineNumber ();
-	token->filePosition = getInputFilePosition ();
-
-	return token;
-}
-
-static void deleteToken (tokenInfo *const token)
-{
-	vStringDelete (token->string);
-	vStringDelete (token->scope);
-	eFree (token);
-}
-
-/*
- *	 Tag generation functions
- */
-
-static void makeConstTag (tokenInfo *const token, const flexKind kind)
-{
-	if (FlexKinds [kind].enabled && ! token->ignoreTag )
-	{
-		const char *const name = vStringValue (token->string);
-		tagEntryInfo e;
-		initTagEntry (&e, name);
-
-		e.lineNumber   = token->lineNumber;
-		e.filePosition = token->filePosition;
-		e.kindName	   = FlexKinds [kind].name;
-		e.kind		   = FlexKinds [kind].letter;
-
-		makeTagEntry (&e);
-	}
-}
-
-static void makeFlexTag (tokenInfo *const token, flexKind kind)
-{
-	vString *	fulltag;
-
-	if (FlexKinds [kind].enabled && ! token->ignoreTag )
-	{
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n makeFlexTag start: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-		if (kind == FLEXTAG_FUNCTION && token->isClass )
-		{
-			kind = FLEXTAG_METHOD;
-		}
-		/*
-		 * If a scope has been added to the token, change the token
-		 * string to include the scope when making the tag.
-		 */
-		if ( vStringLength(token->scope) > 0 )
-		{
-			fulltag = vStringNew ();
-			vStringCopy(fulltag, token->scope);
-			vStringCatS (fulltag, ".");
-			vStringCatS (fulltag, vStringValue(token->string));
-			vStringTerminate(fulltag);
-			vStringCopy(token->string, fulltag);
-			vStringDelete (fulltag);
-		}
-		makeConstTag (token, kind);
-	}
-}
-
-static void makeClassTag (tokenInfo *const token)
-{ 
-	vString *	fulltag;
-
-	if ( ! token->ignoreTag )
-	{
-		fulltag = vStringNew ();
-		if (vStringLength (token->scope) > 0)
-		{
-			vStringCopy(fulltag, token->scope);
-			vStringCatS (fulltag, ".");
-			vStringCatS (fulltag, vStringValue(token->string));
-		}
-		else
-		{
-			vStringCopy(fulltag, token->string);
-		}
-		vStringTerminate(fulltag);
-		if ( ! stringListHas(ClassNames, vStringValue (fulltag)) )
-		{
-			stringListAdd (ClassNames, vStringNewCopy (fulltag));
-			makeFlexTag (token, FLEXTAG_CLASS);
-		}
-		vStringDelete (fulltag);
-	}
-}
-
-static void makeMXTag (tokenInfo *const token)
-{ 
-	vString *	fulltag;
-
-	if ( ! token->ignoreTag )
-	{
-		fulltag = vStringNew ();
-		if (vStringLength (token->scope) > 0)
-		{
-			vStringCopy(fulltag, token->scope);
-			vStringCatS (fulltag, ".");
-			vStringCatS (fulltag, vStringValue(token->string));
-		}
-		else
-		{
-			vStringCopy(fulltag, token->string);
-		}
-		vStringTerminate(fulltag);
-		makeFlexTag (token, FLEXTAG_MXTAG);
-		vStringDelete (fulltag);
-	}
-}
-
-static void makeFunctionTag (tokenInfo *const token)
-{ 
-	vString *	fulltag;
-
-	if ( ! token->ignoreTag )
-	{
-		fulltag = vStringNew ();
-		if (vStringLength (token->scope) > 0)
-		{
-			vStringCopy(fulltag, token->scope);
-			vStringCatS (fulltag, ".");
-			vStringCatS (fulltag, vStringValue(token->string));
-		}
-		else
-		{
-			vStringCopy(fulltag, token->string);
-		}
-		vStringTerminate(fulltag);
-		if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) )
-		{
-			stringListAdd (FunctionNames, vStringNewCopy (fulltag));
-			makeFlexTag (token, FLEXTAG_FUNCTION);
-		}
-		vStringDelete (fulltag);
-	}
-}
-
-/*
- *	 Parsing functions
- */
-
-static void parseString (vString *const string, const int delimiter)
-{
-	boolean end = FALSE;
-	while (! end)
-	{
-		int c = fileGetc ();
-		if (c == EOF)
-			end = TRUE;
-		else if (c == '\\')
-		{
-			c = fileGetc(); /* This maybe a ' or ". */
-			vStringPut(string, c);
-		}
-		else if (c == delimiter)
-			end = TRUE;
-		else
-			vStringPut (string, c);
-	}
-	vStringTerminate (string);
-}
-
-/*	Read a C identifier beginning with "firstChar" and places it into
- *	"name".
- */
-static void parseIdentifier (vString *const string, const int firstChar)
-{
-	int c = firstChar;
-	Assert (isIdentChar (c));
-	do
-	{
-		vStringPut (string, c);
-		c = fileGetc ();
-	} while (isIdentChar (c));
-	vStringTerminate (string);
-	if (!isspace (c))
-		fileUngetc (c);		/* unget non-identifier character */
-}
-
-static void readToken (tokenInfo *const token)
-{
-	int c;
-
-	token->type			= TOKEN_UNDEFINED;
-	token->keyword		= KEYWORD_NONE;
-	vStringClear (token->string);
-
-getNextChar:
-	do
-	{
-		c = fileGetc ();
-		token->lineNumber   = getSourceLineNumber ();
-		token->filePosition = getInputFilePosition ();
-	}
-	while (c == '\t'  ||  c == ' ' ||  c == '\n');
-
-	switch (c)
-	{
-		case EOF: longjmp (Exception, (int)ExceptionEOF);	break;
-		case '(': token->type = TOKEN_OPEN_PAREN;			break;
-		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
-		case ';': token->type = TOKEN_SEMICOLON;			break;
-		case ',': token->type = TOKEN_COMMA;				break;
-		case '.': token->type = TOKEN_PERIOD;				break;
-		case ':': token->type = TOKEN_COLON;				break;
-		case '{': token->type = TOKEN_OPEN_CURLY;			break;
-		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
-		case '=': token->type = TOKEN_EQUAL_SIGN;			break;
-		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
-		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;
-		case '?': token->type = TOKEN_QUESTION_MARK;		break;
-
-		case '\'':
-		case '"':
-				  token->type = TOKEN_STRING;
-				  parseString (token->string, c);
-				  token->lineNumber = getSourceLineNumber ();
-				  token->filePosition = getInputFilePosition ();
-				  break;
-
-		case '\\':
-				  c = fileGetc ();
-				  if (c != '\\'  && c != '"'  &&  !isspace (c))
-					  fileUngetc (c);
-				  token->type = TOKEN_CHARACTER;
-				  token->lineNumber = getSourceLineNumber ();
-				  token->filePosition = getInputFilePosition ();
-				  break;
-
-		case '/':
-				  {
-					  int d = fileGetc ();
-					  if ( (d != '*') &&		/* is this the start of a comment? */
-							  (d != '/') &&		/* is a one line comment? */
-							  (d != '>') )		/* is this a close XML tag? */
-					  {
-						  fileUngetc (d);
-						  token->type = TOKEN_FORWARD_SLASH;
-						  token->lineNumber = getSourceLineNumber ();
-						  token->filePosition = getInputFilePosition ();
-					  }
-					  else
-					  {
-						  if (d == '*')
-						  {
-							  do
-							  {
-								  fileSkipToCharacter ('*');
-								  c = fileGetc ();
-								  if (c == '/')
-									  break;
-								  else
-									  fileUngetc (c);
-							  } while (c != EOF && c != '\0');
-							  goto getNextChar;
-						  }
-						  else if (d == '/')	/* is this the start of a comment?  */
-						  {
-							  fileSkipToCharacter ('\n');
-							  goto getNextChar;
-						  }
-						  else if (d == '>')	/* is this the start of a comment?  */
-						  {
-							  token->type = TOKEN_CLOSE_SGML;
-							  token->lineNumber = getSourceLineNumber ();
-							  token->filePosition = getInputFilePosition ();
-						  }
-					  }
-					  break;
-				  }
-
-		case '<':
-				  {
-					  /*
-					   * An XML comment looks like this 
-					   *   <!-- anything over multiple lines -->
-					   */
-					  int d = fileGetc ();
-
-					  if ( (d != '!' )  && 		/* is this the start of a comment? */
-					       (d != '/' )  &&	 	/* is this the start of a closing mx tag */
-					       (d != 'm' )    ) 	/* is this the start of a mx tag */
-					  {
-						  fileUngetc (d);
-						  token->type = TOKEN_LESS_THAN;
-						  token->lineNumber = getSourceLineNumber ();
-						  token->filePosition = getInputFilePosition ();
-
-					  }
-					  else
-					  {
-						  if (d == '!')
-						  {
-							  int e = fileGetc ();
-							  if ( e != '-' ) 		/* is this the start of a comment? */
-							  {
-								  fileUngetc (e);
-								  fileUngetc (d);
-								  token->type = TOKEN_LESS_THAN;
-								  token->lineNumber = getSourceLineNumber ();
-								  token->filePosition = getInputFilePosition ();
-							  }
-							  else
-							  {
-								  if (e == '-')
-								  {
-									  int f = fileGetc ();
-									  if ( f != '-' ) 		/* is this the start of a comment? */
-									  {
-										  fileUngetc (f);
-										  fileUngetc (e);
-										  fileUngetc (d);
-										  token->type = TOKEN_LESS_THAN;
-										  token->lineNumber = getSourceLineNumber ();
-										  token->filePosition = getInputFilePosition ();
-									  }
-									  else
-									  {
-										  if (f == '-')
-										  {
-											  do
-											  {
-												  fileSkipToCharacter ('-');
-												  c = fileGetc ();
-												  if (c == '-') 
-												  {
-													  d = fileGetc ();
-													  if (d == '>')
-														  break;
-													  else
-													  {
-														  fileUngetc (d);
-														  fileUngetc (c);
-													  }
-													  break;
-												  }
-												  else
-													  fileUngetc (c);
-											  } while (c != EOF && c != '\0');
-											  goto getNextChar;
-										  }
-									  }
-								  }
-							  }
-						  }
-						  else if (d == 'm')
-						  {
-							  int e = fileGetc ();
-							  if ( e != 'x' ) 		/* continuing an mx tag */
-							  {
-								  fileUngetc (e);
-								  fileUngetc (d);
-								  token->type = TOKEN_LESS_THAN;
-								  token->lineNumber = getSourceLineNumber ();
-								  token->filePosition = getInputFilePosition ();
-							  }
-							  else
-							  {
-								  if (e == 'x')
-								  {
-									  int f = fileGetc ();
-									  if ( f != ':' ) 		/* is this the start of a comment? */
-									  {
-										  fileUngetc (f);
-										  fileUngetc (e);
-										  fileUngetc (d);
-										  token->type = TOKEN_LESS_THAN;
-										  token->lineNumber = getSourceLineNumber ();
-										  token->filePosition = getInputFilePosition ();
-									  }
-									  else
-									  {
-										  if (f == ':')
-										  {
-											  token->type = TOKEN_OPEN_MXML;
-											  token->lineNumber = getSourceLineNumber ();
-											  token->filePosition = getInputFilePosition ();
-										  }
-									  }
-								  }
-							  }
-						  }
-						  else if (d == '/')
-						  {
-							  int e = fileGetc ();
-							  if ( e != 'm' ) 		/* continuing an mx tag */
-							  {
-								  fileUngetc (e);
-								  fileUngetc (d);
-								  token->type = TOKEN_LESS_THAN;
-								  token->lineNumber = getSourceLineNumber ();
-								  token->filePosition = getInputFilePosition ();
-							  }
-							  else
-							  {
-								  int f = fileGetc ();
-								  if ( f != 'x' ) 		/* continuing an mx tag */
-								  {
-									  fileUngetc (f);
-									  fileUngetc (e);
-									  token->type = TOKEN_LESS_THAN;
-									  token->lineNumber = getSourceLineNumber ();
-									  token->filePosition = getInputFilePosition ();
-								  }
-								  else
-								  {
-									  if (f == 'x')
-									  {
-										  int g = fileGetc ();
-										  if ( g != ':' ) 		/* is this the start of a comment? */
-										  {
-											  fileUngetc (g);
-											  fileUngetc (f);
-											  fileUngetc (e);
-											  token->type = TOKEN_LESS_THAN;
-											  token->lineNumber = getSourceLineNumber ();
-											  token->filePosition = getInputFilePosition ();
-										  }
-										  else
-										  {
-											  if (g == ':')
-											  {
-												  token->type = TOKEN_CLOSE_MXML;
-												  token->lineNumber = getSourceLineNumber ();
-												  token->filePosition = getInputFilePosition ();
-											  }
-										  }
-									  }
-								  }
-							  }
-						  }
-					  }
-					  break;
-				  }
-
-		case '>':
-				  token->type = TOKEN_GREATER_THAN;
-				  token->lineNumber = getSourceLineNumber ();
-				  token->filePosition = getInputFilePosition ();
-				  break;
-
-		case '!': 
-				  token->type = TOKEN_EXCLAMATION;			
-				  /*token->lineNumber = getSourceLineNumber ();
-				  token->filePosition = getInputFilePosition ();*/
-				  break;
-
-		default:
-				  if (! isIdentChar (c))
-					  token->type = TOKEN_UNDEFINED;
-				  else
-				  {
-					  parseIdentifier (token->string, c);
-					  token->lineNumber = getSourceLineNumber ();
-					  token->filePosition = getInputFilePosition ();
-					  token->keyword = analyzeToken (token->string, Lang_js);
-					  if (isKeyword (token, KEYWORD_NONE))
-						  token->type = TOKEN_IDENTIFIER;
-					  else
-						  token->type = TOKEN_KEYWORD;
-				  }
-				  break;
-	}
-}
-
-static void copyToken (tokenInfo *const dest, tokenInfo *const src)
-{
-	dest->nestLevel = src->nestLevel;
-	dest->lineNumber = src->lineNumber;
-	dest->filePosition = src->filePosition;
-	dest->type = src->type;
-	dest->keyword = src->keyword;
-	dest->isClass = src->isClass;
-	vStringCopy(dest->string, src->string);
-	vStringCopy(dest->scope, src->scope);
-}
-
-/*
- *	 Token parsing functions
- */
-
-static void skipArgumentList (tokenInfo *const token)
-{
-	int nest_level = 0;
-
-	/*
-	 * Other databases can have arguments with fully declared
-	 * datatypes:
-	 *	 (	name varchar(30), text binary(10)  )
-	 * So we must check for nested open and closing parantheses
-	 */
-
-	if (isType (token, TOKEN_OPEN_PAREN))	/* arguments? */
-	{
-		nest_level++;
-		while (! (isType (token, TOKEN_CLOSE_PAREN) && (nest_level == 0)))
-		{
-			readToken (token);
-			if (isType (token, TOKEN_OPEN_PAREN))
-			{
-				nest_level++;
-			}
-			if (isType (token, TOKEN_CLOSE_PAREN))
-			{
-				if (nest_level > 0)
-				{
-					nest_level--;
-				}
-			}
-		} 
-		readToken (token);
-	}
-}
-
-static void skipArrayList (tokenInfo *const token)
-{
-	int nest_level = 0;
-
-	/*
-	 * Handle square brackets
-	 *	 var name[1]
-	 * So we must check for nested open and closing square brackets
-	 */
-
-	if (isType (token, TOKEN_OPEN_SQUARE))	/* arguments? */
-	{
-		nest_level++;
-		while (! (isType (token, TOKEN_CLOSE_SQUARE) && (nest_level == 0)))
-		{
-			readToken (token);
-			if (isType (token, TOKEN_OPEN_SQUARE))
-			{
-				nest_level++;
-			}
-			if (isType (token, TOKEN_CLOSE_SQUARE))
-			{
-				if (nest_level > 0)
-				{
-					nest_level--;
-				}
-			}
-		} 
-		readToken (token);
-	}
-}
-
-static void addContext (tokenInfo* const parent, const tokenInfo* const child)
-{
-	if (vStringLength (parent->string) > 0)
-	{
-		vStringCatS (parent->string, ".");
-	}
-	vStringCatS (parent->string, vStringValue(child->string));
-	vStringTerminate(parent->string);
-}
-
-static void addToScope (tokenInfo* const token, vString* const extra)
-{
-	if (vStringLength (token->scope) > 0)
-	{
-		vStringCatS (token->scope, ".");
-	}
-	vStringCatS (token->scope, vStringValue(extra));
-	vStringTerminate(token->scope);
-}
-
-/*
- *	 Scanning functions
- */
-
-static void findCmdTerm (tokenInfo *const token)
-{
-	/*
-	 * Read until we find either a semicolon or closing brace. 
-	 * Any nested braces will be handled within.
-	 */
-	while (! ( isType (token, TOKEN_SEMICOLON) ||
-				isType (token, TOKEN_CLOSE_CURLY) ) )
-	{
-		/* Handle nested blocks */
-		if ( isType (token, TOKEN_OPEN_CURLY))
-		{
-			parseBlock (token, token);
-		} 
-		else if ( isType (token, TOKEN_OPEN_PAREN) )
-		{
-			skipArgumentList(token);
-		}
-		else 
-		{
-			readToken (token);
-		}
-	} 
-}
-
-static void parseSwitch (tokenInfo *const token)
-{
-	/*
-	 * switch (expression){
-	 * case value1:
-	 *	   statement;
-	 *	   break;
-	 * case value2:
-	 *	   statement;
-	 *	   break;
-	 * default : statement;
-	 * }
-	 */
-
-	readToken (token);
-
-	if (isType (token, TOKEN_OPEN_PAREN)) 
-	{
-		skipArgumentList(token);
-	}
-
-	if (isType (token, TOKEN_OPEN_CURLY)) 
-	{
-		do
-		{
-			readToken (token);
-		} while (! (isType (token, TOKEN_CLOSE_SGML) || 
-					isType (token, TOKEN_CLOSE_MXML) ||
-					isType (token, TOKEN_CLOSE_CURLY) ||
-					isType (token, TOKEN_GREATER_THAN)) ); 
-	}
-
-}
-
-static void parseLoop (tokenInfo *const token)
-{
-	/*
-	 * Handles these statements
-	 *	   for (x=0; x<3; x++)
-	 *		   document.write("This text is repeated three times<br>");
-	 *	   
-	 *	   for (x=0; x<3; x++)
-	 *	   {
-	 *		   document.write("This text is repeated three times<br>");
-	 *	   }
-	 *	   
-	 *	   while (number<5){
-	 *		   document.write(number+"<br>");
-	 *		   number++;
-	 *	   }
-	 *	   
-	 *	   do{
-	 *		   document.write(number+"<br>");
-	 *		   number++;
-	 *	   }
-	 *	   while (number<5);
-	 */
-
-	if (isKeyword (token, KEYWORD_for) || isKeyword (token, KEYWORD_while))
-	{
-		readToken(token);
-
-		if (isType (token, TOKEN_OPEN_PAREN)) 
-		{
-			/*
-			 * Handle nameless functions, these will only
-			 * be considered methods.
-			 */
-			skipArgumentList(token);
-		}
-
-		if (isType (token, TOKEN_OPEN_CURLY)) 
-		{
-			/*
-			 * This will be either a function or a class.
-			 * We can only determine this by checking the body
-			 * of the function.  If we find a "this." we know
-			 * it is a class, otherwise it is a function.
-			 */
-			parseBlock (token, token);
-		} 
-		else 
-		{
-			parseLine(token);
-		}
-	} 
-	else if (isKeyword (token, KEYWORD_do))
-	{
-		readToken(token);
-
-		if (isType (token, TOKEN_OPEN_CURLY)) 
-		{
-			/*
-			 * This will be either a function or a class.
-			 * We can only determine this by checking the body
-			 * of the function.  If we find a "this." we know
-			 * it is a class, otherwise it is a function.
-			 */
-			parseBlock (token, token);
-		} 
-		else 
-		{
-			parseLine(token);
-		}
-
-		readToken(token);
-
-		if (isKeyword (token, KEYWORD_while))
-		{
-			readToken(token);
-
-			if (isType (token, TOKEN_OPEN_PAREN)) 
-			{
-				/*
-				 * Handle nameless functions, these will only
-				 * be considered methods.
-				 */
-				skipArgumentList(token);
-			}
-		}
-	}
-}
-
-static boolean parseIf (tokenInfo *const token)
-{
-	boolean read_next_token = TRUE;
-	/*
-	 * If statements have two forms
-	 *	   if ( ... )
-	 *		   one line;
-	 *
-	 *	   if ( ... )  
-	 *		  statement;
-	 *	   else
-	 *		  statement
-	 *	    
-	 *	   if ( ... ) {
-	 *		  multiple;
-	 *		  statements;
-	 *	   }
-	 *
-	 *
-	 *	   if ( ... ) {
-	 *		  return elem
-	 *	   }
-	 *
-	 *     This example if correctly written, but the
-	 *     else contains only 1 statement without a terminator
-	 *     since the function finishes with the closing brace.
-	 *
-     *     function a(flag){
-     *         if(flag)
-     *             test(1);
-     *         else
-     *             test(2)
-     *     }
-	 *
-	 * TODO:  Deal with statements that can optional end
-	 *		  without a semi-colon.  Currently this messes up
-	 *		  the parsing of blocks.
-	 *		  Need to somehow detect this has happened, and either
-	 *		  backup a token, or skip reading the next token if 
-	 *		  that is possible from all code locations.
-	 *
-	 */
-
-	readToken (token);
-
-	if (isKeyword (token, KEYWORD_if))
-	{
-		/*
-		 * Check for an "else if" and consume the "if"
-		 */
-		readToken (token);
-	}
-
-	if (isType (token, TOKEN_OPEN_PAREN)) 
-	{
-		/* 
-		 * Handle nameless functions, these will only
-		 * be considered methods.
-		 */
-		skipArgumentList(token);
-	}
-
-	if (isType (token, TOKEN_OPEN_CURLY)) 
-	{
-		/*
-		 * This will be either a function or a class.
-		 * We can only determine this by checking the body
-		 * of the function.  If we find a "this." we know
-		 * it is a class, otherwise it is a function.
-		 */
-		parseBlock (token, token);
-	} 
-	else 
-	{
-		findCmdTerm (token);
-
-		/*
-		 * The IF could be followed by an ELSE statement.
-		 * This too could have two formats, a curly braced
-		 * multiline section, or another single line.
-		 */
-
-		if (isType (token, TOKEN_CLOSE_CURLY)) 
-		{
-			/*
-			 * This statement did not have a line terminator.
-			 */
-			read_next_token = FALSE;
-		} 
-		else 
-		{
-			readToken (token);
-
-			if (isType (token, TOKEN_CLOSE_CURLY)) 
-			{
-				/*
-				* This statement did not have a line terminator.
-				*/
-				read_next_token = FALSE;
-			} 
-			else
-			{
-				if (isKeyword (token, KEYWORD_else))
-					read_next_token = parseIf (token); 
-			}
-		} 
-	}
-	return read_next_token;
-}
-
-static void parseFunction (tokenInfo *const token)
-{
-	tokenInfo *const name = newToken ();
-
-	/*
-	 * This deals with these formats
-     *     private static function ioErrorHandler( event:IOErrorEvent ):void {
-	 */
-
-	if ( isKeyword(token, KEYWORD_function) )
-	{
-		readToken (token);
-	}
-
-	copyToken (name, token);
-	/* Add scope in case this is an INNER function 
-	addToScope(name, token->scope);
-	*/
-
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseFunction: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseFunction: name isClass:%d  scope:%s  name:%s\n"
-				, name->isClass
-				, vStringValue(name->scope)
-				, vStringValue(name->string)
-				);
-			);
-
-	readToken (token);
-
-	if ( isType (token, TOKEN_OPEN_PAREN) )
-		skipArgumentList(token);
-
-	if ( isType (token, TOKEN_COLON) )
-	{
-		/*
-		 *   function fname ():ReturnType 
-		 */
-		readToken (token);
-		readToken (token);
-	}
-
-	if ( isType (token, TOKEN_OPEN_CURLY) )
-	{
-		DebugStatement ( 
-				debugPrintf (DEBUG_PARSE
-					, "\n parseFunction end: name isClass:%d  scope:%s  name:%s\n"
-					, name->isClass
-					, vStringValue(name->scope)
-					, vStringValue(name->string)
-					);
-				);
-		parseBlock (token, name);
-		DebugStatement ( 
-				debugPrintf (DEBUG_PARSE
-					, "\n parseFunction end2: token isClass:%d  scope:%s  name:%s\n"
-					, token->isClass
-					, vStringValue(token->scope)
-					, vStringValue(token->string)
-					);
-				);
-		DebugStatement ( 
-				debugPrintf (DEBUG_PARSE
-					, "\n parseFunction end2: token isClass:%d  scope:%s  name:%s\n"
-					, token->isClass
-					, vStringValue(token->scope)
-					, vStringValue(token->string)
-					);
-				);
-		DebugStatement ( 
-				debugPrintf (DEBUG_PARSE
-					, "\n parseFunction end3: name isClass:%d  scope:%s  name:%s\n"
-					, name->isClass
-					, vStringValue(name->scope)
-					, vStringValue(name->string)
-					);
-				);
-		makeFunctionTag (name);
-	}
-
-	findCmdTerm (token);
-
-	deleteToken (name);
-}
-
-static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent)
-{
-	boolean read_next_token = TRUE;
-	vString * saveScope = vStringNew ();
-
-	vStringClear(saveScope);
-	vStringCopy (saveScope, token->scope);
-	token->nestLevel++;
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseBlock start: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	/*
-	 * Make this routine a bit more forgiving.
-	 * If called on an open_curly advance it
-	 */
-	if ( isType (token, TOKEN_OPEN_CURLY) && 
-			isKeyword(token, KEYWORD_NONE) )
-		readToken(token);
-
-	if (! isType (token, TOKEN_CLOSE_CURLY))
-	{
-		/*
-		 * Read until we find the closing brace, 
-		 * any nested braces will be handled within
-		 */
-		do
-		{
-			if (isType (token, TOKEN_OPEN_CURLY))
-			{
-				/* Handle nested blocks */
-				parseBlock (token, parent);
-			} 
-			else 
-			{
-				/*
-				 * It is possible for a line to have no terminator
-				 * if the following line is a closing brace.
-				 * parseLine will detect this case and indicate
-				 * whether we should read an additional token.
-				 */
-				read_next_token = parseLine (token);
-			}
-
-			/*
-			 * Always read a new token unless we find a statement without
-			 * a ending terminator
-			 */
-			if( read_next_token ) 
-				readToken(token);
-
-			/*
-			 * If we find a statement without a terminator consider the 
-			 * block finished, otherwise the stack will be off by one.
-			 */
-		} while (! isType (token, TOKEN_CLOSE_CURLY) && read_next_token );
-	}
-
-	vStringDelete(saveScope);
-	token->nestLevel--;
-
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseBlock end: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	return FALSE;
-}
-
-static void parseMethods (tokenInfo *const token, tokenInfo *const class)
-{
-	tokenInfo *const name = newToken ();
-
-	/*
-	 * This deals with these formats
-	 *	   validProperty  : 2,
-	 *	   validMethod    : function(a,b) {}
-	 *	   'validMethod2' : function(a,b) {}
-     *     container.dirtyTab = {'url': false, 'title':false, 'snapshot':false, '*': false}		
-	 */
-
-	do
-	{
-		readToken (token);
-		if (isType (token, TOKEN_STRING) || isKeyword(token, KEYWORD_NONE))
-		{
-			copyToken (name, token);
-
-			readToken (token);
-			if ( isType (token, TOKEN_COLON) )
-			{
-				readToken (token);
-				if ( isKeyword (token, KEYWORD_function) )
-				{
-					readToken (token);
-					if ( isType (token, TOKEN_OPEN_PAREN) )
-					{
-						skipArgumentList(token);
-					}
-
-					if (isType (token, TOKEN_OPEN_CURLY)) 
-					{
-						addToScope (name, class->string);
-						makeFlexTag (name, FLEXTAG_METHOD);
-						parseBlock (token, name);
-
-						/*
-						 * Read to the closing curly, check next
-						 * token, if a comma, we must loop again
-						 */
-						readToken (token);
-					}
-				}
-				else
-				{
-						addToScope (name, class->string);
-						makeFlexTag (name, FLEXTAG_PROPERTY);
-
-						/*
-						 * Read the next token, if a comma
-						 * we must loop again
-						 */
-						readToken (token);
-				}
-			}
-		}
-	} while ( isType(token, TOKEN_COMMA) );
-
-	findCmdTerm (token);
-
-	deleteToken (name);
-}
-
-static boolean parseVar (tokenInfo *const token, boolean is_public)
-{
-	tokenInfo *const name = newToken ();
-	tokenInfo *const secondary_name = newToken ();
-	vString * saveScope = vStringNew ();
-	boolean is_terminated = TRUE;
-
-	vStringClear(saveScope);
-	vStringCopy (saveScope, token->scope);
-	/*
-	 * Variables are defined as:
-	 *     private static var lastFaultMessage:Date = new Date( 0 );
-	 *     private static var webRequests:ArrayCollection = new ArrayCollection();
-	 */
-
-	if ( isKeyword(token, KEYWORD_var) )
-	{
-		readToken(token);
-	}
-
-	/* Variable name */
-	copyToken (name, token);
-	readToken(token);
-
-	if ( isType (token, TOKEN_COLON) )
-	{
-		/*
-		 *   var vname ():DataType = new Date();
-		 *   var vname ():DataType;
-		 */
-		readToken (token);
-		readToken (token);
-	}
-
-	while (! isType (token, TOKEN_SEMICOLON) )
-	{
-		readToken (token);
-	}
-
-	if ( isType (token, TOKEN_SEMICOLON) )
-	{
-		/*
-		 * Only create variables for global scope
-		 */
-		/* if ( token->nestLevel == 0 && is_global ) */
-		if ( is_public )
-		{
-			if (isType (token, TOKEN_SEMICOLON)) 
-				makeFlexTag (name, FLEXTAG_VARIABLE);
-		}
-	}
-
-	vStringCopy(token->scope, saveScope);
-	deleteToken (name);
-	deleteToken (secondary_name);
-	vStringDelete(saveScope);
-
-	return is_terminated;
-}
-
-static boolean parseClass (tokenInfo *const token)
-{
-	tokenInfo *const name = newToken ();
-	vString * saveScope = vStringNew ();
-	boolean saveIsClass = token->isClass;
-
-	vStringClear(saveScope);
-	vStringCopy (saveScope, token->scope);
-	/*
-	 * Variables are defined as:
-	 *     private static var lastFaultMessage:Date = new Date( 0 );
-	 *     private static var webRequests:ArrayCollection = new ArrayCollection();
-	 */
-
-	if ( isKeyword(token, KEYWORD_class) )
-	{
-		readToken(token);
-	}
-
-	token->isClass = TRUE;
-	/* Add class name to scope */
-	addToScope(token, token->string);
-	/* Class name */
-	copyToken (name, token);
-	readToken(token);
-
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseClass start: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	if ( isType (token, TOKEN_OPEN_CURLY) )
-	{
-		makeClassTag (name);
-		parseBlock (token, name);
-	}
-
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseClass end: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	vStringCopy(token->scope, saveScope);
-	token->isClass = saveIsClass;
-	deleteToken (name);
-	vStringDelete(saveScope);
-
-	return TRUE;
-}
-
-static boolean parseStatement (tokenInfo *const token)
-{
-	tokenInfo *const name = newToken ();
-	tokenInfo *const secondary_name = newToken ();
-	vString * saveScope = vStringNew ();
-	boolean is_public = FALSE;
-	boolean is_class = FALSE;
-	boolean is_terminated = TRUE;
-	boolean is_global = FALSE;
-	boolean is_prototype = FALSE;
-	vString *	fulltag;
-
-	vStringClear(saveScope);
-	vStringCopy (saveScope, token->scope);
-	DebugStatement ( 
-			debugPrintf (DEBUG_PARSE
-				, "\n parseStatement: token isClass:%d  scope:%s  name:%s\n"
-				, token->isClass
-				, vStringValue(token->scope)
-				, vStringValue(token->string)
-				);
-			);
-	/*
-	 * Functions can be named or unnamed.
-	 * This deals with these formats:
-	 * Function
-	 *	   validFunctionOne = function(a,b) {}
-	 *	   testlib.validFunctionFive = function(a,b) {}
-	 *	   var innerThree = function(a,b) {}
-	 *	   var innerFour = (a,b) {}
-	 *	   var D2 = secondary_fcn_name(a,b) {}
-	 *	   var D3 = new Function("a", "b", "return a+b;");
-	 * Class
-	 *	   testlib.extras.ValidClassOne = function(a,b) {
-	 *		   this.a = a; 
-	 *	   }
-	 * Class Methods
-	 *	   testlib.extras.ValidClassOne.prototype = {
-	 *		   'validMethodOne' : function(a,b) {},
-	 *		   'validMethodTwo' : function(a,b) {}
-	 *	   }
-     *     ValidClassTwo = function () 
-     *     {
-     *         this.validMethodThree = function() {}
-     *         // unnamed method
-     *         this.validMethodFour = () {}
-     *     }
-	 *	   Database.prototype.validMethodThree = Database_getTodaysDate;
-	 */
-
-	if ( isKeyword(token, KEYWORD_public) )
-	{
-		is_public = TRUE;
-		readToken(token);
-	}
-
-	if ( isKeyword(token, KEYWORD_private) )
-	{
-		readToken(token);
-	}
-
-	if ( isKeyword(token, KEYWORD_static) )
-	{
-		readToken(token);
-	}
-
-	if (isType(token, TOKEN_KEYWORD))
-	{
-		switch (token->keyword)
-		{
-			case KEYWORD_for:	   
-			case KEYWORD_while:
-			case KEYWORD_do:
-				parseLoop (token); 
-				break;
-			case KEYWORD_if:
-			case KEYWORD_else:
-			case KEYWORD_try:
-			case KEYWORD_catch:
-			case KEYWORD_finally:
-				/* Common semantics */
-				is_terminated = parseIf (token); 
-				break;
-			case KEYWORD_switch:
-				parseSwitch (token); 
-				break;
-			case KEYWORD_class:
-				parseClass (token); 
-				return is_terminated;
-				break;
-			case KEYWORD_function:
-				parseFunction (token); 
-				return is_terminated;
-				break;
-			case KEYWORD_var:
-				parseVar (token, is_public); 
-				return is_terminated;
-				break;
-			default:
-				readToken(token);
-				break;
-		}
-	} 
-
-	copyToken (name, token);
-
-	while (! isType (token, TOKEN_CLOSE_CURLY) &&
-	       ! isType (token, TOKEN_SEMICOLON)   &&
-	       ! isType (token, TOKEN_EQUAL_SIGN)  )
-	{
-		/* Potentially the name of the function */
-		readToken (token);
-		if (isType (token, TOKEN_PERIOD))
-		{
-			/*
-			 * Cannot be a global variable is it has dot references in the name
-			 */
-			is_global = FALSE;
-			do
-			{
-				readToken (token);
-				if ( isKeyword(token, KEYWORD_NONE) )
-				{
-					if ( is_class )
-					{
-						vStringCopy(saveScope, token->scope);
-						addToScope(token, name->string);
-					} 
-					else 
-						addContext (name, token);
-				} 
-				else if ( isKeyword(token, KEYWORD_prototype) ) 
-				{
-					/*
-					 * When we reach the "prototype" tag, we infer:
-					 *     "BindAgent" is a class
-					 *     "build"     is a method
-					 *
-					 * function BindAgent( repeatableIdName, newParentIdName ) {
-					 * }	
-					 *
-					 * CASE 1
-					 * Specified function name: "build"
-					 *     BindAgent.prototype.build = function( mode ) {
-					 *     	  ignore everything within this function
-					 *     }
-					 *
-					 * CASE 2
-					 * Prototype listing
-					 *     ValidClassOne.prototype = {
-					 *         'validMethodOne' : function(a,b) {},
-					 *         'validMethodTwo' : function(a,b) {}
-					 *     }
-					 *
-					 */
-					makeClassTag (name);
-					is_class = TRUE;
-					is_prototype = TRUE;
-
-					/*
-					 * There should a ".function_name" next.
-					 */
-					readToken (token);
-					if (isType (token, TOKEN_PERIOD))
-					{
-						/*
-						 * Handle CASE 1
-						 */
-						readToken (token);
-						if ( isKeyword(token, KEYWORD_NONE) )
-						{
-							vStringCopy(saveScope, token->scope);
-							addToScope(token, name->string);
-
-							makeFlexTag (token, FLEXTAG_METHOD);
-							/*
-							 * We can read until the end of the block / statement.
-							 * We need to correctly parse any nested blocks, but
-							 * we do NOT want to create any tags based on what is
-							 * within the blocks.
-							 */
-							token->ignoreTag = TRUE;
-							/*
-							 * Find to the end of the statement 
-							 */
-							findCmdTerm (token);
-							token->ignoreTag = FALSE;
-							is_terminated = TRUE;
-							goto cleanUp;
-						}
-					} 
-					else if (isType (token, TOKEN_EQUAL_SIGN)) 
-					{
-						readToken (token);
-						if (isType (token, TOKEN_OPEN_CURLY)) 
-						{
-							/*
-							 * Handle CASE 2
-							 *
-							 * Creates tags for each of these class methods
-							 *     ValidClassOne.prototype = {
-							 *         'validMethodOne' : function(a,b) {},
-							 *         'validMethodTwo' : function(a,b) {}
-							 *     }
-							 */
-							parseMethods(token, name);
-							/*
-							 * Find to the end of the statement 
-							 */
-							findCmdTerm (token);
-							token->ignoreTag = FALSE;
-							is_terminated = TRUE;
-							goto cleanUp;
-						}
-					}
-				}
-				readToken (token);
-			} while (isType (token, TOKEN_PERIOD));
-		}
-
-		if ( isType (token, TOKEN_OPEN_PAREN) )
-			skipArgumentList(token);
-
-		if ( isType (token, TOKEN_COLON) )
-		{
-			/*
-			 * Functions are of this form:
-			 *   function fname ():ReturnType {
-			 */
-			readToken (token);
-			readToken (token);
-		}
-
-		if ( isType (token, TOKEN_OPEN_SQUARE) )
-			skipArrayList(token);
-
-	}
-
-	if ( isType (token, TOKEN_CLOSE_CURLY) )
-	{
-		/*
-		 * Reaching this section without having
-		 * processed an open curly brace indicates
-		 * the statement is most likely not terminated.
-		 */
-		is_terminated = FALSE;
-		goto cleanUp;
-	}
-
-	if ( isType (token, TOKEN_SEMICOLON) )
-	{
-		/*
-		 * Only create variables for global scope
-		 */
-		if ( token->nestLevel == 0 && is_global )
-		{
-			/*
-			 * Handles this syntax:
-			 *	   var g_var2;
-			 */
-			if (isType (token, TOKEN_SEMICOLON)) 
-				makeFlexTag (name, FLEXTAG_VARIABLE);
-		}
-		/* 
-		 * Statement has ended.
-		 * This deals with calls to functions, like:
-		 *     alert(..);
-		 */
-		goto cleanUp;
-	}
-
-	if ( isType (token, TOKEN_EQUAL_SIGN) )
-	{
-		readToken (token);
-
-		if ( isKeyword (token, KEYWORD_function) )
-		{
-			readToken (token);
-
-			if ( isKeyword (token, KEYWORD_NONE) && 
-					! isType (token, TOKEN_OPEN_PAREN) )
-			{
-				/*
-				 * Functions of this format:
-				 *	   var D2A = function theAdd(a, b) 
-				 *	   {					 
-				 *		  return a+b;
-				 *	   }					 
-				 * Are really two separate defined functions and 
-				 * can be referenced in two ways:
-				 *	   alert( D2A(1,2) );			  // produces 3
-				 *	   alert( theAdd(1,2) );		  // also produces 3
-				 * So it must have two tags:
-				 *	   D2A
-				 *	   theAdd
-				 * Save the reference to the name for later use, once
-				 * we have established this is a valid function we will
-				 * create the secondary reference to it.
-				 */
-				copyToken (secondary_name, token);
-				readToken (token);
-			}
-
-			if ( isType (token, TOKEN_OPEN_PAREN) )
-				skipArgumentList(token);
-
-			if (isType (token, TOKEN_OPEN_CURLY)) 
-			{
-				/*
-				 * This will be either a function or a class.
-				 * We can only determine this by checking the body
-				 * of the function.  If we find a "this." we know
-				 * it is a class, otherwise it is a function.
-				 */
-				if ( token->isClass ) 
-				{
-					makeFlexTag (name, FLEXTAG_METHOD);
-					if ( vStringLength(secondary_name->string) > 0 )
-						makeFunctionTag (secondary_name);
-					parseBlock (token, name);
-				} 
-				else 
-				{
-					parseBlock (token, name);
-					makeFunctionTag (name);
-
-					if ( vStringLength(secondary_name->string) > 0 )
-						makeFunctionTag (secondary_name);
-
-					/*
-					 * Find to the end of the statement 
-					 */
-					goto cleanUp;
-				}
-			}
-		} 
-		else if (isType (token, TOKEN_OPEN_PAREN)) 
-		{
-			/*
-			 * Handle nameless functions
-			 *     this.method_name = () {}
-			 */
-			skipArgumentList(token);
-
-			if (isType (token, TOKEN_OPEN_CURLY)) 
-			{
-				/*
-				 * Nameless functions are only setup as methods.
-				 */
-				makeFlexTag (name, FLEXTAG_METHOD);
-				parseBlock (token, name);
-			}
-		} 
-		else if (isType (token, TOKEN_OPEN_CURLY)) 
-		{
-			/*
-			 * Creates tags for each of these class methods
-			 *     ValidClassOne.prototype = {
-			 *         'validMethodOne' : function(a,b) {},
-			 *         'validMethodTwo' : function(a,b) {}
-			 *     }
-			 */
-			parseMethods(token, name);
-			if (isType (token, TOKEN_CLOSE_CURLY)) 
-			{
-				/*
-				 * Assume the closing parantheses terminates
-				 * this statements.
-				 */
-				is_terminated = TRUE;
-			}
-		}
-		else if (isKeyword (token, KEYWORD_new))
-		{
-			readToken (token);
-			if ( isKeyword (token, KEYWORD_function) || 
-					isKeyword (token, KEYWORD_capital_function) ||
-					isKeyword (token, KEYWORD_object) ||
-					isKeyword (token, KEYWORD_capital_object) )
-			{
-				if ( isKeyword (token, KEYWORD_object) || 
-						isKeyword (token, KEYWORD_capital_object) )
-					is_class = TRUE;
-
-				readToken (token);
-				if ( isType (token, TOKEN_OPEN_PAREN) )
-					skipArgumentList(token);
-
-				if (isType (token, TOKEN_SEMICOLON)) 
-				{
-					if ( token->nestLevel == 0 )
-					{
-						if ( is_class )
-						{
-							makeClassTag (name);
-						} else {
-							makeFunctionTag (name);
-						}
-					}
-				}
-			}
-		}
-		else if (isKeyword (token, KEYWORD_NONE))
-		{
-			/*
-			 * Only create variables for global scope
-			 */
-			if ( token->nestLevel == 0 && is_global )
-			{
-				/*
-				 * A pointer can be created to the function.  
-				 * If we recognize the function/class name ignore the variable.
-				 * This format looks identical to a variable definition.
-				 * A variable defined outside of a block is considered
-				 * a global variable:
-				 *	   var g_var1 = 1;
-				 *	   var g_var2;
-				 * This is not a global variable:
-				 *	   var g_var = function;
-				 * This is a global variable:
-				 *	   var g_var = different_var_name;
-				 */
-				fulltag = vStringNew ();
-				if (vStringLength (token->scope) > 0)
-				{
-					vStringCopy(fulltag, token->scope);
-					vStringCatS (fulltag, ".");
-					vStringCatS (fulltag, vStringValue(token->string));
-				}
-				else
-				{
-					vStringCopy(fulltag, token->string);
-				}
-				vStringTerminate(fulltag);
-				if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
-						! stringListHas(ClassNames, vStringValue (fulltag)) )
-				{
-					findCmdTerm (token);
-					if (isType (token, TOKEN_SEMICOLON)) 
-						makeFlexTag (name, FLEXTAG_VARIABLE);
-				}
-				vStringDelete (fulltag);
-			}
-		}
-	}
-	findCmdTerm (token);
-
-	/*
-	 * Statements can be optionally terminated in the case of 
-	 * statement prior to a close curly brace as in the
-	 * document.write line below:
-	 *
-	 * function checkForUpdate() {
-	 *	   if( 1==1 ) {
-	 *		   document.write("hello from checkForUpdate<br>")
-	 *	   }
-	 *	   return 1;
-	 * }
-	 */
-	if ( ! is_terminated && isType (token, TOKEN_CLOSE_CURLY)) 
-		is_terminated = FALSE;
-
-
-cleanUp:
-	vStringCopy(token->scope, saveScope);
-	deleteToken (name);
-	deleteToken (secondary_name);
-	vStringDelete(saveScope);
-
-	return is_terminated;
-}
-
-static boolean parseLine (tokenInfo *const token)
-{
-	boolean is_terminated = TRUE;
-	/*
-	 * Detect the common statements, if, while, for, do, ...
-	 * This is necessary since the last statement within a block "{}"
-	 * can be optionally terminated.
-	 *
-	 * If the statement is not terminated, we need to tell
-	 * the calling routine to prevent reading an additional token
-	 * looking for the end of the statement.
-	 */
-
-	if (isType(token, TOKEN_KEYWORD))
-	{
-		switch (token->keyword)
-		{
-			case KEYWORD_for:	   
-			case KEYWORD_while:
-			case KEYWORD_do:
-				parseLoop (token); 
-				break;
-			case KEYWORD_if:
-			case KEYWORD_else:
-			case KEYWORD_try:
-			case KEYWORD_catch:
-			case KEYWORD_finally:
-				/* Common semantics */
-				is_terminated = parseIf (token); 
-				break;
-			case KEYWORD_switch:
-				parseSwitch (token); 
-				break;
-			default:			   
-				parseStatement (token); 
-				break;
-		}
-	} 
-	else 
-	{
-		/*
-		 * Special case where single line statements may not be
-		 * SEMICOLON terminated.  parseBlock needs to know this
-		 * so that it does not read the next token.
-		 */
-		is_terminated = parseStatement (token); 
-	}
-	return is_terminated;
-}
-
-static boolean parseCDATA (tokenInfo *const token)
-{
-	if (isType (token, TOKEN_LESS_THAN))
-	{
-		/*
-		 * Handle these tags 
-		 * <![CDATA[
-		 *    ...
-		 * ]]>
-		 */
-		readToken (token);
-		if (isType (token, TOKEN_EXCLAMATION))
-		{
-			/*
-			 * Not sure why I had to comment these out, but I did.
-			 * readToken (token);
-			 * if (isType (token, TOKEN_OPEN_SQUARE))
-			 * {
-			*/
-				readToken (token);
-				if (isKeyword (token, KEYWORD_cdata))
-				{
-					readToken (token);
-					if (isType (token, TOKEN_OPEN_SQUARE))
-					{
-						parseActionScript (token);
-						if (isType (token, TOKEN_CLOSE_SQUARE))
-						{
-							readToken (token);
-							if (isType (token, TOKEN_CLOSE_SQUARE))
-							{
-								readToken (token);
-							}
-						}
-					}
-				}
-			/*} Not sure */
-		}
-	}
-	else
-	{
-		parseActionScript (token);
-	}
-	return TRUE;
-}
-
-static boolean parseMXML (tokenInfo *const token)
-{
-	tokenInfo *const name = newToken ();
-	tokenInfo *const type = newToken ();
-	/*
-	 * Detect the common statements, if, while, for, do, ...
-	 * This is necessary since the last statement within a block "{}"
-	 * can be optionally terminated.
-	 *
-	 * If the statement is not terminated, we need to tell
-	 * the calling routine to prevent reading an additional token
-	 * looking for the end of the statement.
-	 */
-
-	readToken (token);
-
-	if (isKeyword (token, KEYWORD_script))
-	{
-		/*
-		 * These tags can be of this form:
-		 * <mx:Script src="filename.as" />
-		 */
-		do
-		{
-			readToken (token);
-		} while (! (isType (token, TOKEN_CLOSE_SGML) || 
-					isType (token, TOKEN_CLOSE_MXML) ||
-					isType (token, TOKEN_GREATER_THAN)) ); 
-
-		if (isType (token, TOKEN_CLOSE_MXML))
-		{
-			/*
-			 * We have found a </mx:type> tag 
-			 * Finish reading the "type" and ">"
-			 */
-			readToken (token);
-			readToken (token);
-			goto cleanUp;
-		}
-		if (isType (token, TOKEN_CLOSE_SGML))
-		{
-			/*
-			 * We have found a <mx:Script src="filename.as" />
-			 */
-			goto cleanUp;
-		}
-
-		/*
-		 * This is a beginning of an embedded script.
-		 * These typically are of this format:
-		 *    <mx:Script>
-		 *        <![CDATA[
-		 *        ... ActionScript ...
-		 *        ]]>
-		 *    </mx:Script>
-		 */
-		readToken (token);
-		parseCDATA (token);
-
-		readToken (token);
-		if (isType (token, TOKEN_CLOSE_MXML))
-		{
-			/*
-			 * We have found a </mx:type> tag 
-			 * Finish reading the "type" and ">"
-			 */
-			readToken (token);
-			readToken (token);
-		}
-		goto cleanUp;
-	}
-
-	copyToken (type, token);
-
-	readToken (token);
-	do
-	{
-		if (isType (token, TOKEN_OPEN_MXML))
-		{
-			parseMXML (token);
-		}
-		else if (isKeyword (token, KEYWORD_id))
-		{
-			/* = */
-			readToken (token);
-			readToken (token);
-
-			copyToken (name, token);
-			addToScope (name, type->string);
-			makeMXTag (name);
-		}
-		readToken (token);
-	} while (! (isType (token, TOKEN_CLOSE_SGML) || isType (token, TOKEN_CLOSE_MXML)) ); 
-
-	if (isType (token, TOKEN_CLOSE_MXML))
-	{
-		/*
-		 * We have found a </mx:type> tag 
-		 * Finish reading the "type" and ">"
-		 */
-		readToken (token);
-		readToken (token);
-	}
-
-cleanUp:
-	deleteToken (name);
-	deleteToken (type);
-	return TRUE;
-}
-
-static boolean parseActionScript (tokenInfo *const token)
-{
-	do
-	{
-		readToken (token);
-
-		if (isType (token, TOKEN_LESS_THAN))
-		{
-			/*
-			 * Handle these tags 
-			 * <![CDATA[
-			 *    ...
-			 * ]]>
-			 */
-			readToken (token);
-			if (isType (token, TOKEN_EQUAL_SIGN))
-			{
-				if (isType (token, TOKEN_OPEN_SQUARE))
-				{
-					readToken (token);
-					if (isKeyword (token, KEYWORD_cdata))
-					{
-						readToken (token);
-					}
-				}
-			}
-		}
-		if (isType (token, TOKEN_CLOSE_SQUARE))
-		{
-			/*
-			 * Handle these tags 
-			 * <![CDATA[
-			 *    ...
-			 * ]]>
-			 */
-			readToken (token);
-			if (isType (token, TOKEN_CLOSE_SQUARE))
-			{
-				readToken (token);
-				if (isType (token, TOKEN_GREATER_THAN))
-				{
-					return TRUE;
-				}
-			}
-		}
-		else if (isType (token, TOKEN_CLOSE_MXML))
-		{
-			/*
-			 * Read the Script> tags 
-			 */
-			readToken (token);
-			readToken (token);
-			return TRUE;
-		} 
-		else if (isType (token, TOKEN_OPEN_MXML))
-		{
-			parseMXML (token);
-		} 
-		else 
-		{
-			if (isType(token, TOKEN_KEYWORD))
-			{
-				switch (token->keyword)
-				{
-					case KEYWORD_function:	parseFunction (token); break;
-					default:				parseLine (token); break;
-				}
-			} 
-			else 
-			{
-				parseLine (token); 
-			}
-		}
-	} while (TRUE);
-}
-
-static void parseFlexFile (tokenInfo *const token)
-{
-	do
-	{
-		readToken (token);
-
-		if (isType (token, TOKEN_OPEN_MXML))
-		{
-			parseMXML (token);
-		} 
-		if (isType (token, TOKEN_LESS_THAN))
-		{
-			readToken (token);
-			if (isType (token, TOKEN_QUESTION_MARK))
-			{
-				readToken (token);
-				while (! isType (token, TOKEN_QUESTION_MARK) )
-				{
-					readToken (token);
-				} 
-				readToken (token);
-			}
-		} 
-		else 
-		{
-			parseActionScript (token);
-		}
-	} while (TRUE);
-}
-
-static void initialize (const langType language)
-{
-	Assert (sizeof (FlexKinds) / sizeof (FlexKinds [0]) == FLEXTAG_COUNT);
-	Lang_js = language;
-	buildFlexKeywordHash ();
-}
-
-static void findFlexTags (void)
-{
-	tokenInfo *const token = newToken ();
-	exception_t exception;
-	
-	ClassNames = stringListNew ();
-	FunctionNames = stringListNew ();
-	
-	exception = (exception_t) (setjmp (Exception));
-	while (exception == ExceptionNone)
-		parseFlexFile (token);
-
-	stringListDelete (ClassNames);
-	stringListDelete (FunctionNames);
-	ClassNames = NULL;
-	FunctionNames = NULL;
-	deleteToken (token);
-}
-
-/* Create parser definition stucture */
-extern parserDefinition* FlexParser (void)
-{
-	static const char *const extensions [] = { "as", "mxml", NULL };
-	parserDefinition *const def = parserNew ("Flex");
-	def->extensions = extensions;
-	/*
-	 * New definitions for parsing instead of regex
-	 */
-	def->kinds		= FlexKinds;
-	def->kindCount	= KIND_COUNT (FlexKinds);
-	def->parser		= findFlexTags;
-	def->initialize = initialize;
-
-	return def;
-}
-/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
+/*
+ *	 $Id: flex.c 666 2008-05-15 17:47:31Z dfishburn $
+ *
+ *	 Copyright (c) 2008, David Fishburn
+ *
+ *	 This source code is released for free distribution under the terms of the
+ *	 GNU General Public License.
+ *
+ *	 This module contains functions for generating tags for Adobe languages.
+ *	 There are a number of different ones, but this will begin with:
+ *	     Flex
+ *	         MXML files (*.mMacromedia XML)
+ *	         ActionScript files (*.as)
+ *
+ *	 Flex 3 language reference
+ *		 http://livedocs.adobe.com/flex/3/langref/index.html
+ */
+
+/*
+ *	 INCLUDE FILES
+ */
+#include "general.h"	/* must always come first */
+#include <ctype.h>	/* to define isalpha () */
+#include <setjmp.h>
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "debug.h"
+#include "entry.h"
+#include "keyword.h"
+#include "parse.h"
+#include "read.h"
+#include "routines.h"
+#include "vstring.h"
+
+/*
+ *	 MACROS
+ */
+#define isType(token,t)		(boolean) ((token)->type == (t))
+#define isKeyword(token,k)	(boolean) ((token)->keyword == (k))
+
+/*
+ *	 DATA DECLARATIONS
+ */
+
+typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
+
+/*
+ * Tracks class and function names already created
+ */
+static stringList *ClassNames;
+static stringList *FunctionNames;
+
+/*	Used to specify type of keyword.
+*/
+typedef enum eKeywordId {
+	KEYWORD_NONE = -1,
+	KEYWORD_function,
+	KEYWORD_capital_function,
+	KEYWORD_object,
+	KEYWORD_capital_object,
+	KEYWORD_prototype,
+	KEYWORD_var,
+	KEYWORD_new,
+	KEYWORD_this,
+	KEYWORD_for,
+	KEYWORD_while,
+	KEYWORD_do,
+	KEYWORD_if,
+	KEYWORD_else,
+	KEYWORD_switch,
+	KEYWORD_try,
+	KEYWORD_catch,
+	KEYWORD_finally,
+	KEYWORD_public,
+	KEYWORD_private,
+	KEYWORD_static,
+	KEYWORD_class,
+	KEYWORD_id,
+	KEYWORD_script,
+	KEYWORD_cdata,
+	KEYWORD_mx
+} keywordId;
+
+/*	Used to determine whether keyword is valid for the token language and
+ *	what its ID is.
+ */
+typedef struct sKeywordDesc {
+	const char *name;
+	keywordId id;
+} keywordDesc;
+
+typedef enum eTokenType {
+	TOKEN_UNDEFINED,
+	TOKEN_CHARACTER,
+	TOKEN_CLOSE_PAREN,
+	TOKEN_SEMICOLON,
+	TOKEN_COLON,
+	TOKEN_COMMA,
+	TOKEN_KEYWORD,
+	TOKEN_OPEN_PAREN,
+	TOKEN_OPERATOR,
+	TOKEN_IDENTIFIER,
+	TOKEN_STRING,
+	TOKEN_PERIOD,
+	TOKEN_OPEN_CURLY,
+	TOKEN_CLOSE_CURLY,
+	TOKEN_EQUAL_SIGN,
+	TOKEN_EXCLAMATION,
+	TOKEN_FORWARD_SLASH,
+	TOKEN_OPEN_SQUARE,
+	TOKEN_CLOSE_SQUARE,
+	TOKEN_OPEN_MXML,
+	TOKEN_CLOSE_MXML,
+	TOKEN_CLOSE_SGML,
+	TOKEN_LESS_THAN,
+	TOKEN_GREATER_THAN,
+	TOKEN_QUESTION_MARK
+} tokenType;
+
+typedef struct sTokenInfo {
+	tokenType		type;
+	keywordId		keyword;
+	vString *		string;
+	vString *		scope;
+	unsigned long 	lineNumber;
+	fpos_t 			filePosition;
+	int				nestLevel;
+	boolean			ignoreTag;
+	boolean			isClass;
+} tokenInfo;
+
+/*
+ *	DATA DEFINITIONS
+ */
+
+static langType Lang_js;
+
+static jmp_buf Exception;
+
+typedef enum {
+	FLEXTAG_FUNCTION,
+	FLEXTAG_CLASS,
+	FLEXTAG_METHOD,
+	FLEXTAG_PROPERTY,
+	FLEXTAG_VARIABLE,
+	FLEXTAG_MXTAG,
+	FLEXTAG_COUNT
+} flexKind;
+
+static kindOption FlexKinds [] = {
+	{ TRUE,  'f', "function",	  "functions"		   },
+	{ TRUE,  'c', "class",		  "classes"			   },
+	{ TRUE,  'm', "method",		  "methods"			   },
+	{ TRUE,  'p', "property",	  "properties"		   },
+	{ TRUE,  'v', "variable",	  "global variables"   },
+	{ TRUE,  'x', "mxtag",		  "mxtags" 			   }
+};
+
+static const keywordDesc FlexKeywordTable [] = {
+	/* keyword		keyword ID */
+	{ "function",	KEYWORD_function			},
+	{ "Function",	KEYWORD_capital_function	},
+	{ "object",		KEYWORD_object				},
+	{ "Object",		KEYWORD_capital_object		},
+	{ "prototype",	KEYWORD_prototype			},
+	{ "var",		KEYWORD_var					},
+	{ "new",		KEYWORD_new					},
+	{ "this",		KEYWORD_this				},
+	{ "for",		KEYWORD_for					},
+	{ "while",		KEYWORD_while				},
+	{ "do",			KEYWORD_do					},
+	{ "if",			KEYWORD_if					},
+	{ "else",		KEYWORD_else				},
+	{ "switch",		KEYWORD_switch				},
+	{ "try",		KEYWORD_try					},
+	{ "catch",		KEYWORD_catch				},
+	{ "finally",	KEYWORD_finally				},
+	{ "public",		KEYWORD_public				},
+	{ "private",	KEYWORD_private				},
+	{ "static",		KEYWORD_static				},
+	{ "class",		KEYWORD_class				},
+	{ "id",			KEYWORD_id					},
+	{ "script",		KEYWORD_script				},
+	{ "cdata",		KEYWORD_cdata				},
+	{ "mx",			KEYWORD_mx					}
+};
+
+/*
+ *	 FUNCTION DEFINITIONS
+ */
+
+/* Recursive functions */
+static void parseFunction (tokenInfo *const token);
+static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent);
+static boolean parseLine (tokenInfo *const token);
+static boolean parseActionScript (tokenInfo *const token);
+
+static boolean isIdentChar (const int c)
+{
+	return (boolean)
+		(isalpha (c) || isdigit (c) || c == '$' || 
+		 c == '@' || c == '_' || c == '#');
+}
+
+static void buildFlexKeywordHash (void)
+{
+	const size_t count = sizeof (FlexKeywordTable) /
+		sizeof (FlexKeywordTable [0]);
+	size_t i;
+	for (i = 0	;  i < count  ;  ++i)
+	{
+		const keywordDesc* const p = &FlexKeywordTable [i];
+		addKeyword (p->name, Lang_js, (int) p->id);
+	}
+}
+
+static tokenInfo *newToken (void)
+{
+	tokenInfo *const token = xMalloc (1, tokenInfo);
+
+	token->type			= TOKEN_UNDEFINED;
+	token->keyword		= KEYWORD_NONE;
+	token->string		= vStringNew ();
+	token->scope		= vStringNew ();
+	token->nestLevel	= 0;
+	token->isClass		= FALSE;
+	token->ignoreTag	= FALSE;
+	token->lineNumber   = getSourceLineNumber ();
+	token->filePosition = getInputFilePosition ();
+
+	return token;
+}
+
+static void deleteToken (tokenInfo *const token)
+{
+	vStringDelete (token->string);
+	vStringDelete (token->scope);
+	eFree (token);
+}
+
+/*
+ *	 Tag generation functions
+ */
+
+static void makeConstTag (tokenInfo *const token, const flexKind kind)
+{
+	if (FlexKinds [kind].enabled && ! token->ignoreTag )
+	{
+		const char *const name = vStringValue (token->string);
+		tagEntryInfo e;
+		initTagEntry (&e, name);
+
+		e.lineNumber   = token->lineNumber;
+		e.filePosition = token->filePosition;
+		e.kindName	   = FlexKinds [kind].name;
+		e.kind		   = FlexKinds [kind].letter;
+
+		makeTagEntry (&e);
+	}
+}
+
+static void makeFlexTag (tokenInfo *const token, flexKind kind)
+{
+	vString *	fulltag;
+
+	if (FlexKinds [kind].enabled && ! token->ignoreTag )
+	{
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n makeFlexTag start: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+		if (kind == FLEXTAG_FUNCTION && token->isClass )
+		{
+			kind = FLEXTAG_METHOD;
+		}
+		/*
+		 * If a scope has been added to the token, change the token
+		 * string to include the scope when making the tag.
+		 */
+		if ( vStringLength(token->scope) > 0 )
+		{
+			fulltag = vStringNew ();
+			vStringCopy(fulltag, token->scope);
+			vStringCatS (fulltag, ".");
+			vStringCatS (fulltag, vStringValue(token->string));
+			vStringTerminate(fulltag);
+			vStringCopy(token->string, fulltag);
+			vStringDelete (fulltag);
+		}
+		makeConstTag (token, kind);
+	}
+}
+
+static void makeClassTag (tokenInfo *const token)
+{ 
+	vString *	fulltag;
+
+	if ( ! token->ignoreTag )
+	{
+		fulltag = vStringNew ();
+		if (vStringLength (token->scope) > 0)
+		{
+			vStringCopy(fulltag, token->scope);
+			vStringCatS (fulltag, ".");
+			vStringCatS (fulltag, vStringValue(token->string));
+		}
+		else
+		{
+			vStringCopy(fulltag, token->string);
+		}
+		vStringTerminate(fulltag);
+		if ( ! stringListHas(ClassNames, vStringValue (fulltag)) )
+		{
+			stringListAdd (ClassNames, vStringNewCopy (fulltag));
+			makeFlexTag (token, FLEXTAG_CLASS);
+		}
+		vStringDelete (fulltag);
+	}
+}
+
+static void makeMXTag (tokenInfo *const token)
+{ 
+	vString *	fulltag;
+
+	if ( ! token->ignoreTag )
+	{
+		fulltag = vStringNew ();
+		if (vStringLength (token->scope) > 0)
+		{
+			vStringCopy(fulltag, token->scope);
+			vStringCatS (fulltag, ".");
+			vStringCatS (fulltag, vStringValue(token->string));
+		}
+		else
+		{
+			vStringCopy(fulltag, token->string);
+		}
+		vStringTerminate(fulltag);
+		makeFlexTag (token, FLEXTAG_MXTAG);
+		vStringDelete (fulltag);
+	}
+}
+
+static void makeFunctionTag (tokenInfo *const token)
+{ 
+	vString *	fulltag;
+
+	if ( ! token->ignoreTag )
+	{
+		fulltag = vStringNew ();
+		if (vStringLength (token->scope) > 0)
+		{
+			vStringCopy(fulltag, token->scope);
+			vStringCatS (fulltag, ".");
+			vStringCatS (fulltag, vStringValue(token->string));
+		}
+		else
+		{
+			vStringCopy(fulltag, token->string);
+		}
+		vStringTerminate(fulltag);
+		if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) )
+		{
+			stringListAdd (FunctionNames, vStringNewCopy (fulltag));
+			makeFlexTag (token, FLEXTAG_FUNCTION);
+		}
+		vStringDelete (fulltag);
+	}
+}
+
+/*
+ *	 Parsing functions
+ */
+
+static void parseString (vString *const string, const int delimiter)
+{
+	boolean end = FALSE;
+	while (! end)
+	{
+		int c = fileGetc ();
+		if (c == EOF)
+			end = TRUE;
+		else if (c == '\\')
+		{
+			c = fileGetc(); /* This maybe a ' or ". */
+			vStringPut(string, c);
+		}
+		else if (c == delimiter)
+			end = TRUE;
+		else
+			vStringPut (string, c);
+	}
+	vStringTerminate (string);
+}
+
+/*	Read a C identifier beginning with "firstChar" and places it into
+ *	"name".
+ */
+static void parseIdentifier (vString *const string, const int firstChar)
+{
+	int c = firstChar;
+	Assert (isIdentChar (c));
+	do
+	{
+		vStringPut (string, c);
+		c = fileGetc ();
+	} while (isIdentChar (c));
+	vStringTerminate (string);
+	if (!isspace (c))
+		fileUngetc (c);		/* unget non-identifier character */
+}
+
+static void readToken (tokenInfo *const token)
+{
+	int c;
+
+	token->type			= TOKEN_UNDEFINED;
+	token->keyword		= KEYWORD_NONE;
+	vStringClear (token->string);
+
+getNextChar:
+	do
+	{
+		c = fileGetc ();
+		token->lineNumber   = getSourceLineNumber ();
+		token->filePosition = getInputFilePosition ();
+	}
+	while (c == '\t'  ||  c == ' ' ||  c == '\n');
+
+	switch (c)
+	{
+		case EOF: longjmp (Exception, (int)ExceptionEOF);	break;
+		case '(': token->type = TOKEN_OPEN_PAREN;			break;
+		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
+		case ';': token->type = TOKEN_SEMICOLON;			break;
+		case ',': token->type = TOKEN_COMMA;				break;
+		case '.': token->type = TOKEN_PERIOD;				break;
+		case ':': token->type = TOKEN_COLON;				break;
+		case '{': token->type = TOKEN_OPEN_CURLY;			break;
+		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
+		case '=': token->type = TOKEN_EQUAL_SIGN;			break;
+		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
+		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;
+		case '?': token->type = TOKEN_QUESTION_MARK;		break;
+
+		case '\'':
+		case '"':
+				  token->type = TOKEN_STRING;
+				  parseString (token->string, c);
+				  token->lineNumber = getSourceLineNumber ();
+				  token->filePosition = getInputFilePosition ();
+				  break;
+
+		case '\\':
+				  c = fileGetc ();
+				  if (c != '\\'  && c != '"'  &&  !isspace (c))
+					  fileUngetc (c);
+				  token->type = TOKEN_CHARACTER;
+				  token->lineNumber = getSourceLineNumber ();
+				  token->filePosition = getInputFilePosition ();
+				  break;
+
+		case '/':
+				  {
+					  int d = fileGetc ();
+					  if ( (d != '*') &&		/* is this the start of a comment? */
+							  (d != '/') &&		/* is a one line comment? */
+							  (d != '>') )		/* is this a close XML tag? */
+					  {
+						  fileUngetc (d);
+						  token->type = TOKEN_FORWARD_SLASH;
+						  token->lineNumber = getSourceLineNumber ();
+						  token->filePosition = getInputFilePosition ();
+					  }
+					  else
+					  {
+						  if (d == '*')
+						  {
+							  do
+							  {
+								  fileSkipToCharacter ('*');
+								  c = fileGetc ();
+								  if (c == '/')
+									  break;
+								  else
+									  fileUngetc (c);
+							  } while (c != EOF && c != '\0');
+							  goto getNextChar;
+						  }
+						  else if (d == '/')	/* is this the start of a comment?  */
+						  {
+							  fileSkipToCharacter ('\n');
+							  goto getNextChar;
+						  }
+						  else if (d == '>')	/* is this the start of a comment?  */
+						  {
+							  token->type = TOKEN_CLOSE_SGML;
+							  token->lineNumber = getSourceLineNumber ();
+							  token->filePosition = getInputFilePosition ();
+						  }
+					  }
+					  break;
+				  }
+
+		case '<':
+				  {
+					  /*
+					   * An XML comment looks like this 
+					   *   <!-- anything over multiple lines -->
+					   */
+					  int d = fileGetc ();
+
+					  if ( (d != '!' )  && 		/* is this the start of a comment? */
+					       (d != '/' )  &&	 	/* is this the start of a closing mx tag */
+					       (d != 'm' )    ) 	/* is this the start of a mx tag */
+					  {
+						  fileUngetc (d);
+						  token->type = TOKEN_LESS_THAN;
+						  token->lineNumber = getSourceLineNumber ();
+						  token->filePosition = getInputFilePosition ();
+
+					  }
+					  else
+					  {
+						  if (d == '!')
+						  {
+							  int e = fileGetc ();
+							  if ( e != '-' ) 		/* is this the start of a comment? */
+							  {
+								  fileUngetc (e);
+								  fileUngetc (d);
+								  token->type = TOKEN_LESS_THAN;
+								  token->lineNumber = getSourceLineNumber ();
+								  token->filePosition = getInputFilePosition ();
+							  }
+							  else
+							  {
+								  if (e == '-')
+								  {
+									  int f = fileGetc ();
+									  if ( f != '-' ) 		/* is this the start of a comment? */
+									  {
+										  fileUngetc (f);
+										  fileUngetc (e);
+										  fileUngetc (d);
+										  token->type = TOKEN_LESS_THAN;
+										  token->lineNumber = getSourceLineNumber ();
+										  token->filePosition = getInputFilePosition ();
+									  }
+									  else
+									  {
+										  if (f == '-')
+										  {
+											  do
+											  {
+												  fileSkipToCharacter ('-');
+												  c = fileGetc ();
+												  if (c == '-') 
+												  {
+													  d = fileGetc ();
+													  if (d == '>')
+														  break;
+													  else
+													  {
+														  fileUngetc (d);
+														  fileUngetc (c);
+													  }
+													  break;
+												  }
+												  else
+													  fileUngetc (c);
+											  } while (c != EOF && c != '\0');
+											  goto getNextChar;
+										  }
+									  }
+								  }
+							  }
+						  }
+						  else if (d == 'm')
+						  {
+							  int e = fileGetc ();
+							  if ( e != 'x' ) 		/* continuing an mx tag */
+							  {
+								  fileUngetc (e);
+								  fileUngetc (d);
+								  token->type = TOKEN_LESS_THAN;
+								  token->lineNumber = getSourceLineNumber ();
+								  token->filePosition = getInputFilePosition ();
+							  }
+							  else
+							  {
+								  if (e == 'x')
+								  {
+									  int f = fileGetc ();
+									  if ( f != ':' ) 		/* is this the start of a comment? */
+									  {
+										  fileUngetc (f);
+										  fileUngetc (e);
+										  fileUngetc (d);
+										  token->type = TOKEN_LESS_THAN;
+										  token->lineNumber = getSourceLineNumber ();
+										  token->filePosition = getInputFilePosition ();
+									  }
+									  else
+									  {
+										  if (f == ':')
+										  {
+											  token->type = TOKEN_OPEN_MXML;
+											  token->lineNumber = getSourceLineNumber ();
+											  token->filePosition = getInputFilePosition ();
+										  }
+									  }
+								  }
+							  }
+						  }
+						  else if (d == '/')
+						  {
+							  int e = fileGetc ();
+							  if ( e != 'm' ) 		/* continuing an mx tag */
+							  {
+								  fileUngetc (e);
+								  fileUngetc (d);
+								  token->type = TOKEN_LESS_THAN;
+								  token->lineNumber = getSourceLineNumber ();
+								  token->filePosition = getInputFilePosition ();
+							  }
+							  else
+							  {
+								  int f = fileGetc ();
+								  if ( f != 'x' ) 		/* continuing an mx tag */
+								  {
+									  fileUngetc (f);
+									  fileUngetc (e);
+									  token->type = TOKEN_LESS_THAN;
+									  token->lineNumber = getSourceLineNumber ();
+									  token->filePosition = getInputFilePosition ();
+								  }
+								  else
+								  {
+									  if (f == 'x')
+									  {
+										  int g = fileGetc ();
+										  if ( g != ':' ) 		/* is this the start of a comment? */
+										  {
+											  fileUngetc (g);
+											  fileUngetc (f);
+											  fileUngetc (e);
+											  token->type = TOKEN_LESS_THAN;
+											  token->lineNumber = getSourceLineNumber ();
+											  token->filePosition = getInputFilePosition ();
+										  }
+										  else
+										  {
+											  if (g == ':')
+											  {
+												  token->type = TOKEN_CLOSE_MXML;
+												  token->lineNumber = getSourceLineNumber ();
+												  token->filePosition = getInputFilePosition ();
+											  }
+										  }
+									  }
+								  }
+							  }
+						  }
+					  }
+					  break;
+				  }
+
+		case '>':
+				  token->type = TOKEN_GREATER_THAN;
+				  token->lineNumber = getSourceLineNumber ();
+				  token->filePosition = getInputFilePosition ();
+				  break;
+
+		case '!': 
+				  token->type = TOKEN_EXCLAMATION;			
+				  /*token->lineNumber = getSourceLineNumber ();
+				  token->filePosition = getInputFilePosition ();*/
+				  break;
+
+		default:
+				  if (! isIdentChar (c))
+					  token->type = TOKEN_UNDEFINED;
+				  else
+				  {
+					  parseIdentifier (token->string, c);
+					  token->lineNumber = getSourceLineNumber ();
+					  token->filePosition = getInputFilePosition ();
+					  token->keyword = analyzeToken (token->string, Lang_js);
+					  if (isKeyword (token, KEYWORD_NONE))
+						  token->type = TOKEN_IDENTIFIER;
+					  else
+						  token->type = TOKEN_KEYWORD;
+				  }
+				  break;
+	}
+}
+
+static void copyToken (tokenInfo *const dest, tokenInfo *const src)
+{
+	dest->nestLevel = src->nestLevel;
+	dest->lineNumber = src->lineNumber;
+	dest->filePosition = src->filePosition;
+	dest->type = src->type;
+	dest->keyword = src->keyword;
+	dest->isClass = src->isClass;
+	vStringCopy(dest->string, src->string);
+	vStringCopy(dest->scope, src->scope);
+}
+
+/*
+ *	 Token parsing functions
+ */
+
+static void skipArgumentList (tokenInfo *const token)
+{
+	int nest_level = 0;
+
+	/*
+	 * Other databases can have arguments with fully declared
+	 * datatypes:
+	 *	 (	name varchar(30), text binary(10)  )
+	 * So we must check for nested open and closing parantheses
+	 */
+
+	if (isType (token, TOKEN_OPEN_PAREN))	/* arguments? */
+	{
+		nest_level++;
+		while (! (isType (token, TOKEN_CLOSE_PAREN) && (nest_level == 0)))
+		{
+			readToken (token);
+			if (isType (token, TOKEN_OPEN_PAREN))
+			{
+				nest_level++;
+			}
+			if (isType (token, TOKEN_CLOSE_PAREN))
+			{
+				if (nest_level > 0)
+				{
+					nest_level--;
+				}
+			}
+		} 
+		readToken (token);
+	}
+}
+
+static void skipArrayList (tokenInfo *const token)
+{
+	int nest_level = 0;
+
+	/*
+	 * Handle square brackets
+	 *	 var name[1]
+	 * So we must check for nested open and closing square brackets
+	 */
+
+	if (isType (token, TOKEN_OPEN_SQUARE))	/* arguments? */
+	{
+		nest_level++;
+		while (! (isType (token, TOKEN_CLOSE_SQUARE) && (nest_level == 0)))
+		{
+			readToken (token);
+			if (isType (token, TOKEN_OPEN_SQUARE))
+			{
+				nest_level++;
+			}
+			if (isType (token, TOKEN_CLOSE_SQUARE))
+			{
+				if (nest_level > 0)
+				{
+					nest_level--;
+				}
+			}
+		} 
+		readToken (token);
+	}
+}
+
+static void addContext (tokenInfo* const parent, const tokenInfo* const child)
+{
+	if (vStringLength (parent->string) > 0)
+	{
+		vStringCatS (parent->string, ".");
+	}
+	vStringCatS (parent->string, vStringValue(child->string));
+	vStringTerminate(parent->string);
+}
+
+static void addToScope (tokenInfo* const token, vString* const extra)
+{
+	if (vStringLength (token->scope) > 0)
+	{
+		vStringCatS (token->scope, ".");
+	}
+	vStringCatS (token->scope, vStringValue(extra));
+	vStringTerminate(token->scope);
+}
+
+/*
+ *	 Scanning functions
+ */
+
+static void findCmdTerm (tokenInfo *const token)
+{
+	/*
+	 * Read until we find either a semicolon or closing brace. 
+	 * Any nested braces will be handled within.
+	 */
+	while (! ( isType (token, TOKEN_SEMICOLON) ||
+				isType (token, TOKEN_CLOSE_CURLY) ) )
+	{
+		/* Handle nested blocks */
+		if ( isType (token, TOKEN_OPEN_CURLY))
+		{
+			parseBlock (token, token);
+		} 
+		else if ( isType (token, TOKEN_OPEN_PAREN) )
+		{
+			skipArgumentList(token);
+		}
+		else 
+		{
+			readToken (token);
+		}
+	} 
+}
+
+static void parseSwitch (tokenInfo *const token)
+{
+	/*
+	 * switch (expression){
+	 * case value1:
+	 *	   statement;
+	 *	   break;
+	 * case value2:
+	 *	   statement;
+	 *	   break;
+	 * default : statement;
+	 * }
+	 */
+
+	readToken (token);
+
+	if (isType (token, TOKEN_OPEN_PAREN)) 
+	{
+		skipArgumentList(token);
+	}
+
+	if (isType (token, TOKEN_OPEN_CURLY)) 
+	{
+		do
+		{
+			readToken (token);
+		} while (! (isType (token, TOKEN_CLOSE_SGML) || 
+					isType (token, TOKEN_CLOSE_MXML) ||
+					isType (token, TOKEN_CLOSE_CURLY) ||
+					isType (token, TOKEN_GREATER_THAN)) ); 
+	}
+
+}
+
+static void parseLoop (tokenInfo *const token)
+{
+	/*
+	 * Handles these statements
+	 *	   for (x=0; x<3; x++)
+	 *		   document.write("This text is repeated three times<br>");
+	 *	   
+	 *	   for (x=0; x<3; x++)
+	 *	   {
+	 *		   document.write("This text is repeated three times<br>");
+	 *	   }
+	 *	   
+	 *	   while (number<5){
+	 *		   document.write(number+"<br>");
+	 *		   number++;
+	 *	   }
+	 *	   
+	 *	   do{
+	 *		   document.write(number+"<br>");
+	 *		   number++;
+	 *	   }
+	 *	   while (number<5);
+	 */
+
+	if (isKeyword (token, KEYWORD_for) || isKeyword (token, KEYWORD_while))
+	{
+		readToken(token);
+
+		if (isType (token, TOKEN_OPEN_PAREN)) 
+		{
+			/*
+			 * Handle nameless functions, these will only
+			 * be considered methods.
+			 */
+			skipArgumentList(token);
+		}
+
+		if (isType (token, TOKEN_OPEN_CURLY)) 
+		{
+			/*
+			 * This will be either a function or a class.
+			 * We can only determine this by checking the body
+			 * of the function.  If we find a "this." we know
+			 * it is a class, otherwise it is a function.
+			 */
+			parseBlock (token, token);
+		} 
+		else 
+		{
+			parseLine(token);
+		}
+	} 
+	else if (isKeyword (token, KEYWORD_do))
+	{
+		readToken(token);
+
+		if (isType (token, TOKEN_OPEN_CURLY)) 
+		{
+			/*
+			 * This will be either a function or a class.
+			 * We can only determine this by checking the body
+			 * of the function.  If we find a "this." we know
+			 * it is a class, otherwise it is a function.
+			 */
+			parseBlock (token, token);
+		} 
+		else 
+		{
+			parseLine(token);
+		}
+
+		readToken(token);
+
+		if (isKeyword (token, KEYWORD_while))
+		{
+			readToken(token);
+
+			if (isType (token, TOKEN_OPEN_PAREN)) 
+			{
+				/*
+				 * Handle nameless functions, these will only
+				 * be considered methods.
+				 */
+				skipArgumentList(token);
+			}
+		}
+	}
+}
+
+static boolean parseIf (tokenInfo *const token)
+{
+	boolean read_next_token = TRUE;
+	/*
+	 * If statements have two forms
+	 *	   if ( ... )
+	 *		   one line;
+	 *
+	 *	   if ( ... )  
+	 *		  statement;
+	 *	   else
+	 *		  statement
+	 *	    
+	 *	   if ( ... ) {
+	 *		  multiple;
+	 *		  statements;
+	 *	   }
+	 *
+	 *
+	 *	   if ( ... ) {
+	 *		  return elem
+	 *	   }
+	 *
+	 *     This example if correctly written, but the
+	 *     else contains only 1 statement without a terminator
+	 *     since the function finishes with the closing brace.
+	 *
+     *     function a(flag){
+     *         if(flag)
+     *             test(1);
+     *         else
+     *             test(2)
+     *     }
+	 *
+	 * TODO:  Deal with statements that can optional end
+	 *		  without a semi-colon.  Currently this messes up
+	 *		  the parsing of blocks.
+	 *		  Need to somehow detect this has happened, and either
+	 *		  backup a token, or skip reading the next token if 
+	 *		  that is possible from all code locations.
+	 *
+	 */
+
+	readToken (token);
+
+	if (isKeyword (token, KEYWORD_if))
+	{
+		/*
+		 * Check for an "else if" and consume the "if"
+		 */
+		readToken (token);
+	}
+
+	if (isType (token, TOKEN_OPEN_PAREN)) 
+	{
+		/* 
+		 * Handle nameless functions, these will only
+		 * be considered methods.
+		 */
+		skipArgumentList(token);
+	}
+
+	if (isType (token, TOKEN_OPEN_CURLY)) 
+	{
+		/*
+		 * This will be either a function or a class.
+		 * We can only determine this by checking the body
+		 * of the function.  If we find a "this." we know
+		 * it is a class, otherwise it is a function.
+		 */
+		parseBlock (token, token);
+	} 
+	else 
+	{
+		findCmdTerm (token);
+
+		/*
+		 * The IF could be followed by an ELSE statement.
+		 * This too could have two formats, a curly braced
+		 * multiline section, or another single line.
+		 */
+
+		if (isType (token, TOKEN_CLOSE_CURLY)) 
+		{
+			/*
+			 * This statement did not have a line terminator.
+			 */
+			read_next_token = FALSE;
+		} 
+		else 
+		{
+			readToken (token);
+
+			if (isType (token, TOKEN_CLOSE_CURLY)) 
+			{
+				/*
+				* This statement did not have a line terminator.
+				*/
+				read_next_token = FALSE;
+			} 
+			else
+			{
+				if (isKeyword (token, KEYWORD_else))
+					read_next_token = parseIf (token); 
+			}
+		} 
+	}
+	return read_next_token;
+}
+
+static void parseFunction (tokenInfo *const token)
+{
+	tokenInfo *const name = newToken ();
+
+	/*
+	 * This deals with these formats
+     *     private static function ioErrorHandler( event:IOErrorEvent ):void {
+	 */
+
+	if ( isKeyword(token, KEYWORD_function) )
+	{
+		readToken (token);
+	}
+
+	copyToken (name, token);
+	/* Add scope in case this is an INNER function 
+	addToScope(name, token->scope);
+	*/
+
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseFunction: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseFunction: name isClass:%d  scope:%s  name:%s\n"
+				, name->isClass
+				, vStringValue(name->scope)
+				, vStringValue(name->string)
+				);
+			);
+
+	readToken (token);
+
+	if ( isType (token, TOKEN_OPEN_PAREN) )
+		skipArgumentList(token);
+
+	if ( isType (token, TOKEN_COLON) )
+	{
+		/*
+		 *   function fname ():ReturnType 
+		 */
+		readToken (token);
+		readToken (token);
+	}
+
+	if ( isType (token, TOKEN_OPEN_CURLY) )
+	{
+		DebugStatement ( 
+				debugPrintf (DEBUG_PARSE
+					, "\n parseFunction end: name isClass:%d  scope:%s  name:%s\n"
+					, name->isClass
+					, vStringValue(name->scope)
+					, vStringValue(name->string)
+					);
+				);
+		parseBlock (token, name);
+		DebugStatement ( 
+				debugPrintf (DEBUG_PARSE
+					, "\n parseFunction end2: token isClass:%d  scope:%s  name:%s\n"
+					, token->isClass
+					, vStringValue(token->scope)
+					, vStringValue(token->string)
+					);
+				);
+		DebugStatement ( 
+				debugPrintf (DEBUG_PARSE
+					, "\n parseFunction end2: token isClass:%d  scope:%s  name:%s\n"
+					, token->isClass
+					, vStringValue(token->scope)
+					, vStringValue(token->string)
+					);
+				);
+		DebugStatement ( 
+				debugPrintf (DEBUG_PARSE
+					, "\n parseFunction end3: name isClass:%d  scope:%s  name:%s\n"
+					, name->isClass
+					, vStringValue(name->scope)
+					, vStringValue(name->string)
+					);
+				);
+		makeFunctionTag (name);
+	}
+
+	findCmdTerm (token);
+
+	deleteToken (name);
+}
+
+static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent)
+{
+	boolean read_next_token = TRUE;
+	vString * saveScope = vStringNew ();
+
+	vStringClear(saveScope);
+	vStringCopy (saveScope, token->scope);
+	token->nestLevel++;
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseBlock start: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	/*
+	 * Make this routine a bit more forgiving.
+	 * If called on an open_curly advance it
+	 */
+	if ( isType (token, TOKEN_OPEN_CURLY) && 
+			isKeyword(token, KEYWORD_NONE) )
+		readToken(token);
+
+	if (! isType (token, TOKEN_CLOSE_CURLY))
+	{
+		/*
+		 * Read until we find the closing brace, 
+		 * any nested braces will be handled within
+		 */
+		do
+		{
+			if (isType (token, TOKEN_OPEN_CURLY))
+			{
+				/* Handle nested blocks */
+				parseBlock (token, parent);
+			} 
+			else 
+			{
+				/*
+				 * It is possible for a line to have no terminator
+				 * if the following line is a closing brace.
+				 * parseLine will detect this case and indicate
+				 * whether we should read an additional token.
+				 */
+				read_next_token = parseLine (token);
+			}
+
+			/*
+			 * Always read a new token unless we find a statement without
+			 * a ending terminator
+			 */
+			if( read_next_token ) 
+				readToken(token);
+
+			/*
+			 * If we find a statement without a terminator consider the 
+			 * block finished, otherwise the stack will be off by one.
+			 */
+		} while (! isType (token, TOKEN_CLOSE_CURLY) && read_next_token );
+	}
+
+	vStringDelete(saveScope);
+	token->nestLevel--;
+
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseBlock end: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	return FALSE;
+}
+
+static void parseMethods (tokenInfo *const token, tokenInfo *const class)
+{
+	tokenInfo *const name = newToken ();
+
+	/*
+	 * This deals with these formats
+	 *	   validProperty  : 2,
+	 *	   validMethod    : function(a,b) {}
+	 *	   'validMethod2' : function(a,b) {}
+     *     container.dirtyTab = {'url': false, 'title':false, 'snapshot':false, '*': false}		
+	 */
+
+	do
+	{
+		readToken (token);
+		if (isType (token, TOKEN_STRING) || isKeyword(token, KEYWORD_NONE))
+		{
+			copyToken (name, token);
+
+			readToken (token);
+			if ( isType (token, TOKEN_COLON) )
+			{
+				readToken (token);
+				if ( isKeyword (token, KEYWORD_function) )
+				{
+					readToken (token);
+					if ( isType (token, TOKEN_OPEN_PAREN) )
+					{
+						skipArgumentList(token);
+					}
+
+					if (isType (token, TOKEN_OPEN_CURLY)) 
+					{
+						addToScope (name, class->string);
+						makeFlexTag (name, FLEXTAG_METHOD);
+						parseBlock (token, name);
+
+						/*
+						 * Read to the closing curly, check next
+						 * token, if a comma, we must loop again
+						 */
+						readToken (token);
+					}
+				}
+				else
+				{
+						addToScope (name, class->string);
+						makeFlexTag (name, FLEXTAG_PROPERTY);
+
+						/*
+						 * Read the next token, if a comma
+						 * we must loop again
+						 */
+						readToken (token);
+				}
+			}
+		}
+	} while ( isType(token, TOKEN_COMMA) );
+
+	findCmdTerm (token);
+
+	deleteToken (name);
+}
+
+static boolean parseVar (tokenInfo *const token, boolean is_public)
+{
+	tokenInfo *const name = newToken ();
+	tokenInfo *const secondary_name = newToken ();
+	vString * saveScope = vStringNew ();
+	boolean is_terminated = TRUE;
+
+	vStringClear(saveScope);
+	vStringCopy (saveScope, token->scope);
+	/*
+	 * Variables are defined as:
+	 *     private static var lastFaultMessage:Date = new Date( 0 );
+	 *     private static var webRequests:ArrayCollection = new ArrayCollection();
+	 */
+
+	if ( isKeyword(token, KEYWORD_var) )
+	{
+		readToken(token);
+	}
+
+	/* Variable name */
+	copyToken (name, token);
+	readToken(token);
+
+	if ( isType (token, TOKEN_COLON) )
+	{
+		/*
+		 *   var vname ():DataType = new Date();
+		 *   var vname ():DataType;
+		 */
+		readToken (token);
+		readToken (token);
+	}
+
+	while (! isType (token, TOKEN_SEMICOLON) )
+	{
+		readToken (token);
+	}
+
+	if ( isType (token, TOKEN_SEMICOLON) )
+	{
+		/*
+		 * Only create variables for global scope
+		 */
+		/* if ( token->nestLevel == 0 && is_global ) */
+		if ( is_public )
+		{
+			if (isType (token, TOKEN_SEMICOLON)) 
+				makeFlexTag (name, FLEXTAG_VARIABLE);
+		}
+	}
+
+	vStringCopy(token->scope, saveScope);
+	deleteToken (name);
+	deleteToken (secondary_name);
+	vStringDelete(saveScope);
+
+	return is_terminated;
+}
+
+static boolean parseClass (tokenInfo *const token)
+{
+	tokenInfo *const name = newToken ();
+	vString * saveScope = vStringNew ();
+	boolean saveIsClass = token->isClass;
+
+	vStringClear(saveScope);
+	vStringCopy (saveScope, token->scope);
+	/*
+	 * Variables are defined as:
+	 *     private static var lastFaultMessage:Date = new Date( 0 );
+	 *     private static var webRequests:ArrayCollection = new ArrayCollection();
+	 */
+
+	if ( isKeyword(token, KEYWORD_class) )
+	{
+		readToken(token);
+	}
+
+	token->isClass = TRUE;
+	/* Add class name to scope */
+	addToScope(token, token->string);
+	/* Class name */
+	copyToken (name, token);
+	readToken(token);
+
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseClass start: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	if ( isType (token, TOKEN_OPEN_CURLY) )
+	{
+		makeClassTag (name);
+		parseBlock (token, name);
+	}
+
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseClass end: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	vStringCopy(token->scope, saveScope);
+	token->isClass = saveIsClass;
+	deleteToken (name);
+	vStringDelete(saveScope);
+
+	return TRUE;
+}
+
+static boolean parseStatement (tokenInfo *const token)
+{
+	tokenInfo *const name = newToken ();
+	tokenInfo *const secondary_name = newToken ();
+	vString * saveScope = vStringNew ();
+	boolean is_public = FALSE;
+	boolean is_class = FALSE;
+	boolean is_terminated = TRUE;
+	boolean is_global = FALSE;
+	boolean is_prototype = FALSE;
+	vString *	fulltag;
+
+	vStringClear(saveScope);
+	vStringCopy (saveScope, token->scope);
+	DebugStatement ( 
+			debugPrintf (DEBUG_PARSE
+				, "\n parseStatement: token isClass:%d  scope:%s  name:%s\n"
+				, token->isClass
+				, vStringValue(token->scope)
+				, vStringValue(token->string)
+				);
+			);
+	/*
+	 * Functions can be named or unnamed.
+	 * This deals with these formats:
+	 * Function
+	 *	   validFunctionOne = function(a,b) {}
+	 *	   testlib.validFunctionFive = function(a,b) {}
+	 *	   var innerThree = function(a,b) {}
+	 *	   var innerFour = (a,b) {}
+	 *	   var D2 = secondary_fcn_name(a,b) {}
+	 *	   var D3 = new Function("a", "b", "return a+b;");
+	 * Class
+	 *	   testlib.extras.ValidClassOne = function(a,b) {
+	 *		   this.a = a; 
+	 *	   }
+	 * Class Methods
+	 *	   testlib.extras.ValidClassOne.prototype = {
+	 *		   'validMethodOne' : function(a,b) {},
+	 *		   'validMethodTwo' : function(a,b) {}
+	 *	   }
+     *     ValidClassTwo = function () 
+     *     {
+     *         this.validMethodThree = function() {}
+     *         // unnamed method
+     *         this.validMethodFour = () {}
+     *     }
+	 *	   Database.prototype.validMethodThree = Database_getTodaysDate;
+	 */
+
+	if ( isKeyword(token, KEYWORD_public) )
+	{
+		is_public = TRUE;
+		readToken(token);
+	}
+
+	if ( isKeyword(token, KEYWORD_private) )
+	{
+		readToken(token);
+	}
+
+	if ( isKeyword(token, KEYWORD_static) )
+	{
+		readToken(token);
+	}
+
+	if (isType(token, TOKEN_KEYWORD))
+	{
+		switch (token->keyword)
+		{
+			case KEYWORD_for:	   
+			case KEYWORD_while:
+			case KEYWORD_do:
+				parseLoop (token); 
+				break;
+			case KEYWORD_if:
+			case KEYWORD_else:
+			case KEYWORD_try:
+			case KEYWORD_catch:
+			case KEYWORD_finally:
+				/* Common semantics */
+				is_terminated = parseIf (token); 
+				break;
+			case KEYWORD_switch:
+				parseSwitch (token); 
+				break;
+			case KEYWORD_class:
+				parseClass (token); 
+				return is_terminated;
+				break;
+			case KEYWORD_function:
+				parseFunction (token); 
+				return is_terminated;
+				break;
+			case KEYWORD_var:
+				parseVar (token, is_public); 
+				return is_terminated;
+				break;
+			default:
+				readToken(token);
+				break;
+		}
+	} 
+
+	copyToken (name, token);
+
+	while (! isType (token, TOKEN_CLOSE_CURLY) &&
+	       ! isType (token, TOKEN_SEMICOLON)   &&
+	       ! isType (token, TOKEN_EQUAL_SIGN)  )
+	{
+		/* Potentially the name of the function */
+		readToken (token);
+		if (isType (token, TOKEN_PERIOD))
+		{
+			/*
+			 * Cannot be a global variable is it has dot references in the name
+			 */
+			is_global = FALSE;
+			do
+			{
+				readToken (token);
+				if ( isKeyword(token, KEYWORD_NONE) )
+				{
+					if ( is_class )
+					{
+						vStringCopy(saveScope, token->scope);
+						addToScope(token, name->string);
+					} 
+					else 
+						addContext (name, token);
+				} 
+				else if ( isKeyword(token, KEYWORD_prototype) ) 
+				{
+					/*
+					 * When we reach the "prototype" tag, we infer:
+					 *     "BindAgent" is a class
+					 *     "build"     is a method
+					 *
+					 * function BindAgent( repeatableIdName, newParentIdName ) {
+					 * }	
+					 *
+					 * CASE 1
+					 * Specified function name: "build"
+					 *     BindAgent.prototype.build = function( mode ) {
+					 *     	  ignore everything within this function
+					 *     }
+					 *
+					 * CASE 2
+					 * Prototype listing
+					 *     ValidClassOne.prototype = {
+					 *         'validMethodOne' : function(a,b) {},
+					 *         'validMethodTwo' : function(a,b) {}
+					 *     }
+					 *
+					 */
+					makeClassTag (name);
+					is_class = TRUE;
+					is_prototype = TRUE;
+
+					/*
+					 * There should a ".function_name" next.
+					 */
+					readToken (token);
+					if (isType (token, TOKEN_PERIOD))
+					{
+						/*
+						 * Handle CASE 1
+						 */
+						readToken (token);
+						if ( isKeyword(token, KEYWORD_NONE) )
+						{
+							vStringCopy(saveScope, token->scope);
+							addToScope(token, name->string);
+
+							makeFlexTag (token, FLEXTAG_METHOD);
+							/*
+							 * We can read until the end of the block / statement.
+							 * We need to correctly parse any nested blocks, but
+							 * we do NOT want to create any tags based on what is
+							 * within the blocks.
+							 */
+							token->ignoreTag = TRUE;
+							/*
+							 * Find to the end of the statement 
+							 */
+							findCmdTerm (token);
+							token->ignoreTag = FALSE;
+							is_terminated = TRUE;
+							goto cleanUp;
+						}
+					} 
+					else if (isType (token, TOKEN_EQUAL_SIGN)) 
+					{
+						readToken (token);
+						if (isType (token, TOKEN_OPEN_CURLY)) 
+						{
+							/*
+							 * Handle CASE 2
+							 *
+							 * Creates tags for each of these class methods
+							 *     ValidClassOne.prototype = {
+							 *         'validMethodOne' : function(a,b) {},
+							 *         'validMethodTwo' : function(a,b) {}
+							 *     }
+							 */
+							parseMethods(token, name);
+							/*
+							 * Find to the end of the statement 
+							 */
+							findCmdTerm (token);
+							token->ignoreTag = FALSE;
+							is_terminated = TRUE;
+							goto cleanUp;
+						}
+					}
+				}
+				readToken (token);
+			} while (isType (token, TOKEN_PERIOD));
+		}
+
+		if ( isType (token, TOKEN_OPEN_PAREN) )
+			skipArgumentList(token);
+
+		if ( isType (token, TOKEN_COLON) )
+		{
+			/*
+			 * Functions are of this form:
+			 *   function fname ():ReturnType {
+			 */
+			readToken (token);
+			readToken (token);
+		}
+
+		if ( isType (token, TOKEN_OPEN_SQUARE) )
+			skipArrayList(token);
+
+	}
+
+	if ( isType (token, TOKEN_CLOSE_CURLY) )
+	{
+		/*
+		 * Reaching this section without having
+		 * processed an open curly brace indicates
+		 * the statement is most likely not terminated.
+		 */
+		is_terminated = FALSE;
+		goto cleanUp;
+	}
+
+	if ( isType (token, TOKEN_SEMICOLON) )
+	{
+		/*
+		 * Only create variables for global scope
+		 */
+		if ( token->nestLevel == 0 && is_global )
+		{
+			/*
+			 * Handles this syntax:
+			 *	   var g_var2;
+			 */
+			if (isType (token, TOKEN_SEMICOLON)) 
+				makeFlexTag (name, FLEXTAG_VARIABLE);
+		}
+		/* 
+		 * Statement has ended.
+		 * This deals with calls to functions, like:
+		 *     alert(..);
+		 */
+		goto cleanUp;
+	}
+
+	if ( isType (token, TOKEN_EQUAL_SIGN) )
+	{
+		readToken (token);
+
+		if ( isKeyword (token, KEYWORD_function) )
+		{
+			readToken (token);
+
+			if ( isKeyword (token, KEYWORD_NONE) && 
+					! isType (token, TOKEN_OPEN_PAREN) )
+			{
+				/*
+				 * Functions of this format:
+				 *	   var D2A = function theAdd(a, b) 
+				 *	   {					 
+				 *		  return a+b;
+				 *	   }					 
+				 * Are really two separate defined functions and 
+				 * can be referenced in two ways:
+				 *	   alert( D2A(1,2) );			  // produces 3
+				 *	   alert( theAdd(1,2) );		  // also produces 3
+				 * So it must have two tags:
+				 *	   D2A
+				 *	   theAdd
+				 * Save the reference to the name for later use, once
+				 * we have established this is a valid function we will
+				 * create the secondary reference to it.
+				 */
+				copyToken (secondary_name, token);
+				readToken (token);
+			}
+
+			if ( isType (token, TOKEN_OPEN_PAREN) )
+				skipArgumentList(token);
+
+			if (isType (token, TOKEN_OPEN_CURLY)) 
+			{
+				/*
+				 * This will be either a function or a class.
+				 * We can only determine this by checking the body
+				 * of the function.  If we find a "this." we know
+				 * it is a class, otherwise it is a function.
+				 */
+				if ( token->isClass ) 
+				{
+					makeFlexTag (name, FLEXTAG_METHOD);
+					if ( vStringLength(secondary_name->string) > 0 )
+						makeFunctionTag (secondary_name);
+					parseBlock (token, name);
+				} 
+				else 
+				{
+					parseBlock (token, name);
+					makeFunctionTag (name);
+
+					if ( vStringLength(secondary_name->string) > 0 )
+						makeFunctionTag (secondary_name);
+
+					/*
+					 * Find to the end of the statement 
+					 */
+					goto cleanUp;
+				}
+			}
+		} 
+		else if (isType (token, TOKEN_OPEN_PAREN)) 
+		{
+			/*
+			 * Handle nameless functions
+			 *     this.method_name = () {}
+			 */
+			skipArgumentList(token);
+
+			if (isType (token, TOKEN_OPEN_CURLY)) 
+			{
+				/*
+				 * Nameless functions are only setup as methods.
+				 */
+				makeFlexTag (name, FLEXTAG_METHOD);
+				parseBlock (token, name);
+			}
+		} 
+		else if (isType (token, TOKEN_OPEN_CURLY)) 
+		{
+			/*
+			 * Creates tags for each of these class methods
+			 *     ValidClassOne.prototype = {
+			 *         'validMethodOne' : function(a,b) {},
+			 *         'validMethodTwo' : function(a,b) {}
+			 *     }
+			 */
+			parseMethods(token, name);
+			if (isType (token, TOKEN_CLOSE_CURLY)) 
+			{
+				/*
+				 * Assume the closing parantheses terminates
+				 * this statements.
+				 */
+				is_terminated = TRUE;
+			}
+		}
+		else if (isKeyword (token, KEYWORD_new))
+		{
+			readToken (token);
+			if ( isKeyword (token, KEYWORD_function) || 
+					isKeyword (token, KEYWORD_capital_function) ||
+					isKeyword (token, KEYWORD_object) ||
+					isKeyword (token, KEYWORD_capital_object) )
+			{
+				if ( isKeyword (token, KEYWORD_object) || 
+						isKeyword (token, KEYWORD_capital_object) )
+					is_class = TRUE;
+
+				readToken (token);
+				if ( isType (token, TOKEN_OPEN_PAREN) )
+					skipArgumentList(token);
+
+				if (isType (token, TOKEN_SEMICOLON)) 
+				{
+					if ( token->nestLevel == 0 )
+					{
+						if ( is_class )
+						{
+							makeClassTag (name);
+						} else {
+							makeFunctionTag (name);
+						}
+					}
+				}
+			}
+		}
+		else if (isKeyword (token, KEYWORD_NONE))
+		{
+			/*
+			 * Only create variables for global scope
+			 */
+			if ( token->nestLevel == 0 && is_global )
+			{
+				/*
+				 * A pointer can be created to the function.  
+				 * If we recognize the function/class name ignore the variable.
+				 * This format looks identical to a variable definition.
+				 * A variable defined outside of a block is considered
+				 * a global variable:
+				 *	   var g_var1 = 1;
+				 *	   var g_var2;
+				 * This is not a global variable:
+				 *	   var g_var = function;
+				 * This is a global variable:
+				 *	   var g_var = different_var_name;
+				 */
+				fulltag = vStringNew ();
+				if (vStringLength (token->scope) > 0)
+				{
+					vStringCopy(fulltag, token->scope);
+					vStringCatS (fulltag, ".");
+					vStringCatS (fulltag, vStringValue(token->string));
+				}
+				else
+				{
+					vStringCopy(fulltag, token->string);
+				}
+				vStringTerminate(fulltag);
+				if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
+						! stringListHas(ClassNames, vStringValue (fulltag)) )
+				{
+					findCmdTerm (token);
+					if (isType (token, TOKEN_SEMICOLON)) 
+						makeFlexTag (name, FLEXTAG_VARIABLE);
+				}
+				vStringDelete (fulltag);
+			}
+		}
+	}
+	findCmdTerm (token);
+
+	/*
+	 * Statements can be optionally terminated in the case of 
+	 * statement prior to a close curly brace as in the
+	 * document.write line below:
+	 *
+	 * function checkForUpdate() {
+	 *	   if( 1==1 ) {
+	 *		   document.write("hello from checkForUpdate<br>")
+	 *	   }
+	 *	   return 1;
+	 * }
+	 */
+	if ( ! is_terminated && isType (token, TOKEN_CLOSE_CURLY)) 
+		is_terminated = FALSE;
+
+
+cleanUp:
+	vStringCopy(token->scope, saveScope);
+	deleteToken (name);
+	deleteToken (secondary_name);
+	vStringDelete(saveScope);
+
+	return is_terminated;
+}
+
+static boolean parseLine (tokenInfo *const token)
+{
+	boolean is_terminated = TRUE;
+	/*
+	 * Detect the common statements, if, while, for, do, ...
+	 * This is necessary since the last statement within a block "{}"
+	 * can be optionally terminated.
+	 *
+	 * If the statement is not terminated, we need to tell
+	 * the calling routine to prevent reading an additional token
+	 * looking for the end of the statement.
+	 */
+
+	if (isType(token, TOKEN_KEYWORD))
+	{
+		switch (token->keyword)
+		{
+			case KEYWORD_for:	   
+			case KEYWORD_while:
+			case KEYWORD_do:
+				parseLoop (token); 
+				break;
+			case KEYWORD_if:
+			case KEYWORD_else:
+			case KEYWORD_try:
+			case KEYWORD_catch:
+			case KEYWORD_finally:
+				/* Common semantics */
+				is_terminated = parseIf (token); 
+				break;
+			case KEYWORD_switch:
+				parseSwitch (token); 
+				break;
+			default:			   
+				parseStatement (token); 
+				break;
+		}
+	} 
+	else 
+	{
+		/*
+		 * Special case where single line statements may not be
+		 * SEMICOLON terminated.  parseBlock needs to know this
+		 * so that it does not read the next token.
+		 */
+		is_terminated = parseStatement (token); 
+	}
+	return is_terminated;
+}
+
+static boolean parseCDATA (tokenInfo *const token)
+{
+	if (isType (token, TOKEN_LESS_THAN))
+	{
+		/*
+		 * Handle these tags 
+		 * <![CDATA[
+		 *    ...
+		 * ]]>
+		 */
+		readToken (token);
+		if (isType (token, TOKEN_EXCLAMATION))
+		{
+			/*
+			 * Not sure why I had to comment these out, but I did.
+			 * readToken (token);
+			 * if (isType (token, TOKEN_OPEN_SQUARE))
+			 * {
+			*/
+				readToken (token);
+				if (isKeyword (token, KEYWORD_cdata))
+				{
+					readToken (token);
+					if (isType (token, TOKEN_OPEN_SQUARE))
+					{
+						parseActionScript (token);
+						if (isType (token, TOKEN_CLOSE_SQUARE))
+						{
+							readToken (token);
+							if (isType (token, TOKEN_CLOSE_SQUARE))
+							{
+								readToken (token);
+							}
+						}
+					}
+				}
+			/*} Not sure */
+		}
+	}
+	else
+	{
+		parseActionScript (token);
+	}
+	return TRUE;
+}
+
+static boolean parseMXML (tokenInfo *const token)
+{
+	tokenInfo *const name = newToken ();
+	tokenInfo *const type = newToken ();
+	/*
+	 * Detect the common statements, if, while, for, do, ...
+	 * This is necessary since the last statement within a block "{}"
+	 * can be optionally terminated.
+	 *
+	 * If the statement is not terminated, we need to tell
+	 * the calling routine to prevent reading an additional token
+	 * looking for the end of the statement.
+	 */
+
+	readToken (token);
+
+	if (isKeyword (token, KEYWORD_script))
+	{
+		/*
+		 * These tags can be of this form:
+		 * <mx:Script src="filename.as" />
+		 */
+		do
+		{
+			readToken (token);
+		} while (! (isType (token, TOKEN_CLOSE_SGML) || 
+					isType (token, TOKEN_CLOSE_MXML) ||
+					isType (token, TOKEN_GREATER_THAN)) ); 
+
+		if (isType (token, TOKEN_CLOSE_MXML))
+		{
+			/*
+			 * We have found a </mx:type> tag 
+			 * Finish reading the "type" and ">"
+			 */
+			readToken (token);
+			readToken (token);
+			goto cleanUp;
+		}
+		if (isType (token, TOKEN_CLOSE_SGML))
+		{
+			/*
+			 * We have found a <mx:Script src="filename.as" />
+			 */
+			goto cleanUp;
+		}
+
+		/*
+		 * This is a beginning of an embedded script.
+		 * These typically are of this format:
+		 *    <mx:Script>
+		 *        <![CDATA[
+		 *        ... ActionScript ...
+		 *        ]]>
+		 *    </mx:Script>
+		 */
+		readToken (token);
+		parseCDATA (token);
+
+		readToken (token);
+		if (isType (token, TOKEN_CLOSE_MXML))
+		{
+			/*
+			 * We have found a </mx:type> tag 
+			 * Finish reading the "type" and ">"
+			 */
+			readToken (token);
+			readToken (token);
+		}
+		goto cleanUp;
+	}
+
+	copyToken (type, token);
+
+	readToken (token);
+	do
+	{
+		if (isType (token, TOKEN_OPEN_MXML))
+		{
+			parseMXML (token);
+		}
+		else if (isKeyword (token, KEYWORD_id))
+		{
+			/* = */
+			readToken (token);
+			readToken (token);
+
+			copyToken (name, token);
+			addToScope (name, type->string);
+			makeMXTag (name);
+		}
+		readToken (token);
+	} while (! (isType (token, TOKEN_CLOSE_SGML) || isType (token, TOKEN_CLOSE_MXML)) ); 
+
+	if (isType (token, TOKEN_CLOSE_MXML))
+	{
+		/*
+		 * We have found a </mx:type> tag 
+		 * Finish reading the "type" and ">"
+		 */
+		readToken (token);
+		readToken (token);
+	}
+
+cleanUp:
+	deleteToken (name);
+	deleteToken (type);
+	return TRUE;
+}
+
+static boolean parseActionScript (tokenInfo *const token)
+{
+	do
+	{
+		readToken (token);
+
+		if (isType (token, TOKEN_LESS_THAN))
+		{
+			/*
+			 * Handle these tags 
+			 * <![CDATA[
+			 *    ...
+			 * ]]>
+			 */
+			readToken (token);
+			if (isType (token, TOKEN_EQUAL_SIGN))
+			{
+				if (isType (token, TOKEN_OPEN_SQUARE))
+				{
+					readToken (token);
+					if (isKeyword (token, KEYWORD_cdata))
+					{
+						readToken (token);
+					}
+				}
+			}
+		}
+		if (isType (token, TOKEN_CLOSE_SQUARE))
+		{
+			/*
+			 * Handle these tags 
+			 * <![CDATA[
+			 *    ...
+			 * ]]>
+			 */
+			readToken (token);
+			if (isType (token, TOKEN_CLOSE_SQUARE))
+			{
+				readToken (token);
+				if (isType (token, TOKEN_GREATER_THAN))
+				{
+					return TRUE;
+				}
+			}
+		}
+		else if (isType (token, TOKEN_CLOSE_MXML))
+		{
+			/*
+			 * Read the Script> tags 
+			 */
+			readToken (token);
+			readToken (token);
+			return TRUE;
+		} 
+		else if (isType (token, TOKEN_OPEN_MXML))
+		{
+			parseMXML (token);
+		} 
+		else 
+		{
+			if (isType(token, TOKEN_KEYWORD))
+			{
+				switch (token->keyword)
+				{
+					case KEYWORD_function:	parseFunction (token); break;
+					default:				parseLine (token); break;
+				}
+			} 
+			else 
+			{
+				parseLine (token); 
+			}
+		}
+	} while (TRUE);
+}
+
+static void parseFlexFile (tokenInfo *const token)
+{
+	do
+	{
+		readToken (token);
+
+		if (isType (token, TOKEN_OPEN_MXML))
+		{
+			parseMXML (token);
+		} 
+		if (isType (token, TOKEN_LESS_THAN))
+		{
+			readToken (token);
+			if (isType (token, TOKEN_QUESTION_MARK))
+			{
+				readToken (token);
+				while (! isType (token, TOKEN_QUESTION_MARK) )
+				{
+					readToken (token);
+				} 
+				readToken (token);
+			}
+		} 
+		else 
+		{
+			parseActionScript (token);
+		}
+	} while (TRUE);
+}
+
+static void initialize (const langType language)
+{
+	Assert (sizeof (FlexKinds) / sizeof (FlexKinds [0]) == FLEXTAG_COUNT);
+	Lang_js = language;
+	buildFlexKeywordHash ();
+}
+
+static void findFlexTags (void)
+{
+	tokenInfo *const token = newToken ();
+	exception_t exception;
+	
+	ClassNames = stringListNew ();
+	FunctionNames = stringListNew ();
+	
+	exception = (exception_t) (setjmp (Exception));
+	while (exception == ExceptionNone)
+		parseFlexFile (token);
+
+	stringListDelete (ClassNames);
+	stringListDelete (FunctionNames);
+	ClassNames = NULL;
+	FunctionNames = NULL;
+	deleteToken (token);
+}
+
+/* Create parser definition stucture */
+extern parserDefinition* FlexParser (void)
+{
+	static const char *const extensions [] = { "as", "mxml", NULL };
+	parserDefinition *const def = parserNew ("Flex");
+	def->extensions = extensions;
+	/*
+	 * New definitions for parsing instead of regex
+	 */
+	def->kinds		= FlexKinds;
+	def->kindCount	= KIND_COUNT (FlexKinds);
+	def->parser		= findFlexTags;
+	def->initialize = initialize;
+
+	return def;
+}
+/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
diff --git a/plugins/symbol-db/anjuta-tags/keyword.c b/plugins/symbol-db/anjuta-tags/keyword.c
index 92dbe0c..2a549d9 100644
--- a/plugins/symbol-db/anjuta-tags/keyword.c
+++ b/plugins/symbol-db/anjuta-tags/keyword.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: keyword.c 658 2008-04-20 23:21:35Z elliotth $
+*   $Id: keyword.c 715 2009-07-06 03:31:00Z dhiebert $
 *
 *   Copyright (c) 1998-2002, Darren Hiebert
 *
@@ -123,8 +123,7 @@ static hashEntry *newEntry (
 extern void addKeyword (const char *const string, langType language, int value)
 {
 	const unsigned long hashedValue = hashValue (string);
-	hashEntry *tableEntry = getHashTableEntry (hashedValue);
-	hashEntry *entry = tableEntry;
+	hashEntry *entry = getHashTableEntry (hashedValue);
 
 	if (entry == NULL)
 	{
diff --git a/plugins/symbol-db/anjuta-tags/lisp.c b/plugins/symbol-db/anjuta-tags/lisp.c
index 0e6add5..6fdc4dd 100644
--- a/plugins/symbol-db/anjuta-tags/lisp.c
+++ b/plugins/symbol-db/anjuta-tags/lisp.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: lisp.c 443 2006-05-30 04:37:13Z darren $
+*   $Id: lisp.c 717 2009-07-07 03:40:50Z dhiebert $
 *
 *   Copyright (c) 2000-2002, Darren Hiebert
 *
@@ -126,7 +126,7 @@ static void findLispTags (void)
 extern parserDefinition* LispParser (void)
 {
 	static const char *const extensions [] = {
-		"cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL
+		"cl", "clisp", "el", "l", "lisp", "lsp", NULL
 	};
 	parserDefinition* def = parserNew ("Lisp");
 	def->kinds      = LispKinds;
diff --git a/plugins/symbol-db/anjuta-tags/matlab.c b/plugins/symbol-db/anjuta-tags/matlab.c
index d514b5c..0811457 100644
--- a/plugins/symbol-db/anjuta-tags/matlab.c
+++ b/plugins/symbol-db/anjuta-tags/matlab.c
@@ -1,12 +1,12 @@
 /*
-*   $Id: yacc.c 443 2006-05-30 04:37:13Z darren $
+*   $Id$
 *
-*   Copyright (c) 2001-2002, Nick Hibma <n_hibma van-laarhoven org>
+*   Copyright (c) 2008, David Fishburn
 *
 *   This source code is released for free distribution under the terms of the
 *   GNU General Public License.
 *
-*   This module contains functions for generating tags for YACC language files.
+*   This module contains functions for generating tags for MATLAB language files.
 */
 
 /*
diff --git a/plugins/symbol-db/anjuta-tags/ocaml.c b/plugins/symbol-db/anjuta-tags/ocaml.c
new file mode 100644
index 0000000..8fd6872
--- /dev/null
+++ b/plugins/symbol-db/anjuta-tags/ocaml.c
@@ -0,0 +1,1842 @@
+/*
+*   Copyright (c) 2009, Vincent Berthoux
+*
+*   This source code is released for free distribution under the terms of the
+*   GNU General Public License.
+*
+*   This module contains functions for generating tags for Objective Caml
+*   language files.
+*/
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"	/* must always come first */
+
+#include <string.h>
+
+#include "keyword.h"
+#include "entry.h"
+#include "options.h"
+#include "read.h"
+#include "routines.h"
+#include "vstring.h"
+
+/* To get rid of unused parameter warning in
+ * -Wextra */
+#ifdef UNUSED
+#elif defined(__GNUC__)
+# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+# define UNUSED(x) /* unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
+#define OCAML_MAX_STACK_SIZE 256
+
+typedef enum {
+	K_CLASS,        /* Ocaml class, relatively rare */
+	K_METHOD,       /* class method */
+	K_MODULE,       /* Ocaml module OR functor */
+	K_VAR,
+	K_TYPE,         /* name of an OCaml type */
+	K_FUNCTION,
+	K_CONSTRUCTOR,  /* Constructor of a sum type */
+	K_RECORDFIELD,
+	K_EXCEPTION
+} ocamlKind;
+
+static kindOption OcamlKinds[] = {
+	{TRUE, 'c', "class", "classes"},
+	{TRUE, 'm', "method", "Object's method"},
+	{TRUE, 'M', "module", "Module or functor"},
+	{TRUE, 'v', "var", "Global variable"},
+	{TRUE, 't', "type", "Type name"},
+	{TRUE, 'f', "function", "A function"},
+	{TRUE, 'C', "Constructor", "A constructor"},
+	{TRUE, 'r', "Record field", "A 'structure' field"},
+	{TRUE, 'e', "Exception", "An exception"}
+};
+
+typedef enum {
+	OcaKEYWORD_and,
+	OcaKEYWORD_begin,
+	OcaKEYWORD_class,
+	OcaKEYWORD_do,
+	OcaKEYWORD_done,
+	OcaKEYWORD_else,
+	OcaKEYWORD_end,
+	OcaKEYWORD_exception,
+	OcaKEYWORD_for,
+	OcaKEYWORD_functor,
+	OcaKEYWORD_fun,
+	OcaKEYWORD_if,
+	OcaKEYWORD_in,
+	OcaKEYWORD_let,
+	OcaKEYWORD_match,
+	OcaKEYWORD_method,
+	OcaKEYWORD_module,
+	OcaKEYWORD_mutable,
+	OcaKEYWORD_object,
+	OcaKEYWORD_of,
+	OcaKEYWORD_rec,
+	OcaKEYWORD_sig,
+	OcaKEYWORD_struct,
+	OcaKEYWORD_then,
+	OcaKEYWORD_try,
+	OcaKEYWORD_type,
+	OcaKEYWORD_val,
+	OcaKEYWORD_virtual,
+	OcaKEYWORD_while,
+	OcaKEYWORD_with,
+
+	OcaIDENTIFIER,
+	Tok_PARL,       /* '(' */
+	Tok_PARR,       /* ')' */
+	Tok_BRL,        /* '[' */
+	Tok_BRR,        /* ']' */
+	Tok_CurlL,      /* '{' */
+	Tok_CurlR,      /* '}' */
+	Tok_Prime,      /* '\'' */
+	Tok_Pipe,       /* '|' */
+	Tok_EQ,         /* '=' */
+	Tok_Val,        /* string/number/poo */
+	Tok_Op,         /* any operator recognized by the language */
+	Tok_semi,       /* ';' */
+	Tok_comma,      /* ',' */
+	Tok_To,         /* '->' */
+	Tok_Sharp,      /* '#' */
+	Tok_Backslash,  /* '\\' */
+
+	Tok_EOF         /* END of file */
+} ocamlKeyword;
+
+typedef struct sOcaKeywordDesc {
+	const char *name;
+	ocamlKeyword id;
+} ocaKeywordDesc;
+
+typedef ocamlKeyword ocaToken;
+
+static const ocaKeywordDesc OcamlKeywordTable[] = {
+	{ "and"       , OcaKEYWORD_and       }, 
+	{ "begin"     , OcaKEYWORD_begin     }, 
+	{ "class"     , OcaKEYWORD_class     }, 
+	{ "do"        , OcaKEYWORD_do        }, 
+	{ "done"      , OcaKEYWORD_done      }, 
+	{ "else"      , OcaKEYWORD_else      }, 
+	{ "end"       , OcaKEYWORD_end       }, 
+	{ "exception" , OcaKEYWORD_exception }, 
+	{ "for"       , OcaKEYWORD_for       }, 
+	{ "fun"       , OcaKEYWORD_fun       }, 
+	{ "function"  , OcaKEYWORD_fun       }, 
+	{ "functor"   , OcaKEYWORD_functor   }, 
+	{ "in"        , OcaKEYWORD_in        }, 
+	{ "let"       , OcaKEYWORD_let       }, 
+	{ "match"     , OcaKEYWORD_match     }, 
+	{ "method"    , OcaKEYWORD_method    }, 
+	{ "module"    , OcaKEYWORD_module    }, 
+	{ "mutable"   , OcaKEYWORD_mutable   }, 
+	{ "object"    , OcaKEYWORD_object    }, 
+	{ "of"        , OcaKEYWORD_of        }, 
+	{ "rec"       , OcaKEYWORD_rec       }, 
+	{ "sig"       , OcaKEYWORD_sig       }, 
+	{ "struct"    , OcaKEYWORD_struct    }, 
+	{ "then"      , OcaKEYWORD_then      }, 
+	{ "try"       , OcaKEYWORD_try       }, 
+	{ "type"      , OcaKEYWORD_type      }, 
+	{ "val"       , OcaKEYWORD_val       }, 
+	{ "value"     , OcaKEYWORD_let       }, /* just to handle revised syntax */
+	{ "virtual"   , OcaKEYWORD_virtual   }, 
+	{ "while"     , OcaKEYWORD_while     }, 
+	{ "with"      , OcaKEYWORD_with      }, 
+
+	{ "or"        , Tok_Op               }, 
+	{ "mod "      , Tok_Op               }, 
+	{ "land "     , Tok_Op               }, 
+	{ "lor "      , Tok_Op               }, 
+	{ "lxor "     , Tok_Op               }, 
+	{ "lsl "      , Tok_Op               }, 
+	{ "lsr "      , Tok_Op               }, 
+	{ "asr"       , Tok_Op               }, 
+	{ "->"        , Tok_To               }, 
+	{ "true"      , Tok_Val              }, 
+	{ "false"     , Tok_Val              }
+};
+
+static langType Lang_Ocaml;
+
+boolean exportLocalInfo = FALSE;
+
+/*//////////////////////////////////////////////////////////////////
+//// lexingInit             */
+typedef struct _lexingState {
+	vString *name;	/* current parsed identifier/operator */
+	const unsigned char *cp;	/* position in stream */
+} lexingState;
+
+/* array of the size of all possible value for a char */
+boolean isOperator[1 << (8 * sizeof (char))] = { FALSE };
+
+static void initKeywordHash ( void )
+{
+	const size_t count = sizeof (OcamlKeywordTable) / sizeof (ocaKeywordDesc);
+	size_t i;
+
+	for (i = 0; i < count; ++i)
+	{
+		addKeyword (OcamlKeywordTable[i].name, Lang_Ocaml,
+			(int) OcamlKeywordTable[i].id);
+	}
+}
+
+/* definition of all the operator in OCaml,
+ * /!\ certain operator get special treatment
+ * in regards of their role in OCaml grammar :
+ * '|' ':' '=' '~' and '?' */
+static void initOperatorTable ( void )
+{
+	isOperator['!'] = TRUE;
+	isOperator['$'] = TRUE;
+	isOperator['%'] = TRUE;
+	isOperator['&'] = TRUE;
+	isOperator['*'] = TRUE;
+	isOperator['+'] = TRUE;
+	isOperator['-'] = TRUE;
+	isOperator['.'] = TRUE;
+	isOperator['/'] = TRUE;
+	isOperator[':'] = TRUE;
+	isOperator['<'] = TRUE;
+	isOperator['='] = TRUE;
+	isOperator['>'] = TRUE;
+	isOperator['?'] = TRUE;
+	isOperator['@'] = TRUE;
+	isOperator['^'] = TRUE;
+	isOperator['~'] = TRUE;
+	isOperator['|'] = TRUE;
+}
+
+/*//////////////////////////////////////////////////////////////////////
+//// Lexing                                     */
+static boolean isNum (char c)
+{
+	return c >= '0' && c <= '9';
+}
+static boolean isLowerAlpha (char c)
+{
+	return c >= 'a' && c <= 'z';
+}
+
+static boolean isUpperAlpha (char c)
+{
+	return c >= 'A' && c <= 'Z';
+}
+
+static boolean isAlpha (char c)
+{
+	return isLowerAlpha (c) || isUpperAlpha (c);
+}
+
+static boolean isIdent (char c)
+{
+	return isNum (c) || isAlpha (c) || c == '_' || c == '\'';
+}
+
+static boolean isSpace (char c)
+{
+	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+static void eatWhiteSpace (lexingState * st)
+{
+	const unsigned char *cp = st->cp;
+	while (isSpace (*cp))
+		cp++;
+
+	st->cp = cp;
+}
+
+static void eatString (lexingState * st)
+{
+	boolean lastIsBackSlash = FALSE;
+	boolean unfinished = TRUE;
+	const unsigned char *c = st->cp + 1;
+
+	while (unfinished)
+	{
+		/* end of line should never happen.
+		 * we tolerate it */
+		if (c == NULL || c[0] == '\0')
+			break;
+		else if (*c == '"' && !lastIsBackSlash)
+			unfinished = FALSE;
+		else
+			lastIsBackSlash = *c == '\\';
+
+		c++;
+	}
+
+	st->cp = c;
+}
+
+static void eatComment (lexingState * st)
+{
+	boolean unfinished = TRUE;
+	boolean lastIsStar = FALSE;
+	const unsigned char *c = st->cp + 2;
+
+	while (unfinished)
+	{
+		/* we've reached the end of the line..
+		 * so we have to reload a line... */
+		if (c == NULL || *c == '\0')
+		{
+			st->cp = fileReadLine ();
+			/* WOOPS... no more input...
+			 * we return, next lexing read
+			 * will be null and ok */
+			if (st->cp == NULL)
+				return;
+			c = st->cp;
+			continue;
+		}
+		/* we've reached the end of the comment */
+		else if (*c == ')' && lastIsStar)
+			unfinished = FALSE;
+		/* here we deal with imbricated comment, which
+		 * are allowed in OCaml */
+		else if (c[0] == '(' && c[1] == '*')
+		{
+			st->cp = c;
+			eatComment (st);
+			c = st->cp;
+			lastIsStar = FALSE;
+		}
+		else
+			lastIsStar = '*' == *c;
+
+		c++;
+	}
+
+	st->cp = c;
+}
+
+static void readIdentifier (lexingState * st)
+{
+	const unsigned char *p;
+	vStringClear (st->name);
+
+	/* first char is a simple letter */
+	if (isAlpha (*st->cp) || *st->cp == '_')
+		vStringPut (st->name, (int) *st->cp);
+
+	/* Go till you get identifier chars */
+	for (p = st->cp + 1; isIdent (*p); p++)
+		vStringPut (st->name, (int) *p);
+
+	st->cp = p;
+
+	vStringTerminate (st->name);
+}
+
+static ocamlKeyword eatNumber (lexingState * st)
+{
+	while (isNum (*st->cp))
+		st->cp++;
+	return Tok_Val;
+}
+
+/* Operator can be defined in OCaml as a function
+ * so we must be ample enough to parse them normally */
+static ocamlKeyword eatOperator (lexingState * st)
+{
+	int count = 0;
+	const unsigned char *root = st->cp;
+
+	vStringClear (st->name);
+
+	while (isOperator[st->cp[count]])
+	{
+		vStringPut (st->name, st->cp[count]);
+		count++;
+	}
+
+	vStringTerminate (st->name);
+
+	st->cp += count;
+	if (count <= 1)
+	{
+		switch (root[0])
+		{
+		case '|':
+			return Tok_Pipe;
+		case '=':
+			return Tok_EQ;
+		default:
+			return Tok_Op;
+		}
+	}
+	else if (count == 2 && root[0] == '-' && root[1] == '>')
+		return Tok_To;
+	else
+		return Tok_Op;
+}
+
+/* The lexer is in charge of reading the file.
+ * Some of sub-lexer (like eatComment) also read file.
+ * lexing is finished when the lexer return Tok_EOF */
+static ocamlKeyword lex (lexingState * st)
+{
+	int retType;
+	/* handling data input here */
+	while (st->cp == NULL || st->cp[0] == '\0')
+	{
+		st->cp = fileReadLine ();
+		if (st->cp == NULL)
+			return Tok_EOF;
+	}
+
+	if (isAlpha (*st->cp))
+	{
+		readIdentifier (st);
+		retType = lookupKeyword (vStringValue (st->name), Lang_Ocaml);
+
+		if (retType == -1)	/* If it's not a keyword */
+		{
+			return OcaIDENTIFIER;
+		}
+		else
+		{
+			return retType;
+		}
+	}
+	else if (isNum (*st->cp))
+		return eatNumber (st);
+	else if (isSpace (*st->cp))
+	{
+		eatWhiteSpace (st);
+		return lex (st);
+	}
+	/* OCaml permit the definition of our own operators
+	 * so here we check all the consecuting chars which
+	 * are operators to discard them. */
+	else if (isOperator[*st->cp])
+		return eatOperator (st);
+	else
+		switch (*st->cp)
+		{
+		case '(':
+			if (st->cp[1] == '*')	/* ergl, a comment */
+			{
+				eatComment (st);
+				return lex (st);
+			}
+			else
+			{
+				st->cp++;
+				return Tok_PARL;
+			}
+
+		case ')':
+			st->cp++;
+			return Tok_PARR;
+		case '[':
+			st->cp++;
+			return Tok_BRL;
+		case ']':
+			st->cp++;
+			return Tok_BRR;
+		case '{':
+			st->cp++;
+			return Tok_CurlL;
+		case '}':
+			st->cp++;
+			return Tok_CurlR;
+		case '\'':
+			st->cp++;
+			return Tok_Prime;
+		case ',':
+			st->cp++;
+			return Tok_comma;
+		case '=':
+			st->cp++;
+			return Tok_EQ;
+		case ';':
+			st->cp++;
+			return Tok_semi;
+		case '"':
+			eatString (st);
+			return Tok_Val;
+		case '_':
+			st->cp++;
+			return Tok_Val;
+		case '#':
+			st->cp++;
+			return Tok_Sharp;
+		case '\\':
+			st->cp++;
+			return Tok_Backslash;
+
+		default:
+			st->cp++;
+			break;
+		}
+
+	/* default return if nothing is recognized,
+	 * shouldn't happen, but at least, it will
+	 * be handled without destroying the parsing. */
+	return Tok_Val;
+}
+
+/*//////////////////////////////////////////////////////////////////////
+//// Parsing                                    */
+typedef void (*parseNext) (vString * const ident, ocaToken what);
+
+/********** Helpers */
+/* This variable hold the 'parser' which is going to
+ * handle the next token */
+parseNext toDoNext;
+
+/* Special variable used by parser eater to
+ * determine which action to put after their
+ * job is finished. */
+parseNext comeAfter;
+
+/* If a token put an end to current delcaration/
+ * statement */
+ocaToken terminatingToken;
+
+/* Token to be searched by the different
+ * parser eater. */
+ocaToken waitedToken;
+
+/* name of the last class, used for
+ * context stacking. */
+vString *lastClass;
+
+vString *voidName;
+
+typedef enum _sContextKind {
+	ContextStrong,
+	ContextSoft
+} contextKind;
+
+typedef enum _sContextType {
+	ContextType,
+	ContextModule,
+	ContextClass,
+	ContextValue,
+	ContextFunction,
+	ContextMethod,
+	ContextBlock
+} contextType;
+
+typedef struct _sOcamlContext {
+	contextKind kind;	/* well if the context is strong or not */
+	contextType type;
+	parseNext callback;	/* what to do when a context is pop'd */
+	vString *contextName;	/* name, if any, of the surrounding context */
+} ocamlContext;
+
+/* context stack, can be used to output scope information
+ * into the tag file. */
+ocamlContext stack[OCAML_MAX_STACK_SIZE];
+/* current position in the tag */
+int stackIndex;
+
+/* special function, often recalled, so putting it here */
+static void globalScope (vString * const ident, ocaToken what);
+
+/* Return : index of the last named context if one
+ *          is found, -1 otherwise */
+static int getLastNamedIndex ( void )
+{
+	int i;
+
+	for (i = stackIndex - 1; i >= 0; --i)
+	{
+		if (stack[i].contextName->buffer &&
+			strlen (stack[i].contextName->buffer) > 0)
+		{
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static const char *contextDescription (contextType t)
+{
+	switch (t)
+	{
+	case ContextFunction:
+		return "function";
+	case ContextMethod:
+		return "method";
+	case ContextValue:
+		return "value";
+	case ContextModule:
+		return "Module";
+	case ContextType:
+		return "type";
+	case ContextClass:
+		return "class";
+	case ContextBlock:
+		return "begin/end";
+	}
+
+	return NULL;
+}
+
+static char contextTypeSuffix (contextType t)
+{
+	switch (t)
+	{
+	case ContextFunction:
+	case ContextMethod:
+	case ContextValue:
+	case ContextModule:
+		return '/';
+	case ContextType:
+		return '.';
+	case ContextClass:
+		return '#';
+	case ContextBlock:
+		return ' ';
+	}
+
+	return '$';
+}
+
+/* Push a new context, handle null string */
+static void pushContext (contextKind kind, contextType type, parseNext after,
+        vString const *contextName)
+{
+	int parentIndex;
+
+	if (stackIndex >= OCAML_MAX_STACK_SIZE)
+	{
+		verbose ("OCaml Maximum depth reached");
+		return;
+	}
+
+
+	stack[stackIndex].kind = kind;
+	stack[stackIndex].type = type;
+	stack[stackIndex].callback = after;
+
+	parentIndex = getLastNamedIndex ();
+	if (contextName == NULL)
+	{
+		vStringClear (stack[stackIndex++].contextName);
+		return;
+	}
+
+	if (parentIndex >= 0)
+	{
+		vStringCopy (stack[stackIndex].contextName,
+			stack[parentIndex].contextName);
+		vStringPut (stack[stackIndex].contextName,
+			contextTypeSuffix (stack[parentIndex].type));
+
+		vStringCat (stack[stackIndex].contextName, contextName);
+	}
+	else
+		vStringCopy (stack[stackIndex].contextName, contextName);
+
+	stackIndex++;
+}
+
+static void pushStrongContext (vString * name, contextType type)
+{
+	pushContext (ContextStrong, type, &globalScope, name);
+}
+
+static void pushSoftContext (parseNext continuation,
+	vString * name, contextType type)
+{
+	pushContext (ContextSoft, type, continuation, name);
+}
+
+static void pushEmptyContext (parseNext continuation)
+{
+	pushContext (ContextSoft, ContextValue, continuation, NULL);
+}
+
+/* unroll the stack until the last named context.
+ * then discard it. Used to handle the :
+ * let f x y = ...
+ * in ...
+ * where the context is reseted after the in. Context may have
+ * been really nested before that. */
+static void popLastNamed ( void )
+{
+	int i = getLastNamedIndex ();
+
+	if (i >= 0)
+	{
+		stackIndex = i;
+		toDoNext = stack[i].callback;
+		vStringClear (stack[i].contextName);
+	}
+	else
+	{
+		/* ok, no named context found... 
+		 * (should not happen). */
+		stackIndex = 0;
+		toDoNext = &globalScope;
+	}
+}
+
+/* pop a context without regarding it's content
+ * (beside handling empty stack case) */
+static void popSoftContext ( void )
+{
+	if (stackIndex <= 0)
+	{
+		toDoNext = &globalScope;
+	}
+	else
+	{
+		stackIndex--;
+		toDoNext = stack[stackIndex].callback;
+		vStringClear (stack[stackIndex].contextName);
+	}
+}
+
+/* Reset everything until the last global space.
+ * a strong context can be :
+ * - module
+ * - class definition
+ * - the initial global space
+ * - a _global_ delcaration (let at global scope or in a module).
+ * Created to exit quickly deeply nested context */
+static contextType popStrongContext ( void )
+{
+	int i;
+
+	for (i = stackIndex - 1; i >= 0; --i)
+	{
+		if (stack[i].kind == ContextStrong)
+		{
+			stackIndex = i;
+			toDoNext = stack[i].callback;
+			vStringClear (stack[i].contextName);
+			return stack[i].type;
+		}
+	}
+	/* ok, no strong context found... */
+	stackIndex = 0;
+	toDoNext = &globalScope;
+	return -1;
+}
+
+/* Ignore everything till waitedToken and jump to comeAfter.
+ * If the "end" keyword is encountered break, doesn't remember
+ * why though. */
+static void tillToken (vString * const UNUSED (ident), ocaToken what)
+{
+	if (what == waitedToken)
+		toDoNext = comeAfter;
+	else if (what == OcaKEYWORD_end)
+	{
+		popStrongContext ();
+		toDoNext = &globalScope;
+	}
+}
+
+/* Ignore everything till a waitedToken is seen, but
+ * take care of balanced parentheses/bracket use */
+static void contextualTillToken (vString * const UNUSED (ident), ocaToken what)
+{
+	static int parentheses = 0;
+	static int bracket = 0;
+	static int curly = 0;
+
+	switch (what)
+	{
+	case Tok_PARL:
+		parentheses--;
+		break;
+	case Tok_PARR:
+		parentheses++;
+		break;
+	case Tok_CurlL:
+		curly--;
+		break;
+	case Tok_CurlR:
+		curly++;
+		break;
+	case Tok_BRL:
+		bracket--;
+		break;
+	case Tok_BRR:
+		bracket++;
+		break;
+
+	default:	/* other token are ignored */
+		break;
+	}
+
+	if (what == waitedToken && parentheses == 0 && bracket == 0 && curly == 0)
+		toDoNext = comeAfter;
+
+	else if (what == OcaKEYWORD_end)
+	{
+		popStrongContext ();
+		toDoNext = &globalScope;
+	}
+}
+
+/* Wait for waitedToken and jump to comeAfter or let
+ * the globalScope handle declarations */
+static void tillTokenOrFallback (vString * const ident, ocaToken what)
+{
+	if (what == waitedToken)
+		toDoNext = comeAfter;
+	else
+		globalScope (ident, what);
+}
+
+/* ignore token till waitedToken, or give up if find
+ * terminatingToken. Use globalScope to handle new
+ * declarations. */
+static void tillTokenOrTerminatingOrFallback (vString * const ident,
+	ocaToken what)
+{
+	if (what == waitedToken)
+		toDoNext = comeAfter;
+	else if (what == terminatingToken)
+		toDoNext = globalScope;
+	else
+		globalScope (ident, what);
+}
+
+/* ignore the next token in the stream and jump to the
+ * given comeAfter state */
+static void ignoreToken (vString * const UNUSED (ident), ocaToken UNUSED (what))
+{
+	toDoNext = comeAfter;
+}
+
+/********** Grammar */
+/* the purpose of each function is detailled near their
+ * implementation */
+
+static void killCurrentState ( void )
+{
+
+	/* Tracking the kind of previous strong
+	 * context, if it doesn't match with a
+	 * really strong entity, repop */
+	switch (popStrongContext ())
+	{
+
+	case ContextValue:
+		popStrongContext ();
+		break;
+	case ContextFunction:
+		popStrongContext ();
+		break;
+	case ContextMethod:
+		popStrongContext ();
+		break;
+
+	case ContextType:
+		popStrongContext();
+		break;
+	case ContextBlock:
+		break;
+	case ContextModule:
+		break;
+	case ContextClass:
+		break;
+	default:
+		/* nothing more */
+		break;
+	}
+}
+
+/* used to prepare tag for OCaml, just in case their is a need to
+ * add additional information to the tag. */
+static void prepareTag (tagEntryInfo * tag, vString const *name, ocamlKind kind)
+{
+	int parentIndex;
+
+	initTagEntry (tag, vStringValue (name));
+	tag->kindName = OcamlKinds[kind].name;
+	tag->kind = OcamlKinds[kind].letter;
+
+	parentIndex = getLastNamedIndex ();
+	if (parentIndex >= 0)
+	{
+		tag->extensionFields.scope[0] =
+			contextDescription (stack[parentIndex].type);
+		tag->extensionFields.scope[1] =
+			vStringValue (stack[parentIndex].contextName);
+	}
+}
+
+/* Used to centralise tag creation, and be able to add
+ * more information to it in the future */
+static void addTag (vString * const ident, int kind)
+{
+	tagEntryInfo toCreate;
+	prepareTag (&toCreate, ident, kind);
+	makeTagEntry (&toCreate);
+}
+
+boolean needStrongPoping = FALSE;
+static void requestStrongPoping ( void )
+{
+	needStrongPoping = TRUE;
+}
+
+static void cleanupPreviousParser ( void )
+{
+	if (needStrongPoping)
+	{
+		needStrongPoping = FALSE;
+		popStrongContext ();
+	}
+}
+
+/* Due to some circular dependencies, the following functions
+ * must be forward-declared. */
+static void letParam (vString * const ident, ocaToken what);
+static void localScope (vString * const ident, ocaToken what);
+static void mayRedeclare (vString * const ident, ocaToken what);
+static void typeSpecification (vString * const ident, ocaToken what);
+
+/*
+ * Parse a record type
+ * type ident = // parsed previously
+ *  {
+ *      ident1: type1;
+ *      ident2: type2;
+ *  }
+ */
+static void typeRecord (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case OcaIDENTIFIER:
+		addTag (ident, K_RECORDFIELD);
+		terminatingToken = Tok_CurlR;
+		waitedToken = Tok_semi;
+		comeAfter = &typeRecord;
+		toDoNext = &tillTokenOrTerminatingOrFallback;
+		break;
+
+	case OcaKEYWORD_mutable:
+		/* ignore it */
+		break;
+
+	case Tok_CurlR:
+		popStrongContext ();
+		toDoNext = &globalScope;
+		break;
+
+	default:	/* don't care */
+		break;
+	}
+}
+
+/* handle :
+ * exception ExceptionName ... */
+static void exceptionDecl (vString * const ident, ocaToken what)
+{
+	if (what == OcaIDENTIFIER)
+	{
+		addTag (ident, K_EXCEPTION);
+	}
+	/* don't know what to do on else... */
+
+	toDoNext = &globalScope;
+}
+
+tagEntryInfo tempTag;
+vString *tempIdent;
+
+/* Ensure a constructor is not a type path beginning
+ * with a module */
+static void constructorValidation (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_Op:	/* if we got a '.' which is an operator */
+		toDoNext = &globalScope;
+		popStrongContext ();
+		needStrongPoping = FALSE;
+		break;
+
+	case OcaKEYWORD_of:	/* OK, it must be a constructor :) */
+		makeTagEntry (&tempTag);
+		vStringClear (tempIdent);
+		toDoNext = &tillTokenOrFallback;
+		comeAfter = &typeSpecification;
+		waitedToken = Tok_Pipe;
+		break;
+
+	case Tok_Pipe:	/* OK, it was a constructor :)  */
+		makeTagEntry (&tempTag);
+		vStringClear (tempIdent);
+		toDoNext = &typeSpecification;
+		break;
+
+	default:	/* and mean that we're not facing a module name */
+		makeTagEntry (&tempTag);
+		vStringClear (tempIdent);
+		toDoNext = &tillTokenOrFallback;
+		comeAfter = &typeSpecification;
+		waitedToken = Tok_Pipe;
+
+		/* nothing in the context, discard it */
+		popStrongContext ();
+
+		/* to be sure we use this token */
+		globalScope (ident, what);
+	}
+}
+
+
+/* Parse beginning of type definition
+ * type 'avar ident =
+ * or
+ * type ('var1, 'var2) ident =
+ */
+static void typeDecl (vString * const ident, ocaToken what)
+{
+
+	switch (what)
+	{
+		/* parameterized */
+	case Tok_Prime:
+		comeAfter = &typeDecl;
+		toDoNext = &ignoreToken;
+		break;
+		/* LOTS of parameters */
+	case Tok_PARL:
+		comeAfter = &typeDecl;
+		waitedToken = Tok_PARR;
+		toDoNext = &tillToken;
+		break;
+
+	case OcaIDENTIFIER:
+		addTag (ident, K_TYPE);
+		pushStrongContext (ident, ContextType);
+		requestStrongPoping ();
+		waitedToken = Tok_EQ;
+		comeAfter = &typeSpecification;
+		toDoNext = &tillTokenOrFallback;
+		break;
+
+	default:
+		globalScope (ident, what);
+	}
+}
+
+/* Parse type of kind
+ * type bidule = Ctor1 of ...
+ *             | Ctor2
+ *             | Ctor3 of ...
+ * or
+ * type bidule = | Ctor1 of ... | Ctor2
+ *
+ * when type bidule = { ... } is detected,
+ * let typeRecord handle it. */
+static void typeSpecification (vString * const ident, ocaToken what)
+{
+
+	switch (what)
+	{
+	case OcaIDENTIFIER:
+		if (isUpperAlpha (ident->buffer[0]))
+		{
+			/* here we handle type aliases of type
+			 * type foo = AnotherModule.bar
+			 * AnotherModule can mistakenly be took
+			 * for a constructor. */
+			vStringCopy (tempIdent, ident);
+			prepareTag (&tempTag, tempIdent, K_CONSTRUCTOR);
+			toDoNext = &constructorValidation;
+		}
+		else
+		{
+			toDoNext = &tillTokenOrFallback;
+			comeAfter = &typeSpecification;
+			waitedToken = Tok_Pipe;
+		}
+		break;
+
+	case OcaKEYWORD_and:
+		toDoNext = &typeDecl;
+		break;
+
+	case Tok_BRL:	/* the '[' & ']' are ignored to accommodate */
+	case Tok_BRR:	/* with the revised syntax */
+	case Tok_Pipe:
+		/* just ignore it */
+		break;
+
+	case Tok_CurlL:
+		toDoNext = &typeRecord;
+		break;
+
+	default:	/* don't care */
+		break;
+	}
+}
+
+
+static boolean dirtySpecialParam = FALSE;
+
+
+/* parse the ~label and ~label:type parameter */
+static void parseLabel (vString * const ident, ocaToken what)
+{
+	static int parCount = 0;
+
+	switch (what)
+	{
+	case OcaIDENTIFIER:
+		if (!dirtySpecialParam)
+		{
+
+			if (exportLocalInfo)
+				addTag (ident, K_VAR);
+
+			dirtySpecialParam = TRUE;
+		}
+		break;
+
+	case Tok_PARL:
+		parCount++;
+		break;
+
+	case Tok_PARR:
+		parCount--;
+		if (parCount == 0)
+			toDoNext = &letParam;
+		break;
+
+	case Tok_Op:
+		if (ident->buffer[0] == ':')
+		{
+			toDoNext = &ignoreToken;
+			comeAfter = &letParam;
+		}
+		else if (parCount == 0 && dirtySpecialParam)
+		{
+			toDoNext = &letParam;
+			letParam (ident, what);
+		}
+		break;
+
+	default:
+		if (parCount == 0 && dirtySpecialParam)
+		{
+			toDoNext = &letParam;
+			letParam (ident, what);
+		}
+		break;
+	}
+}
+
+
+/* Optional argument with syntax like this :
+ * ?(foo = value) */
+static void parseOptionnal (vString * const ident, ocaToken what)
+{
+	static int parCount = 0;
+
+
+	switch (what)
+	{
+	case OcaIDENTIFIER:
+		if (!dirtySpecialParam)
+		{
+			if (exportLocalInfo)
+				addTag (ident, K_VAR);
+
+			dirtySpecialParam = TRUE;
+
+			if (parCount == 0)
+				toDoNext = &letParam;
+		}
+		break;
+
+	case Tok_PARL:
+		parCount++;
+		break;
+
+	case Tok_PARR:
+		parCount--;
+		if (parCount == 0)
+			toDoNext = &letParam;
+		break;
+
+	default:	/* don't care */
+		break;
+	}
+}
+
+
+/** handle let inside functions (so like it's name
+ * say : local let */
+static void localLet (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_PARL:
+		/* We ignore this token to be able to parse such
+		 * declarations :
+		 * let (ident : type) = ...
+		 */
+		break;
+
+	case OcaKEYWORD_rec:
+		/* just ignore to be able to parse such declarations:
+		 * let rec ident = ... */
+		break;
+
+	case Tok_Op:
+		/* we are defining a new operator, it's a
+		 * function definition */
+		if (exportLocalInfo)
+			addTag (ident, K_FUNCTION);
+
+		pushSoftContext (mayRedeclare, ident, ContextFunction);
+		toDoNext = &letParam;
+		break;
+
+		/* Can be a weiiird binding, or an '_' */
+	case Tok_Val:
+		if (exportLocalInfo)
+			addTag (ident, K_VAR);
+		pushSoftContext (mayRedeclare, ident, ContextValue);
+		toDoNext = &letParam;
+		break;
+
+	case OcaIDENTIFIER:
+		if (exportLocalInfo)
+			addTag (ident, K_VAR);
+		pushSoftContext (mayRedeclare, ident, ContextValue);
+		toDoNext = &letParam;
+		break;
+
+	case OcaKEYWORD_end:
+		popStrongContext ();
+		break;
+
+	default:
+		toDoNext = &localScope;
+		break;
+	}
+}
+
+/* parse :
+ * | pattern pattern -> ...
+ * or
+ * pattern apttern apttern -> ...
+ * we ignore all identifiers declared in the pattern,
+ * because their scope is likely to be even more limited
+ * than the let definitions.
+ * Used after a match ... with, or a function ... or fun ...
+ * because their syntax is similar.  */
+static void matchPattern (vString * const UNUSED (ident), ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_To:
+		pushEmptyContext (&matchPattern);
+		toDoNext = &mayRedeclare;
+		break;
+
+
+	case OcaKEYWORD_in:
+		popLastNamed ();
+		break;
+
+	default:
+		break;
+	}
+}
+
+/* Used at the beginning of a new scope (begin of a
+ * definition, parenthesis...) to catch inner let
+ * definition that may be in. */
+static void mayRedeclare (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case OcaKEYWORD_let:
+	case OcaKEYWORD_val:
+		toDoNext = localLet;
+		break;
+
+	case OcaKEYWORD_object:
+		vStringClear (lastClass);
+		pushContext (ContextStrong, ContextClass,
+			&localScope, NULL /*voidName */ );
+		needStrongPoping = FALSE;
+		toDoNext = &globalScope;
+		break;
+
+	case OcaKEYWORD_for:
+	case OcaKEYWORD_while:
+		toDoNext = &tillToken;
+		waitedToken = OcaKEYWORD_do;
+		comeAfter = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_try:
+		toDoNext = &mayRedeclare;
+		pushSoftContext (matchPattern, ident, ContextFunction);
+		break;
+
+	case OcaKEYWORD_fun:
+		toDoNext = &matchPattern;
+		break;
+
+		/* Handle the special ;; from the OCaml
+		 * Top level */
+	case Tok_semi:
+	default:
+		toDoNext = &localScope;
+		localScope (ident, what);
+	}
+}
+
+/* parse :
+ * p1 p2 ... pn = ...
+ * or
+ * ?(p1=v) p2 ~p3 ~pn:ja ... = ... */
+static void letParam (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_EQ:
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaIDENTIFIER:
+		if (exportLocalInfo)
+			addTag (ident, K_VAR);
+		break;
+
+	case Tok_Op:
+		switch (ident->buffer[0])
+		{
+		case ':':
+			/*popSoftContext(); */
+			/* we got a type signature */
+			comeAfter = &mayRedeclare;
+			toDoNext = &tillTokenOrFallback;
+			waitedToken = Tok_EQ;
+			break;
+
+			/* parse something like
+			 * ~varname:type 
+			 * or
+			 * ~varname
+			 * or
+			 * ~(varname: long type) */
+		case '~':
+			toDoNext = &parseLabel;
+			dirtySpecialParam = FALSE;
+			break;
+
+			/* Optional argument with syntax like this :
+			 * ?(bla = value) 
+			 * or
+			 * ?bla */
+		case '?':
+			toDoNext = &parseOptionnal;
+			dirtySpecialParam = FALSE;
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:	/* don't care */
+		break;
+	}
+}
+
+
+/* parse object ...
+ * used to be sure the class definition is not a type
+ * alias */
+static void classSpecif (vString * const UNUSED (ident), ocaToken what)
+{
+	switch (what)
+	{
+	case OcaKEYWORD_object:
+		pushStrongContext (lastClass, ContextClass);
+		toDoNext = &globalScope;
+		break;
+
+	default:
+		vStringClear (lastClass);
+		toDoNext = &globalScope;
+	}
+}
+
+/* Handle a method ... class declaration.
+ * nearly a copy/paste of globalLet. */
+static void methodDecl (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_PARL:
+		/* We ignore this token to be able to parse such
+		 * declarations :
+		 * let (ident : type) = ...  */
+		break;
+
+	case OcaKEYWORD_mutable:
+	case OcaKEYWORD_virtual:
+	case OcaKEYWORD_rec:
+		/* just ignore to be able to parse such declarations:
+		 * let rec ident = ... */
+		break;
+
+	case OcaIDENTIFIER:
+		addTag (ident, K_METHOD);
+		/* Normal pushing to get good subs */
+		pushStrongContext (ident, ContextMethod);
+		/*pushSoftContext( globalScope, ident, ContextMethod ); */
+		toDoNext = &letParam;
+		break;
+
+	case OcaKEYWORD_end:
+		popStrongContext ();
+		break;
+
+	default:
+		toDoNext = &globalScope;
+		break;
+	}
+}
+
+/* name of the last module, used for
+ * context stacking. */
+vString *lastModule;
+
+
+/* parse
+ * ... struct (* new global scope *) end
+ * or
+ * ... sig (* new global scope *) end
+ * or
+ * functor ... -> moduleSpecif
+ */
+static void moduleSpecif (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case OcaKEYWORD_functor:
+		toDoNext = &contextualTillToken;
+		waitedToken = Tok_To;
+		comeAfter = &moduleSpecif;
+		break;
+
+	case OcaKEYWORD_struct:
+	case OcaKEYWORD_sig:
+		pushStrongContext (lastModule, ContextModule);
+		toDoNext = &globalScope;
+		break;
+
+	case Tok_PARL:	/* ( */
+		toDoNext = &contextualTillToken;
+		comeAfter = &globalScope;
+		waitedToken = Tok_PARR;
+		contextualTillToken (ident, what);
+		break;
+
+	default:
+		vStringClear (lastModule);
+		toDoNext = &globalScope;
+	}
+}
+
+/* parse :
+ * module name = ...
+ * then pass the token stream to moduleSpecif */
+static void moduleDecl (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case OcaKEYWORD_type:
+		/* just ignore it, name come after */
+		break;
+
+	case OcaIDENTIFIER:
+		addTag (ident, K_MODULE);
+		vStringCopy (lastModule, ident);
+		waitedToken = Tok_EQ;
+		comeAfter = &moduleSpecif;
+		toDoNext = &contextualTillToken;
+		break;
+
+	default:	/* don't care */
+		break;
+	}
+}
+
+/* parse :
+ * class name = ...
+ * or
+ * class virtual ['a,'b] classname = ... */
+static void classDecl (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case OcaIDENTIFIER:
+		addTag (ident, K_CLASS);
+		vStringCopy (lastClass, ident);
+		toDoNext = &contextualTillToken;
+		waitedToken = Tok_EQ;
+		comeAfter = &classSpecif;
+		break;
+
+	case Tok_BRL:
+		toDoNext = &tillToken;
+		waitedToken = Tok_BRR;
+		comeAfter = &classDecl;
+		break;
+
+	default:
+		break;
+	}
+}
+
+/* Handle a global
+ * let ident ...
+ * or
+ * let rec ident ... */
+static void globalLet (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_PARL:
+		/* We ignore this token to be able to parse such
+		 * declarations :
+		 * let (ident : type) = ...
+		 */
+		break;
+
+	case OcaKEYWORD_mutable:
+	case OcaKEYWORD_virtual:
+	case OcaKEYWORD_rec:
+		/* just ignore to be able to parse such declarations:
+		 * let rec ident = ... */
+		break;
+
+	case Tok_Op:
+		/* we are defining a new operator, it's a
+		 * function definition */
+		addTag (ident, K_FUNCTION);
+		pushStrongContext (ident, ContextFunction);
+		toDoNext = &letParam;
+		break;
+
+	case OcaIDENTIFIER:
+		addTag (ident, K_VAR);
+		pushStrongContext (ident, ContextValue);
+		requestStrongPoping ();
+		toDoNext = &letParam;
+		break;
+
+	case OcaKEYWORD_end:
+		popStrongContext ();
+		break;
+
+	default:
+		toDoNext = &globalScope;
+		break;
+	}
+}
+
+/* Handle the "strong" top levels, all 'big' declarations
+ * happen here */
+static void globalScope (vString * const UNUSED (ident), ocaToken what)
+{
+	/* Do not touch, this is used only by the global scope
+	 * to handle an 'and' */
+	static parseNext previousParser = NULL;
+
+	switch (what)
+	{
+	case OcaKEYWORD_and:
+		cleanupPreviousParser ();
+		toDoNext = previousParser;
+		break;
+
+	case OcaKEYWORD_type:
+		cleanupPreviousParser ();
+		toDoNext = &typeDecl;
+		previousParser = &typeDecl;
+		break;
+
+	case OcaKEYWORD_class:
+		cleanupPreviousParser ();
+		toDoNext = &classDecl;
+		previousParser = &classDecl;
+		break;
+
+	case OcaKEYWORD_module:
+		cleanupPreviousParser ();
+		toDoNext = &moduleDecl;
+		previousParser = &moduleDecl;
+		break;
+
+	case OcaKEYWORD_end:
+		needStrongPoping = FALSE;
+		killCurrentState ();
+		/*popStrongContext(); */
+		break;
+
+	case OcaKEYWORD_method:
+		cleanupPreviousParser ();
+		toDoNext = &methodDecl;
+		/* and is not allowed in methods */
+		break;
+
+		/* val is mixed with let as global
+		 * to be able to handle mli & new syntax */
+	case OcaKEYWORD_val:
+	case OcaKEYWORD_let:
+		cleanupPreviousParser ();
+		toDoNext = &globalLet;
+		previousParser = &globalLet;
+		break;
+
+	case OcaKEYWORD_exception:
+		cleanupPreviousParser ();
+		toDoNext = &exceptionDecl;
+		previousParser = NULL;
+		break;
+
+		/* must be a #line directive, discard the
+		 * whole line. */
+	case Tok_Sharp:
+		/* ignore */
+		break;
+
+	default:
+		/* we don't care */
+		break;
+	}
+}
+
+/* Parse expression. Well ignore it is more the case,
+ * ignore all tokens except "shocking" keywords */
+static void localScope (vString * const ident, ocaToken what)
+{
+	switch (what)
+	{
+	case Tok_Pipe:
+	case Tok_PARR:
+	case Tok_BRR:
+	case Tok_CurlR:
+		popSoftContext ();
+		break;
+
+		/* Everything that `begin` has an `end`
+		 * as end is overloaded and signal many end
+		 * of things, we add an empty strong context to
+		 * avoid problem with the end.
+		 */
+	case OcaKEYWORD_begin:
+		pushContext (ContextStrong, ContextBlock, &mayRedeclare, NULL);
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_in:
+		popLastNamed ();
+		break;
+
+		/* Ok, we got a '{', which is much likely to create
+		 * a record. We cannot treat it like other [ && (,
+		 * because it may contain the 'with' keyword and screw
+		 * everything else. */
+	case Tok_CurlL:
+		toDoNext = &contextualTillToken;
+		waitedToken = Tok_CurlR;
+		comeAfter = &localScope;
+		contextualTillToken (ident, what);
+		break;
+
+		/* Yeah imperative feature of OCaml,
+		 * a ';' like in C */
+	case Tok_semi:
+		toDoNext = &mayRedeclare;
+		break;
+
+	case Tok_PARL:
+	case Tok_BRL:
+		pushEmptyContext (&localScope);
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_and:
+		popLastNamed ();
+		toDoNext = &localLet;
+		break;
+
+	case OcaKEYWORD_else:
+	case OcaKEYWORD_then:
+		popSoftContext ();
+		pushEmptyContext (&localScope);
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_if:
+		pushEmptyContext (&localScope);
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_match:
+		pushEmptyContext (&localScope);
+		toDoNext = &mayRedeclare;
+		break;
+
+	case OcaKEYWORD_with:
+		popSoftContext ();
+		toDoNext = &matchPattern;
+		pushEmptyContext (&matchPattern);
+		break;
+
+	case OcaKEYWORD_end:
+		killCurrentState ();
+		break;
+
+
+	case OcaKEYWORD_fun:
+		comeAfter = &mayRedeclare;
+		toDoNext = &tillToken;
+		waitedToken = Tok_To;
+		break;
+
+	case OcaKEYWORD_done:
+	case OcaKEYWORD_val:
+		/* doesn't care */
+		break;
+
+	default:
+		requestStrongPoping ();
+		globalScope (ident, what);
+		break;
+	}
+}
+
+/*////////////////////////////////////////////////////////////////
+//// Deal with the system                                       */
+/* in OCaml the file name is the module name used in the language
+ * with it first letter put in upper case */
+static void computeModuleName ( void )
+{
+	/* in Ocaml the file name define a module.
+	 * so we define a module =)
+	 */
+	const char *filename = getSourceFileName ();
+	int beginIndex = 0;
+	int endIndex = strlen (filename) - 1;
+	vString *moduleName = vStringNew ();
+
+	while (filename[endIndex] != '.' && endIndex > 0)
+		endIndex--;
+
+	/* avoid problem with path in front of filename */
+	beginIndex = endIndex;
+	while (beginIndex > 0)
+	{
+		if (filename[beginIndex] == '\\' || filename[beginIndex] == '/')
+		{
+			beginIndex++;
+			break;
+		}
+
+		beginIndex--;
+	}
+
+	vStringNCopyS (moduleName, &filename[beginIndex], endIndex - beginIndex);
+	vStringTerminate (moduleName);
+
+	if (isLowerAlpha (moduleName->buffer[0]))
+		moduleName->buffer[0] += ('A' - 'a');
+
+	makeSimpleTag (moduleName, OcamlKinds, K_MODULE);
+	vStringDelete (moduleName);
+}
+
+/* Allocate all string of the context stack */
+static void initStack ( void )
+{
+	int i;
+	for (i = 0; i < OCAML_MAX_STACK_SIZE; ++i)
+		stack[i].contextName = vStringNew ();
+}
+
+static void clearStack ( void )
+{
+	int i;
+	for (i = 0; i < OCAML_MAX_STACK_SIZE; ++i)
+		vStringDelete (stack[i].contextName);
+}
+
+static void findOcamlTags (void)
+{
+	vString *name = vStringNew ();
+	lexingState st;
+	ocaToken tok;
+
+	computeModuleName ();
+	initStack ();
+	tempIdent = vStringNew ();
+	lastModule = vStringNew ();
+	lastClass = vStringNew ();
+	voidName = vStringNew ();
+	vStringCopyS (voidName, "_");
+
+	st.name = vStringNew ();
+	st.cp = fileReadLine ();
+	toDoNext = &globalScope;
+	tok = lex (&st);
+	while (tok != Tok_EOF)
+	{
+		(*toDoNext) (st.name, tok);
+		tok = lex (&st);
+	}
+
+	vStringDelete (name);
+	vStringDelete (voidName);
+	vStringDelete (tempIdent);
+	vStringDelete (lastModule);
+	vStringDelete (lastClass);
+	clearStack ();
+}
+
+static void ocamlInitialize (const langType language)
+{
+	Lang_Ocaml = language;
+
+	initOperatorTable ();
+	initKeywordHash ();
+}
+
+extern parserDefinition *OcamlParser (void)
+{
+	static const char *const extensions[] = { "ml", "mli", NULL };
+	parserDefinition *def = parserNew ("OCaml");
+	def->kinds = OcamlKinds;
+	def->kindCount = KIND_COUNT (OcamlKinds);
+	def->extensions = extensions;
+	def->parser = findOcamlTags;
+	def->initialize = ocamlInitialize;
+
+	return def;
+}
diff --git a/plugins/symbol-db/anjuta-tags/parsers.h b/plugins/symbol-db/anjuta-tags/parsers.h
index bddff58..3dcc8ae 100644
--- a/plugins/symbol-db/anjuta-tags/parsers.h
+++ b/plugins/symbol-db/anjuta-tags/parsers.h
@@ -1,5 +1,5 @@
 /*
-*   $Id: parsers.h 693 2008-12-14 13:19:48Z dfishburn $
+*   $Id: parsers.h 717 2009-07-07 03:40:50Z dhiebert $
 *
 *   Copyright (c) 2000-2003, Darren Hiebert
 *
@@ -38,6 +38,7 @@
 	LuaParser, \
 	MakefileParser, \
 	MatLabParser, \
+	OcamlParser, \
 	PascalParser, \
 	PerlParser, \
 	PhpParser, \
diff --git a/plugins/symbol-db/anjuta-tags/php.c b/plugins/symbol-db/anjuta-tags/php.c
index 0dd60c5..f7b91f8 100644
--- a/plugins/symbol-db/anjuta-tags/php.c
+++ b/plugins/symbol-db/anjuta-tags/php.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: php.c 624 2007-09-15 22:53:31Z jafl $
+*   $Id: php.c 729 2009-07-10 23:34:21Z jafl $
 *
 *   Copyright (c) 2000, Jesus Castagnetto <jmcastagnetto zkey com>
 *
@@ -64,17 +64,17 @@ static kindOption PhpKinds [] = {
 
 static void installPHPRegex (const langType language)
 {
-	addTagRegex(language, "(^|[ \t])class[ \t]+([" ALPHA "_][" ALNUM "_]*)",
+	addTagRegex(language, "^[ \t]*(abstract[ \t]+)?class[ \t]+([" ALPHA "_][" ALNUM "_]*)",
 		"\\2", "c,class,classes", NULL);
-	addTagRegex(language, "(^|[ \t])interface[ \t]+([" ALPHA "_][" ALNUM "_]*)",
-		"\\2", "i,interface,interfaces", NULL);
-	addTagRegex(language, "(^|[ \t])define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)",
-		"\\2", "d,define,constant definitions", NULL);
-	addTagRegex(language, "(^|[ \t])function[ \t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)",
-		"\\2", "f,function,functions", NULL);
-	addTagRegex(language, "(^|[ \t])(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=",
-		"\\3", "v,variable,variables", NULL);
-	addTagRegex(language, "(^|[ \t])(var|public|protected|private|static)[ \t]+\\$([" ALPHA "_][" ALNUM "_]*)[ \t]*[=;]",
+	addTagRegex(language, "^[ \t]*interface[ \t]+([" ALPHA "_][" ALNUM "_]*)",
+		"\\1", "i,interface,interfaces", NULL);
+	addTagRegex(language, "^[ \t]*define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)",
+		"\\1", "d,define,constant definitions", NULL);
+	addTagRegex(language, "^[ \t]*((static|public|protected|private)[ \t]+)*function[ \t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)",
+		"\\3", "f,function,functions", NULL);
+	addTagRegex(language, "^[ \t]*(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=",
+		"\\2", "v,variable,variables", NULL);
+	addTagRegex(language, "^[ \t]*((var|public|protected|private|static)[ \t]+)+\\$([" ALPHA "_][" ALNUM "_]*)[ \t]*[=;]",
 		"\\3", "v,variable,variables", NULL);
 
 	/* function regex is covered by PHP regex */
diff --git a/plugins/symbol-db/anjuta-tags/python.c b/plugins/symbol-db/anjuta-tags/python.c
index f565200..5fdf31b 100644
--- a/plugins/symbol-db/anjuta-tags/python.c
+++ b/plugins/symbol-db/anjuta-tags/python.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: python.c 704 2009-05-17 16:17:25Z elias $
+*   $Id: python.c 720 2009-07-07 03:55:23Z dhiebert $
 *
 *   Copyright (c) 2000-2003, Darren Hiebert
 *
@@ -19,23 +19,14 @@
 #include "entry.h"
 #include "options.h"
 #include "read.h"
-#include "routines.h"
+#include "main.h"
 #include "vstring.h"
+#include "routines.h"
+#include "debug.h"
 
 /*
-*   DATA DEFINITIONS
+*   DATA DECLARATIONS
 */
-typedef enum {
-	K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE
-} pythonKind;
-
-static kindOption PythonKinds[] = {
-	{TRUE, 'c', "class",    "classes"},
-	{TRUE, 'f', "function", "functions"},
-	{TRUE, 'm', "member",   "class members"},
-    {TRUE, 'v', "variable", "variables"}
-};
-
 typedef struct NestingLevel NestingLevel;
 typedef struct NestingLevels NestingLevels;
 
@@ -43,16 +34,31 @@ struct NestingLevel
 {
 	int indentation;
 	vString *name;
-	boolean is_class;
+	int type;
 };
 
 struct NestingLevels
 {
 	NestingLevel *levels;
-	int n;
+	int n;					/* number of levels in use */
 	int allocated;
 };
 
+typedef enum {
+	K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE, K_IMPORT
+} pythonKind;
+
+/*
+*   DATA DEFINITIONS
+*/
+static kindOption PythonKinds[] = {
+	{TRUE, 'c', "class",    "classes"},
+	{TRUE, 'f', "function", "functions"},
+	{TRUE, 'm', "member",   "class members"},
+    {TRUE, 'v', "variable", "variables"},
+    {TRUE, 'i', "namespace", "imports"}
+};
+
 static char const * const singletriple = "'''";
 static char const * const doubletriple = "\"\"\"";
 
@@ -60,7 +66,60 @@ static char const * const doubletriple = "\"\"\"";
 *   FUNCTION DEFINITIONS
 */
 
-#define vStringLast(vs) ((vs)->buffer[(vs)->length - 1])
+static NestingLevels *nestingLevelsNew (void)
+{
+	NestingLevels *nls = xCalloc (1, NestingLevels);
+	return nls;
+}
+
+static void nestingLevelsFree (NestingLevels *nls)
+{
+	int i;
+	for (i = 0; i < nls->allocated; i++)
+		vStringDelete(nls->levels[i].name);
+	if (nls->levels) eFree(nls->levels);
+	eFree(nls);
+}
+
+static void nestingLevelsPush (NestingLevels *nls,
+	const vString *name, int type)
+{
+	NestingLevel *nl = NULL;
+
+	if (nls->n >= nls->allocated)
+	{
+		nls->allocated++;
+		nls->levels = xRealloc(nls->levels,
+			nls->allocated, NestingLevel);
+		nls->levels[nls->n].name = vStringNew();
+	}
+	nl = &nls->levels[nls->n];
+	nls->n++;
+
+	vStringCopy(nl->name, name);
+	nl->type = type;
+}
+
+#if 0
+static NestingLevel *nestingLevelsGetCurrent (NestingLevels *nls)
+{
+	Assert (nls != NULL);
+
+	if (nls->n < 1)
+		return NULL;
+
+	return &nls->levels[nls->n - 1];
+}
+
+static void nestingLevelsPop (NestingLevels *nls)
+{
+	const NestingLevel *nl = nestingLevelsGetCurrent(nls);
+
+	Assert (nl != NULL);
+	vStringClear(nl->name);
+	nls->n--;
+}
+#endif
 
 static boolean isIdentifierFirstCharacter (int c)
 {
@@ -76,13 +135,14 @@ static boolean isIdentifierCharacter (int c)
  * extract all relevant information and create a tag.
  */
 static void makeFunctionTag (vString *const function,
-	vString *const parent, int is_class_parent)
+	vString *const parent, int is_class_parent, const char *arglist __unused__)
 {
 	tagEntryInfo tag;
 	initTagEntry (&tag, vStringValue (function));
-	
+
 	tag.kindName = "function";
 	tag.kind = 'f';
+	/* tag.extensionFields.arglist = arglist; */
 
 	if (vStringLength (parent) > 0)
 	{
@@ -263,11 +323,82 @@ static void parseClass (const char *cp, vString *const class,
 	vStringDelete (inheritance);
 }
 
+static void parseImports (const char *cp)
+{
+	const char *pos;
+	vString *name, *name_next;
+
+	cp = skipEverything (cp);
+
+	if ((pos = strstr (cp, "import")) == NULL)
+		return;
+
+	cp = pos + 6;
+
+	/* continue only if there is some space between the keyword and the identifier */
+	if (! isspace (*cp))
+		return;
+
+	cp++;
+	cp = skipSpace (cp);
+
+	name = vStringNew ();
+	name_next = vStringNew ();
+
+	cp = skipEverything (cp);
+	while (*cp)
+	{
+		cp = parseIdentifier (cp, name);
+
+		cp = skipEverything (cp);
+		/* we parse the next possible import statement as well to be able to ignore 'foo' in
+		 * 'import foo as bar' */
+		parseIdentifier (cp, name_next);
+
+		/* take the current tag only if the next one is not "as" */
+		if (strcmp (vStringValue (name_next), "as") != 0 &&
+			strcmp (vStringValue (name), "as") != 0)
+		{
+			makeSimpleTag (name, PythonKinds, K_IMPORT);
+		}
+	}
+	vStringDelete (name);
+	vStringDelete (name_next);
+}
+
+/* modified from get.c getArglistFromStr().
+ * warning: terminates rest of string past arglist!
+ * note: does not ignore brackets inside strings! */
+static char *parseArglist(const char *buf)
+{
+	char *start, *end;
+	int level;
+	if (NULL == buf)
+		return NULL;
+	if (NULL == (start = strchr(buf, '(')))
+		return NULL;
+	for (level = 1, end = start + 1; level > 0; ++end)
+	{
+		if ('\0' == *end)
+			break;
+		else if ('(' == *end)
+			++ level;
+		else if (')' == *end)
+			-- level;
+	}
+	*end = '\0';
+	return strdup(start);
+}
+
 static void parseFunction (const char *cp, vString *const def,
 	vString *const parent, int is_class_parent)
 {
+	char *arglist;
+
 	cp = parseIdentifier (cp, def);
-	makeFunctionTag (def, parent, is_class_parent);
+	arglist = parseArglist (cp);
+	makeFunctionTag (def, parent, is_class_parent, arglist);
+	eFree (arglist);
 }
 
 /* Get the combined name of a nested symbol. Classes are separated with ".",
@@ -295,13 +426,16 @@ static boolean constructParentString(NestingLevels *nls, int indent,
 			break;
 		if (prev)
 		{
-			if (prev->is_class)
+			vStringCatS(result, ".");	/* make Geany symbol list grouping work properly */
+/*
+			if (prev->type == K_CLASS)
 				vStringCatS(result, ".");
 			else
 				vStringCatS(result, "/");
+*/
 		}
 		vStringCat(result, nl->name);
-		is_class = nl->is_class;
+		is_class = (nl->type == K_CLASS);
 		prev = nl;
 	}
 	return is_class;
@@ -331,27 +465,8 @@ static void checkParent(NestingLevels *nls, int indent, vString *parent)
 	}
 }
 
-static NestingLevels *newNestingLevels(void)
-{
-	NestingLevels *nls = xCalloc (1, NestingLevels);
-	return nls;
-}
-
-static void freeNestingLevels(NestingLevels *nls)
-{
-	int i;
-	for (i = 0; i < nls->allocated; i++)
-		vStringDelete(nls->levels[i].name);
-	if (nls->levels) eFree(nls->levels);
-	eFree(nls);
-}
-
-/* TODO: This is totally out of place in python.c, but strlist.h is not usable.
- * Maybe should just move these three functions to a separate file, even if no
- * other parser uses them.
- */
 static void addNestingLevel(NestingLevels *nls, int indentation,
-	vString *name, boolean is_class)
+	const vString *name, boolean is_class)
 {
 	int i;
 	NestingLevel *nl = NULL;
@@ -363,20 +478,16 @@ static void addNestingLevel(NestingLevels *nls, int indentation,
 	}
 	if (i == nls->n)
 	{
-		if (i >= nls->allocated)
-		{
-			nls->allocated++;
-			nls->levels = xRealloc(nls->levels,
-				nls->allocated, NestingLevel);
-			nls->levels[i].name = vStringNew();
-		}
+		nestingLevelsPush(nls, name, 0);
 		nl = nls->levels + i;
 	}
-	nls->n = i + 1;
-
-	vStringCopy(nl->name, name);
+	else
+	{	/* reuse existing slot */
+		nls->n = i + 1;
+		vStringCopy(nl->name, name);
+	}
 	nl->indentation = indentation;
-	nl->is_class = is_class;
+	nl->type = is_class ? K_CLASS : !K_CLASS;
 }
 
 /* Return a pointer to the start of the next triple string, or NULL. Store
@@ -467,18 +578,18 @@ static const char *findVariable(const char *line)
 }
 
 /* Skip type declaration that optionally follows a cdef/cpdef */
-static const char *skipTypeDecl (const char *cp, boolean *is_class) 
-{ 
+static const char *skipTypeDecl (const char *cp, boolean *is_class)
+{
 	const char *lastStart = cp, *ptr = cp;
 	int loopCount = 0;
 	ptr = skipSpace(cp);
-	if (!strncmp("extern", ptr, 6)) { 
-		ptr += 6; 
-		ptr = skipSpace(ptr); 
+	if (!strncmp("extern", ptr, 6)) {
+		ptr += 6;
+		ptr = skipSpace(ptr);
 		if (!strncmp("from", ptr, 4)) { return NULL; }
 	}
 	if (!strncmp("class", ptr, 5)) {
-		ptr += 5 ; 
+		ptr += 5 ;
 		*is_class = TRUE;
 		ptr = skipSpace(ptr);
 		return ptr;
@@ -489,7 +600,7 @@ static const char *skipTypeDecl (const char *cp, boolean *is_class)
 		if (!*ptr || *ptr == '=') return NULL;
 		if (*ptr == '(') {
 		    return lastStart; /* if we stopped on a '(' we are done */
-		}                             
+		}
 		ptr = skipSpace(ptr);
 		lastStart = ptr;
 		while (*lastStart == '*') lastStart++;  /* cdef int *identifier */
@@ -503,7 +614,7 @@ static void findPythonTags (void)
 	vString *const name = vStringNew ();
 	vString *const parent = vStringNew();
 
-	NestingLevels *const nesting_levels = newNestingLevels();
+	NestingLevels *const nesting_levels = nestingLevelsNew();
 
 	const char *line;
 	int line_skip = 0;
@@ -540,7 +651,7 @@ static void findPythonTags (void)
 		cp = skipSpace (cp);
 		indent = cp - line;
 		line_skip = 0;
-		
+
 		checkParent(nesting_levels, indent, parent);
 
 		/* Deal with multiline string ending. */
@@ -549,7 +660,7 @@ static void findPythonTags (void)
 			find_triple_end(cp, &longStringLiteral);
 			continue;
 		}
-		
+
 		/* Deal with multiline string start. */
 		longstring = find_triple_start(cp, &longStringLiteral);
 		if (longstring)
@@ -578,7 +689,7 @@ static void findPythonTags (void)
 				is_class = TRUE;
 			}
 			else if (!strncmp (keyword, "cdef ", 5))
-		    { 
+		    {
 		        cp = skipSpace(keyword + 4);
 		        candidate = skipTypeDecl (cp, &is_class);
 		        if (candidate)
@@ -589,7 +700,7 @@ static void findPythonTags (void)
 
 		    }
     		else if (!strncmp (keyword, "cpdef ", 6))
-		    { 
+		    {
 		        cp = skipSpace(keyword + 5);
 		        candidate = skipTypeDecl (cp, &is_class);
 		        if (candidate)
@@ -636,12 +747,14 @@ static void findPythonTags (void)
 
 			makeVariableTag (name, parent);
 		}
+		/* Find and parse imports */
+		parseImports(line);
 	}
 	/* Clean up all memory we allocated. */
 	vStringDelete (parent);
 	vStringDelete (name);
 	vStringDelete (continuation);
-	freeNestingLevels (nesting_levels);
+	nestingLevelsFree (nesting_levels);
 }
 
 extern parserDefinition *PythonParser (void)
diff --git a/plugins/symbol-db/anjuta-tags/read.c b/plugins/symbol-db/anjuta-tags/read.c
index ff42bf1..7940c86 100644
--- a/plugins/symbol-db/anjuta-tags/read.c
+++ b/plugins/symbol-db/anjuta-tags/read.c
@@ -1,5 +1,5 @@
 /*
-*   $Id: read.c 659 2008-04-20 23:27:48Z elliotth $
+*   $Id: read.c 708 2009-07-04 05:29:02Z dhiebert $
 *
 *   Copyright (c) 1996-2002, Darren Hiebert
 *
@@ -449,7 +449,7 @@ extern int fileGetc (void)
 	return c;
 }
 
-extern int fileSkipToCharacter (const int c)
+extern int fileSkipToCharacter (int c)
 {
 	int d;
 	do
diff --git a/plugins/symbol-db/anjuta-tags/tex.c b/plugins/symbol-db/anjuta-tags/tex.c
index b467e06..a285797 100644
--- a/plugins/symbol-db/anjuta-tags/tex.c
+++ b/plugins/symbol-db/anjuta-tags/tex.c
@@ -1,12 +1,12 @@
 /*
  *	 $Id: tex.c 666 2008-05-15 17:47:31Z dfishburn $
  *
- *	 Copyright (c) 2003, Darren Hiebert
+ *	 Copyright (c) 2008, David Fishburn
  *
  *	 This source code is released for free distribution under the terms of the
  *	 GNU General Public License.
  *
- *	 This module contains functions for generating tags for Tex languages.
+ *	 This module contains functions for generating tags for TeX language files.
  *
  *	 Tex language reference:
  *		 http://en.wikibooks.org/wiki/TeX#The_Structure_of_TeX
diff --git a/plugins/symbol-db/anjuta-tags/vstring.h b/plugins/symbol-db/anjuta-tags/vstring.h
index 8088150..611d3a9 100644
--- a/plugins/symbol-db/anjuta-tags/vstring.h
+++ b/plugins/symbol-db/anjuta-tags/vstring.h
@@ -1,5 +1,5 @@
 /*
-*   $Id: vstring.h 550 2007-06-07 05:50:32Z dhiebert $
+*   $Id: vstring.h 719 2009-07-07 03:46:59Z dhiebert $
 *
 *   Copyright (c) 1998-2002, Darren Hiebert
 *
@@ -35,6 +35,7 @@
 
 #define vStringValue(vs)      ((vs)->buffer)
 #define vStringItem(vs,i)     ((vs)->buffer[i])
+#define vStringLast(vs)       ((vs)->buffer[(vs)->length - 1])
 #define vStringLength(vs)     ((vs)->length)
 #define vStringSize(vs)       ((vs)->size)
 #define vStringCat(vs,s)      vStringCatS((vs), vStringValue((s)))
diff --git a/plugins/symbol-db/symbol-db-engine-core.c b/plugins/symbol-db/symbol-db-engine-core.c
index 02cee54..779017d 100644
--- a/plugins/symbol-db/symbol-db-engine-core.c
+++ b/plugins/symbol-db/symbol-db-engine-core.c
@@ -5707,7 +5707,7 @@ symbol_db_engine_update_project_symbols (SymbolDBEngine *dbe,
 		filetm.tm_min = timestamp->minute;
 		filetm.tm_sec = timestamp->second;
 
-		/* add one hour to the db_file_time. */
+		/* remove one hour to the db_file_time. */
 		db_time = mktime (&filetm) - 3600;
 /*
 		DEBUG_PRINT ("%s %d ## %d", file_abs_path, db_time, 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]