OSDN Git Service

f291f0c5b67e3289d199f95bc194e5ad5f686843
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / parsers / cplusplus.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:       cplusplus.cpp
3 //  Version:    1.2.0.5
4 //  Created:    29-Dec-1998
5 //
6 //  Copyright:  Stcherbatchenko Andrei
7 //  E-mail:     windfall@gmx.de
8 //
9 //  Implementation of the CCrystalEditView class, a part of the Crystal Edit -
10 //  syntax coloring text editor.
11 //
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 ////////////////////////////////////////////////////////////////////////////
17
18 ////////////////////////////////////////////////////////////////////////////
19 //  16-Aug-99
20 //      Ferdinand Prantl:
21 //  +   FEATURE: corrected bug in syntax highlighting C comments
22 //  +   FEATURE: extended levels 1- 4 of keywords in some languages
23 //
24 //  ... it's being edited very rapidly so sorry for non-commented
25 //        and maybe "ugly" code ...
26 ////////////////////////////////////////////////////////////////////////////
27
28 #include "StdAfx.h"
29 #include "crystallineparser.h"
30 #include "../SyntaxColors.h"
31 #include "../utils/string_util.h"
32
33 #ifdef _DEBUG
34 #define new DEBUG_NEW
35 #endif
36
37 //  C++ keywords (MSVC5.0 + POET5.0)
38 static const TCHAR * s_apszCppKeywordList[] =
39   {
40     _T ("__asm"),
41     _T ("__based"),
42     _T ("__cdecl"),
43     _T ("__declspec"),
44     _T ("__except"),
45     _T ("__export"),
46     _T ("__far16"),
47     _T ("__fastcall"),
48     _T ("__finally"),
49     _T ("__inline"),
50     _T ("__int16"),
51     _T ("__int32"),
52     _T ("__int64"),
53     _T ("__int8"),
54     _T ("__leave"),
55     _T ("__multiple_inheritance"),
56     _T ("__pascal"),
57     _T ("__single_inheritance"),
58     _T ("__stdcall"),
59     _T ("__syscall"),
60     _T ("__try"),
61     _T ("__uuidof"),
62     _T ("__virtual_inheritance"),
63     _T ("_asm"),
64     _T ("_cdecl"),
65     _T ("_export"),
66     _T ("_far16"),
67     _T ("_fastcall"),
68     _T ("_pascal"),
69     _T ("_persistent"),
70     _T ("_stdcall"),
71     _T ("_syscall"),
72     _T ("alignas"),
73     _T ("alignof"),
74     _T ("auto"),
75     _T ("bool"),
76     _T ("break"),
77     _T ("case"),
78     _T ("catch"),
79     _T ("char16_t"),
80     _T ("char32_t"),
81     _T ("char"),
82     _T ("class"),
83     _T ("const"),
84     _T ("const_cast"),
85     _T ("constexpr"),
86     _T ("continue"),
87     _T ("decltype"),
88     _T ("cset"),
89     _T ("default"),
90     _T ("delete"),
91     _T ("depend"),
92     _T ("dllexport"),
93     _T ("dllimport"),
94     _T ("do"),
95     _T ("double"),
96     _T ("dynamic_cast"),
97     _T ("else"),
98     _T ("enum"),
99     _T ("explicit"),
100     _T ("extern"),
101     _T ("false"),
102     _T ("float"),
103     _T ("for"),
104     _T ("friend"),
105     _T ("goto"),
106     _T ("if"),
107     _T ("indexdef"),
108     _T ("inline"),
109     _T ("int"),
110     _T ("interface"),
111     _T ("long"),
112     _T ("main"),
113     _T ("mutable"),
114     _T ("naked"),
115     _T ("namespace"),
116     _T ("new"),
117     _T ("noexcept"),
118     _T ("nullptr"),
119     _T ("ondemand"),
120     _T ("operator"),
121     _T ("persistent"),
122     _T ("private"),
123     _T ("protected"),
124     _T ("public"),
125     _T ("register"),
126     _T ("reinterpret_cast"),
127     _T ("return"),
128     _T ("short"),
129     _T ("signed"),
130     _T ("sizeof"),
131     _T ("static"),
132     _T ("static_assert"),
133     _T ("static_cast"),
134     _T ("struct"),
135     _T ("switch"),
136     _T ("template"),
137     _T ("this"),
138     _T ("thread"),
139     _T ("thread_local"),
140     _T ("throw"),
141     _T ("transient"),
142     _T ("transient"),
143     _T ("true"),
144     _T ("try"),
145     _T ("typedef"),
146     _T ("typeid"),
147     _T ("typename"),
148     _T ("union"),
149     _T ("unsigned"),
150     _T ("useindex"),
151     _T ("using"),
152     _T ("uuid"),
153     _T ("virtual"),
154     _T ("void"),
155     _T ("volatile"),
156     _T ("while"),
157     _T ("wmain"),
158     _T ("xalloc"),
159   };
160
161 static const TCHAR * s_apszUser1KeywordList[] =
162   {
163     _T ("BOOL"),
164     _T ("BSTR"),
165     _T ("BYTE"),
166     _T ("CHAR"),
167     _T ("COLORREF"),
168     _T ("DWORD"),
169     _T ("DWORD32"),
170     _T ("FALSE"),
171     _T ("HANDLE"),
172     _T ("INT"),
173     _T ("INT16"),
174     _T ("INT32"),
175     _T ("INT64"),
176     _T ("INT8"),
177     _T ("LONG"),
178     _T ("LPARAM"),
179     _T ("LPBOOL"),
180     _T ("LPBYTE"),
181     _T ("LPCSTR"),
182     _T ("LPCTSTR"),
183     _T ("LPCTSTR"),
184     _T ("LPCWSTR"),
185     _T ("LPDWORD"),
186     _T ("LPINT"),
187     _T ("LPLONG"),
188     _T ("LPRECT"),
189     _T ("LPSTR"),
190     _T ("LPTSTR"),
191     _T ("LPTSTR"),
192     _T ("LPVOID"),
193     _T ("LPVOID"),
194     _T ("LPWORD"),
195     _T ("LPWSTR"),
196     _T ("LRESULT"),
197     _T ("LRESULT"),
198     _T ("PBOOL"),
199     _T ("PBYTE"),
200     _T ("PDWORD"),
201     _T ("PDWORD32"),
202     _T ("PINT"),
203     _T ("PINT16"),
204     _T ("PINT32"),
205     _T ("PINT64"),
206     _T ("PINT8"),
207     _T ("POSITION"),
208     _T ("PUINT"),
209     _T ("PUINT16"),
210     _T ("PUINT32"),
211     _T ("PUINT64"),
212     _T ("PUINT8"),
213     _T ("PULONG32"),
214     _T ("PWORD"),
215     _T ("TCHAR"),
216     _T ("TRUE"),
217     _T ("UINT"),
218     _T ("UINT16"),
219     _T ("UINT32"),
220     _T ("UINT64"),
221     _T ("UINT8"),
222     _T ("ULONG32"),
223     _T ("VOID"),
224     _T ("WCHAR"),
225     _T ("WNDPROC"),
226     _T ("WORD"),
227     _T ("WPARAM"),
228   };
229
230 static bool
231 IsCppKeyword (const TCHAR *pszChars, int nLength)
232 {
233   return ISXKEYWORD (s_apszCppKeywordList, pszChars, nLength);
234 }
235
236 static bool
237 IsUser1Keyword (const TCHAR *pszChars, int nLength)
238 {
239   return ISXKEYWORD (s_apszUser1KeywordList, pszChars, nLength);
240 }
241
242 unsigned
243 CrystalLineParser::ParseLineC (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
244 {
245   if (nLength == 0)
246     return dwCookie & COOKIE_EXT_COMMENT;
247
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;
254   int nPrevI = -1;
255   int I=0;
256   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
257     {
258       if (I == nPrevI)
259         {
260           // CharNext did not advance, so we're at the end of the string
261           // and we already handled this character, so stop
262           break;
263         }
264
265       if (bRedefineBlock)
266         {
267           int nPos = I;
268           if (bDecIndex)
269             nPos = nPrevI;
270           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
271             {
272               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
273             }
274           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
275             {
276               DEFINE_BLOCK (nPos, COLORINDEX_STRING);
277             }
278           else if (dwCookie & COOKIE_PREPROCESSOR)
279             {
280               DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
281             }
282           else
283             {
284               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))
285                 {
286                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
287                 }
288               else
289                 {
290                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
291                   bRedefineBlock = true;
292                   bDecIndex = true;
293                   goto out;
294                 }
295             }
296           bRedefineBlock = false;
297           bDecIndex = false;
298         }
299 out:
300
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)
304         break;
305
306       if (dwCookie & COOKIE_COMMENT)
307         {
308           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
309           dwCookie |= COOKIE_COMMENT;
310           break;
311         }
312
313       //  String constant "...."
314       if (dwCookie & COOKIE_STRING)
315         {
316           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
317             {
318               dwCookie &= ~COOKIE_STRING;
319               bRedefineBlock = true;
320             }
321           continue;
322         }
323
324       //  Char constant '..'
325       if (dwCookie & COOKIE_CHAR)
326         {
327           if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
328             {
329               dwCookie &= ~COOKIE_CHAR;
330               bRedefineBlock = true;
331             }
332           continue;
333         }
334
335       //  Extended comment /*....*/
336       if (dwCookie & COOKIE_EXT_COMMENT)
337         {
338           if ((pszCommentBegin < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))
339             {
340               dwCookie &= ~COOKIE_EXT_COMMENT;
341               bRedefineBlock = true;
342               pszCommentEnd = pszChars + I + 1;
343             }
344           continue;
345         }
346
347       if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/'))
348         {
349           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
350           dwCookie |= COOKIE_COMMENT;
351           break;
352         }
353
354       //  Preprocessor directive #....
355       if (dwCookie & COOKIE_PREPROCESSOR)
356         {
357           if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))
358             {
359               DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
360               dwCookie |= COOKIE_EXT_COMMENT;
361             }
362           continue;
363         }
364
365       //  Normal text
366       if (pszChars[I] == '"')
367         {
368           DEFINE_BLOCK (I, COLORINDEX_STRING);
369           dwCookie |= COOKIE_STRING;
370           continue;
371         }
372       if (pszChars[I] == '\'')
373         {
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]))
376             {
377               DEFINE_BLOCK (I, COLORINDEX_STRING);
378               dwCookie |= COOKIE_CHAR;
379               continue;
380             }
381         }
382       if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))
383         {
384           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
385           dwCookie |= COOKIE_EXT_COMMENT;
386           pszCommentBegin = pszChars + I + 1;
387           continue;
388         }
389
390       if (bFirstChar)
391         {
392           if (pszChars[I] == '#')
393             {
394               DEFINE_BLOCK (I, COLORINDEX_PREPROCESSOR);
395               dwCookie |= COOKIE_PREPROCESSOR;
396               continue;
397             }
398           if (!xisspace (pszChars[I]))
399             bFirstChar = false;
400         }
401
402       if (pBuf == nullptr)
403         continue;               //  We don't need to extract keywords,
404       //  for faster parsing skip the rest of loop
405
406       if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))
407         {
408           if (nIdentBegin == -1)
409             nIdentBegin = I;
410         }
411       else
412         {
413           if (nIdentBegin >= 0)
414             {
415               if (IsCppKeyword (pszChars + nIdentBegin, I - nIdentBegin))
416                 {
417                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
418                 }
419               else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
420                 {
421                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
422                 }
423               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
424                 {
425                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
426                 }
427               else
428                 {
429                   bool bFunction = false;
430
431                   for (int j = I; j < nLength; j++)
432                     {
433                       if (!xisspace (pszChars[j]))
434                         {
435                           if (pszChars[j] == '(')
436                             {
437                               bFunction = true;
438                             }
439                           break;
440                         }
441                     }
442                   if (bFunction)
443                     {
444                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
445                     }
446                 }
447               bRedefineBlock = true;
448               bDecIndex = true;
449               nIdentBegin = -1;
450             }
451         }
452     }
453
454   if (nIdentBegin >= 0)
455     {
456       if (IsCppKeyword (pszChars + nIdentBegin, I - nIdentBegin))
457         {
458           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
459         }
460       else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
461         {
462           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
463         }
464       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
465         {
466           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
467         }
468       else
469         {
470           bool bFunction = false;
471
472           for (int j = I; j < nLength; j++)
473             {
474               if (!xisspace (pszChars[j]))
475                 {
476                   if (pszChars[j] == '(')
477                     {
478                       bFunction = true;
479                     }
480                   break;
481                 }
482             }
483           if (bFunction)
484             {
485               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
486             }
487         }
488     }
489
490   if (pszChars[nLength - 1] != '\\' || IsMBSTrail(pszChars, nLength - 1))
491     dwCookie &= COOKIE_EXT_COMMENT;
492   return dwCookie;
493 }