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

📄 sql.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*   $Id: sql.c,v 1.10 2003/12/21 19:19:27 darren Exp $
*
*   Copyright (c) 2002-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 PL/SQL language
*   files.
*/

/*
*   INCLUDE FILES
*/
#include "general.h"	/* must always come first */

#include <ctype.h>	/* to define isalpha () */
#include <setjmp.h>

#include "debug.h"
#include "entry.h"
#include "keyword.h"
#include "parse.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"

/*
*   On-line PL/SQL Reference Guide:
*   http://info-it.umsystem.edu/oradocs/doc/server/doc/PLS23/toc.htm
*
*   Sample PL/SQL code is available from:
*   http://www.orafaq.com/faqscrpt.htm#GENPLSQL
*/

/*
*   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;

/*  Used to specify type of keyword.
 */
typedef enum eKeywordId {
    KEYWORD_NONE = -1,
    KEYWORD_is,
    KEYWORD_begin,
    KEYWORD_body,
    KEYWORD_cursor,
    KEYWORD_declare,
    KEYWORD_end,
    KEYWORD_function,
    KEYWORD_if,
    KEYWORD_loop,
    KEYWORD_package,
    KEYWORD_pragma,
    KEYWORD_procedure,
    KEYWORD_record,
    KEYWORD_ref,
    KEYWORD_rem,
    KEYWORD_return,
    KEYWORD_subtype,
    KEYWORD_table,
    KEYWORD_trigger,
    KEYWORD_type
} 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_BLOCK_LABEL_BEGIN,
    TOKEN_BLOCK_LABEL_END,
    TOKEN_CHARACTER,
    TOKEN_CLOSE_PAREN,
    TOKEN_SEMICOLON,
    TOKEN_COMMA,
    TOKEN_IDENTIFIER,
    TOKEN_KEYWORD,
    TOKEN_OPEN_PAREN,
    TOKEN_OPERATOR,
    TOKEN_OTHER,
    TOKEN_STRING
} tokenType;

typedef struct sTokenInfo {
    tokenType	type;
    keywordId	keyword;
    vString *	string;
    unsigned long lineNumber;
    fpos_t filePosition;
} tokenInfo;

/*
*   DATA DEFINITIONS
*/

static langType Lang_sql;

static jmp_buf Exception;

typedef enum {
    SQLTAG_CURSOR,
    SQLTAG_PROTOTYPE,
    SQLTAG_FUNCTION,
    SQLTAG_FIELD,
    SQLTAG_LOCAL_VARIABLE,
    SQLTAG_BLOCK_LABEL,
    SQLTAG_PACKAGE,
    SQLTAG_PROCEDURE,
    SQLTAG_RECORD,
    SQLTAG_SUBTYPE,
    SQLTAG_TABLE,
    SQLTAG_TRIGGER,
    SQLTAG_VARIABLE,
    SQLTAG_COUNT
} sqlKind;

static kindOption SqlKinds [] = {
    { TRUE,  'c', "cursor",    "cursors"	},
    { FALSE, 'd', "prototype", "prototypes"	},
    { TRUE,  'f', "function",  "functions"	},
    { TRUE,  'F', "field",     "record fields"	},
    { FALSE, 'l', "local",     "local variables"},
    { TRUE,  'L', "label",     "block label"    },
    { TRUE,  'P', "package",   "packages"	},
    { TRUE,  'p', "procedure", "procedures"	},
    { TRUE,  'r', "record",    "records"	},
    { TRUE,  's', "subtype",   "subtypes"	},
    { TRUE,  't', "table",     "tables"		},
    { TRUE,  'T', "trigger",   "triggers"	},
    { TRUE,  'v', "variable",  "variables"	},
};

static const keywordDesc SqlKeywordTable [] = {
    /* keyword		keyword ID */
    { "as",		KEYWORD_is		},
    { "begin",		KEYWORD_begin		},
    { "body",		KEYWORD_body		},
    { "cursor",		KEYWORD_cursor		},
    { "declare",	KEYWORD_declare		},
    { "end",		KEYWORD_end		},
    { "function",	KEYWORD_function	},
    { "if",		KEYWORD_if		},
    { "is",		KEYWORD_is		},
    { "loop",		KEYWORD_loop		},
    { "package",	KEYWORD_package		},
    { "pragma",		KEYWORD_pragma		},
    { "procedure",	KEYWORD_procedure	},
    { "record",		KEYWORD_record		},
    { "ref",		KEYWORD_ref		},
    { "rem",		KEYWORD_rem		},
    { "return",		KEYWORD_return		},
    { "subtype",	KEYWORD_subtype		},
    { "table",		KEYWORD_table		},
    { "trigger",	KEYWORD_trigger		},
    { "type",		KEYWORD_type		}
};

/*
*   FUNCTION DECLARATIONS
*/

static void parseBlock (tokenInfo *const token, const boolean local);

/*
*   FUNCTION DEFINITIONS
*/

static boolean isIdentChar1 (const int c)
{
    return (boolean) isalpha (c);
}

static boolean isIdentChar (const int c)
{
    return (boolean)
	(isalpha (c) || isdigit (c) || c == '$' || c == '_' || c == '#');
}

static void buildSqlKeywordHash (void)
{
    const size_t count = sizeof (SqlKeywordTable) /
			 sizeof (SqlKeywordTable [0]);
    size_t i;
    for (i = 0  ;  i < count  ;  ++i)
    {
	const keywordDesc* const p = &SqlKeywordTable [i];
	addKeyword (p->name, Lang_sql, (int) p->id);
    }
}

static tokenInfo *newToken (void)
{
    tokenInfo *const token = xMalloc (1, tokenInfo);

    token->type         = TOKEN_UNDEFINED;
    token->keyword      = KEYWORD_NONE;
    token->string       = vStringNew ();

    return token;
}

static void deleteToken (tokenInfo *const token)
{
    vStringDelete (token->string);
    eFree (token);
}

/*
*   Tag generation functions
*/

static void makeSqlTag (tokenInfo *const token, const sqlKind kind)
{
    if (SqlKinds [kind].enabled)
    {
	const char *const name = vStringValue (token->string);
	tagEntryInfo e;
	initTagEntry (&e, name);

	e.lineNumber   = token->lineNumber;
	e.filePosition = token->filePosition;
	e.kindName     = SqlKinds [kind].name;
	e.kind         = SqlKinds [kind].letter;

	makeTagEntry (&e);
    }
}

/*
*   Parsing functions
*/

static int skipToCharacter (const int c)
{
    int d;
    do
    {
	d = fileGetc ();
    } while (d != EOF  &&  d != c);
    return d;
}

static void parseString (vString *const string, const int delimiter)
{
    boolean end = FALSE;
    int c;
    while (! end)
    {
	c = fileGetc ();
	if (c == EOF)
	    end = TRUE;
	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 (isIdentChar1 (c));
    do
    {
	vStringPut (string, c);
	c = fileGetc ();
    } while (isIdentChar (c));
    vStringTerminate (string);
    if (!isspace (c))
	fileUngetc (c);		/* unget non-identifier character */
}

static keywordId analyzeToken (vString *const name)
{
    static vString *keyword = NULL;
    if (keyword == NULL)
	keyword = vStringNew ();
    vStringCopyToLower (keyword, name);
    return (keywordId) lookupKeyword (vStringValue (keyword), Lang_sql);
}

static void readToken (tokenInfo *const token)
{
    int c;

    token->type         = TOKEN_UNDEFINED;
    token->keyword      = KEYWORD_NONE;
    vStringClear (token->string);

getNextChar:
    do
	c = fileGetc ();
    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 '\'':
	case '"':
	    token->type = TOKEN_STRING;
	    parseString (token->string, c);
	    break;

	case '-':
	    c = fileGetc ();
	    if (c == '-')		/* is this the start of a comment? */
	    {
		skipToCharacter ('\n');
		goto getNextChar;
	    }
	    else
	    {
		if (!isspace (c))
		    fileUngetc (c);
 		token->type = TOKEN_OPERATOR;
	    }
	    break;

	case '<':
	case '>':
	{
	    const int initial = c;

⌨️ 快捷键说明

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