]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexFortran.cxx
e2109a0ab59c03f0434db4176badc35e53e660b0
[wxWidgets.git] / src / stc / scintilla / src / LexFortran.cxx
1 // Scintilla source code edit control
2 /** @file LexFortran.cxx
3 ** Lexer for Fortran.
4 ** Writen by Chuan-jian Shen, Last changed Nov. 2002
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 <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
23
24 static inline bool IsAWordChar(const int ch) {
25 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
26 }
27
28 static inline bool IsAWordStart(const int ch) {
29 return (ch < 0x80) && (isalnum(ch));
30 }
31
32 inline bool IsABlank(unsigned int ch) {
33 return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
34 }
35 static void ColouriseFortranDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
36 Accessor &styler, bool isFixFormat) {
37
38 WordList &keywords = *keywordlists[0];
39 WordList &keywords2 = *keywordlists[1];
40 WordList &keywords3 = *keywordlists[2];
41
42 int posLineStart = 0, prevState = 0;
43 int endPos = startPos + length;
44
45 // backtrack to the beginning of the document, this may be slow for big documents.
46 // initStyle = SCE_F_DEFAULT;
47 // StyleContext sc(0, startPos+length, initStyle, styler);
48
49 // backtrack to the nearest keyword
50 while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_F_WORD)) {
51 startPos--;
52 }
53 startPos = styler.LineStart(styler.GetLine(startPos));
54 initStyle = styler.StyleAt(startPos - 1);
55 StyleContext sc(startPos, endPos-startPos, initStyle, styler);
56
57 for (; sc.More(); sc.Forward()) {
58
59 // remember the position of the line
60 if (sc.atLineStart) {
61 posLineStart = sc.currentPos;
62 sc.SetState(SCE_F_DEFAULT);
63 }
64
65 // Handle line continuation generically.
66 if (sc.ch == '&') {
67 char chTemp = ' ';
68 int j = 1;
69 while (IsABlank(chTemp) && j<132) {
70 chTemp = static_cast<char>(sc.GetRelative(j));
71 j ++;
72 }
73 if (chTemp == '!') {
74 sc.SetState(SCE_F_CONTINUATION);
75 if (sc.chNext == '!') sc.ForwardSetState(SCE_F_COMMENT);
76 } else if (chTemp == '\r' || chTemp == '\n') {
77 int currentState = sc.state;
78 sc.SetState(SCE_F_CONTINUATION);
79 if (currentState == SCE_F_STRING1 || currentState == SCE_F_STRING2) {
80 sc.ForwardSetState(SCE_F_DEFAULT);
81 while (IsASpace(sc.ch) && sc.More()) sc.Forward();
82 if (sc.ch == '&') {
83 sc.SetState(SCE_F_CONTINUATION);
84 sc.Forward();
85 }
86 sc.SetState(currentState);
87 }
88 }
89 continue;
90 }
91
92 // Determine if the current state should terminate.
93 if (sc.state == SCE_F_OPERATOR) {
94 sc.SetState(SCE_F_DEFAULT);
95 } else if (sc.state == SCE_F_NUMBER) {
96 if (!IsAWordChar(sc.ch)) {
97 sc.SetState(SCE_F_DEFAULT);
98 }
99 } else if (sc.state == SCE_F_IDENTIFIER) {
100 if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
101 char s[100];
102 sc.GetCurrentLowered(s, sizeof(s));
103 if (keywords.InList(s)) {
104 sc.ChangeState(SCE_F_WORD);
105 } else if (keywords2.InList(s)) {
106 sc.ChangeState(SCE_F_WORD2);
107 } else if (keywords3.InList(s)) {
108 sc.ChangeState(SCE_F_WORD3);
109 }
110 sc.SetState(SCE_F_DEFAULT);
111 }
112 } else if (sc.state == SCE_F_COMMENT) {
113 if (sc.ch == '\r' || sc.ch == '\n') {
114 sc.SetState(SCE_F_DEFAULT);
115 }
116 } else if (sc.state == SCE_F_STRING1) {
117 prevState = sc.state;
118 if (sc.ch == '\'') {
119 if (sc.chNext == '\'') {
120 sc.Forward();
121 } else {
122 sc.ForwardSetState(SCE_F_DEFAULT);
123 prevState = SCE_F_DEFAULT;
124 }
125 } else if (sc.atLineEnd) {
126 if (isFixFormat) {
127 sc.ForwardSetState(SCE_F_DEFAULT);
128 posLineStart = sc.currentPos;
129 } else {
130 sc.ChangeState(SCE_F_STRINGEOL);
131 sc.ForwardSetState(SCE_F_DEFAULT);
132 }
133 }
134 } else if (sc.state == SCE_F_STRING2) {
135 prevState = sc.state;
136 if (sc.atLineEnd) {
137 if (isFixFormat) {
138 sc.ForwardSetState(SCE_F_DEFAULT);
139 posLineStart = sc.currentPos;
140 } else {
141 sc.ChangeState(SCE_F_STRINGEOL);
142 sc.ForwardSetState(SCE_F_DEFAULT);
143 }
144 } else if (sc.ch == '\"') {
145 if (sc.chNext == '\"') {
146 sc.Forward();
147 } else {
148 sc.ForwardSetState(SCE_F_DEFAULT);
149 prevState = SCE_F_DEFAULT;
150 }
151 }
152 } else if (sc.state == SCE_F_OPERATOR2) {
153 if (sc.ch == '.') {
154 sc.ForwardSetState(SCE_F_DEFAULT);
155 }
156 } else if (sc.state == SCE_F_CONTINUATION) {
157 sc.SetState(SCE_F_DEFAULT);
158 } else if (sc.state == SCE_F_LABEL) {
159 if (sc.currentPos >= static_cast<unsigned int>(posLineStart+5)) {
160 sc.SetState(SCE_F_DEFAULT);
161 }
162 }
163
164 // Determine if a new state should be entered.
165 if (sc.state == SCE_F_DEFAULT) {
166 int toLineStart = sc.currentPos - posLineStart;
167 if (isFixFormat && (toLineStart < 6 || toLineStart > 72)) {
168 if (sc.atLineStart && (tolower(sc.ch) == 'c' || sc.ch == '*') || sc.ch == '!') {
169 sc.SetState(SCE_F_COMMENT);
170 } else if (toLineStart > 72) {
171 sc.SetState(SCE_F_COMMENT);
172 } else if (toLineStart < 5 && !IsASpace(sc.ch)) {
173 sc.SetState(SCE_F_LABEL);
174 } else if (toLineStart == 5 && (!IsASpace(sc.ch) && sc.ch != '0')) {
175 sc.SetState(SCE_F_CONTINUATION);
176 sc.ForwardSetState(prevState);
177 }
178 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
179 sc.SetState(SCE_F_NUMBER);
180 } else if (sc.ch == '.' && isalpha(sc.chNext)) {
181 sc.SetState(SCE_F_OPERATOR2);
182 } else if (IsAWordStart(sc.ch)) {
183 sc.SetState(SCE_F_IDENTIFIER);
184 } else if (sc.ch == '!') {
185 sc.SetState(SCE_F_COMMENT);
186 } else if (sc.ch == '\"') {
187 sc.SetState(SCE_F_STRING2);
188 } else if (sc.ch == '\'') {
189 sc.SetState(SCE_F_STRING1);
190 } else if (isoperator(static_cast<char>(sc.ch))) {
191 sc.SetState(SCE_F_OPERATOR);
192 }
193 }
194 }
195 sc.Complete();
196 }
197
198 // The folding depends on the mercy of the programer.
199 static int classifyFoldPointFortran(const char* s, const char* prevWord) {
200 int lev = 0;
201 if (strcmp(prevWord, "end") == 0) return lev;
202 if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0)
203 return -1;
204 if (strcmp(s, "associate") == 0 || strcmp(s, "block") == 0
205 || strcmp(s, "blockdata") == 0 || strcmp(s, "select") == 0
206 || strcmp(s, "do") == 0 || strcmp(s, "enum") ==0
207 || strcmp(s, "forall") == 0 || strcmp(s, "function") == 0
208 || strcmp(s, "interface") == 0 || strcmp(s, "module") == 0
209 || strcmp(s, "program") == 0 || strcmp(s, "subroutine") == 0
210 || strcmp(s, "then") == 0 || strcmp(s, "where") == 0) {
211 lev = 1;
212 } else if (strcmp(s, "end") == 0 || strcmp(s, "continue") == 0
213 || strcmp(s, "endassociate") == 0 || strcmp(s, "endblock") == 0
214 || strcmp(s, "endblockdata") == 0 || strcmp(s, "endselect") == 0
215 || strcmp(s, "enddo") == 0 || strcmp(s, "endenum") ==0
216 || strcmp(s, "endif") == 0
217 || strcmp(s, "endforall") == 0 || strcmp(s, "endfunction") == 0
218 || strcmp(s, "endinterface") == 0 || strcmp(s, "endmodule") == 0
219 || strcmp(s, "endprogram") == 0 || strcmp(s, "endsubroutine") == 0
220 || strcmp(s, "endwhere") == 0 || strcmp(s, "procedure") == 0 ) {
221 lev = -1;
222 }
223 return lev;
224 }
225 static void FoldFortranDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) {
226 //~ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
227 // Do not know how to fold the comment at the moment.
228 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
229 unsigned int endPos = startPos + length;
230 int visibleChars = 0;
231 int lineCurrent = styler.GetLine(startPos);
232 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
233 int levelCurrent = levelPrev;
234 char chNext = styler[startPos];
235 int styleNext = styler.StyleAt(startPos);
236 int style = initStyle;
237
238 int lastStart = 0;
239 char prevWord[32] = "";
240
241 for (unsigned int i = startPos; i < endPos; i++) {
242 char ch = chNext;
243 chNext = styler.SafeGetCharAt(i + 1);
244 int stylePrev = style;
245 style = styleNext;
246 styleNext = styler.StyleAt(i + 1);
247 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
248
249 if (stylePrev == SCE_F_DEFAULT && style == SCE_F_WORD)
250 {
251 // Store last word start point.
252 lastStart = i;
253 }
254
255 if (style == SCE_F_WORD) {
256 if(iswordchar(ch) && !iswordchar(chNext)) {
257 char s[32];
258 unsigned int j;
259 for(j = 0; ( j < 31 ) && ( j < i-lastStart+1 ); j++) {
260 s[j] = static_cast<char>(tolower(styler[lastStart + j]));
261 }
262 s[j] = '\0';
263 levelCurrent += classifyFoldPointFortran(s, prevWord);
264 strcpy(prevWord, s);
265 }
266 }
267 if (atEOL) {
268 int lev = levelPrev;
269 if (visibleChars == 0 && foldCompact)
270 lev |= SC_FOLDLEVELWHITEFLAG;
271 if ((levelCurrent > levelPrev) && (visibleChars > 0))
272 lev |= SC_FOLDLEVELHEADERFLAG;
273 if (lev != styler.LevelAt(lineCurrent)) {
274 styler.SetLevel(lineCurrent, lev);
275 }
276 lineCurrent++;
277 levelPrev = levelCurrent;
278 visibleChars = 0;
279 strcpy(prevWord, "");
280 }
281
282 if (!isspacechar(ch))
283 visibleChars++;
284 }
285
286 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
287 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
288 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
289 }
290
291 static const char * const FortranWordLists[] = {
292 "Primary keywords and identifiers",
293 "Intrinsic functions",
294 "Extended and user defined functions",
295 0,
296 };
297
298 static void ColouriseFortranDocFreeFormat(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
299 Accessor &styler) {
300 ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, false);
301 }
302
303 static void ColouriseFortranDocFixFormat(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
304 Accessor &styler) {
305 ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, true);
306 }
307
308
309 LexerModule lmFortran(SCLEX_FORTRAN, ColouriseFortranDocFreeFormat, "fortran", FoldFortranDoc, FortranWordLists);
310 LexerModule lmF77(SCLEX_F77, ColouriseFortranDocFixFormat, "f77", FoldFortranDoc, FortranWordLists);