1 ///////////////////////////////////////////////////////////////////////////
4 // Created: 29-Dec-1998
6 // Copyright: Stcherbatchenko Andrei
7 // E-mail: windfall@gmx.de
9 // Implementation of the CCrystalEditView class, a part of the Crystal Edit -
10 // syntax coloring text editor.
12 // You are free to use or modify this code to the following restrictions:
13 // - Acknowledge me somewhere in your about box, simple "Parts of code by.."
14 // will be enough. If you can't (or don't want to), contact me personally.
15 // - LEAVE THIS HEADER INTACT
16 ////////////////////////////////////////////////////////////////////////////
18 ////////////////////////////////////////////////////////////////////////////
21 // + FEATURE: corrected bug in syntax highlighting C comments
22 // + FEATURE: extended levels 1- 4 of keywords in some languages
24 // ... it's being edited very rapidly so sorry for non-commented
25 // and maybe "ugly" code ...
26 ////////////////////////////////////////////////////////////////////////////
29 #include "crystallineparser.h"
30 #include "../SyntaxColors.h"
31 #include "../utils/string_util.h"
37 // C++ keywords (MSVC5.0 + POET5.0)
38 static const TCHAR * s_apszCppKeywordList[] =
55 _T ("__multiple_inheritance"),
57 _T ("__single_inheritance"),
62 _T ("__virtual_inheritance"),
126 _T ("reinterpret_cast"),
132 _T ("static_assert"),
161 static const TCHAR * s_apszUser1KeywordList[] =
231 IsCppKeyword (const TCHAR *pszChars, int nLength)
233 return ISXKEYWORD (s_apszCppKeywordList, pszChars, nLength);
237 IsUser1Keyword (const TCHAR *pszChars, int nLength)
239 return ISXKEYWORD (s_apszUser1KeywordList, pszChars, nLength);
243 CrystalLineParser::ParseLineC (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
246 return dwCookie & COOKIE_EXT_COMMENT;
248 bool bFirstChar = (dwCookie & ~COOKIE_EXT_COMMENT) == 0;
249 const TCHAR *pszCommentBegin = nullptr;
250 const TCHAR *pszCommentEnd = nullptr;
251 bool bRedefineBlock = true;
252 bool bDecIndex = false;
253 int nIdentBegin = -1;
256 for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
260 // CharNext did not advance, so we're at the end of the string
261 // and we already handled this character, so stop
270 if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
272 DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
274 else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
276 DEFINE_BLOCK (nPos, COLORINDEX_STRING);
278 else if (dwCookie & COOKIE_PREPROCESSOR)
280 DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
284 if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))
286 DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
290 DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
291 bRedefineBlock = true;
296 bRedefineBlock = false;
301 // Can be bigger than length if there is binary data
302 // See bug #1474782 Crash when comparing SQL with with binary data
303 if (I >= nLength || pszChars[I] == 0)
306 if (dwCookie & COOKIE_COMMENT)
308 DEFINE_BLOCK (I, COLORINDEX_COMMENT);
309 dwCookie |= COOKIE_COMMENT;
313 // String constant "...."
314 if (dwCookie & COOKIE_STRING)
316 if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
318 dwCookie &= ~COOKIE_STRING;
319 bRedefineBlock = true;
324 // Char constant '..'
325 if (dwCookie & COOKIE_CHAR)
327 if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
329 dwCookie &= ~COOKIE_CHAR;
330 bRedefineBlock = true;
335 // Extended comment /*....*/
336 if (dwCookie & COOKIE_EXT_COMMENT)
338 if ((pszCommentBegin < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))
340 dwCookie &= ~COOKIE_EXT_COMMENT;
341 bRedefineBlock = true;
342 pszCommentEnd = pszChars + I + 1;
347 if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/'))
349 DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
350 dwCookie |= COOKIE_COMMENT;
354 // Preprocessor directive #....
355 if (dwCookie & COOKIE_PREPROCESSOR)
357 if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))
359 DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
360 dwCookie |= COOKIE_EXT_COMMENT;
366 if (pszChars[I] == '"')
368 DEFINE_BLOCK (I, COLORINDEX_STRING);
369 dwCookie |= COOKIE_STRING;
372 if (pszChars[I] == '\'')
374 // if (I + 1 < nLength && pszChars[I + 1] == '\'' || I + 2 < nLength && pszChars[I + 1] != '\\' && pszChars[I + 2] == '\'' || I + 3 < nLength && pszChars[I + 1] == '\\' && pszChars[I + 3] == '\'')
375 if (!I || !xisalnum (pszChars[nPrevI]))
377 DEFINE_BLOCK (I, COLORINDEX_STRING);
378 dwCookie |= COOKIE_CHAR;
382 if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))
384 DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
385 dwCookie |= COOKIE_EXT_COMMENT;
386 pszCommentBegin = pszChars + I + 1;
392 if (pszChars[I] == '#')
394 DEFINE_BLOCK (I, COLORINDEX_PREPROCESSOR);
395 dwCookie |= COOKIE_PREPROCESSOR;
398 if (!xisspace (pszChars[I]))
403 continue; // We don't need to extract keywords,
404 // for faster parsing skip the rest of loop
406 if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))
408 if (nIdentBegin == -1)
413 if (nIdentBegin >= 0)
415 if (IsCppKeyword (pszChars + nIdentBegin, I - nIdentBegin))
417 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
419 else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
421 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
423 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
425 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
429 bool bFunction = false;
431 for (int j = I; j < nLength; j++)
433 if (!xisspace (pszChars[j]))
435 if (pszChars[j] == '(')
444 DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
447 bRedefineBlock = true;
454 if (nIdentBegin >= 0)
456 if (IsCppKeyword (pszChars + nIdentBegin, I - nIdentBegin))
458 DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
460 else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
462 DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
464 else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
466 DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
470 bool bFunction = false;
472 for (int j = I; j < nLength; j++)
474 if (!xisspace (pszChars[j]))
476 if (pszChars[j] == '(')
485 DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
490 if (pszChars[nLength - 1] != '\\' || IsMBSTrail(pszChars, nLength - 1))
491 dwCookie &= COOKIE_EXT_COMMENT;