1 // Scintilla source code edit control
2 /** @file LexFortran.cxx
3  ** Lexer for Fortran.
4  ** Written by Chuan-jian Shen, Last changed Sep. 2003
5  **/
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8 /***************************************/
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15 /***************************************/
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19 
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26 /***************************************/
27 
28 using namespace Scintilla;
29 
30 /***********************************************/
IsAWordChar(const int ch)31 static inline bool IsAWordChar(const int ch) {
32 	return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
33 }
34 /**********************************************/
IsAWordStart(const int ch)35 static inline bool IsAWordStart(const int ch) {
36 	return (ch < 0x80) && (isalnum(ch));
37 }
38 /***************************************/
IsABlank(unsigned int ch)39 static inline bool IsABlank(unsigned int ch) {
40 	return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
41 }
42 /***************************************/
IsALineEnd(char ch)43 static inline bool IsALineEnd(char ch) {
44 	return ((ch == '\n') || (ch == '\r')) ;
45 }
46 /***************************************/
GetContinuedPos(Sci_PositionU pos,Accessor & styler)47 static Sci_PositionU GetContinuedPos(Sci_PositionU pos, Accessor &styler) {
48 	while (!IsALineEnd(styler.SafeGetCharAt(pos++))) continue;
49 	if (styler.SafeGetCharAt(pos) == '\n') pos++;
50 	while (IsABlank(styler.SafeGetCharAt(pos++))) continue;
51 	char chCur = styler.SafeGetCharAt(pos);
52 	if (chCur == '&') {
53 		while (IsABlank(styler.SafeGetCharAt(++pos))) continue;
54 		return pos;
55 	} else {
56 		return pos;
57 	}
58 }
59 /***************************************/
ColouriseFortranDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler,bool isFixFormat)60 static void ColouriseFortranDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
61         WordList *keywordlists[], Accessor &styler, bool isFixFormat) {
62 	WordList &keywords = *keywordlists[0];
63 	WordList &keywords2 = *keywordlists[1];
64 	WordList &keywords3 = *keywordlists[2];
65 	/***************************************/
66 	Sci_Position posLineStart = 0;
67 	int numNonBlank = 0, prevState = 0;
68 	Sci_Position endPos = startPos + length;
69 	/***************************************/
70 	// backtrack to the nearest keyword
71 	while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_F_WORD)) {
72 		startPos--;
73 	}
74 	startPos = styler.LineStart(styler.GetLine(startPos));
75 	initStyle = styler.StyleAt(startPos - 1);
76 	StyleContext sc(startPos, endPos-startPos, initStyle, styler);
77 	/***************************************/
78 	for (; sc.More(); sc.Forward()) {
79 		// remember the start position of the line
80 		if (sc.atLineStart) {
81 			posLineStart = sc.currentPos;
82 			numNonBlank = 0;
83 			sc.SetState(SCE_F_DEFAULT);
84 		}
85 		if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
86 		/***********************************************/
87 		// Handle the fix format generically
88 		Sci_Position toLineStart = sc.currentPos - posLineStart;
89 		if (isFixFormat && (toLineStart < 6 || toLineStart >= 72)) {
90 			if ((toLineStart == 0 && (tolower(sc.ch) == 'c' || sc.ch == '*')) || sc.ch == '!') {
91 				if (sc.MatchIgnoreCase("cdec$") || sc.MatchIgnoreCase("*dec$") || sc.MatchIgnoreCase("!dec$") ||
92 				        sc.MatchIgnoreCase("cdir$") || sc.MatchIgnoreCase("*dir$") || sc.MatchIgnoreCase("!dir$") ||
93 				        sc.MatchIgnoreCase("cms$")  || sc.MatchIgnoreCase("*ms$")  || sc.MatchIgnoreCase("!ms$")  ||
94 				        sc.chNext == '$') {
95 					sc.SetState(SCE_F_PREPROCESSOR);
96 				} else {
97 					sc.SetState(SCE_F_COMMENT);
98 				}
99 
100 				while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
101 			} else if (toLineStart >= 72) {
102 				sc.SetState(SCE_F_COMMENT);
103 				while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
104 			} else if (toLineStart < 5) {
105 				if (IsADigit(sc.ch))
106 					sc.SetState(SCE_F_LABEL);
107 				else
108 					sc.SetState(SCE_F_DEFAULT);
109 			} else if (toLineStart == 5) {
110 				//if (!IsASpace(sc.ch) && sc.ch != '0') {
111 				if (sc.ch != '\r' && sc.ch != '\n') {
112 					sc.SetState(SCE_F_CONTINUATION);
113 					if (!IsASpace(sc.ch) && sc.ch != '0')
114 						sc.ForwardSetState(prevState);
115 				} else
116 					sc.SetState(SCE_F_DEFAULT);
117 			}
118 			continue;
119 		}
120 		/***************************************/
121 		// Handle line continuation generically.
122 		if (!isFixFormat && sc.ch == '&' && sc.state != SCE_F_COMMENT) {
123 			char chTemp = ' ';
124 			Sci_Position j = 1;
125 			while (IsABlank(chTemp) && j<132) {
126 				chTemp = static_cast<char>(sc.GetRelative(j));
127 				j++;
128 			}
129 			if (chTemp == '!') {
130 				sc.SetState(SCE_F_CONTINUATION);
131 				if (sc.chNext == '!') sc.ForwardSetState(SCE_F_COMMENT);
132 			} else if (chTemp == '\r' || chTemp == '\n') {
133 				int currentState = sc.state;
134 				sc.SetState(SCE_F_CONTINUATION);
135 				sc.ForwardSetState(SCE_F_DEFAULT);
136 				while (IsASpace(sc.ch) && sc.More()) {
137 					sc.Forward();
138 					if (sc.atLineStart) numNonBlank = 0;
139 					if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
140 				}
141 				if (sc.ch == '&') {
142 					sc.SetState(SCE_F_CONTINUATION);
143 					sc.Forward();
144 				}
145 				sc.SetState(currentState);
146 			}
147 		}
148 		/***************************************/
149 		// Hanndle preprocessor directives
150 		if (sc.ch == '#' && numNonBlank == 1)
151 		{
152 			sc.SetState(SCE_F_PREPROCESSOR);
153 			while (!sc.atLineEnd && sc.More())
154 				sc.Forward(); // Until line end
155 		}
156 		/***************************************/
157 		// Determine if the current state should terminate.
158 		if (sc.state == SCE_F_OPERATOR) {
159 			sc.SetState(SCE_F_DEFAULT);
160 		} else if (sc.state == SCE_F_NUMBER) {
161 			if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) {
162 				sc.SetState(SCE_F_DEFAULT);
163 			}
164 		} else if (sc.state == SCE_F_IDENTIFIER) {
165 			if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
166 				char s[100];
167 				sc.GetCurrentLowered(s, sizeof(s));
168 				if (keywords.InList(s)) {
169 					sc.ChangeState(SCE_F_WORD);
170 				} else if (keywords2.InList(s)) {
171 					sc.ChangeState(SCE_F_WORD2);
172 				} else if (keywords3.InList(s)) {
173 					sc.ChangeState(SCE_F_WORD3);
174 				}
175 				sc.SetState(SCE_F_DEFAULT);
176 			}
177 		} else if (sc.state == SCE_F_COMMENT || sc.state == SCE_F_PREPROCESSOR) {
178 			if (sc.ch == '\r' || sc.ch == '\n') {
179 				sc.SetState(SCE_F_DEFAULT);
180 			}
181 		} else if (sc.state == SCE_F_STRING1) {
182 			prevState = sc.state;
183 			if (sc.ch == '\'') {
184 				if (sc.chNext == '\'') {
185 					sc.Forward();
186 				} else {
187 					sc.ForwardSetState(SCE_F_DEFAULT);
188 					prevState = SCE_F_DEFAULT;
189 				}
190 			} else if (sc.atLineEnd) {
191 				sc.ChangeState(SCE_F_STRINGEOL);
192 				sc.ForwardSetState(SCE_F_DEFAULT);
193 			}
194 		} else if (sc.state == SCE_F_STRING2) {
195 			prevState = sc.state;
196 			if (sc.atLineEnd) {
197 				sc.ChangeState(SCE_F_STRINGEOL);
198 				sc.ForwardSetState(SCE_F_DEFAULT);
199 			} else if (sc.ch == '\"') {
200 				if (sc.chNext == '\"') {
201 					sc.Forward();
202 				} else {
203 					sc.ForwardSetState(SCE_F_DEFAULT);
204 					prevState = SCE_F_DEFAULT;
205 				}
206 			}
207 		} else if (sc.state == SCE_F_OPERATOR2) {
208 			if (sc.ch == '.') {
209 				sc.ForwardSetState(SCE_F_DEFAULT);
210 			}
211 		} else if (sc.state == SCE_F_CONTINUATION) {
212 			sc.SetState(SCE_F_DEFAULT);
213 		} else if (sc.state == SCE_F_LABEL) {
214 			if (!IsADigit(sc.ch)) {
215 				sc.SetState(SCE_F_DEFAULT);
216 			} else {
217 				if (isFixFormat && sc.currentPos-posLineStart > 4)
218 					sc.SetState(SCE_F_DEFAULT);
219 				else if (numNonBlank > 5)
220 					sc.SetState(SCE_F_DEFAULT);
221 			}
222 		}
223 		/***************************************/
224 		// Determine if a new state should be entered.
225 		if (sc.state == SCE_F_DEFAULT) {
226 			if (sc.ch == '!') {
227 				if (sc.MatchIgnoreCase("!dec$") || sc.MatchIgnoreCase("!dir$") ||
228 					sc.MatchIgnoreCase("!ms$") || sc.chNext == '$') {
229 					sc.SetState(SCE_F_PREPROCESSOR);
230 				} else {
231 					sc.SetState(SCE_F_COMMENT);
232 				}
233 			} else if ((!isFixFormat) && IsADigit(sc.ch) && numNonBlank == 1) {
234 				sc.SetState(SCE_F_LABEL);
235 			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
236 				sc.SetState(SCE_F_NUMBER);
237 			} else if ((tolower(sc.ch) == 'b' || tolower(sc.ch) == 'o' ||
238 				tolower(sc.ch) == 'z') && (sc.chNext == '\"' || sc.chNext == '\'')) {
239 				sc.SetState(SCE_F_NUMBER);
240 				sc.Forward();
241 			} else if (sc.ch == '.' && isalpha(sc.chNext)) {
242 				sc.SetState(SCE_F_OPERATOR2);
243 			} else if (IsAWordStart(sc.ch)) {
244 				sc.SetState(SCE_F_IDENTIFIER);
245 			} else if (sc.ch == '\"') {
246 				sc.SetState(SCE_F_STRING2);
247 			} else if (sc.ch == '\'') {
248 				sc.SetState(SCE_F_STRING1);
249 			} else if (isoperator(static_cast<char>(sc.ch))) {
250 				sc.SetState(SCE_F_OPERATOR);
251 			}
252 		}
253 	}
254 	sc.Complete();
255 }
256 /***************************************/
CheckLevelCommentLine(const unsigned int nComL,Sci_Position nComColB[],Sci_Position nComColF[],Sci_Position & nComCur,bool comLineB[],bool comLineF[],bool & comLineCur,int & levelDeltaNext)257 static void CheckLevelCommentLine(const unsigned int nComL,
258 				  Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position &nComCur,
259 				  bool comLineB[], bool comLineF[], bool &comLineCur,
260 				  int &levelDeltaNext) {
261 	levelDeltaNext = 0;
262 	if (!comLineCur) {
263 		return;
264 	}
265 
266 	if (!comLineF[0] || nComColF[0] != nComCur) {
267 		unsigned int i=0;
268 		for (; i<nComL; i++) {
269 			if (!comLineB[i] || nComColB[i] != nComCur) {
270 				break;
271 			}
272 		}
273 		if (i == nComL) {
274 			levelDeltaNext = -1;
275 		}
276 	}
277 	else if (!comLineB[0] || nComColB[0] != nComCur) {
278 		unsigned int i=0;
279 		for (; i<nComL; i++) {
280 			if (!comLineF[i] || nComColF[i] != nComCur) {
281 				break;
282 			}
283 		}
284 		if (i == nComL) {
285 			levelDeltaNext = 1;
286 		}
287 	}
288 }
289 /***************************************/
GetIfLineComment(Accessor & styler,bool isFixFormat,const Sci_Position line,bool & isComLine,Sci_Position & comCol)290 static void GetIfLineComment(Accessor &styler, bool isFixFormat, const Sci_Position line, bool &isComLine, Sci_Position &comCol) {
291 	Sci_Position col = 0;
292 	isComLine = false;
293 	Sci_Position pos = styler.LineStart(line);
294 	Sci_Position len = styler.Length();
295 	while(pos<len) {
296 		char ch = styler.SafeGetCharAt(pos);
297 		if (ch == '!' || (isFixFormat && col == 0 && (tolower(ch) == 'c' || ch == '*'))) {
298 			isComLine = true;
299 			comCol = col;
300 			break;
301 		}
302 		else if (!IsABlank(ch) || IsALineEnd(ch)) {
303 			break;
304 		}
305 		pos++;
306 		col++;
307 	}
308 }
309 /***************************************/
StepCommentLine(Accessor & styler,bool isFixFormat,Sci_Position lineCurrent,const unsigned int nComL,Sci_Position nComColB[],Sci_Position nComColF[],Sci_Position & nComCur,bool comLineB[],bool comLineF[],bool & comLineCur)310 static void StepCommentLine(Accessor &styler, bool isFixFormat, Sci_Position lineCurrent, const unsigned int nComL,
311 				  Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position &nComCur,
312 				  bool comLineB[], bool comLineF[], bool &comLineCur) {
313 	Sci_Position nLineTotal = styler.GetLine(styler.Length()-1) + 1;
314 	if (lineCurrent >= nLineTotal) {
315 		return;
316 	}
317 
318 	for (int i=nComL-2; i>=0; i--) {
319 		nComColB[i+1] = nComColB[i];
320 		comLineB[i+1] = comLineB[i];
321 	}
322 	nComColB[0] = nComCur;
323 	comLineB[0] = comLineCur;
324 	nComCur = nComColF[0];
325 	comLineCur = comLineF[0];
326 	for (unsigned int i=0; i+1<nComL; i++) {
327 		nComColF[i] = nComColF[i+1];
328 		comLineF[i] = comLineF[i+1];
329 	}
330 	Sci_Position chL = lineCurrent + nComL;
331 	if (chL < nLineTotal) {
332 		GetIfLineComment(styler, isFixFormat, chL, comLineF[nComL-1], nComColF[nComL-1]);
333 	}
334 	else {
335 		comLineF[nComL-1] = false;
336 	}
337 }
338 /***************************************/
CheckBackComLines(Accessor & styler,bool isFixFormat,Sci_Position lineCurrent,const unsigned int nComL,Sci_Position nComColB[],Sci_Position nComColF[],Sci_Position nComCur,bool comLineB[],bool comLineF[],bool & comLineCur)339 static void CheckBackComLines(Accessor &styler, bool isFixFormat, Sci_Position lineCurrent, const unsigned int nComL,
340 				  Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position nComCur,
341 				  bool comLineB[], bool comLineF[], bool &comLineCur) {
342 	unsigned int nLines = nComL + nComL + 1;
343 	bool* comL = new bool[nLines];
344 	Sci_Position* nComCol = new Sci_Position[nLines];
345 	bool comL0;
346 	Sci_Position nComCol0;
347 	GetIfLineComment(styler, isFixFormat, lineCurrent-nComL-1, comL0, nComCol0);
348 	for (unsigned int i=0; i<nComL; i++) {
349 		unsigned copyTo = nComL - i - 1;
350 		comL[copyTo]    = comLineB[i];
351 		nComCol[copyTo] = nComColB[i];
352 	}
353 	assert(nComL < nLines);
354 	comL[nComL] = comLineCur;
355 	nComCol[nComL] = nComCur;
356 	for (unsigned int i=0; i<nComL; i++) {
357 		unsigned copyTo = i + nComL + 1;
358 		comL[copyTo]    = comLineF[i];
359 		nComCol[copyTo] = nComColF[i];
360 	}
361 
362 	Sci_Position lineC = lineCurrent - nComL + 1;
363 	Sci_PositionU iStart;
364 	if (lineC <= 0) {
365 		lineC = 0;
366 		iStart = nComL - lineCurrent;
367 	}
368 	else {
369 		iStart = 1;
370 	}
371 	bool levChanged = false;
372 	int lev = styler.LevelAt(lineC) & SC_FOLDLEVELNUMBERMASK;
373 
374 	for (Sci_PositionU i=iStart; i<=nComL; i++) {
375 		if (comL[i] && (!comL[i-1] || nComCol[i] != nComCol[i-1])) {
376 			bool increase = true;
377 			Sci_PositionU until = i + nComL;
378 			for (Sci_PositionU j=i+1; j<=until; j++) {
379 				if (!comL[j] || nComCol[j] != nComCol[i]) {
380 					increase = false;
381 					break;
382 				}
383 			}
384 			lev = styler.LevelAt(lineC) & SC_FOLDLEVELNUMBERMASK;
385 			if (increase) {
386 				int levH = lev | SC_FOLDLEVELHEADERFLAG;
387 				lev += 1;
388 				if (levH != styler.LevelAt(lineC)) {
389 					styler.SetLevel(lineC, levH);
390 				}
391 				for (Sci_Position j=lineC+1; j<=lineCurrent; j++) {
392 					if (lev != styler.LevelAt(j)) {
393 						styler.SetLevel(j, lev);
394 					}
395 				}
396 				break;
397 			}
398 			else {
399 				if (lev != styler.LevelAt(lineC)) {
400 					styler.SetLevel(lineC, lev);
401 				}
402 			}
403 			levChanged = true;
404 		}
405 		else if (levChanged && comL[i]) {
406 			if (lev != styler.LevelAt(lineC)) {
407 				styler.SetLevel(lineC, lev);
408 			}
409 		}
410 		lineC++;
411 	}
412 	delete[] comL;
413 	delete[] nComCol;
414 }
415 /***************************************/
416 // To determine the folding level depending on keywords
classifyFoldPointFortran(const char * s,const char * prevWord,const char chNextNonBlank)417 static int classifyFoldPointFortran(const char* s, const char* prevWord, const char chNextNonBlank) {
418 	int lev = 0;
419 
420 	if ((strcmp(prevWord, "module") == 0 && strcmp(s, "subroutine") == 0)
421 		|| (strcmp(prevWord, "module") == 0 && strcmp(s, "function") == 0)) {
422 		lev = 0;
423 	} else if (strcmp(s, "associate") == 0 || strcmp(s, "block") == 0
424 	        || strcmp(s, "blockdata") == 0 || strcmp(s, "select") == 0
425 	        || strcmp(s, "selecttype") == 0 || strcmp(s, "selectcase") == 0
426 	        || strcmp(s, "do") == 0 || strcmp(s, "enum") ==0
427 	        || strcmp(s, "function") == 0 || strcmp(s, "interface") == 0
428 	        || strcmp(s, "module") == 0 || strcmp(s, "program") == 0
429 	        || strcmp(s, "subroutine") == 0 || strcmp(s, "then") == 0
430 	        || (strcmp(s, "type") == 0 && chNextNonBlank != '(')
431 		|| strcmp(s, "critical") == 0 || strcmp(s, "submodule") == 0){
432 		if (strcmp(prevWord, "end") == 0)
433 			lev = 0;
434 		else
435 			lev = 1;
436 	} else if ((strcmp(s, "end") == 0 && chNextNonBlank != '=')
437 	        || strcmp(s, "endassociate") == 0 || strcmp(s, "endblock") == 0
438 	        || strcmp(s, "endblockdata") == 0 || strcmp(s, "endselect") == 0
439 	        || strcmp(s, "enddo") == 0 || strcmp(s, "endenum") ==0
440 	        || strcmp(s, "endif") == 0 || strcmp(s, "endforall") == 0
441 	        || strcmp(s, "endfunction") == 0 || strcmp(s, "endinterface") == 0
442 	        || strcmp(s, "endmodule") == 0 || strcmp(s, "endprogram") == 0
443 	        || strcmp(s, "endsubroutine") == 0 || strcmp(s, "endtype") == 0
444 	        || strcmp(s, "endwhere") == 0 || strcmp(s, "endcritical") == 0
445 		|| (strcmp(prevWord, "module") == 0 && strcmp(s, "procedure") == 0)  // Take care of the "module procedure" statement
446 		|| strcmp(s, "endsubmodule") == 0 || strcmp(s, "endteam") == 0) {
447 		lev = -1;
448 	} else if (strcmp(prevWord, "end") == 0 && strcmp(s, "if") == 0){ // end if
449 		lev = 0;
450 	} else if (strcmp(prevWord, "type") == 0 && strcmp(s, "is") == 0){ // type is
451 		lev = -1;
452 	} else if ((strcmp(prevWord, "end") == 0 && strcmp(s, "procedure") == 0)
453 			   || strcmp(s, "endprocedure") == 0) {
454 			lev = 1; // level back to 0, because no folding support for "module procedure" in submodule
455 	} else if (strcmp(prevWord, "change") == 0 && strcmp(s, "team") == 0){ // change team
456 		lev = 1;
457 	}
458 	return lev;
459 }
460 /***************************************/
461 // Folding the code
FoldFortranDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,Accessor & styler,bool isFixFormat)462 static void FoldFortranDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
463         Accessor &styler, bool isFixFormat) {
464 
465 	bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0;
466 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
467 	Sci_PositionU endPos = startPos + length;
468 	int visibleChars = 0;
469 	Sci_Position lineCurrent = styler.GetLine(startPos);
470 	bool isPrevLine;
471 	if (lineCurrent > 0) {
472 		lineCurrent--;
473 		startPos = styler.LineStart(lineCurrent);
474 		isPrevLine = true;
475 	} else {
476 		isPrevLine = false;
477 	}
478 	char chNext = styler[startPos];
479 	int styleNext = styler.StyleAt(startPos);
480 	int style = initStyle;
481 	int levelDeltaNext = 0;
482 
483 	const unsigned int nComL = 3; // defines how many comment lines should be before they are folded
484 	Sci_Position nComColB[nComL] = {};
485 	Sci_Position nComColF[nComL] = {};
486 	Sci_Position nComCur = 0;
487 	bool comLineB[nComL] = {};
488 	bool comLineF[nComL] = {};
489 	bool comLineCur;
490 	Sci_Position nLineTotal = styler.GetLine(styler.Length()-1) + 1;
491 	if (foldComment) {
492 		for (unsigned int i=0; i<nComL; i++) {
493 			Sci_Position chL = lineCurrent-(i+1);
494 			if (chL < 0) {
495 				comLineB[i] = false;
496 				break;
497 			}
498 			GetIfLineComment(styler, isFixFormat, chL, comLineB[i], nComColB[i]);
499 			if (!comLineB[i]) {
500 				for (unsigned int j=i+1; j<nComL; j++) {
501 					comLineB[j] = false;
502 				}
503 				break;
504 			}
505 		}
506 		for (unsigned int i=0; i<nComL; i++) {
507 			Sci_Position chL = lineCurrent+i+1;
508 			if (chL >= nLineTotal) {
509 				comLineF[i] = false;
510 				break;
511 			}
512 			GetIfLineComment(styler, isFixFormat, chL, comLineF[i], nComColF[i]);
513 		}
514 		GetIfLineComment(styler, isFixFormat, lineCurrent, comLineCur, nComCur);
515 		CheckBackComLines(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur,
516 				comLineB, comLineF, comLineCur);
517 	}
518 	int levelCurrent = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
519 
520 	/***************************************/
521 	Sci_Position lastStart = 0;
522 	char prevWord[32] = "";
523 	/***************************************/
524 	for (Sci_PositionU i = startPos; i < endPos; i++) {
525 		char ch = chNext;
526 		chNext = styler.SafeGetCharAt(i + 1);
527 		char chNextNonBlank = chNext;
528 		bool nextEOL = false;
529 		if (IsALineEnd(chNextNonBlank)) {
530 			nextEOL = true;
531 		}
532 		Sci_PositionU j=i+1;
533 		while(IsABlank(chNextNonBlank) && j<endPos) {
534 			j ++ ;
535 			chNextNonBlank = styler.SafeGetCharAt(j);
536 			if (IsALineEnd(chNextNonBlank)) {
537 				nextEOL = true;
538 			}
539 		}
540 		if (!nextEOL && j == endPos) {
541 			nextEOL = true;
542 		}
543 		int stylePrev = style;
544 		style = styleNext;
545 		styleNext = styler.StyleAt(i + 1);
546 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
547 		//
548 		if (((isFixFormat && stylePrev == SCE_F_CONTINUATION) || stylePrev == SCE_F_DEFAULT
549 			|| stylePrev == SCE_F_OPERATOR) && (style == SCE_F_WORD || style == SCE_F_LABEL)) {
550 			// Store last word and label start point.
551 			lastStart = i;
552 		}
553 		/***************************************/
554 		if (style == SCE_F_WORD) {
555 			if(iswordchar(ch) && !iswordchar(chNext)) {
556 				char s[32];
557 				Sci_PositionU k;
558 				for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
559 					s[k] = static_cast<char>(tolower(styler[lastStart+k]));
560 				}
561 				s[k] = '\0';
562 				// Handle the forall and where statement and structure.
563 				if (strcmp(s, "forall") == 0 || (strcmp(s, "where") == 0 && strcmp(prevWord, "else") != 0)) {
564 					if (strcmp(prevWord, "end") != 0) {
565 						j = i + 1;
566 						char chBrace = '(', chSeek = ')', ch1 = styler.SafeGetCharAt(j);
567 						// Find the position of the first (
568 						while (ch1 != chBrace && j<endPos) {
569 							j++;
570 							ch1 = styler.SafeGetCharAt(j);
571 						}
572 						char styBrace = styler.StyleAt(j);
573 						int depth = 1;
574 						char chAtPos;
575 						char styAtPos;
576 						while (j<endPos) {
577 							j++;
578 							chAtPos = styler.SafeGetCharAt(j);
579 							styAtPos = styler.StyleAt(j);
580 							if (styAtPos == styBrace) {
581 								if (chAtPos == chBrace) depth++;
582 								if (chAtPos == chSeek) depth--;
583 								if (depth == 0) break;
584 							}
585 						}
586 						Sci_Position tmpLineCurrent = lineCurrent;
587 						while (j<endPos) {
588 							j++;
589 							chAtPos = styler.SafeGetCharAt(j);
590 							styAtPos = styler.StyleAt(j);
591 							if (!IsALineEnd(chAtPos) && (styAtPos == SCE_F_COMMENT || IsABlank(chAtPos))) continue;
592 							if (isFixFormat) {
593 								if (!IsALineEnd(chAtPos)) {
594 									break;
595 								} else {
596 									if (tmpLineCurrent < styler.GetLine(styler.Length()-1)) {
597 										tmpLineCurrent++;
598 										j = styler.LineStart(tmpLineCurrent);
599 										if (styler.StyleAt(j+5) == SCE_F_CONTINUATION
600 											&& !IsABlank(styler.SafeGetCharAt(j+5)) && styler.SafeGetCharAt(j+5) != '0') {
601 											j += 5;
602 											continue;
603 										} else {
604 											levelDeltaNext++;
605 											break;
606 										}
607 									}
608 								}
609 							} else {
610 								if (chAtPos == '&' && styler.StyleAt(j) == SCE_F_CONTINUATION) {
611 									j = GetContinuedPos(j+1, styler);
612 									continue;
613 								} else if (IsALineEnd(chAtPos)) {
614 									levelDeltaNext++;
615 									break;
616 								} else {
617 									break;
618 								}
619 							}
620 						}
621 					}
622 				} else {
623 					int wordLevelDelta = classifyFoldPointFortran(s, prevWord, chNextNonBlank);
624 					levelDeltaNext += wordLevelDelta;
625 					if (((strcmp(s, "else") == 0) && (nextEOL || chNextNonBlank == '!')) ||
626 						(strcmp(prevWord, "else") == 0 && strcmp(s, "where") == 0) || strcmp(s, "elsewhere") == 0) {
627 						if (!isPrevLine) {
628 							levelCurrent--;
629 						}
630 						levelDeltaNext++;
631 					} else if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0) {
632 						if (!isPrevLine) {
633 							levelCurrent--;
634 						}
635 					} else if ((strcmp(prevWord, "select") == 0 && strcmp(s, "case") == 0) || strcmp(s, "selectcase") == 0 ||
636 							   (strcmp(prevWord, "select") == 0 && strcmp(s, "type") == 0) || strcmp(s, "selecttype") == 0) {
637 						levelDeltaNext += 2;
638 					} else if ((strcmp(s, "case") == 0 && chNextNonBlank == '(') || (strcmp(prevWord, "case") == 0 && strcmp(s, "default") == 0) ||
639 							   (strcmp(prevWord, "type") == 0 && strcmp(s, "is") == 0) ||
640 							   (strcmp(prevWord, "class") == 0 && strcmp(s, "is") == 0) ||
641 							   (strcmp(prevWord, "class") == 0 && strcmp(s, "default") == 0) ) {
642 						if (!isPrevLine) {
643 							levelCurrent--;
644 						}
645 						levelDeltaNext++;
646 					} else if ((strcmp(prevWord, "end") == 0 && strcmp(s, "select") == 0) || strcmp(s, "endselect") == 0) {
647 						levelDeltaNext -= 2;
648 					}
649 
650 					// There are multiple forms of "do" loop. The older form with a label "do 100 i=1,10" would require matching
651 					// labels to ensure the folding level does not decrease too far when labels are used for other purposes.
652 					// Since this is difficult, do-label constructs are not folded.
653 					if (strcmp(s, "do") == 0 && IsADigit(chNextNonBlank)) {
654 						// Remove delta for do-label
655 						levelDeltaNext -= wordLevelDelta;
656 					}
657 				}
658 				strcpy(prevWord, s);
659 			}
660 		}
661 		if (atEOL) {
662 			if (foldComment) {
663 				int ldNext;
664 				CheckLevelCommentLine(nComL, nComColB, nComColF, nComCur, comLineB, comLineF, comLineCur, ldNext);
665 				levelDeltaNext += ldNext;
666 			}
667 			int lev = levelCurrent;
668 			if (visibleChars == 0 && foldCompact)
669 				lev |= SC_FOLDLEVELWHITEFLAG;
670 			if ((levelDeltaNext > 0) && (visibleChars > 0))
671 				lev |= SC_FOLDLEVELHEADERFLAG;
672 			if (lev != styler.LevelAt(lineCurrent))
673 				styler.SetLevel(lineCurrent, lev);
674 
675 			lineCurrent++;
676 			levelCurrent += levelDeltaNext;
677 			levelDeltaNext = 0;
678 			visibleChars = 0;
679 			strcpy(prevWord, "");
680 			isPrevLine = false;
681 
682 			if (foldComment) {
683 				StepCommentLine(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur,
684 						comLineB, comLineF, comLineCur);
685 			}
686 		}
687 		/***************************************/
688 		if (!isspacechar(ch)) visibleChars++;
689 	}
690 	/***************************************/
691 }
692 /***************************************/
693 static const char * const FortranWordLists[] = {
694 	"Primary keywords and identifiers",
695 	"Intrinsic functions",
696 	"Extended and user defined functions",
697 	0,
698 };
699 /***************************************/
ColouriseFortranDocFreeFormat(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)700 static void ColouriseFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
701         Accessor &styler) {
702 	ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, false);
703 }
704 /***************************************/
ColouriseFortranDocFixFormat(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)705 static void ColouriseFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
706         Accessor &styler) {
707 	ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, true);
708 }
709 /***************************************/
FoldFortranDocFreeFormat(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)710 static void FoldFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle,
711         WordList *[], Accessor &styler) {
712 	FoldFortranDoc(startPos, length, initStyle,styler, false);
713 }
714 /***************************************/
FoldFortranDocFixFormat(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)715 static void FoldFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle,
716         WordList *[], Accessor &styler) {
717 	FoldFortranDoc(startPos, length, initStyle,styler, true);
718 }
719 /***************************************/
720 LexerModule lmFortran(SCLEX_FORTRAN, ColouriseFortranDocFreeFormat, "fortran", FoldFortranDocFreeFormat, FortranWordLists);
721 LexerModule lmF77(SCLEX_F77, ColouriseFortranDocFixFormat, "f77", FoldFortranDocFixFormat, FortranWordLists);
722