diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/KeyWords.cxx | 3 | ||||
| -rw-r--r-- | src/LexBasic.cxx | 325 | ||||
| -rw-r--r-- | src/LexCaml.cxx | 389 | 
3 files changed, 717 insertions, 0 deletions
| diff --git a/src/KeyWords.cxx b/src/KeyWords.cxx index 66e82094c..858eb54a3 100644 --- a/src/KeyWords.cxx +++ b/src/KeyWords.cxx @@ -137,7 +137,10 @@ int Scintilla_LinkLexers() {  	LINK_LEXER(lmAVE);  	LINK_LEXER(lmBaan);  	LINK_LEXER(lmBash); +	LINK_LEXER(lmBlitzBasic); +	LINK_LEXER(lmPureBasic);  	LINK_LEXER(lmBullant); +	LINK_LEXER(lmCaml);  	LINK_LEXER(lmClw);  	LINK_LEXER(lmClwNoCase);  	LINK_LEXER(lmConf); diff --git a/src/LexBasic.cxx b/src/LexBasic.cxx new file mode 100644 index 000000000..b8f83f171 --- /dev/null +++ b/src/LexBasic.cxx @@ -0,0 +1,325 @@ +// Scintilla source code edit control +/** @file LexBB.cxx + ** Lexer for BlitzBasic. + **/ +// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +// This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics +// and derivatives. Once they diverge enough, might want to split it into multiple +// lexers for more code clearity. +// +// Mail me (elias <at> users <dot> sf <dot> net) for any bugs. + +// Folding only works for simple things like functions or types. + +// You may want to have a look at my ctags lexer as well, if you additionally to coloring +// and folding need to extract things like label tags in your editor. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +/* Bits: + * 1  - whitespace + * 2  - operator + * 4  - identifier + * 8  - decimal digit + * 16 - hex digit + * 32 - bin digit + */ +static int character_classification[128] = +{ +    0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0, +    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, +    1,  2,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  10, 2, +    60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2,  2,  2,  2,  2,  2, +    2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4, +    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  4, +    2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4, +    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  0 +}; + +static bool IsSpace(int c) { +	return c < 128 && (character_classification[c] & 1); +} + +static bool IsOperator(int c) { +	return c < 128 && (character_classification[c] & 2); +} + +static bool IsIdentifier(int c) { +	return c < 128 && (character_classification[c] & 4); +} + +static bool IsDigit(int c) { +	return c < 128 && (character_classification[c] & 8); +} + +static bool IsHexDigit(int c) { +	return c < 128 && (character_classification[c] & 16); +} + +static bool IsBinDigit(int c) { +	return c < 128 && (character_classification[c] & 32); +} + +static int LowerCase(int c) +{ +	if (c >= 'A' && c <= 'Z') +		return 'a' + c - 'A'; +	return c; +} + +static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle, +                           WordList *keywordlists[], Accessor &styler) { +	bool wasfirst = true, isfirst = true; // true if first token in a line +	styler.StartAt(startPos); + +	StyleContext sc(startPos, length, initStyle, styler); + +	// Can't use sc.More() here else we miss the last character +	for (; ; sc.Forward()) { +		if (sc.state == SCE_B_IDENTIFIER) { +			if (!IsIdentifier(sc.ch)) { +				// Labels +				if (wasfirst && sc.Match(':')) { +					sc.ChangeState(SCE_B_LABEL); +					sc.ForwardSetState(SCE_B_DEFAULT); +				} else { +					char s[100]; +					int kstates[4] = { +						SCE_B_KEYWORD, +						SCE_B_KEYWORD2, +						SCE_B_KEYWORD3, +						SCE_B_KEYWORD4, +					}; +					sc.GetCurrentLowered(s, sizeof(s)); +					for (int i = 0; i < 4; i++) { +						if (keywordlists[i]->InList(s)) { +							sc.ChangeState(kstates[i]); +						} +					} +					// Types, must set them as operator else they will be +					// matched as number/constant +					if (sc.Match('.') || sc.Match('$') || sc.Match('%') || +						sc.Match('#')) { +						sc.SetState(SCE_B_OPERATOR); +					} else { +						sc.SetState(SCE_B_DEFAULT); +					} +				} +			} +		} else if (sc.state == SCE_B_OPERATOR) { +			if (!IsOperator(sc.ch) || sc.Match('#')) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_LABEL) { +			if (!IsIdentifier(sc.ch)) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_CONSTANT) { +			if (!IsIdentifier(sc.ch)) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_NUMBER) { +			if (!IsDigit(sc.ch)) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_HEXNUMBER) { +			if (!IsHexDigit(sc.ch)) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_BINNUMBER) { +			if (!IsBinDigit(sc.ch)) +				sc.SetState(SCE_B_DEFAULT); +		} else if (sc.state == SCE_B_STRING) { +			if (sc.ch == '"') { +				sc.ForwardSetState(SCE_B_DEFAULT); +			} +			if (sc.atLineEnd) { +				sc.ChangeState(SCE_B_ERROR); +				sc.SetState(SCE_B_DEFAULT); +			} +		} else if (sc.state == SCE_B_COMMENT) { +			if (sc.atLineEnd) { +				sc.SetState(SCE_B_DEFAULT); +			} +		} + +		if (sc.atLineStart) +			isfirst = true; + +		if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) { +			if (isfirst && sc.Match('.')) { +				sc.SetState(SCE_B_LABEL); +			} else if (sc.Match(';')) { +				sc.SetState(SCE_B_COMMENT); +			} else if (sc.Match('"')) { +				sc.SetState(SCE_B_STRING); +			} else if (IsDigit(sc.ch)) { +				sc.SetState(SCE_B_NUMBER); +			} else if (sc.Match('$')) { +				sc.SetState(SCE_B_HEXNUMBER); +			} else if (sc.Match('%')) { +				sc.SetState(SCE_B_BINNUMBER); +			} else if (sc.Match('#')) { +				sc.SetState(SCE_B_CONSTANT); +			} else if (IsOperator(sc.ch)) { +				sc.SetState(SCE_B_OPERATOR); +			} else if (IsIdentifier(sc.ch)) { +				wasfirst = isfirst; +				sc.SetState(SCE_B_IDENTIFIER); +			} else if (!IsSpace(sc.ch)) { +				sc.SetState(SCE_B_ERROR); +			} +		} + +		if (!IsSpace(sc.ch)) +			isfirst = false; + +		if (!sc.More()) +			break; +	} +	sc.Complete(); +} + +static int CheckBlitzFoldPoint(char const *token, int &level) { +	if (!strcmp(token, "function") || +		!strcmp(token, "type")) { +		level |= SC_FOLDLEVELHEADERFLAG; +		return 1; +	} +	if (!strcmp(token, "end function") || +		!strcmp(token, "end type")) { +		return -1; +	} +	return 0; +} + +static int CheckPureFoldPoint(char const *token, int &level) { +	if (!strcmp(token, "procedure") || +		!strcmp(token, "enumeration") || +		!strcmp(token, "interface") || +		!strcmp(token, "structure")) { +		level |= SC_FOLDLEVELHEADERFLAG; +		return 1; +	} +	if (!strcmp(token, "endprocedure") || +		!strcmp(token, "endenumeration") || +		!strcmp(token, "endinterface") || +		!strcmp(token, "endstructure")) { +		return -1; +	} +	return 0; +} + +static void FoldBasicDoc(unsigned int startPos, int length, +	Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) { +	int line = styler.GetLine(startPos); +	int level = styler.LevelAt(line); +	int go = 0, done = 0; +	int endPos = startPos + length; +	char word[256]; +	int wordlen = 0; +	int i; +        bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; +	// Scan for tokens at the start of the line (they may include +	// whitespace, for tokens like "End Function" +	for (i = startPos; i < endPos; i++) { +		int c = styler.SafeGetCharAt(i); +		if (!done && !go) { +			if (wordlen) { // are we scanning a token already? +				word[wordlen] = static_cast<char>(LowerCase(c)); +				if (!IsIdentifier(c)) { // done with token +					word[wordlen] = '\0'; +					go = CheckFoldPoint(word, level); +					if (!go) { +						// Treat any whitespace as single blank, for +						// things like "End   Function". +						if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) { +							word[wordlen] = ' '; +							if (wordlen < 255) +								wordlen++; +						} +						else // done with this line +							done = 1; +					} +				} else if (wordlen < 255) { +					wordlen++; +				} +			} else { // start scanning at first non-whitespace character +				if (!IsSpace(c)) { +					if (IsIdentifier(c)) { +						word[0] = static_cast<char>(LowerCase(c)); +						wordlen = 1; +					} else // done with this line +						done = 1; +				} +			} +		} +		if (c == '\n') { // line end +			if (!done && wordlen == 0 && foldCompact) // line was only space +				level |= SC_FOLDLEVELWHITEFLAG; +			if (level != styler.LevelAt(line)) +				styler.SetLevel(line, level); +			level += go; +			line++; +			// reset state +			wordlen = 0; +			level &= ~SC_FOLDLEVELHEADERFLAG; +			level &= ~SC_FOLDLEVELWHITEFLAG; +			go = 0; +			done = 0; +		} +	} +} + +static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle, +                           WordList *keywordlists[], Accessor &styler) { +	ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler); +} + +static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle, +                           WordList *keywordlists[], Accessor &styler) { +	ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler); +} + +static void FoldBlitzBasicDoc(unsigned int startPos, int length, int, +	WordList *[], Accessor &styler) { +	FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint); +} + +static void FoldPureBasicDoc(unsigned int startPos, int length, int, +	WordList *[], Accessor &styler) { +	FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint); +} + +static const char * const blitzbasicWordListDesc[] = { +	"BlitzBasic Keywords", +	"user1", +	"user2", +	"user3", +	0 +}; + +static const char * const purebasicWordListDesc[] = { +	"PureBasic Keywords", +	"PureBasic PreProcessor Keywords", +	"user defined 1", +	"user defined 2", +	0 +}; + +LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic", +	FoldBlitzBasicDoc, blitzbasicWordListDesc); + +LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic", +	FoldPureBasicDoc, purebasicWordListDesc); + diff --git a/src/LexCaml.cxx b/src/LexCaml.cxx new file mode 100644 index 000000000..ac1bfba5d --- /dev/null +++ b/src/LexCaml.cxx @@ -0,0 +1,389 @@ +// Scintilla source code edit control +/** @file LexCaml.cxx + ** Lexer for Objective Caml. + **/ +// Copyright 2005 by Robert Roessler <robertr@rftp.com> +// The License.txt file describes the conditions under which this software may be distributed. +/*	Release History +	20050204 Initial release. +	20050205 Quick compiler standards/"cleanliness" adjustment. +	20050206 Added cast for IsLeadByte(). +	20050209 Changes to "external" build support. +*/ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +//	Since the Microsoft __iscsym[f] funcs are not ANSI... +inline int  iscaml(int c) {return isalnum(c) || c == '_';} +inline int iscamlf(int c) {return isalpha(c) || c == '_';} + +#ifdef BUILD_AS_EXTERNAL_LEXER +/* +	(actually seems to work!) +*/ +#include "WindowAccessor.h" +#include "ExternalLexer.h" + +#if PLAT_WIN +#include <windows.h> +#endif + +static void ColouriseCamlDoc( +	unsigned int startPos, int length, +	int initStyle, +	WordList *keywordlists[], +	Accessor &styler); + +static void FoldCamlDoc( +	unsigned int startPos, int length, +	int initStyle, +	WordList *keywordlists[], +	Accessor &styler); + +static void InternalLexOrFold(int lexOrFold, unsigned int startPos, int length, +	int initStyle, char *words[], WindowID window, char *props); + +static const char* LexerName = "caml"; + +#ifdef TRACE +void Platform::DebugPrintf(const char *format, ...) { +	char buffer[2000]; +	va_list pArguments; +	va_start(pArguments, format); +	vsprintf(buffer,format,pArguments); +	va_end(pArguments); +	Platform::DebugDisplay(buffer); +} +#else +void Platform::DebugPrintf(const char *, ...) { +} +#endif + +bool Platform::IsDBCSLeadByte(int codePage, char ch) { +	return ::IsDBCSLeadByteEx(codePage, ch) != 0; +} + +long Platform::SendScintilla(WindowID w, unsigned int msg, unsigned long wParam, long lParam) { +	return ::SendMessage(reinterpret_cast<HWND>(w), msg, wParam, lParam); +} + +long Platform::SendScintillaPointer(WindowID w, unsigned int msg, unsigned long wParam, void *lParam) { +	return ::SendMessage(reinterpret_cast<HWND>(w), msg, wParam, +		reinterpret_cast<LPARAM>(lParam)); +} + +void EXT_LEXER_DECL Fold(unsigned int lexer, unsigned int startPos, int length, +	int initStyle, char *words[], WindowID window, char *props) +{ +	// below useless evaluation(s) to supress "not used" warnings +	lexer; +	// build expected data structures and do the Fold +	InternalLexOrFold(1, startPos, length, initStyle, words, window, props); + +} + +int EXT_LEXER_DECL GetLexerCount() +{ +	return 1;	// just us [Objective] Caml lexers here! +} + +void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength) +{ +	// below useless evaluation(s) to supress "not used" warnings +	Index; +	// return as much of our lexer name as will fit (what's up with Index?) +	if (buflength > 0) { +		buflength--; +		int n = strlen(LexerName); +		if (n > buflength) +			n = buflength; +		memcpy(name, LexerName, n), name[n] = '\0'; +	} +} + +void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, +	int initStyle, char *words[], WindowID window, char *props) +{ +	// below useless evaluation(s) to supress "not used" warnings +	lexer; +	// build expected data structures and do the Lex +	InternalLexOrFold(0, startPos, length, initStyle, words, window, props); +} + +static void InternalLexOrFold(int foldOrLex, unsigned int startPos, int length, +	int initStyle, char *words[], WindowID window, char *props) +{ +	// create and initialize a WindowAccessor (including contained PropSet) +	PropSet ps; +	ps.SetMultiple(props); +	WindowAccessor wa(window, ps); +	// create and initialize WordList(s) +	int nWL = 0; +	for (; words[nWL]; nWL++) ;	// count # of WordList PTRs needed +	WordList** wl = new WordList* [nWL + 1];// alloc WordList PTRs +	int i = 0; +	for (; i < nWL; i++) { +		wl[i] = new WordList();	// (works or THROWS bad_alloc EXCEPTION) +		wl[i]->Set(words[i]); +	} +	wl[i] = 0; +	// call our "internal" folder/lexer (... then do Flush!) +	if (foldOrLex) +		FoldCamlDoc(startPos, length, initStyle, wl, wa); +	else +		ColouriseCamlDoc(startPos, length, initStyle, wl, wa); +	wa.Flush(); +	// clean up before leaving +	for (i = nWL - 1; i >= 0; i--) +		delete wl[i]; +	delete [] wl; +} + +static +#endif	/* BUILD_AS_EXTERNAL_LEXER */ + +void ColouriseCamlDoc( +	unsigned int startPos, int length, +	int initStyle, +	WordList *keywordlists[], +	Accessor &styler) +{ +	// initialize styler +	styler.StartAt(startPos); +	styler.StartSegment(startPos); +	// set up [initial] state info (terminating states that shouldn't "bleed") +	int state = initStyle, nesting = 0; +	if (state < SCE_CAML_STRING) +		state = SCE_CAML_DEFAULT; +	if (state >= SCE_CAML_COMMENT) +		nesting = state - SCE_CAML_COMMENT; +	int chLast = startPos? static_cast<unsigned char>(styler[startPos - 1]): ' '; +	int chNext = static_cast<unsigned char>(styler[startPos]); + +	int chBase = 'd', chToken = 0, chLit = 0, chSkip; +	WordList& keywords = *keywordlists[0]; +	WordList& keywords2 = *keywordlists[1]; + +	// foreach char in range... +	unsigned int i = startPos; +	for (unsigned int endPos = startPos + length; i < endPos; i += chSkip) { +		// set up [per-char] state info +		int ch = chNext; +		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1)); +		int state2 = -1;	// (ASSUME no state change) +		int chColor = i - 1;// (ASSUME standard coloring range) +		chSkip = 1;			// (ASSUME scanner "eats" 1 char) + +		// this may be the correct thing to do... or not +		if (styler.IsLeadByte(static_cast<char>(ch))) { +			chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), +				chSkip++; +			continue; +		} + +		// step state machine +		switch (state) { +		case SCE_CAML_DEFAULT: +			// it's wide open; what do we have? +			if (iscamlf(ch)) +				state2 = SCE_CAML_IDENTIFIER, chToken = i; +			else if (ch == '`') +				state2 = SCE_CAML_TAGNAME, chToken = i; +			else if (ch == '#' && isdigit(chNext)) +				state2 = SCE_CAML_LINENUM, chToken = i; +			else if (isdigit(ch)) { +				state2 = SCE_CAML_NUMBER, +					chBase = strchr("xXoObB", chNext)? chNext: 'd'; +				if (chBase != 'd') +					ch = chNext, +						chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), +						chSkip++; +			} else if (ch == '\'')	/* (char literal?) */ +				state2 = SCE_CAML_CHAR, chToken = i, chLit = 0; +			else if (ch == '\"') +				state2 = SCE_CAML_STRING; +			else if (ch == '(' && chNext == '*') +				state2 = SCE_CAML_COMMENT, +					ch = ' ',	// (make SURE "(*)" isn't seen as a closed comment) +					chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), +					chSkip++, nesting = 0; +			else if (strchr("!?~"		/* Caml "prefix-symbol" */ +					"=<>@^|&+-*/$%"		/* Caml "infix-symbol" */ +					"()[]{};,:.#", ch))	/* Caml "bracket" or ;,:.# */ +				state2 = SCE_CAML_OPERATOR, chToken = i; +			break; + +		case SCE_CAML_IDENTIFIER: +			// [try to] interpret as [additional] identifier char +			if (!(iscaml(ch) || ch == '\'')) { +				const int n = i - chToken; +				if (n < 24) { +					// length is believable as keyword, [re-]construct token +					char t[24]; +					int p = 0; +					for (int q = chToken; p < n; p++, q++) +						t[p] = styler[q]; +					t[p] = '\0'; +					// special-case "_" token as KEYWORD +					if ((n == 1 && chLast == '_') || keywords.InList(t)) +						state = SCE_CAML_KEYWORD; +					else if (keywords2.InList(t)) +						state = SCE_CAML_KEYWORD2; +				} +				state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; +			} +			break; + +		case SCE_CAML_TAGNAME: +			// [try to] interpret as [additional] tagname char +			if (!(iscaml(ch) || ch == '\'')) +				state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; +			break; + +		/*case SCE_CAML_KEYWORD: +		case SCE_CAML_KEYWORD2: +			// [try to] interpret as [additional] keyword char +			if (!iscaml(ch)) +				state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; +			break;*/ + +		case SCE_CAML_LINENUM: +			// [try to] interpret as [additional] linenum directive char +			if (!isdigit(ch)) +				state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; +			break; + +		case SCE_CAML_OPERATOR: { +			// [try to] interpret as [additional] operator char +			char* o = 0; +			if (iscaml(ch) || isspace(ch)			/* ident or whitespace */ +				|| ((o = strchr(")]};,\'\"`#", ch)) != 0)/* "termination" chars */ +				|| !strchr("!$%&*+-./:<=>?@^|~", ch)/* "operator" chars */) { +				// check for INCLUSIVE termination +				if (o && strchr(")]};,", ch)) { +					if ((ch == ')' && chLast == '(') || (ch == ']' && chLast == '[')) +						// special-case "()" and "[]" tokens as KEYWORDS +						state = SCE_CAML_KEYWORD; +					chColor++; +				} else +					chNext = ch, chSkip--; +				state2 = SCE_CAML_DEFAULT; +			} +			break; +		} + +		case SCE_CAML_NUMBER: +			// [try to] interpret as [additional] numeric literal char +			// N.B. - improperly accepts "extra" digits in base 2 or 8 literals +			if (isdigit(ch) || ch == '_' +				|| ((chBase == 'x' || chBase == 'X') && isxdigit(ch))) +				break; +			// how about an integer suffix? +			if ((ch == 'l' || ch == 'L' || ch == 'n') +				&& (isdigit(chLast) || chLast == '_')) +				break; +			// or a floating-point literal? +			if (ch == '.' && (isdigit(chLast) || chLast == '_')) +				break; +			// with an exponent? (I) +			if ((ch == 'e' || ch == 'E') +				&& (isdigit(chLast) || chLast == '_' || chLast == '.')) +				break; +			// with an exponent? (II) +			if ((ch == '+' || ch == '-') && (chLast == 'e' || chLast == 'E')) +				break; +			// it looks like we have run out of number +			state2 = SCE_CAML_DEFAULT, chNext = ch, chSkip--; +			break; + +		case SCE_CAML_CHAR: +			// [try to] interpret as [additional] char literal char +			if (ch == '\\') { +				chLit = 1;	// (definitely IS a char literal) +				if (chLast == '\\') +					ch = ' ';	// (so termination test isn't fooled) +			// should we be terminating - one way or another? +			} else if ((ch == '\'' && chLast != '\\') || ch == '\r' || ch == '\n') { +				state2 = SCE_CAML_DEFAULT; +				if (ch == '\'') +					chColor++; +				else +					state = SCE_CAML_IDENTIFIER; +			// ... maybe a char literal, maybe not +			} else if (chLit < 1 && i - chToken >= 2) +				state = SCE_CAML_IDENTIFIER, chNext = ch, chSkip--; +			break; + +		case SCE_CAML_STRING: +			// [try to] interpret as [additional] string literal char +			if (ch == '\\' && chLast == '\\') +				ch = ' ';	// (so '\\' doesn't cause us trouble) +			else if (ch == '\"' && chLast != '\\') +				state2 = SCE_CAML_DEFAULT, chColor++; +			break; + +		case SCE_CAML_COMMENT: +		case SCE_CAML_COMMENT+1: +		case SCE_CAML_COMMENT+2: +		case SCE_CAML_COMMENT+3: +			// we're IN a comment - does this start a NESTED comment? +			if (ch == '(' && chNext == '*') +				state2 = state + 1, +					ch = ' ',	// (make SURE "(*)" isn't seen as a closed comment) +					chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2)), +					chSkip++, nesting++; +			// [try to] interpret as [additional] comment char +			else if (ch == ')' && chLast == '*') +				state2 = nesting? (state - 1): SCE_CAML_DEFAULT, chColor++, nesting--; +			break; +		} + +		// handle state change and char coloring as required +		if (state2 >= 0) { +			if (chColor > 0) +				styler.ColourTo(chColor, state); +			state = state2; +		} +		chLast = ch; +	} + +	// do terminal char coloring (JIC) +	styler.ColourTo(i, state); +//	styler.Flush();	// (is this always called by calling code?) +} + +#ifdef BUILD_AS_EXTERNAL_LEXER +static +#endif	/* BUILD_AS_EXTERNAL_LEXER */ +void FoldCamlDoc( +	unsigned int startPos, int length, +	int initStyle, +	WordList *keywordlists[], +	Accessor &styler) +{ +	// below useless evaluation(s) to supress "not used" warnings +	startPos || length || initStyle || keywordlists[0] || styler.Length(); +} + +static const char * const camlWordListDesc[] = { +	"Keywords",		// primary Objective Caml keywords +	"Keywords2",	// "optional" keywords (typically from Pervasives) +	0 +}; + +#ifndef BUILD_AS_EXTERNAL_LEXER +LexerModule lmCaml(SCLEX_CAML, ColouriseCamlDoc, "caml", FoldCamlDoc, camlWordListDesc); +#endif	/* BUILD_AS_EXTERNAL_LEXER */ | 
