1 // Scintilla source code edit control
2 /** @file LexFortran.cxx
4 ** Writen by Chuan-jian Shen, Last changed Nov. 2002
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.
19 #include "StyleContext.h"
21 #include "Scintilla.h"
24 static inline bool IsAWordChar(const int ch
) {
25 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '%');
28 static inline bool IsAWordStart(const int ch
) {
29 return (ch
< 0x80) && (isalnum(ch
));
32 inline bool IsABlank(unsigned int ch
) {
33 return (ch
== ' ') || (ch
== 0x09) || (ch
== 0x0b) ;
35 static void ColouriseFortranDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
36 Accessor
&styler
, bool isFixFormat
) {
38 WordList
&keywords
= *keywordlists
[0];
39 WordList
&keywords2
= *keywordlists
[1];
40 WordList
&keywords3
= *keywordlists
[2];
42 int posLineStart
= 0, prevState
= 0;
43 int endPos
= startPos
+ length
;
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);
49 // backtrack to the nearest keyword
50 while ((startPos
> 1) && (styler
.StyleAt(startPos
) != SCE_F_WORD
)) {
53 startPos
= styler
.LineStart(styler
.GetLine(startPos
));
54 initStyle
= styler
.StyleAt(startPos
- 1);
55 StyleContext
sc(startPos
, endPos
-startPos
, initStyle
, styler
);
57 for (; sc
.More(); sc
.Forward()) {
59 // remember the position of the line
61 posLineStart
= sc
.currentPos
;
62 sc
.SetState(SCE_F_DEFAULT
);
65 // Handle line continuation generically.
69 while (IsABlank(chTemp
) && j
<132) {
70 chTemp
= static_cast<char>(sc
.GetRelative(j
));
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();
83 sc
.SetState(SCE_F_CONTINUATION
);
86 sc
.SetState(currentState
);
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
);
99 } else if (sc
.state
== SCE_F_IDENTIFIER
) {
100 if (!IsAWordChar(sc
.ch
) || (sc
.ch
== '%')) {
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
);
110 sc
.SetState(SCE_F_DEFAULT
);
112 } else if (sc
.state
== SCE_F_COMMENT
) {
113 if (sc
.ch
== '\r' || sc
.ch
== '\n') {
114 sc
.SetState(SCE_F_DEFAULT
);
116 } else if (sc
.state
== SCE_F_STRING1
) {
117 prevState
= sc
.state
;
119 if (sc
.chNext
== '\'') {
122 sc
.ForwardSetState(SCE_F_DEFAULT
);
123 prevState
= SCE_F_DEFAULT
;
125 } else if (sc
.atLineEnd
) {
127 sc
.ForwardSetState(SCE_F_DEFAULT
);
128 posLineStart
= sc
.currentPos
;
130 sc
.ChangeState(SCE_F_STRINGEOL
);
131 sc
.ForwardSetState(SCE_F_DEFAULT
);
134 } else if (sc
.state
== SCE_F_STRING2
) {
135 prevState
= sc
.state
;
138 sc
.ForwardSetState(SCE_F_DEFAULT
);
139 posLineStart
= sc
.currentPos
;
141 sc
.ChangeState(SCE_F_STRINGEOL
);
142 sc
.ForwardSetState(SCE_F_DEFAULT
);
144 } else if (sc
.ch
== '\"') {
145 if (sc
.chNext
== '\"') {
148 sc
.ForwardSetState(SCE_F_DEFAULT
);
149 prevState
= SCE_F_DEFAULT
;
152 } else if (sc
.state
== SCE_F_OPERATOR2
) {
154 sc
.ForwardSetState(SCE_F_DEFAULT
);
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
);
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
);
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
);
198 // The folding depends on the mercy of the programer.
199 static int classifyFoldPointFortran(const char* s
, const char* prevWord
) {
201 if (strcmp(prevWord
, "end") == 0) return lev
;
202 if ((strcmp(prevWord
, "else") == 0 && strcmp(s
, "if") == 0) || strcmp(s
, "elseif") == 0)
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) {
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 ) {
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
;
239 char prevWord
[32] = "";
241 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
243 chNext
= styler
.SafeGetCharAt(i
+ 1);
244 int stylePrev
= style
;
246 styleNext
= styler
.StyleAt(i
+ 1);
247 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
249 if (stylePrev
== SCE_F_DEFAULT
&& style
== SCE_F_WORD
)
251 // Store last word start point.
255 if (style
== SCE_F_WORD
) {
256 if(iswordchar(ch
) && !iswordchar(chNext
)) {
259 for(j
= 0; ( j
< 31 ) && ( j
< i
-lastStart
+1 ); j
++) {
260 s
[j
] = static_cast<char>(tolower(styler
[lastStart
+ j
]));
263 levelCurrent
+= classifyFoldPointFortran(s
, prevWord
);
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
);
277 levelPrev
= levelCurrent
;
279 strcpy(prevWord
, "");
282 if (!isspacechar(ch
))
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
);
291 static const char * const FortranWordLists
[] = {
292 "Primary keywords and identifiers",
293 "Intrinsic functions",
294 "Extended and user defined functions",
298 static void ColouriseFortranDocFreeFormat(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
300 ColouriseFortranDoc(startPos
, length
, initStyle
, keywordlists
, styler
, false);
303 static void ColouriseFortranDocFixFormat(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
305 ColouriseFortranDoc(startPos
, length
, initStyle
, keywordlists
, styler
, true);
309 LexerModule
lmFortran(SCLEX_FORTRAN
, ColouriseFortranDocFreeFormat
, "fortran", FoldFortranDoc
, FortranWordLists
);
310 LexerModule
lmF77(SCLEX_F77
, ColouriseFortranDocFixFormat
, "f77", FoldFortranDoc
, FortranWordLists
);