public void Style(Scintilla scintilla, int startPos, int endPos) { // 改行コードをWindowsフォーマット(CR+LF)またはUnixフォーマット(LF)から // Macフォーマット(CR)にしたときに発生する例外(IndexOutOfRangeException)を回避 startPos = startPos < 0 ? 0 : startPos; endPos = endPos > scintilla.TextLength ? scintilla.TextLength : endPos; int lineNumber = scintilla.LineFromPosition(startPos); startPos = scintilla.Lines[lineNumber].Position; char chBeforePrev = '\0'; char chPrev = '\0'; char ch = '\0'; char chNext = '\0'; char chAfterNext = '\0'; int length = 0; ParseState state = ParseState.None; switch (scintilla.GetStyleAt(startPos - 1)) { case HspLexer.StylePreprocessor: state = ParseState.AfterPreprocessor; break; case HspLexer.StyleString: state = ParseState.String; break; case HspLexer.StyleComment: state = ParseState.Comment; break; } scintilla.StartStyling(startPos); int currentPos = startPos; int currentLine = lineNumber; int currentLineStartPos = startPos; int currentLineEndPos = scintilla.Lines[lineNumber].EndPosition; while (currentPos < endPos) { chBeforePrev = (char)scintilla.GetCharAt(currentPos - 2); chPrev = (char)scintilla.GetCharAt(currentPos - 1); ch = (char)scintilla.GetCharAt(currentPos); chNext = (char)scintilla.GetCharAt(currentPos + 1); chAfterNext = (char)scintilla.GetCharAt(currentPos + 2); Process: switch (state) { case ParseState.None: if (ch == '\"') { // 文字列 scintilla.SetStyling(1, HspLexer.StyleStringLine); state = ParseState.StringLine; } else if (ch == '{' && chNext == '\"') { // 複数行文字列 scintilla.SetStyling(2, HspLexer.StyleString); state = ParseState.String; ++currentPos; } else if (ch == '\'') { // 文字 scintilla.SetStyling(1, HspLexer.StyleCharacter); state = ParseState.Character; } else if (ch == ';') { // 単一行コメント scintilla.SetStyling(1, HspLexer.StyleCommentLine); state = ParseState.CommentLine; } else if (ch == '/' && chNext == '/') { // 単一行コメント scintilla.SetStyling(2, HspLexer.StyleCommentLine); state = ParseState.CommentLine; ++currentPos; } else if (ch == '/' && chNext == '*') { // 複数行コメント scintilla.SetStyling(2, HspLexer.StyleComment); state = ParseState.Comment; ++currentPos; } else if (ch == '*' && (Char.IsLetter(chNext) || chNext == '_') && String.IsNullOrWhiteSpace(scintilla.GetTextRange( currentLineStartPos, currentPos - currentLineStartPos))) { // ラベル scintilla.SetStyling(2, HspLexer.StyleLabel); state = ParseState.Label; ++currentPos; } else if (ch == '#' && length == 0 && String.IsNullOrWhiteSpace(scintilla.GetTextRange( currentLineStartPos, currentPos - currentLineStartPos))) { // プリプロセッサ state = ParseState.Preprocessor; goto Process; } else if ((Char.IsLetter(ch) || ch == '_') && length == 0) { // 識別子 state = ParseState.Identifier; goto Process; } else if (ch == ':') { // 行区切り currentLineStartPos = currentPos + 1; scintilla.SetStyling(1, HspLexer.StyleDefault); } else if (ch == '\0') { // NULL文字の場合はすぐreturn return; } else { scintilla.SetStyling(1, HspLexer.StyleDefault); } break; case ParseState.StringLine: if (ch == '\\' && chNext == '\\') { // エスケープシーケンス '\\' scintilla.SetStyling(2, HspLexer.StyleStringLine); ++currentPos; } else if (ch == '\\' && chNext == '\"') { // エスケープシーケンス '\"' scintilla.SetStyling(2, HspLexer.StyleStringLine); ++currentPos; } else if (ch == '\"') { scintilla.SetStyling(1, HspLexer.StyleStringLine); state = ParseState.None; } else { scintilla.SetStyling(1, HspLexer.StyleStringLine); } break; case ParseState.String: if (ch == '\\' && chNext == '\\') { // エスケープシーケンス '\\' scintilla.SetStyling(2, HspLexer.StyleString); ++currentPos; } else if (ch == '\\' && chNext == '\"') { // エスケープシーケンス '\"' scintilla.SetStyling(2, HspLexer.StyleString); ++currentPos; } else if (ch == '\"' && chNext == '}') { scintilla.SetStyling(2, HspLexer.StyleString); state = ParseState.None; ++currentPos; } else { scintilla.SetStyling(1, HspLexer.StyleString); } break; case ParseState.Character: if (ch == '\'') { scintilla.SetStyling(1, HspLexer.StyleCharacter); state = ParseState.None; } else { scintilla.SetStyling(1, HspLexer.StyleCharacter); } break; case ParseState.CommentLine: if (ch == '\n') { scintilla.SetStyling(1, HspLexer.StyleCommentLine); state = ParseState.None; } else { scintilla.SetStyling(1, HspLexer.StyleCommentLine); } break; case ParseState.Comment: if (ch == '*' && chNext == '/') { scintilla.SetStyling(2, HspLexer.StyleComment); state = ParseState.None; ++currentPos; } else { scintilla.SetStyling(1, HspLexer.StyleComment); } break; case ParseState.Label: if (Char.IsLetterOrDigit(ch) || ch == '_') { scintilla.SetStyling(1, HspLexer.StyleLabel); } else { state = ParseState.None; goto Process; } break; case ParseState.Preprocessor: if (ch == '#' && length == 0 && String.IsNullOrWhiteSpace(scintilla.GetTextRange( currentLineStartPos, currentPos - currentLineStartPos))) { ++length; } else if ((ch == '\t' || ch == '\u0020' || ch == '\u3000') && length == 1) { // '#' の後のタブ文字, 半角スペース, 全角スペースの場合 state = ParseState.SpaceInPreprocessor; goto Process; } else if ((Char.IsLetter(ch) || ch == '_') && length == 1) { ++length; } else if ((Char.IsLetterOrDigit(ch) || ch == '_') && length > 1) { ++length; } else { int style = HspLexer.StyleDefault; string identifier = scintilla.GetTextRange(currentPos - length, length); char[] removeChars = { '\t', '\u0020', '\u3000' }; identifier = removeChars.Aggregate(identifier, (s, c) => s.Replace(c.ToString(), String.Empty)); identifier = identifier.ToLower(); if (this.mKeywords.ContainsKey(identifier)) { switch (this.mKeywords[identifier].mType) { case KeywordType.Preprocessor: style = HspLexer.StylePreprocessor; break; } } scintilla.SetStyling(length, style); length = 0; switch (style) { case HspLexer.StyleDefault: state = ParseState.None; break; case HspLexer.StylePreprocessor: state = ParseState.AfterPreprocessor; break; } goto Process; } break; case ParseState.SpaceInPreprocessor: if ((ch == '\t' || ch == '\u0020' || ch == '\u3000')) { ++length; } else if ((Char.IsLetter(ch) || ch == '_')) { state = ParseState.Preprocessor; goto Process; } else { scintilla.SetStyling(length, HspLexer.StyleDefault); length = 0; state = ParseState.None; goto Process; } break; case ParseState.AfterPreprocessor: if (ch == '\\' && chNext == '\r' && chAfterNext == '\n') { scintilla.SetStyling(3, HspLexer.StylePreprocessor); currentPos += 2; } else if (ch == '\\' && chNext == '\n') { scintilla.SetStyling(2, HspLexer.StylePreprocessor); ++currentPos; } else if (ch == '\r' && chNext == '\n') { scintilla.SetStyling(2, HspLexer.StyleDefault); state = ParseState.None; ++currentPos; } else if (ch == '\n') { scintilla.SetStyling(1, HspLexer.StyleDefault); state = ParseState.None; } else { scintilla.SetStyling(1, HspLexer.StylePreprocessor); } break; case ParseState.Identifier: if (Char.IsLetterOrDigit(ch) || ch == '_') { ++length; } else { int style = HspLexer.StyleDefault; string identifier = scintilla.GetTextRange(currentPos - length, length); identifier = identifier.ToLower(); if (this.mKeywords.ContainsKey(identifier)) { switch (this.mKeywords[identifier].mType) { case KeywordType.Macro: style = HspLexer.StyleMacro; break; case KeywordType.Function: style = HspLexer.StyleFunction; break; case KeywordType.Type: style = HspLexer.StyleType; break; } } scintilla.SetStyling(length, style); length = 0; state = ParseState.None; goto Process; } break; } ++currentPos; currentLine = scintilla.LineFromPosition(currentPos); if (currentLineStartPos < scintilla.Lines[currentLine].Position) { currentLineStartPos = scintilla.Lines[currentLine].Position; } currentLineEndPos = scintilla.Lines[currentLine].EndPosition; } }