⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sql.c

📁 ctags的最新版5.7,可以比较5.6版看看,免费下载
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 findToken (tokenInfo *const token, const tokenType type){	while (! isType (token, type))	{		readToken (token);	}}static void findCmdTerm (tokenInfo *const token, const boolean check_first){	if ( check_first ) 	{		if ( isCmdTerm(token) )			return;	}	do	{		readToken (token);	} while ( !isCmdTerm(token) );}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 parseSubProgram (tokenInfo *const token){	tokenInfo *const name  = newToken ();	/*	 * This must handle both prototypes and the body of	 * the procedures.	 *	 * Prototype:	 *	   FUNCTION func_name RETURN integer;	 *	   PROCEDURE proc_name( parameters );	 * Procedure	 *	   FUNCTION GET_ML_USERNAME RETURN VARCHAR2	 *	   IS	 *	   BEGIN	 *		   RETURN v_sync_user_id;	 *	   END GET_ML_USERNAME;	 *	 *	   PROCEDURE proc_name( parameters )	 *		   IS	 *		   BEGIN	 *		   END;	 *	   CREATE PROCEDURE proc_name( parameters )	 *		   EXTERNAL NAME ... ;	 *	   CREATE PROCEDURE proc_name( parameters )	 *		   BEGIN	 *		   END;	 *	 *	   CREATE FUNCTION f_GetClassName(	 *		   IN @object VARCHAR(128)	 *		  ,IN @code   VARCHAR(128)	 *	   )	 *	   RETURNS VARCHAR(200)	 *	   DETERMINISTIC	 *	   BEGIN	 *	   	 *		   IF( @object = 'user_state' ) THEN	 *			   SET something = something;	 *		   END IF;	 *	   	 *		   RETURN @name;	 *	   END;	 */	const sqlKind kind = isKeyword (token, KEYWORD_function) ?		SQLTAG_FUNCTION : SQLTAG_PROCEDURE;	Assert (isKeyword (token, KEYWORD_function) ||			isKeyword (token, KEYWORD_procedure));	readToken (name);	readToken (token);	if (isType (token, TOKEN_PERIOD))	{		readToken (name);		readToken (token);	}	skipArgumentList (token);	if (kind == SQLTAG_FUNCTION)	{		if (isKeyword (token, KEYWORD_return))		{			/* Read datatype */			readToken (token);			/*			 * Read token after which could be the			 * command terminator if a prototype			 */			readToken (token);		}	}	if( isCmdTerm (token) )	{		makeSqlTag (name, SQLTAG_PROTOTYPE);	} 	else 	{		while (!(isKeyword (token, KEYWORD_is) ||					isKeyword (token, KEYWORD_begin) ||					isCmdTerm (token)				)			  )		{			/* read return type */			readToken (token);		}		if (isKeyword (token, KEYWORD_is) || 				isKeyword (token, KEYWORD_begin) )		{			addToScope(token, name->string);			if (isType (name, TOKEN_IDENTIFIER) ||					isType (name, TOKEN_STRING) ||					!isKeyword (token, KEYWORD_NONE)			   )				makeSqlTag (name, kind);			parseBlock (token, TRUE);			vStringClear (token->scope);		} 	}	deleteToken (name);}static void parseRecord (tokenInfo *const token){	/*	 * Make it a bit forgiving, this is called from	 * multiple functions, parseTable, parseType	 */	if (!isType (token, TOKEN_OPEN_PAREN))		readToken (token);	Assert (isType (token, TOKEN_OPEN_PAREN));	do	{		if ( isType (token, TOKEN_COMMA) || isType (token, TOKEN_OPEN_PAREN) )			readToken (token);		/*		 * Create table statements can end with various constraints		 * which must be excluded from the SQLTAG_FIELD.		 *	  create table t1 (		 *		  c1 integer,		 *		  c2 char(30),		 *		  c3 numeric(10,5),		 *		  c4 integer,		 *		  constraint whatever,		 *		  primary key(c1),		 *		  foreign key (), 		 *		  check ()		 *	  )		 */		if (! (isKeyword(token, KEYWORD_primary) ||					isKeyword(token, KEYWORD_references) ||					isKeyword(token, KEYWORD_unique) ||					isKeyword(token, KEYWORD_check) ||					isKeyword(token, KEYWORD_constraint) ||					isKeyword(token, KEYWORD_foreign) ) )		{			if (isType (token, TOKEN_IDENTIFIER) ||					isType (token, TOKEN_STRING))				makeSqlTag (token, SQLTAG_FIELD);		}		while (!(isType (token, TOKEN_COMMA) ||					isType (token, TOKEN_CLOSE_PAREN) ||					isType (token, TOKEN_OPEN_PAREN) 				))		{			readToken (token);			/* 			 * A table structure can look like this:			 *	  create table t1 (			 *		  c1 integer,			 *		  c2 char(30),			 *		  c3 numeric(10,5),			 *		  c4 integer			 *	  )			 * We can't just look for a COMMA or CLOSE_PAREN			 * since that will not deal with the numeric(10,5)			 * case.  So we need to skip the argument list 			 * when we find an open paren.			 */			if (isType (token, TOKEN_OPEN_PAREN))			{				/* Reads to the next token after the TOKEN_CLOSE_PAREN */				skipArgumentList(token);			}		}	} while (! isType (token, TOKEN_CLOSE_PAREN));}static void parseType (tokenInfo *const token){	tokenInfo *const name = newToken ();	vString * saveScope = vStringNew ();	vStringCopy(saveScope, token->scope);	/* If a scope has been set, add it to the name */	addToScope (name, token->scope);	readToken (name);	if (isType (name, TOKEN_IDENTIFIER))	{		readToken (token);		if (isKeyword (token, KEYWORD_is))		{			readToken (token);			addToScope (token, name->string);			switch (token->keyword)			{				case KEYWORD_record:				case KEYWORD_object:					makeSqlTag (name, SQLTAG_RECORD);					parseRecord (token);					break;				case KEYWORD_table:					makeSqlTag (name, SQLTAG_TABLE);					break;				case KEYWORD_ref:					readToken (token);					if (isKeyword (token, KEYWORD_cursor))						makeSqlTag (name, SQLTAG_CURSOR);					break;				default: break;			}			vStringClear (token->scope);		}	}	vStringCopy(token->scope, saveScope);	deleteToken (name);	vStringDelete(saveScope);}static void parseSimple (tokenInfo *const token, const sqlKind kind){	/* This will simply make the tagname from the first word found */	readToken (token);	if (isType (token, TOKEN_IDENTIFIER) ||			isType (token, TOKEN_STRING))		makeSqlTag (token, kind);}static void parseDeclare (tokenInfo *const token, const boolean local){	/*	 * PL/SQL declares are of this format:	 *	  IS|AS	 *	  [declare]	 *		 CURSOR curname ...	 *		 varname1 datatype;	 *		 varname2 datatype;	 *		 varname3 datatype;	 *	  begin	 */	if (isKeyword (token, KEYWORD_declare))		readToken (token);	while (! isKeyword (token, KEYWORD_begin) && ! isKeyword (token, KEYWORD_end))	{		switch (token->keyword)		{			case KEYWORD_cursor:	parseSimple (token, SQLTAG_CURSOR); break;			case KEYWORD_function:	parseSubProgram (token); break;			case KEYWORD_procedure: parseSubProgram (token); break;			case KEYWORD_subtype:	parseSimple (token, SQLTAG_SUBTYPE); break;			case KEYWORD_trigger:	parseSimple (token, SQLTAG_TRIGGER); break;			case KEYWORD_type:		parseType (token); break;			default:									if (isType (token, TOKEN_IDENTIFIER))									{										if (local)										{											makeSqlTag (token, SQLTAG_LOCAL_VARIABLE);										} 										else 										{											makeSqlTag (token, SQLTAG_VARIABLE);										}									}									break;		}		findToken (token, TOKEN_SEMICOLON);		readToken (token);	}}static void parseDeclareANSI (tokenInfo *const token, const boolean local){	tokenInfo *const type = newToken ();	/*	 * ANSI declares are of this format:	 *	 BEGIN	 *		 DECLARE varname1 datatype;	 *		 DECLARE varname2 datatype;	 *		 ...	 *	 * This differ from PL/SQL where DECLARE preceeds the BEGIN block	 * and the DECLARE keyword is not repeated.	 */	while (isKeyword (token, KEYWORD_declare))	{		readToken (token);		readToken (type);		if (isKeyword (type, KEYWORD_cursor))			makeSqlTag (token, SQLTAG_CURSOR);		else if (isKeyword (token, KEYWORD_local) &&				isKeyword (type, KEYWORD_temporary))		{			/*			 * DECLARE LOCAL TEMPORARY TABLE table_name (			 *	  c1 int,			 *	  c2 int			 * );			 */			readToken (token);			if (isKeyword (token, KEYWORD_table))			{				readToken (token);				if (isType(token, TOKEN_IDENTIFIER) || 						isType(token, TOKEN_STRING) )				{					makeSqlTag (token, SQLTAG_TABLE);				}			}		}		else if (isType (token, TOKEN_IDENTIFIER) || 				isType (token, TOKEN_STRING))		{			if (local)				makeSqlTag (token, SQLTAG_LOCAL_VARIABLE);			else				makeSqlTag (token, SQLTAG_VARIABLE);		}		findToken (token, TOKEN_SEMICOLON);		readToken (token);	}	deleteToken (type);}static void parseLabel (tokenInfo *const token){	/*	 * A label has this format:	 *	   <<tobacco_dependency>>	 *	   DECLARE	 *		  v_senator VARCHAR2(100) := 'THURMOND, JESSE';	 *	   BEGIN	 *		  IF total_contributions (v_senator, 'TOBACCO') > 25000	 *		  THEN	 *			 <<alochol_dependency>>	 *			 DECLARE	 *				v_senator VARCHAR2(100) := 'WHATEVERIT, TAKES';	 *			 BEGIN	 *				...	 */	Assert (isType (token, TOKEN_BLOCK_LABEL_BEGIN));	readToken (token);	if (isType (token, TOKEN_IDENTIFIER))	{		makeSqlTag (token, SQLTAG_BLOCK_LABEL);		readToken (token);		  /* read end of label */	}}static void parseStatements (tokenInfo *const token){	do	{		if (isType (token, TOKEN_BLOCK_LABEL_BEGIN))			parseLabel (token);		else		{			switch (token->keyword)			{				case KEYWORD_exception:					/*					 * EXCEPTION					 *	 <exception handler>;					 *					 * Where an exception handler could be:					 *	 BEGIN					 *		WHEN OTHERS THEN					 *			x := x + 3;					 *	 END;					 * In this case we need to skip this keyword and 					 * move on to the next token without reading until					 * TOKEN_SEMICOLON;					 */					readToken (token);					continue;				case KEYWORD_when:					/*					 * WHEN statements can be used in exception clauses					 * and CASE statements.  The CASE statement should skip					 * these given below we skip over to an END statement.					 * But for an exception clause, we can have:					 *	   EXCEPTION					 *		   WHEN OTHERS THEN					 *		   BEGIN					 *				  x := x + 3;					 *		   END;					 * If we skip to the TOKEN_SEMICOLON, we miss the begin					 * of a nested BEGIN END block.  So read the next token					 * after the THEN and restart the LOOP.					 */					while (! isKeyword (token, KEYWORD_then))						readToken (token);					readToken (token);					continue;				case KEYWORD_if:					/*					 * We do not want to look for a ; since for an empty					 * IF block, it would skip over the END.					 *	IF...THEN					 *	END IF;					 */					while (! isKeyword (token, KEYWORD_then))						readToken (token);					parseStatements (token);					/* 					 * parseStatements returns when it finds an END, an IF					 * statement should be followed by an IF (ANSI anyway)					 * so read the following IF as well					 */					readToken (token);					break;				case KEYWORD_loop:				case KEYWORD_case:				case KEYWORD_for:					/*					 *	LOOP...					 *	END LOOP;					 *						 *	FOR loop_name AS cursor_name CURSOR FOR ...					 *	END FOR;					 */					readToken (token);					parseStatements (token);					break;				case KEYWORD_declare:				case KEYWORD_begin:					parseBlock (token, TRUE);					break;				default:					readToken (token);					break;			}			/*			 * Not all statements must end in a semi-colon 			 *	   begin			 *		   if current publisher <> 'publish' then			 *			 signal UE_FailStatement			 *		   end if			 *	   end;			 * The last statement prior to an end ("signal" above) does			 * not need a semi-colon, nor does the end if, since it is 			 * also the last statement prior to the end of the block.			 *			 * So we must read to the first semi-colon or an END block			 */			while (! (isKeyword (token, KEYWORD_end) ||						(isType (token, TOKEN_SEMICOLON)))	  )			{				readToken (token);			}		}		/*		 * We assumed earlier all statements ended with a semi-colon,		 * see comment above, now, only read if the current token 		 * is not a semi-colon		 */		if ( isType (token, TOKEN_SEMICOLON) )		{			readToken (token);		}	} while (! isKeyword (token, KEYWORD_end));}static void parseBlock (tokenInfo *const token, const boolean local){	if (isType (token, TOKEN_BLOCK_LABEL_BEGIN))	{		parseLabel (token);		readToken (token);	}	if (! isKeyword (token, KEYWORD_begin))	{		readToken (token);		/*		 * These are Oracle style declares which generally come		 * between an IS/AS and BEGIN block.		 */		parseDeclare (token, local);	}	if (isKeyword (token, KEYWORD_begin))	{		readToken (token);		/*		 * Check for ANSI declarations which always follow		 * a BEGIN statement.  This routine will not advance		 * the token if none are found.		 */		parseDeclareANSI (token, local);		while (! isKeyword (token, KEYWORD_end))		{			parseStatements (token);		}		findCmdTerm (token, FALSE);	}}static void parsePackage (tokenInfo *const token){	/* 	 * Packages can be specified in a number of ways:	 *		CREATE OR REPLACE PACKAGE pkg_name AS	 * or	 *		CREATE OR REPLACE PACKAGE owner.pkg_name AS	 * or by specifying a package body	 *	   CREATE OR REPLACE PACKAGE BODY pkg_name AS	 *	   CREATE OR REPLACE PACKAGE BODY owner.pkg_name AS	 */	tokenInfo *const name = newToken ();	readToken (name);	if (isKeyword (name, KEYWORD_body))	{		/*		 * Ignore the BODY tag since we will process		 * the body or prototypes in the same manner		 */		readToken (name);	}	/* Check for owner.pkg_name */	while (! isKeyword (token, KEYWORD_is))	{		readToken (token);		if ( isType(token, TOKEN_PERIOD) )		{			readToken (name);		}	}	if (isKeyword (token, KEYWORD_is))	{		if (isType (name, TOKEN_IDENTIFIER) ||				isType (name, TOKEN_STRING))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -