176 lines
4.9 KiB
C
176 lines
4.9 KiB
C
/*
|
|
* $Id: sml.c 536 2007-06-02 06:09:00Z elliotth $
|
|
*
|
|
* Copyright (c) 2002, Venkatesh Prasad Ranganath and 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 SML language files.
|
|
*/
|
|
#include "third_party/ctags/general.h"
|
|
/* must always come first */
|
|
#include "third_party/ctags/entry.h"
|
|
#include "third_party/ctags/parse.h"
|
|
#include "third_party/ctags/read.h"
|
|
#include "third_party/ctags/vstring.h"
|
|
|
|
/*
|
|
* DATA DECLARATIONS
|
|
*/
|
|
typedef enum {
|
|
K_AND = -2,
|
|
K_NONE = -1,
|
|
K_EXCEPTION,
|
|
K_FUNCTION,
|
|
K_FUNCTOR,
|
|
K_SIGNATURE,
|
|
K_STRUCTURE,
|
|
K_TYPE,
|
|
K_VAL
|
|
} smlKind;
|
|
|
|
/*
|
|
* DATA DEFINITIONS
|
|
*/
|
|
static kindOption SmlKinds[] = {
|
|
{TRUE, 'e', "exception", "exception declarations"},
|
|
{TRUE, 'f', "function", "function definitions"},
|
|
{TRUE, 'c', "functor", "functor definitions"},
|
|
{TRUE, 's', "signature", "signature declarations"},
|
|
{TRUE, 'r', "structure", "structure declarations"},
|
|
{TRUE, 't', "type", "type definitions"},
|
|
{TRUE, 'v', "value", "value bindings"}};
|
|
|
|
static struct {
|
|
const char *keyword;
|
|
smlKind kind;
|
|
} SmlKeywordTypes[] = {{"abstype", K_TYPE}, {"and", K_AND},
|
|
{"datatype", K_TYPE}, {"exception", K_EXCEPTION},
|
|
{"functor", K_FUNCTOR}, {"fun", K_FUNCTION},
|
|
{"signature", K_SIGNATURE}, {"structure", K_STRUCTURE},
|
|
{"type", K_TYPE}, {"val", K_VAL}};
|
|
|
|
static unsigned int CommentLevel = 0;
|
|
|
|
/*
|
|
* FUNCTION DEFINITIONS
|
|
*/
|
|
|
|
static void makeSmlTag(smlKind type, vString *name) {
|
|
tagEntryInfo tag;
|
|
initTagEntry(&tag, vStringValue(name));
|
|
tag.kindName = SmlKinds[type].name;
|
|
tag.kind = SmlKinds[type].letter;
|
|
makeTagEntry(&tag);
|
|
}
|
|
|
|
static const unsigned char *skipSpace(const unsigned char *cp) {
|
|
while (isspace((int)*cp)) ++cp;
|
|
return cp;
|
|
}
|
|
|
|
static boolean isIdentifier(int c) {
|
|
boolean result = FALSE;
|
|
/* Consider '_' as an delimiter to aid user in tracking it's usage. */
|
|
const char *const alternateIdentifiers = "!%&$#+-<>=/?@\\~'^|*_";
|
|
if (isalnum(c))
|
|
result = TRUE;
|
|
else if (c != '\0' && strchr(alternateIdentifiers, c) != NULL)
|
|
result = TRUE;
|
|
return result;
|
|
}
|
|
|
|
static const unsigned char *parseIdentifier(const unsigned char *cp,
|
|
vString *const identifier) {
|
|
boolean stringLit = FALSE;
|
|
vStringClear(identifier);
|
|
while (*cp != '\0' && (!isIdentifier((int)*cp) || stringLit)) {
|
|
int oneback = *cp;
|
|
cp++;
|
|
if (oneback == '(' && *cp == '*' && stringLit == FALSE) {
|
|
CommentLevel++;
|
|
return ++cp;
|
|
}
|
|
if (*cp == '"' && oneback != '\\') {
|
|
stringLit = TRUE;
|
|
continue;
|
|
}
|
|
if (stringLit && *cp == '"' && oneback != '\\') stringLit = FALSE;
|
|
}
|
|
if (strcmp((const char *)cp, "") == 0 || cp == NULL) return cp;
|
|
|
|
while (isIdentifier((int)*cp)) {
|
|
vStringPut(identifier, (int)*cp);
|
|
cp++;
|
|
}
|
|
vStringTerminate(identifier);
|
|
return cp;
|
|
}
|
|
|
|
static smlKind findNextIdentifier(const unsigned char **cp) {
|
|
smlKind result = K_NONE;
|
|
vString *const identifier = vStringNew();
|
|
unsigned int count = sizeof(SmlKeywordTypes) / sizeof(SmlKeywordTypes[0]);
|
|
unsigned int i;
|
|
*cp = parseIdentifier(*cp, identifier);
|
|
for (i = 0; i < count && result == K_NONE; ++i) {
|
|
const char *id = vStringValue(identifier);
|
|
if (strcmp(id, SmlKeywordTypes[i].keyword) == 0)
|
|
result = SmlKeywordTypes[i].kind;
|
|
}
|
|
vStringDelete(identifier);
|
|
return result;
|
|
}
|
|
|
|
static void findSmlTags(void) {
|
|
vString *const identifier = vStringNew();
|
|
const unsigned char *line;
|
|
smlKind lastTag = K_NONE;
|
|
|
|
while ((line = fileReadLine()) != NULL) {
|
|
const unsigned char *cp = skipSpace(line);
|
|
do {
|
|
smlKind foundTag;
|
|
if (CommentLevel != 0) {
|
|
cp = (const unsigned char *)strstr((const char *)cp, "*)");
|
|
if (cp == NULL)
|
|
continue;
|
|
else {
|
|
--CommentLevel;
|
|
cp += 2;
|
|
}
|
|
}
|
|
foundTag = findNextIdentifier(&cp);
|
|
if (foundTag != K_NONE) {
|
|
cp = skipSpace(cp);
|
|
cp = parseIdentifier(cp, identifier);
|
|
if (foundTag == K_AND)
|
|
makeSmlTag(lastTag, identifier);
|
|
else {
|
|
makeSmlTag(foundTag, identifier);
|
|
lastTag = foundTag;
|
|
}
|
|
}
|
|
if (strstr((const char *)cp, "(*") != NULL) {
|
|
cp += 2;
|
|
cp = (const unsigned char *)strstr((const char *)cp, "*)");
|
|
if (cp == NULL) ++CommentLevel;
|
|
}
|
|
} while (cp != NULL && strcmp((const char *)cp, "") != 0);
|
|
}
|
|
vStringDelete(identifier);
|
|
}
|
|
|
|
extern parserDefinition *SmlParser(void) {
|
|
static const char *const extensions[] = {"sml", "sig", NULL};
|
|
parserDefinition *def = parserNew("SML");
|
|
def->kinds = SmlKinds;
|
|
def->kindCount = KIND_COUNT(SmlKinds);
|
|
def->extensions = extensions;
|
|
def->parser = findSmlTags;
|
|
return def;
|
|
}
|
|
|
|
/* vi:set tabstop=4 shiftwidth=4: */
|