LexDMAP.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Scintilla source code edit control
  2. /** @file LexDMAP.cxx
  3. ** Lexer for MSC Nastran DMAP.
  4. ** Written by Mark Robinson, based on the Fortran lexer by Chuan-jian Shen, Last changed Aug. 2013
  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. #include "WordList.h"
  20. #include "LexAccessor.h"
  21. #include "Accessor.h"
  22. #include "StyleContext.h"
  23. #include "CharacterSet.h"
  24. #include "LexerModule.h"
  25. /***************************************/
  26. #ifdef SCI_NAMESPACE
  27. using namespace Scintilla;
  28. #endif
  29. /***********************************************/
  30. static inline bool IsAWordChar(const int ch) {
  31. return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
  32. }
  33. /**********************************************/
  34. static inline bool IsAWordStart(const int ch) {
  35. return (ch < 0x80) && (isalnum(ch));
  36. }
  37. /***************************************/
  38. static void ColouriseDMAPDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
  39. WordList *keywordlists[], Accessor &styler) {
  40. WordList &keywords = *keywordlists[0];
  41. WordList &keywords2 = *keywordlists[1];
  42. WordList &keywords3 = *keywordlists[2];
  43. /***************************************/
  44. Sci_Position posLineStart = 0, numNonBlank = 0;
  45. Sci_Position endPos = startPos + length;
  46. /***************************************/
  47. // backtrack to the nearest keyword
  48. while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_DMAP_WORD)) {
  49. startPos--;
  50. }
  51. startPos = styler.LineStart(styler.GetLine(startPos));
  52. initStyle = styler.StyleAt(startPos - 1);
  53. StyleContext sc(startPos, endPos-startPos, initStyle, styler);
  54. /***************************************/
  55. for (; sc.More(); sc.Forward()) {
  56. // remember the start position of the line
  57. if (sc.atLineStart) {
  58. posLineStart = sc.currentPos;
  59. numNonBlank = 0;
  60. sc.SetState(SCE_DMAP_DEFAULT);
  61. }
  62. if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
  63. /***********************************************/
  64. // Handle data appearing after column 72; it is ignored
  65. Sci_Position toLineStart = sc.currentPos - posLineStart;
  66. if (toLineStart >= 72 || sc.ch == '$') {
  67. sc.SetState(SCE_DMAP_COMMENT);
  68. while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
  69. continue;
  70. }
  71. /***************************************/
  72. // Determine if the current state should terminate.
  73. if (sc.state == SCE_DMAP_OPERATOR) {
  74. sc.SetState(SCE_DMAP_DEFAULT);
  75. } else if (sc.state == SCE_DMAP_NUMBER) {
  76. if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) {
  77. sc.SetState(SCE_DMAP_DEFAULT);
  78. }
  79. } else if (sc.state == SCE_DMAP_IDENTIFIER) {
  80. if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
  81. char s[100];
  82. sc.GetCurrentLowered(s, sizeof(s));
  83. if (keywords.InList(s)) {
  84. sc.ChangeState(SCE_DMAP_WORD);
  85. } else if (keywords2.InList(s)) {
  86. sc.ChangeState(SCE_DMAP_WORD2);
  87. } else if (keywords3.InList(s)) {
  88. sc.ChangeState(SCE_DMAP_WORD3);
  89. }
  90. sc.SetState(SCE_DMAP_DEFAULT);
  91. }
  92. } else if (sc.state == SCE_DMAP_COMMENT) {
  93. if (sc.ch == '\r' || sc.ch == '\n') {
  94. sc.SetState(SCE_DMAP_DEFAULT);
  95. }
  96. } else if (sc.state == SCE_DMAP_STRING1) {
  97. if (sc.ch == '\'') {
  98. if (sc.chNext == '\'') {
  99. sc.Forward();
  100. } else {
  101. sc.ForwardSetState(SCE_DMAP_DEFAULT);
  102. }
  103. } else if (sc.atLineEnd) {
  104. sc.ChangeState(SCE_DMAP_STRINGEOL);
  105. sc.ForwardSetState(SCE_DMAP_DEFAULT);
  106. }
  107. } else if (sc.state == SCE_DMAP_STRING2) {
  108. if (sc.atLineEnd) {
  109. sc.ChangeState(SCE_DMAP_STRINGEOL);
  110. sc.ForwardSetState(SCE_DMAP_DEFAULT);
  111. } else if (sc.ch == '\"') {
  112. if (sc.chNext == '\"') {
  113. sc.Forward();
  114. } else {
  115. sc.ForwardSetState(SCE_DMAP_DEFAULT);
  116. }
  117. }
  118. }
  119. /***************************************/
  120. // Determine if a new state should be entered.
  121. if (sc.state == SCE_DMAP_DEFAULT) {
  122. if (sc.ch == '$') {
  123. sc.SetState(SCE_DMAP_COMMENT);
  124. } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)) || (sc.ch == '-' && IsADigit(sc.chNext))) {
  125. sc.SetState(SCE_F_NUMBER);
  126. } else if (IsAWordStart(sc.ch)) {
  127. sc.SetState(SCE_DMAP_IDENTIFIER);
  128. } else if (sc.ch == '\"') {
  129. sc.SetState(SCE_DMAP_STRING2);
  130. } else if (sc.ch == '\'') {
  131. sc.SetState(SCE_DMAP_STRING1);
  132. } else if (isoperator(static_cast<char>(sc.ch))) {
  133. sc.SetState(SCE_DMAP_OPERATOR);
  134. }
  135. }
  136. }
  137. sc.Complete();
  138. }
  139. /***************************************/
  140. // To determine the folding level depending on keywords
  141. static int classifyFoldPointDMAP(const char* s, const char* prevWord) {
  142. int lev = 0;
  143. if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "enddo") == 0 || strcmp(s, "endif") == 0) {
  144. lev = -1;
  145. } else if ((strcmp(prevWord, "do") == 0 && strcmp(s, "while") == 0) || strcmp(s, "then") == 0) {
  146. lev = 1;
  147. }
  148. return lev;
  149. }
  150. // Folding the code
  151. static void FoldDMAPDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
  152. WordList *[], Accessor &styler) {
  153. //
  154. // bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
  155. // Do not know how to fold the comment at the moment.
  156. //
  157. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  158. Sci_PositionU endPos = startPos + length;
  159. int visibleChars = 0;
  160. Sci_Position lineCurrent = styler.GetLine(startPos);
  161. int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
  162. int levelCurrent = levelPrev;
  163. char chNext = styler[startPos];
  164. int styleNext = styler.StyleAt(startPos);
  165. int style = initStyle;
  166. /***************************************/
  167. Sci_Position lastStart = 0;
  168. char prevWord[32] = "";
  169. /***************************************/
  170. for (Sci_PositionU i = startPos; i < endPos; i++) {
  171. char ch = chNext;
  172. chNext = styler.SafeGetCharAt(i + 1);
  173. int stylePrev = style;
  174. style = styleNext;
  175. styleNext = styler.StyleAt(i + 1);
  176. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  177. //
  178. if ((stylePrev == SCE_DMAP_DEFAULT || stylePrev == SCE_DMAP_OPERATOR || stylePrev == SCE_DMAP_COMMENT) && (style == SCE_DMAP_WORD)) {
  179. // Store last word and label start point.
  180. lastStart = i;
  181. }
  182. /***************************************/
  183. if (style == SCE_DMAP_WORD) {
  184. if(iswordchar(ch) && !iswordchar(chNext)) {
  185. char s[32];
  186. Sci_PositionU k;
  187. for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
  188. s[k] = static_cast<char>(tolower(styler[lastStart+k]));
  189. }
  190. s[k] = '\0';
  191. levelCurrent += classifyFoldPointDMAP(s, prevWord);
  192. strcpy(prevWord, s);
  193. }
  194. }
  195. if (atEOL) {
  196. int lev = levelPrev;
  197. if (visibleChars == 0 && foldCompact)
  198. lev |= SC_FOLDLEVELWHITEFLAG;
  199. if ((levelCurrent > levelPrev) && (visibleChars > 0))
  200. lev |= SC_FOLDLEVELHEADERFLAG;
  201. if (lev != styler.LevelAt(lineCurrent)) {
  202. styler.SetLevel(lineCurrent, lev);
  203. }
  204. lineCurrent++;
  205. levelPrev = levelCurrent;
  206. visibleChars = 0;
  207. strcpy(prevWord, "");
  208. }
  209. /***************************************/
  210. if (!isspacechar(ch)) visibleChars++;
  211. }
  212. /***************************************/
  213. // Fill in the real level of the next line, keeping the current flags as they will be filled in later
  214. int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
  215. styler.SetLevel(lineCurrent, levelPrev | flagsNext);
  216. }
  217. /***************************************/
  218. static const char * const DMAPWordLists[] = {
  219. "Primary keywords and identifiers",
  220. "Intrinsic functions",
  221. "Extended and user defined functions",
  222. 0,
  223. };
  224. /***************************************/
  225. LexerModule lmDMAP(SCLEX_DMAP, ColouriseDMAPDoc, "DMAP", FoldDMAPDoc, DMAPWordLists);