299 lines
8.0 KiB
C
299 lines
8.0 KiB
C
/*
|
|
* $Id: asm.c 536 2007-06-02 06:09:00Z elliotth $
|
|
*
|
|
* Copyright (c) 2000-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 assembly language
|
|
* files.
|
|
*/
|
|
#include "third_party/ctags/general.h"
|
|
/* must always come first */
|
|
#include "third_party/ctags/debug.h"
|
|
#include "third_party/ctags/keyword.h"
|
|
#include "third_party/ctags/parse.h"
|
|
#include "third_party/ctags/read.h"
|
|
#include "third_party/ctags/routines.h"
|
|
#include "third_party/ctags/vstring.h"
|
|
|
|
/*
|
|
* DATA DECLARATIONS
|
|
*/
|
|
typedef enum { K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE } AsmKind;
|
|
|
|
typedef enum {
|
|
OP_UNDEFINED = -1,
|
|
OP_ALIGN,
|
|
OP_COLON_EQUAL,
|
|
OP_END,
|
|
OP_ENDM,
|
|
OP_ENDMACRO,
|
|
OP_ENDP,
|
|
OP_ENDS,
|
|
OP_EQU,
|
|
OP_EQUAL,
|
|
OP_LABEL,
|
|
OP_MACRO,
|
|
OP_PROC,
|
|
OP_RECORD,
|
|
OP_SECTIONS,
|
|
OP_SET,
|
|
OP_STRUCT,
|
|
OP_LAST
|
|
} opKeyword;
|
|
|
|
typedef struct {
|
|
const char *operator;
|
|
opKeyword keyword;
|
|
} asmKeyword;
|
|
|
|
typedef struct {
|
|
opKeyword keyword;
|
|
AsmKind kind;
|
|
} opKind;
|
|
|
|
/*
|
|
* DATA DEFINITIONS
|
|
*/
|
|
static langType Lang_asm;
|
|
|
|
static kindOption AsmKinds[] = {
|
|
{TRUE, 'd', "define", "defines"},
|
|
{TRUE, 'l', "label", "labels"},
|
|
{TRUE, 'm', "macro", "macros"},
|
|
{TRUE, 't', "type", "types (structs and records)"}};
|
|
|
|
static const asmKeyword AsmKeywords[] = {
|
|
{"align", OP_ALIGN}, {"endmacro", OP_ENDMACRO}, {"endm", OP_ENDM},
|
|
{"end", OP_END}, {"endp", OP_ENDP}, {"ends", OP_ENDS},
|
|
{"equ", OP_EQU}, {"label", OP_LABEL}, {"macro", OP_MACRO},
|
|
{":=", OP_COLON_EQUAL}, {"=", OP_EQUAL}, {"proc", OP_PROC},
|
|
{"record", OP_RECORD}, {"sections", OP_SECTIONS}, {"set", OP_SET},
|
|
{"struct", OP_STRUCT}};
|
|
|
|
static const opKind OpKinds[] = {
|
|
/* must be ordered same as opKeyword enumeration */
|
|
{OP_ALIGN, K_NONE}, {OP_COLON_EQUAL, K_DEFINE}, {OP_END, K_NONE},
|
|
{OP_ENDM, K_NONE}, {OP_ENDMACRO, K_NONE}, {OP_ENDP, K_NONE},
|
|
{OP_ENDS, K_NONE}, {OP_EQU, K_DEFINE}, {OP_EQUAL, K_DEFINE},
|
|
{OP_LABEL, K_LABEL}, {OP_MACRO, K_MACRO}, {OP_PROC, K_LABEL},
|
|
{OP_RECORD, K_TYPE}, {OP_SECTIONS, K_NONE}, {OP_SET, K_DEFINE},
|
|
{OP_STRUCT, K_TYPE}};
|
|
|
|
/*
|
|
* FUNCTION DEFINITIONS
|
|
*/
|
|
static void buildAsmKeywordHash(void) {
|
|
const size_t count = sizeof(AsmKeywords) / sizeof(AsmKeywords[0]);
|
|
size_t i;
|
|
for (i = 0; i < count; ++i) {
|
|
const asmKeyword *const p = AsmKeywords + i;
|
|
addKeyword(p->operator, Lang_asm,(int) p->keyword);
|
|
}
|
|
}
|
|
|
|
static opKeyword analyzeOperator(const vString *const op) {
|
|
vString *keyword = vStringNew();
|
|
opKeyword result;
|
|
|
|
vStringCopyToLower(keyword, op);
|
|
result = (opKeyword)lookupKeyword(vStringValue(keyword), Lang_asm);
|
|
vStringDelete(keyword);
|
|
return result;
|
|
}
|
|
|
|
static boolean isInitialSymbolCharacter(int c) {
|
|
return (boolean)(c != '\0' && (isalpha(c) || strchr("_$", c) != NULL));
|
|
}
|
|
|
|
static boolean isSymbolCharacter(int c) {
|
|
/* '?' character is allowed in AMD 29K family */
|
|
return (boolean)(c != '\0' && (isalnum(c) || strchr("_$?", c) != NULL));
|
|
}
|
|
|
|
static boolean readPreProc(const unsigned char *const line) {
|
|
boolean result;
|
|
const unsigned char *cp = line;
|
|
vString *name = vStringNew();
|
|
while (isSymbolCharacter((int)*cp)) {
|
|
vStringPut(name, *cp);
|
|
++cp;
|
|
}
|
|
vStringTerminate(name);
|
|
result = (boolean)(strcmp(vStringValue(name), "define") == 0);
|
|
if (result) {
|
|
while (isspace((int)*cp)) ++cp;
|
|
vStringClear(name);
|
|
while (isSymbolCharacter((int)*cp)) {
|
|
vStringPut(name, *cp);
|
|
++cp;
|
|
}
|
|
vStringTerminate(name);
|
|
makeSimpleTag(name, AsmKinds, K_DEFINE);
|
|
}
|
|
vStringDelete(name);
|
|
return result;
|
|
}
|
|
|
|
static AsmKind operatorKind(const vString *const operator,
|
|
boolean * const found) {
|
|
AsmKind result = K_NONE;
|
|
const opKeyword kw = analyzeOperator(operator);
|
|
*found = (boolean)(kw != OP_UNDEFINED);
|
|
if (*found) {
|
|
result = OpKinds[kw].kind;
|
|
Assert(OpKinds[kw].keyword == kw);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* We must check for "DB", "DB.L", "DCB.W" (68000)
|
|
*/
|
|
static boolean isDefineOperator(const vString *const operator) {
|
|
const unsigned char *const op = (unsigned char *)vStringValue(operator);
|
|
const size_t length = vStringLength(operator);
|
|
const boolean result =
|
|
(boolean)(length > 0 && toupper((int)*op) == 'D' &&
|
|
(length == 2 || (length == 4 && (int)op[2] == '.') ||
|
|
(length == 5 && (int)op[3] == '.')));
|
|
return result;
|
|
}
|
|
|
|
static void makeAsmTag(const vString *const name, const vString *const operator,
|
|
const boolean labelCandidate,
|
|
const boolean nameFollows) {
|
|
if (vStringLength(name) > 0) {
|
|
boolean found;
|
|
const AsmKind kind = operatorKind(operator, & found);
|
|
if (found) {
|
|
if (kind != K_NONE) makeSimpleTag(name, AsmKinds, kind);
|
|
} else if (isDefineOperator(operator)) {
|
|
if (!nameFollows) makeSimpleTag(name, AsmKinds, K_DEFINE);
|
|
} else if (labelCandidate) {
|
|
operatorKind(name, &found);
|
|
if (!found) makeSimpleTag(name, AsmKinds, K_LABEL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static const unsigned char *readSymbol(const unsigned char *const start,
|
|
vString *const sym) {
|
|
const unsigned char *cp = start;
|
|
vStringClear(sym);
|
|
if (isInitialSymbolCharacter((int)*cp)) {
|
|
while (isSymbolCharacter((int)*cp)) {
|
|
vStringPut(sym, *cp);
|
|
++cp;
|
|
}
|
|
vStringTerminate(sym);
|
|
}
|
|
return cp;
|
|
}
|
|
|
|
static const unsigned char *readOperator(const unsigned char *const start,
|
|
vString *const operator) {
|
|
const unsigned char *cp = start;
|
|
vStringClear(operator);
|
|
while (*cp != '\0' && !isspace((int)*cp)) {
|
|
vStringPut(operator, * cp);
|
|
++cp;
|
|
}
|
|
vStringTerminate(operator);
|
|
return cp;
|
|
}
|
|
|
|
static void findAsmTags(void) {
|
|
vString *name = vStringNew();
|
|
vString *operator= vStringNew();
|
|
const unsigned char *line;
|
|
boolean inCComment = FALSE;
|
|
|
|
while ((line = fileReadLine()) != NULL) {
|
|
const unsigned char *cp = line;
|
|
boolean labelCandidate = (boolean)(!isspace((int)*cp));
|
|
boolean nameFollows = FALSE;
|
|
const boolean isComment =
|
|
(boolean)(*cp != '\0' && strchr(";*@", *cp) != NULL);
|
|
|
|
/* skip comments */
|
|
if (strncmp((const char *)cp, "/*", (size_t)2) == 0) {
|
|
inCComment = TRUE;
|
|
cp += 2;
|
|
}
|
|
if (inCComment) {
|
|
do {
|
|
if (strncmp((const char *)cp, "*/", (size_t)2) == 0) {
|
|
inCComment = FALSE;
|
|
cp += 2;
|
|
break;
|
|
}
|
|
++cp;
|
|
} while (*cp != '\0');
|
|
}
|
|
if (isComment || inCComment) continue;
|
|
|
|
/* read preprocessor defines */
|
|
if (*cp == '#') {
|
|
++cp;
|
|
readPreProc(cp);
|
|
continue;
|
|
}
|
|
|
|
/* skip white space */
|
|
while (isspace((int)*cp)) ++cp;
|
|
|
|
/* read symbol */
|
|
cp = readSymbol(cp, name);
|
|
if (vStringLength(name) > 0 && *cp == ':') {
|
|
labelCandidate = TRUE;
|
|
++cp;
|
|
}
|
|
|
|
if (!isspace((int)*cp) && *cp != '\0') continue;
|
|
|
|
/* skip white space */
|
|
while (isspace((int)*cp)) ++cp;
|
|
|
|
/* skip leading dot */
|
|
#if 0
|
|
if (*cp == '.')
|
|
++cp;
|
|
#endif
|
|
|
|
cp = readOperator(cp, operator);
|
|
|
|
/* attempt second read of symbol */
|
|
if (vStringLength(name) == 0) {
|
|
while (isspace((int)*cp)) ++cp;
|
|
cp = readSymbol(cp, name);
|
|
nameFollows = TRUE;
|
|
}
|
|
makeAsmTag(name, operator, labelCandidate, nameFollows);
|
|
}
|
|
vStringDelete(name);
|
|
vStringDelete(operator);
|
|
}
|
|
|
|
static void initialize(const langType language) {
|
|
Lang_asm = language;
|
|
buildAsmKeywordHash();
|
|
}
|
|
|
|
extern parserDefinition *AsmParser(void) {
|
|
static const char *const extensions[] = {"asm", "ASM", "s", "S", NULL};
|
|
static const char *const patterns[] = {
|
|
"*.A51", "*.29[kK]", "*.[68][68][kKsSxX]", "*.[xX][68][68]", NULL};
|
|
parserDefinition *def = parserNew("Asm");
|
|
def->kinds = AsmKinds;
|
|
def->kindCount = KIND_COUNT(AsmKinds);
|
|
def->extensions = extensions;
|
|
def->patterns = patterns;
|
|
def->parser = findAsmTags;
|
|
def->initialize = initialize;
|
|
return def;
|
|
}
|
|
|
|
/* vi:set tabstop=4 shiftwidth=4: */
|