Enrico Tröger 9dd67b2669 Backport js.c and asm.c from CTags SVN.
Fix Assembler tagmanager support and add appropriate symbol types.
Fix JavaScript parse bug ().
Change default return value of lookupKeyword() in keyword.c as it was done in CTags SVN(r339) and adjust affected parsers.


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@2308 ea778897-0a13-0410-b9d1-a72fbfd435f5
2008-03-05 18:18:19 +00:00

387 lines
7.9 KiB
C

/*
* $Id$
*
* 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 FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "keyword.h"
#include "parse.h"
#include "read.h"
#include "main.h"
#include "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', "macro", "defines" },
{ TRUE, 'l', "namespace", "labels" },
{ TRUE, 'm', "function", "macros" },
{ TRUE, 't', "struct", "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: */