// Scintilla source code edit control /** @file LexFortran.cxx ** Lexer for Fortran. ** Written by Chuan-jian Shen, Last changed Sep. 2003 **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. /***************************************/ #include #include #include #include #include #include #include #include /***************************************/ #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" /***************************************/ using namespace Lexilla; /***********************************************/ static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%'); } /**********************************************/ static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch)); } /***************************************/ static inline bool IsABlank(unsigned int ch) { return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ; } /***************************************/ static inline bool IsALineEnd(char ch) { return ((ch == '\n') || (ch == '\r')) ; } /***************************************/ static Sci_PositionU GetContinuedPos(Sci_PositionU pos, Accessor &styler) { while (!IsALineEnd(styler.SafeGetCharAt(pos++))) continue; if (styler.SafeGetCharAt(pos) == '\n') pos++; while (IsABlank(styler.SafeGetCharAt(pos++))) continue; char chCur = styler.SafeGetCharAt(pos); if (chCur == '&') { while (IsABlank(styler.SafeGetCharAt(++pos))) continue; return pos; } else { return pos; } } /***************************************/ static void ColouriseFortranDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler, bool isFixFormat) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; /***************************************/ Sci_Position posLineStart = 0; int numNonBlank = 0, prevState = 0; Sci_Position endPos = startPos + length; /***************************************/ // backtrack to the nearest keyword while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_F_WORD)) { startPos--; } startPos = styler.LineStart(styler.GetLine(startPos)); initStyle = styler.StyleAt(startPos - 1); StyleContext sc(startPos, endPos-startPos, initStyle, styler); /***************************************/ for (; sc.More(); sc.Forward()) { // remember the start position of the line if (sc.atLineStart) { posLineStart = sc.currentPos; numNonBlank = 0; sc.SetState(SCE_F_DEFAULT); } if (!IsASpaceOrTab(sc.ch)) numNonBlank ++; /***********************************************/ // Handle the fix format generically Sci_Position toLineStart = sc.currentPos - posLineStart; if (isFixFormat && (toLineStart < 6 || toLineStart >= 72)) { if ((toLineStart == 0 && (tolower(sc.ch) == 'c' || sc.ch == '*')) || sc.ch == '!') { if (sc.MatchIgnoreCase("cdec$") || sc.MatchIgnoreCase("*dec$") || sc.MatchIgnoreCase("!dec$") || sc.MatchIgnoreCase("cdir$") || sc.MatchIgnoreCase("*dir$") || sc.MatchIgnoreCase("!dir$") || sc.MatchIgnoreCase("cms$") || sc.MatchIgnoreCase("*ms$") || sc.MatchIgnoreCase("!ms$") || sc.chNext == '$') { sc.SetState(SCE_F_PREPROCESSOR); } else { sc.SetState(SCE_F_COMMENT); } while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end } else if (toLineStart >= 72) { sc.SetState(SCE_F_COMMENT); while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end } else if (toLineStart < 5) { if (IsADigit(sc.ch)) sc.SetState(SCE_F_LABEL); else sc.SetState(SCE_F_DEFAULT); } else if (toLineStart == 5) { //if (!IsASpace(sc.ch) && sc.ch != '0') { if (sc.ch != '\r' && sc.ch != '\n') { sc.SetState(SCE_F_CONTINUATION); if (!IsASpace(sc.ch) && sc.ch != '0') sc.ForwardSetState(prevState); } else sc.SetState(SCE_F_DEFAULT); } continue; } /***************************************/ // Handle line continuation generically. if (!isFixFormat && sc.ch == '&' && sc.state != SCE_F_COMMENT) { char chTemp = ' '; Sci_Position j = 1; while (IsABlank(chTemp) && j<132) { chTemp = static_cast(sc.GetRelative(j)); j++; } if (chTemp == '!') { sc.SetState(SCE_F_CONTINUATION); if (sc.chNext == '!') sc.ForwardSetState(SCE_F_COMMENT); } else if (chTemp == '\r' || chTemp == '\n') { int currentState = sc.state; sc.SetState(SCE_F_CONTINUATION); sc.ForwardSetState(SCE_F_DEFAULT); while (IsASpace(sc.ch) && sc.More()) { sc.Forward(); if (sc.atLineStart) numNonBlank = 0; if (!IsASpaceOrTab(sc.ch)) numNonBlank ++; } if (sc.ch == '&') { sc.SetState(SCE_F_CONTINUATION); sc.Forward(); } sc.SetState(currentState); } } /***************************************/ // Hanndle preprocessor directives if (sc.ch == '#' && numNonBlank == 1) { sc.SetState(SCE_F_PREPROCESSOR); while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end } /***************************************/ // Determine if the current state should terminate. if (sc.state == SCE_F_OPERATOR) { sc.SetState(SCE_F_DEFAULT); } else if (sc.state == SCE_F_NUMBER) { if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) { sc.SetState(SCE_F_DEFAULT); } } else if (sc.state == SCE_F_IDENTIFIER) { if (!IsAWordChar(sc.ch) || (sc.ch == '%')) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_F_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_F_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_F_WORD3); } sc.SetState(SCE_F_DEFAULT); } } else if (sc.state == SCE_F_COMMENT || sc.state == SCE_F_PREPROCESSOR) { if (sc.ch == '\r' || sc.ch == '\n') { sc.SetState(SCE_F_DEFAULT); } } else if (sc.state == SCE_F_STRING1) { prevState = sc.state; if (sc.ch == '\'') { if (sc.chNext == '\'') { sc.Forward(); } else { sc.ForwardSetState(SCE_F_DEFAULT); prevState = SCE_F_DEFAULT; } } else if (sc.atLineEnd) { sc.ChangeState(SCE_F_STRINGEOL); sc.ForwardSetState(SCE_F_DEFAULT); } } else if (sc.state == SCE_F_STRING2) { prevState = sc.state; if (sc.atLineEnd) { sc.ChangeState(SCE_F_STRINGEOL); sc.ForwardSetState(SCE_F_DEFAULT); } else if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_F_DEFAULT); prevState = SCE_F_DEFAULT; } } } else if (sc.state == SCE_F_OPERATOR2) { if (sc.ch == '.') { sc.ForwardSetState(SCE_F_DEFAULT); } } else if (sc.state == SCE_F_CONTINUATION) { sc.SetState(SCE_F_DEFAULT); } else if (sc.state == SCE_F_LABEL) { if (!IsADigit(sc.ch)) { sc.SetState(SCE_F_DEFAULT); } else { if (isFixFormat && sc.currentPos-posLineStart > 4) sc.SetState(SCE_F_DEFAULT); else if (numNonBlank > 5) sc.SetState(SCE_F_DEFAULT); } } /***************************************/ // Determine if a new state should be entered. if (sc.state == SCE_F_DEFAULT) { if (sc.ch == '!') { if (sc.MatchIgnoreCase("!dec$") || sc.MatchIgnoreCase("!dir$") || sc.MatchIgnoreCase("!ms$") || sc.chNext == '$') { sc.SetState(SCE_F_PREPROCESSOR); } else { sc.SetState(SCE_F_COMMENT); } } else if ((!isFixFormat) && IsADigit(sc.ch) && numNonBlank == 1) { sc.SetState(SCE_F_LABEL); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_F_NUMBER); } else if ((tolower(sc.ch) == 'b' || tolower(sc.ch) == 'o' || tolower(sc.ch) == 'z') && (sc.chNext == '\"' || sc.chNext == '\'')) { sc.SetState(SCE_F_NUMBER); sc.Forward(); } else if (sc.ch == '.' && isalpha(sc.chNext)) { sc.SetState(SCE_F_OPERATOR2); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_F_IDENTIFIER); } else if (sc.ch == '\"') { sc.SetState(SCE_F_STRING2); } else if (sc.ch == '\'') { sc.SetState(SCE_F_STRING1); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_F_OPERATOR); } } } sc.Complete(); } /***************************************/ static void CheckLevelCommentLine(const unsigned int nComL, Sci_Position nComColB[], Sci_Position nComColF[], Sci_Position &nComCur, bool comLineB[], bool comLineF[], bool &comLineCur, int &levelDeltaNext) { levelDeltaNext = 0; if (!comLineCur) { return; } if (!comLineF[0] || nComColF[0] != nComCur) { unsigned int i=0; for (; i= nLineTotal) { return; } for (int i=nComL-2; i>=0; i--) { nComColB[i+1] = nComColB[i]; comLineB[i+1] = comLineB[i]; } nComColB[0] = nComCur; comLineB[0] = comLineCur; nComCur = nComColF[0]; comLineCur = comLineF[0]; for (unsigned int i=0; i+1 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); isPrevLine = true; } else { isPrevLine = false; } char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; int levelDeltaNext = 0; const unsigned int nComL = 3; // defines how many comment lines should be before they are folded Sci_Position nComColB[nComL] = {}; Sci_Position nComColF[nComL] = {}; Sci_Position nComCur = 0; bool comLineB[nComL] = {}; bool comLineF[nComL] = {}; bool comLineCur; Sci_Position nLineTotal = styler.GetLine(styler.Length()-1) + 1; if (foldComment) { for (unsigned int i=0; i= nLineTotal) { comLineF[i] = false; break; } GetIfLineComment(styler, isFixFormat, chL, comLineF[i], nComColF[i]); } GetIfLineComment(styler, isFixFormat, lineCurrent, comLineCur, nComCur); CheckBackComLines(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur, comLineB, comLineF, comLineCur); } int levelCurrent = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; /***************************************/ Sci_Position lastStart = 0; char prevWord[32] = ""; /***************************************/ for (Sci_PositionU i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); char chNextNonBlank = chNext; bool nextEOL = false; if (IsALineEnd(chNextNonBlank)) { nextEOL = true; } Sci_PositionU j=i+1; while(IsABlank(chNextNonBlank) && j(tolower(styler[lastStart+k])); } s[k] = '\0'; // Handle the forall and where statement and structure. if (strcmp(s, "forall") == 0 || (strcmp(s, "where") == 0 && strcmp(prevWord, "else") != 0)) { if (strcmp(prevWord, "end") != 0) { j = i + 1; char chBrace = '(', chSeek = ')', ch1 = styler.SafeGetCharAt(j); // Find the position of the first ( while (ch1 != chBrace && j 0) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); lineCurrent++; levelCurrent += levelDeltaNext; levelDeltaNext = 0; visibleChars = 0; strcpy(prevWord, ""); isPrevLine = false; if (foldComment) { StepCommentLine(styler, isFixFormat, lineCurrent, nComL, nComColB, nComColF, nComCur, comLineB, comLineF, comLineCur); } } /***************************************/ if (!isspacechar(ch)) visibleChars++; } /***************************************/ } /***************************************/ static const char * const FortranWordLists[] = { "Primary keywords and identifiers", "Intrinsic functions", "Extended and user defined functions", 0, }; /***************************************/ static void ColouriseFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, false); } /***************************************/ static void ColouriseFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, true); } /***************************************/ static void FoldFortranDocFreeFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler) { FoldFortranDoc(startPos, length, initStyle,styler, false); } /***************************************/ static void FoldFortranDocFixFormat(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler) { FoldFortranDoc(startPos, length, initStyle,styler, true); } /***************************************/ extern const LexerModule lmFortran(SCLEX_FORTRAN, ColouriseFortranDocFreeFormat, "fortran", FoldFortranDocFreeFormat, FortranWordLists); extern const LexerModule lmF77(SCLEX_F77, ColouriseFortranDocFixFormat, "f77", FoldFortranDocFixFormat, FortranWordLists);