home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------
-
- ScanLib ©1995 Dietmar Eilert
-
- GoldED syntax parser example library (uses a syntax cache). Dice:
-
- DMAKE
-
- -------------------------------------------------------------------------------
-
- */
-
- #include "defs.h"
-
- /// "Header stuff"
-
- // Buffer handles are allocated for each text buffer to keep track of ressources:
-
- struct BufferHandle {
-
- struct EditConfig *bh_EditConfig; // pointer to text data
- struct GlobalConfig *bh_GlobalConfig; // editor configuration
- struct SyntaxChunk *bh_SyntaxStack; // parser output
- struct RefreshRequest bh_RefreshRequest; // display refresh request
- };
-
- // known opcodes are described by syntax structures
-
- struct Keyword {
-
- UBYTE *Pattern; // known pattern (e.g. "move")
- UWORD Len; // base length
- UWORD Level; // syntax level
- };
-
- #define UPPER(a) ((a) & 95) // simple uppercase conversion
- #define EMPTY_STACK ((struct SyntaxChunk *)~0) // empty stack flag
-
- // syntax levels recognized by this parser
-
- #define SYNTAX_STANDARD 0
- #define SYNTAX_LABELGLOBAL 1
- #define SYNTAX_LABELLOCAL 2
- #define SYNTAX_BRANCH 3
- #define SYNTAX_OPCODE 4
- #define SYNTAX_ARGUMENTS 5
- #define SYNTAX_COMMENTSHORT 6
- #define SYNTAX_COMMENTLONG 7
- #define SYNTAX_XDEFXREF 8
- #define SYNTAX_DATA 9
- #define SYNTAX_ASSEMBLER 10
- #define SYNTAX_FORBIDDEN 11
-
- ///
- /// "Prototype"
-
- // library functions
-
- Prototype LibCall struct ParserData *MountScanner(void);
- Prototype LibCall ULONG StartScanner(__A0 struct GlobalConfig *, __A1 struct EditConfig *, __D0 struct SyntaxChunk *);
- Prototype LibCall ULONG CloseScanner(__D0 ULONG);
- Prototype LibCall void FlushScanner(__D0 ULONG);
- Prototype LibCall void SetupScanner(__A0 struct GlobalConfig *);
- Prototype LibCall struct RefreshRequest *BriefScanner(__D0 ULONG, __A0 struct ScannerNotify *);
- Prototype LibCall struct SyntaxChunk *ParseLine (__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
- Prototype LibCall void UnparseLines(__A0 struct LineNode *, __D0 ULONG);
- Prototype LibCall void ParseSection(__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
-
- // private functions
-
- Prototype struct SyntaxChunk *ParseString(UBYTE *, UWORD, ULONG);
- Prototype struct SyntaxChunk *DupStack(struct SyntaxChunk *);
- Prototype void PrepareHash(void);
- Prototype UWORD CheckOpcode(UBYTE *, UWORD, UWORD);
- Prototype BOOL memicmp(UBYTE *, UBYTE *, UWORD);
-
- ///
- /// "Globals"
-
- struct Keyword *Hash[256];
-
- struct Keyword Reserved[] = {
-
- // opcode opcode_length syntax_level
-
- { "ADDSYM", 0, SYNTAX_ASSEMBLER },
- { "BASEREG", 0, SYNTAX_ASSEMBLER },
- { "BEQ", 0, SYNTAX_BRANCH },
- { "BGE", 0, SYNTAX_BRANCH },
- { "BGT", 0, SYNTAX_BRANCH },
- { "BHI", 0, SYNTAX_BRANCH },
- { "BLE", 0, SYNTAX_BRANCH },
- { "BLM", 0, SYNTAX_BRANCH },
- { "BLS", 0, SYNTAX_BRANCH },
- { "BMI", 0, SYNTAX_BRANCH },
- { "BNE", 0, SYNTAX_BRANCH },
- { "BOPT", 0, SYNTAX_ASSEMBLER },
- { "BPL", 0, SYNTAX_BRANCH },
- { "BRA", 0, SYNTAX_BRANCH },
- { "BVC", 0, SYNTAX_BRANCH },
- { "BVS", 0, SYNTAX_BRANCH },
- { "CNOP", 0, SYNTAX_ASSEMBLER },
- { "COMMENT", 0, SYNTAX_ASSEMBLER },
- { "CSECT", 0, SYNTAX_ASSEMBLER },
- { "CSTR", 0, SYNTAX_ASSEMBLER },
- { "DBEQ", 0, SYNTAX_BRANCH },
- { "DBGE", 0, SYNTAX_BRANCH },
- { "DBGT", 0, SYNTAX_BRANCH },
- { "DBHI", 0, SYNTAX_BRANCH },
- { "DBLE", 0, SYNTAX_BRANCH },
- { "DBLM", 0, SYNTAX_BRANCH },
- { "DBLS", 0, SYNTAX_BRANCH },
- { "DBMI", 0, SYNTAX_BRANCH },
- { "DBNE", 0, SYNTAX_BRANCH },
- { "DBPL", 0, SYNTAX_BRANCH },
- { "DBVC", 0, SYNTAX_BRANCH },
- { "DBVS", 0, SYNTAX_BRANCH },
- { "DC", 0, SYNTAX_DATA },
- { "DEBUG", 0, SYNTAX_ASSEMBLER },
- { "DL", 0, SYNTAX_DATA },
- { "DS", 0, SYNTAX_DATA },
- { "DW", 0, SYNTAX_DATA },
- { "ELSEIF", 0, SYNTAX_ASSEMBLER },
- { "END", 0, SYNTAX_ASSEMBLER },
- { "END", 0, SYNTAX_ASSEMBLER },
- { "ENDC", 0, SYNTAX_ASSEMBLER },
- { "ENDM", 0, SYNTAX_ASSEMBLER },
- { "ENDR", 0, SYNTAX_ASSEMBLER },
- { "EQU", 0, SYNTAX_ASSEMBLER },
- { "EQU", 0, SYNTAX_ASSEMBLER },
- { "EQUR", 0, SYNTAX_ASSEMBLER },
- { "EVEN", 0, SYNTAX_ASSEMBLER },
- { "EXEOBJ", 0, SYNTAX_ASSEMBLER },
- { "FAIL", 0, SYNTAX_ASSEMBLER },
- { "IFC", 0, SYNTAX_ASSEMBLER },
- { "IFD", 0, SYNTAX_ASSEMBLER },
- { "IFEQ", 0, SYNTAX_ASSEMBLER },
- { "IFGE", 0, SYNTAX_ASSEMBLER },
- { "IFGT", 0, SYNTAX_ASSEMBLER },
- { "IFLE", 0, SYNTAX_ASSEMBLER },
- { "IFLT", 0, SYNTAX_ASSEMBLER },
- { "IFNC", 0, SYNTAX_ASSEMBLER },
- { "IFND", 0, SYNTAX_ASSEMBLER },
- { "IFNE", 0, SYNTAX_ASSEMBLER },
- { "ILLEGAL", 0, SYNTAX_FORBIDDEN },
- { "INCDIR", 0, SYNTAX_ASSEMBLER },
- { "INCLUDE", 0, SYNTAX_ASSEMBLER },
- { "JMP", 0, SYNTAX_BRANCH },
- { "JSR", 0, SYNTAX_BRANCH },
- { "MACLIB", 0, SYNTAX_ASSEMBLER },
- { "MACRO", 0, SYNTAX_ASSEMBLER },
- { "MC68000", 0, SYNTAX_ASSEMBLER },
- { "MC68010", 0, SYNTAX_ASSEMBLER },
- { "MC68020", 0, SYNTAX_ASSEMBLER },
- { "MC68030", 0, SYNTAX_ASSEMBLER },
- { "MC68040", 0, SYNTAX_ASSEMBLER },
- { "MC68060", 0, SYNTAX_ASSEMBLER },
- { "MEXIT", 0, SYNTAX_ASSEMBLER },
- { "MULTIPASS", 0, SYNTAX_ASSEMBLER },
- { "NEWSYNTAX", 0, SYNTAX_ASSEMBLER },
- { "OBJFILE", 0, SYNTAX_ASSEMBLER },
- { "OFFSET", 0, SYNTAX_ASSEMBLER },
- { "OPT", 0, SYNTAX_ASSEMBLER },
- { "ORG", 0, SYNTAX_ASSEMBLER },
- { "OUTPUT", 0, SYNTAX_ASSEMBLER },
- { "OUTPUT", 0, SYNTAX_ASSEMBLER },
- { "REPT", 0, SYNTAX_ASSEMBLER },
- { "RESET", 0, SYNTAX_FORBIDDEN },
- { "RTE", 0, SYNTAX_FORBIDDEN },
- { "SECTION", 0, SYNTAX_ASSEMBLER },
- { "SEQ", 0, SYNTAX_BRANCH },
- { "SET", 0, SYNTAX_ASSEMBLER },
- { "SGE", 0, SYNTAX_BRANCH },
- { "SGT", 0, SYNTAX_BRANCH },
- { "SHI", 0, SYNTAX_BRANCH },
- { "SLE", 0, SYNTAX_BRANCH },
- { "SLM", 0, SYNTAX_BRANCH },
- { "SLS", 0, SYNTAX_BRANCH },
- { "SMI", 0, SYNTAX_BRANCH },
- { "SNE", 0, SYNTAX_BRANCH },
- { "SPL", 0, SYNTAX_BRANCH },
- { "STOP", 0, SYNTAX_FORBIDDEN },
- { "STOP", 0, SYNTAX_FORBIDDEN },
- { "SVC", 0, SYNTAX_BRANCH },
- { "SVS", 0, SYNTAX_BRANCH },
- { "SYM", 0, SYNTAX_ASSEMBLER },
- { "TAS", 0, SYNTAX_FORBIDDEN },
- { "TRASHREG", 0, SYNTAX_ASSEMBLER },
- { "VERBOSEOPTIM", 0, SYNTAX_ASSEMBLER },
- { "XDEF", 0, SYNTAX_XDEFXREF },
- { "XREF", 0, SYNTAX_XDEFXREF },
-
- { NULL, 0, 0}
- };
-
- ///
- /// "Library functions"
-
- /* ------------------------------- MountScanner --------------------------------
-
- Called by the editor before first usage of a scanner. Return a description of
- our abilities.
-
- */
-
- LibCall struct ParserData *
- MountScanner()
- {
- static struct ParserData parserData;
-
- // syntax elements understood by parser
-
- static UBYTE *levelNames[] = {
-
- "Standard text",
- "Label global",
- "Label local",
- "Branches",
- "Opcode",
- "Arguments",
- "Comment - short",
- "Comment - long",
- "xdef/xref",
- "Data",
- "Assembler",
- "Forbidden",
-
- NULL
- };
-
- // color suggestions
-
- static ULONG *levelColors[] = {
-
- MAKE_RGB4(0, 0, 0),
- MAKE_RGB4(15, 15, 0),
- MAKE_RGB4(0, 15, 15),
- MAKE_RGB4(15, 0, 0),
- MAKE_RGB4(0, 15, 0),
- MAKE_RGB4(0, 0, 15),
- MAKE_RGB4(15, 15, 15),
- MAKE_RGB4(15, 0, 15),
- MAKE_RGB4(0, 0, 0),
- MAKE_RGB4(0, 0, 0),
- MAKE_RGB4(0, 0, 0),
- MAKE_RGB4(15, 15, 15),
- MAKE_RGB4(0, 15, 0),
- };
-
- parserData.pd_Release = SCANLIBVERSION;
- parserData.pd_Version = 1;
- parserData.pd_Serial = 0;
- parserData.pd_Info = "Warp A68K 0.9 ©'95 D.Eilert";
- parserData.pd_Levels = 12;
- parserData.pd_Names = levelNames;
- parserData.pd_Colors = levelColors;
- parserData.pd_Flags = SCPRF_SYNTAXCACHE | SCPRF_CONTEXT;
- parserData.pd_Reserved = 0;
-
- PrepareHash();
-
- return(&parserData);
- }
-
-
- /* ------------------------------- StartScanner --------------------------------
-
- Called by the editor after a new text buffer has been created. We allocate a
- buffer to hold text-specific data. The buffer address is returned as handle.
-
- */
-
- LibCall ULONG
- StartScanner(__A0 struct GlobalConfig *globalConfigPtr, __A1 struct EditConfig *editConfigPtr, __D0 struct SyntaxChunk *syntaxStack)
- {
- struct BufferHandle *handle;
-
- if (handle = AllocVec(sizeof(struct BufferHandle), MEMF_PUBLIC | MEMF_CLEAR)) {
-
- handle->bh_GlobalConfig = globalConfigPtr;
- handle->bh_EditConfig = editConfigPtr;
- handle->bh_SyntaxStack = syntaxStack;
- }
-
- return((ULONG)handle);
- }
-
-
- /* ------------------------------- CloseScanner --------------------------------
-
- Called by the editor if a text buffer is about to be closed. Deallocate buffer
- specific 'global' data.
-
- */
-
- LibCall ULONG
- CloseScanner(__D0 ULONG scanID)
- {
- if (scanID) {
-
- struct BufferHandle *handle = (struct BufferHandle *)scanID;
-
- FreeVec(handle);
- }
-
- return(0);
- }
-
-
- /* ------------------------------- FlushScanner --------------------------------
-
- Called by the editor in low memory situations: we are supposed to free as much
- memory as possible.
-
- */
-
- LibCall void
- FlushScanner(__D0 ULONG scanID)
- {
- struct BufferHandle *handle;
- struct EditConfig *config;
- struct LineNode *lineNode;
-
- handle = (struct BufferHandle *)scanID;
- config = handle->bh_EditConfig;
-
- if (lineNode = config->TextNodes)
- UnparseLines(lineNode, config->Lines);
- }
-
-
- /* ------------------------------- SetupScanner --------------------------------
-
- Called by the editor if the user wants to change the scanner's configuration.
- We do not support user configuration (parserData.pd_Flags: SCPRF_CONFIGWIN flag
- unset).
-
- */
-
- LibCall void
- SetupScanner(__A0 globalConfigPtr)
- {
- ;
- }
-
-
- /* ------------------------------- BriefScanner --------------------------------
-
- Called to notify a context scanner if lines have been added, deleted or
- modified. We aren't a context scanner (parserData.pd_Flags: SCPRF_CONTEXT
- flag unset), so we won't ever have to request additional display requests:
- the editor's built-in refresh of damage regions is sufficient.
-
- */
-
- LibCall struct RefreshRequest *
- BriefScanner(__D0 ULONG scanID, __A0 struct ScannerNotify *notify)
- {
- return(NULL);
- }
-
-
- /* --------------------------------- ParseLine ---------------------------------
-
- Parse a line, build a syntax description
-
- */
-
- LibCall struct SyntaxChunk *
- ParseLine(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG line)
- {
- if (lineNode->Fold)
-
- return(NULL);
-
- else if (lineNode->Len) {
-
- // line not yet parsed ?
-
- if (lineNode->UserData == NULL) {
-
- struct SyntaxChunk *syntaxStack = ParseString(lineNode->Text, lineNode->Len, scanID);
-
- if (syntaxStack == EMPTY_STACK)
- lineNode->UserData = EMPTY_STACK;
- else
- lineNode->UserData = DupStack(syntaxStack);
- }
-
- if (lineNode->UserData == EMPTY_STACK)
- return((struct SyntaxChunk *)NULL);
- else
- return((struct SyntaxChunk *)lineNode->UserData);
- }
- else
- return(NULL);
- }
-
- /* -------------------------------- UnparseLines -------------------------------
-
- Called by the editor if lines are to be deleted. We are supposed to free
- private data attached to the lines.
-
- */
-
- LibCall void
- UnparseLines(__A0 struct LineNode *lineNode, __D0 ULONG lines)
- {
- while (lines--) {
-
- // free syntax cache
-
- if (lineNode->UserData) {
-
- if (lineNode->UserData != (APTR)EMPTY_STACK)
- FreeVec((APTR)lineNode->UserData);
-
- lineNode->UserData = NULL;
- }
-
- // free folded subblock
-
- if (lineNode->Fold)
- UnparseLines(lineNode->Fold->TextNodes, lineNode->Fold->Lines);
-
- ++lineNode;
- }
- }
-
- /* -------------------------------- ParseSection -------------------------------
-
- Called by the editor if lines are to be displayed. The scanner is encouraged to
- preparse the lines.
-
- */
-
- LibCall void
- ParseSection(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG lines)
- {
- while (lines--) {
-
- // fold headers have to be ignored
-
- if (lineNode->Fold == NULL) {
-
- // line not yet parsed ?
-
- if (lineNode->Len)
- if (lineNode->UserData == NULL)
- lineNode->UserData = DupStack(ParseString(lineNode->Text, lineNode->Len, scanID));
- }
-
- ++lineNode;
- }
- }
-
- ///
- /// "private"
-
- /* -------------------------------- PrepareHash --------------------------------
-
- Prepare reserved keyword hashtable (used to find keyword description if ascii
- value of first letter is known).
-
- */
-
- void
- PrepareHash()
- {
- struct Keyword *keyword;
-
- memset(Hash, 0, sizeof(Hash));
-
- keyword = Reserved;
-
- while (keyword->Pattern) {
-
- UWORD ascii = *keyword->Pattern;
-
- Hash[ascii] = keyword;
-
- // ignore keywords starting with the same letter
-
- while (keyword->Pattern && (*keyword->Pattern == ascii)) {
-
- keyword->Len = strlen(keyword->Pattern);
-
- ++keyword;
- }
- }
- }
-
-
- /* -------------------------------- ParseString --------------------------------
-
- Parse a string, build a syntax description. This is a simple example only:
- C++-Comments (// ....) are highlighted. Return EMPTY_STACK in case there is
- nothing to highlight.
-
- */
-
- struct SyntaxChunk *
- ParseString(UBYTE *text, UWORD len, ULONG scanID)
- {
- if (len) {
-
- UWORD indent, elements, section;
-
- BOOL readOpcode = FALSE;
- BOOL readArgs = FALSE;
- BOOL readComment = FALSE;
-
- struct SyntaxChunk *syntaxStack = ((struct BufferHandle *)scanID)->bh_SyntaxStack;
-
- // leading spaces have to be ignored
-
- for (indent = 0; len && (*text == 32); ++indent, --len)
- ++text;
-
- // trailing spaces have to be ignored
-
- while (len && (text[len - 1] == 32))
- --len;
-
- if (len) {
-
- if (*text == '*') {
-
- // comment detected (ignore rest of line)
-
- syntaxStack[0].sc_Level = SYNTAX_COMMENTLONG;
- syntaxStack[0].sc_Start = indent;
- syntaxStack[0].sc_End = indent + len - 1;
-
- elements = 1;
- }
- else {
-
- section = 0;
-
- for (elements = 0; len; ++text, ++indent, --len) {
-
- if ((*text == 34) || (*text == 39)) {
-
- // string (argument) detected
-
- UWORD stringLen = 1;
-
- while (stringLen < len)
- if (text[stringLen++] == *text)
- break;
-
- if (readArgs) {
-
- syntaxStack[elements].sc_Level = SYNTAX_ARGUMENTS;
- syntaxStack[elements].sc_Start = indent;
- syntaxStack[elements].sc_End = indent + stringLen - 1;
-
- ++elements;
- }
-
- // move to next section (consider end-of-loop action)
-
- --stringLen;
-
- text += stringLen;
- indent += stringLen;
- len -= stringLen;
- }
- else if (*text == ';') {
-
- // comment detected (rest of line)
-
- syntaxStack[elements].sc_Level = SYNTAX_COMMENTSHORT;
- syntaxStack[elements].sc_Start = indent;
- syntaxStack[elements].sc_End = indent + len - 1;
-
- ++elements;
-
- // terminate parsing
-
- break;
- }
- else if (*text != 32) {
-
- // examine next word
-
- UWORD wordLen, baseLen = 0;
-
- for (wordLen = 1; (text[wordLen] != 32) && (wordLen < len); ++wordLen) {
-
- if (text[wordLen] == '.')
- baseLen = wordLen;
- }
-
- if ((section == 0) && ((indent == 0) || (text[wordLen - 1] == ':'))) {
-
- // label detected: local or global label ?
-
- if ((*text == '.') || (text[wordLen - 1] == '$'))
- syntaxStack[elements].sc_Level = SYNTAX_LABELLOCAL;
- else
- syntaxStack[elements].sc_Level = SYNTAX_LABELGLOBAL;
-
- syntaxStack[elements].sc_Start = indent;
- syntaxStack[elements].sc_End = indent + wordLen - 1;
-
- ++elements;
-
- readOpcode = TRUE;
- }
- else if (readComment) {
-
- // syntax error: comment expected
- }
- else if (readArgs) {
-
- // found arguments
-
- syntaxStack[elements].sc_Level = SYNTAX_ARGUMENTS;
- syntaxStack[elements].sc_Start = indent;
- syntaxStack[elements].sc_End = indent + wordLen - 1;
-
- ++elements;
-
- readComment = TRUE;
- }
- else {
-
- // found opcode
-
- syntaxStack[elements].sc_Level = CheckOpcode(text, wordLen, baseLen);
- syntaxStack[elements].sc_Start = indent;
- syntaxStack[elements].sc_End = indent + wordLen - 1;
-
- ++elements;
-
- readArgs = TRUE;
- }
-
- // move to next section (consider end-of-loop action)
-
- --wordLen;
- ++section;
-
- text += wordLen;
- indent += wordLen;
- len -= wordLen;
- }
- }
- }
-
- if (elements) {
-
- // terminate syntax stack
-
- syntaxStack[elements].sc_Start = FALSE;
- syntaxStack[elements].sc_End = FALSE;
- syntaxStack[elements].sc_Level = FALSE;
-
- return(syntaxStack);
- }
- else
- return(EMPTY_STACK);
- }
- }
-
- return(EMPTY_STACK);
- }
-
- /* --------------------------------- DupStack ----------------------------------
-
- Duplicate syntax stack (to be FreeVec'ed). Return NULL in case of failure.
-
- */
-
- struct SyntaxChunk *
- DupStack(syntaxStack)
-
- struct SyntaxChunk *syntaxStack;
- {
- if (syntaxStack && (syntaxStack != EMPTY_STACK)) {
-
- struct SyntaxChunk *chunk;
- UWORD elements;
-
- // determine stack size
-
- for (elements = 0, chunk = syntaxStack; chunk->sc_Level; ++chunk)
- ++elements;
-
- // create copy of syntax stack (to be attached to a text line by the caller)
-
- if (elements) {
-
- ULONG size = (++elements) * sizeof(struct SyntaxChunk);
-
- chunk = syntaxStack;
-
- if (syntaxStack = AllocVec(size, MEMF_PUBLIC))
- movmem(chunk, syntaxStack, size);
- }
- else
- syntaxStack = EMPTY_STACK;
- }
-
- return(syntaxStack);
- }
-
-
- /* -------------------------------- CheckOpcode --------------------------------
-
- Check opcode, return syntax level.
-
- */
-
- UWORD
- CheckOpcode(text, wordLen, baseLen)
-
- UBYTE *text;
- UWORD wordLen, baseLen;
- {
- struct Keyword *keyword;
- UWORD first;
-
- first = UPPER(*text);
-
- // is there a known opcode starting with the same letter ?
-
- if (keyword = Hash[first]) {
-
- UWORD syntaxLevel = SYNTAX_OPCODE;
-
- // no opcode extension (e.g. ".l") ?
-
- if (baseLen == 0)
- baseLen = wordLen;
-
- // search sorted list of known opcodes
-
- while (keyword->Pattern) {
-
- if (*keyword->Pattern > first)
-
- break;
-
- else if (*keyword->Pattern == first) {
-
- if (keyword->Len == baseLen)
- if (memicmp(text, keyword->Pattern, baseLen))
- return(keyword->Level);
- }
-
- ++keyword;
- }
-
- return(syntaxLevel);
- }
- else
- return(SYNTAX_OPCODE);
- }
-
-
- /* ---------------------------------- memicmp ----------------------------------
-
- case-insensitive memcmp replacement (<pattern> is supposed to be uppercase).
- Return TRUE if <text> equals <pattern>.
-
- */
-
- BOOL
- memicmp(text, pattern, len)
-
- UBYTE *text, *pattern;
- UWORD len;
- {
- while (len--)
- if (UPPER(*text++) != *pattern++)
- return(FALSE);
-
- return(TRUE);
- }
-
- ///
-