OSDN Git Service

crystaledit: Make almost the same code into a common function
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / pascal.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:    pascal.cpp
3 //  Version: 1.1.0.4
4 //  Updated: 19-Jul-1998
5 //
6 //  Copyright:  Ferdinand Prantl, portions by Stcherbatchenko Andrei
7 //  E-mail:     prantl@ff.cuni.cz
8 //
9 //  Pascal syntax highlighing definition
10 //
11 //  You are free to use or modify this code to the following restrictions:
12 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
13 //  will be enough. If you can't (or don't want to), contact me personally.
14 //  - LEAVE THIS HEADER INTACT
15 ////////////////////////////////////////////////////////////////////////////
16
17 #include "StdAfx.h"
18 #include "crystallineparser.h"
19 #include "SyntaxColors.h"
20 #include "string_util.h"
21
22 #ifdef _DEBUG
23 #define new DEBUG_NEW
24 #endif
25
26 //  Pascal keywords
27 static LPCTSTR s_apszPascalKeywordList[] =
28   {
29     _T ("Abstract"),
30     _T ("and"),
31     _T ("array"),
32     _T ("As"),
33     _T ("asm"),
34     _T ("assembler"),
35     _T ("begin"),
36     _T ("case"),
37     _T ("Class"),
38     _T ("const"),
39     _T ("constructor"),
40     _T ("Default"),
41     _T ("destructor"),
42     _T ("div"),
43     _T ("do"),
44     _T ("downto"),
45     _T ("Dynamic"),
46     _T ("else"),
47     _T ("end"),
48     _T ("Except"),
49     _T ("exit"),
50     _T ("Export"),
51     _T ("external"),
52     _T ("far"),
53     _T ("file"),
54     _T ("Finally"),
55     _T ("for"),
56     _T ("function"),
57     _T ("goto"),
58     _T ("if"),
59     _T ("implementation"),
60     _T ("In"),
61     _T ("Index"),
62     _T ("inherited"),
63     _T ("inline"),
64     _T ("interface"),
65     _T ("Is"),
66     _T ("label"),
67     _T ("mod"),
68     _T ("near"),
69     _T ("nil"),
70     _T ("not"),
71     _T ("object"),
72     _T ("of"),
73     _T ("On"),
74     _T ("or"),
75     _T ("Out"),
76     _T ("Overload"),
77     _T ("Override"),
78     _T ("Packed"),
79     _T ("Private"),
80     _T ("procedure"),
81     _T ("program"),
82     _T ("Property"),
83     _T ("Protected"),
84     _T ("Public"),
85     _T ("Published"),
86     _T ("Raise"),
87     _T ("record"),
88     _T ("repeat"),
89     _T ("set"),
90     _T ("Shl"),
91     _T ("Shr"),
92     _T ("string"),
93     _T ("then"),
94     _T ("ThreadVar"),
95     _T ("to"),
96     _T ("Try"),
97     _T ("type"),
98     _T ("unit"),
99     _T ("until"),
100     _T ("uses"),
101     _T ("var"),
102     _T ("virtual"),
103     _T ("Virtual"),
104     _T ("while"),
105     _T ("with"),
106     _T ("xor"),
107   };
108
109 static bool
110 IsPascalKeyword (LPCTSTR pszChars, int nLength)
111 {
112   return ISXKEYWORDI (s_apszPascalKeywordList, pszChars, nLength);
113 }
114
115 DWORD
116 CrystalLineParser::ParseLinePascal (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
117 {
118   if (nLength == 0)
119     return dwCookie & (COOKIE_EXT_COMMENT | COOKIE_EXT_COMMENT2);
120
121   bool bFirstChar = (dwCookie & ~COOKIE_EXT_COMMENT) == 0;
122   bool bRedefineBlock = true;
123   bool bDecIndex = false;
124   int nIdentBegin = -1;
125   int nPrevI = -1;
126   int I=0;
127   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
128     {
129       if (I == nPrevI)
130         {
131           // CharNext did not advance, so we're at the end of the string
132           // and we already handled this character, so stop
133           break;
134         }
135
136       if (bRedefineBlock)
137         {
138           int nPos = I;
139           if (bDecIndex)
140             nPos = nPrevI;
141           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT | COOKIE_EXT_COMMENT2))
142             {
143               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
144             }
145           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
146             {
147               DEFINE_BLOCK (nPos, COLORINDEX_STRING);
148             }
149           else
150             {
151               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))
152                 {
153                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
154                 }
155               else
156                 {
157                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
158                   bRedefineBlock = true;
159                   bDecIndex = true;
160                   goto out;
161                 }
162             }
163           bRedefineBlock = false;
164           bDecIndex = false;
165         }
166 out:
167
168       // Can be bigger than length if there is binary data
169       // See bug #1474782 Crash when comparing SQL with with binary data
170       if (I >= nLength || pszChars[I] == 0)
171         break;
172
173       if (dwCookie & COOKIE_COMMENT)
174         {
175           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
176           dwCookie |= COOKIE_COMMENT;
177           break;
178         }
179
180       //  String constant "...."
181       if (dwCookie & COOKIE_STRING)
182         {
183           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
184             {
185               dwCookie &= ~COOKIE_STRING;
186               bRedefineBlock = true;
187             }
188           continue;
189         }
190
191       //  Char constant '..'
192       if (dwCookie & COOKIE_CHAR)
193         {
194           if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
195             {
196               dwCookie &= ~COOKIE_CHAR;
197               bRedefineBlock = true;
198             }
199           continue;
200         }
201
202       //  Extended comment /*....*/
203       if (dwCookie & COOKIE_EXT_COMMENT)
204         {
205           // if (I > 0 && pszChars[I] == ')' && pszChars[nPrevI] == '*')
206           if ((I > 1 && pszChars[I] == ')' && pszChars[nPrevI] == '*' && *::CharPrev(pszChars, pszChars + nPrevI) != '(') || (I == 1 && pszChars[I] == ')' && pszChars[nPrevI] == '*'))
207             {
208               dwCookie &= ~COOKIE_EXT_COMMENT;
209               bRedefineBlock = true;
210             }
211           continue;
212         }
213
214       //  Extended comment {....}
215       if (dwCookie & COOKIE_EXT_COMMENT2)
216         {
217           if (pszChars[I] == '}')
218             {
219               dwCookie &= ~COOKIE_EXT_COMMENT2;
220               bRedefineBlock = true;
221             }
222           continue;
223         }
224
225       if (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/')
226         {
227           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
228           dwCookie |= COOKIE_COMMENT;
229           break;
230         }
231
232       //  Normal text
233       if (pszChars[I] == '"')
234         {
235           DEFINE_BLOCK (I, COLORINDEX_STRING);
236           dwCookie |= COOKIE_STRING;
237           continue;
238         }
239       if (pszChars[I] == '\'')
240         {
241           // 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] == '\'')
242           if (!I || !xisalnum (pszChars[nPrevI]))
243             {
244               DEFINE_BLOCK (I, COLORINDEX_STRING);
245               dwCookie |= COOKIE_CHAR;
246               continue;
247             }
248         }
249       if (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '(')
250         {
251           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
252           dwCookie |= COOKIE_EXT_COMMENT;
253           continue;
254         }
255
256       if (pszChars[I] == '{')
257         {
258           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
259           dwCookie |= COOKIE_EXT_COMMENT2;
260           continue;
261         }
262
263       if (bFirstChar)
264         {
265           if (!xisspace (pszChars[I]))
266             bFirstChar = false;
267         }
268
269       if (pBuf == nullptr)
270         continue;               //  We don't need to extract keywords,
271       //  for faster parsing skip the rest of loop
272
273       if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))
274         {
275           if (nIdentBegin == -1)
276             nIdentBegin = I;
277         }
278       else
279         {
280           if (nIdentBegin >= 0)
281             {
282               if (IsPascalKeyword (pszChars + nIdentBegin, I - nIdentBegin))
283                 {
284                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
285                 }
286               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
287                 {
288                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
289                 }
290               else
291                 {
292                   bool bFunction = false;
293
294                   for (int j = I; j < nLength; j++)
295                     {
296                       if (!xisspace (pszChars[j]))
297                         {
298                           if (pszChars[j] == '(')
299                             {
300                               bFunction = true;
301                             }
302                           break;
303                         }
304                     }
305                   if (bFunction)
306                     {
307                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
308                     }
309                 }
310               bRedefineBlock = true;
311               bDecIndex = true;
312               nIdentBegin = -1;
313             }
314         }
315     }
316
317   if (nIdentBegin >= 0)
318     {
319       if (IsPascalKeyword (pszChars + nIdentBegin, I - nIdentBegin))
320         {
321           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
322         }
323       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
324         {
325           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
326         }
327       else
328         {
329           bool bFunction = false;
330
331           for (int j = I; j < nLength; j++)
332             {
333               if (!xisspace (pszChars[j]))
334                 {
335                   if (pszChars[j] == '(')
336                     {
337                       bFunction = true;
338                     }
339                   break;
340                 }
341             }
342           if (bFunction)
343             {
344               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
345             }
346         }
347     }
348
349   if (pszChars[nLength - 1] != '\\' || IsMBSTrail(pszChars, nLength - 1))
350     dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_EXT_COMMENT2);
351   return dwCookie;
352 }