/pnwtl/third_party/scintilla/lexers/LexVerilog.cxx

https://code.google.com/p/pnotepad/ · C++ · 334 lines · 289 code · 22 blank · 23 comment · 204 complexity · c46e5d6806ca81c07181edf83c760209 MD5 · raw file

  1. // Scintilla source code edit control
  2. /** @file LexVerilog.cxx
  3. ** Lexer for Verilog.
  4. ** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson
  5. **/
  6. // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
  7. // The License.txt file describes the conditions under which this software may be distributed.
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <assert.h>
  13. #include <ctype.h>
  14. #include "ILexer.h"
  15. #include "Scintilla.h"
  16. #include "SciLexer.h"
  17. #include "PropSetSimple.h"
  18. #include "WordList.h"
  19. #include "LexAccessor.h"
  20. #include "Accessor.h"
  21. #include "StyleContext.h"
  22. #include "CharacterSet.h"
  23. #include "LexerModule.h"
  24. #ifdef SCI_NAMESPACE
  25. using namespace Scintilla;
  26. #endif
  27. static inline bool IsAWordChar(const int ch) {
  28. return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
  29. }
  30. static inline bool IsAWordStart(const int ch) {
  31. return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$');
  32. }
  33. static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
  34. Accessor &styler) {
  35. WordList &keywords = *keywordlists[0];
  36. WordList &keywords2 = *keywordlists[1];
  37. WordList &keywords3 = *keywordlists[2];
  38. WordList &keywords4 = *keywordlists[3];
  39. // Do not leak onto next line
  40. if (initStyle == SCE_V_STRINGEOL)
  41. initStyle = SCE_V_DEFAULT;
  42. StyleContext sc(startPos, length, initStyle, styler);
  43. for (; sc.More(); sc.Forward()) {
  44. if (sc.atLineStart && (sc.state == SCE_V_STRING)) {
  45. // Prevent SCE_V_STRINGEOL from leaking back to previous line
  46. sc.SetState(SCE_V_STRING);
  47. }
  48. // Handle line continuation generically.
  49. if (sc.ch == '\\') {
  50. if (sc.chNext == '\n' || sc.chNext == '\r') {
  51. sc.Forward();
  52. if (sc.ch == '\r' && sc.chNext == '\n') {
  53. sc.Forward();
  54. }
  55. continue;
  56. }
  57. }
  58. // Determine if the current state should terminate.
  59. if (sc.state == SCE_V_OPERATOR) {
  60. sc.SetState(SCE_V_DEFAULT);
  61. } else if (sc.state == SCE_V_NUMBER) {
  62. if (!IsAWordChar(sc.ch)) {
  63. sc.SetState(SCE_V_DEFAULT);
  64. }
  65. } else if (sc.state == SCE_V_IDENTIFIER) {
  66. if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
  67. char s[100];
  68. sc.GetCurrent(s, sizeof(s));
  69. if (keywords.InList(s)) {
  70. sc.ChangeState(SCE_V_WORD);
  71. } else if (keywords2.InList(s)) {
  72. sc.ChangeState(SCE_V_WORD2);
  73. } else if (keywords3.InList(s)) {
  74. sc.ChangeState(SCE_V_WORD3);
  75. } else if (keywords4.InList(s)) {
  76. sc.ChangeState(SCE_V_USER);
  77. }
  78. sc.SetState(SCE_V_DEFAULT);
  79. }
  80. } else if (sc.state == SCE_V_PREPROCESSOR) {
  81. if (!IsAWordChar(sc.ch)) {
  82. sc.SetState(SCE_V_DEFAULT);
  83. }
  84. } else if (sc.state == SCE_V_COMMENT) {
  85. if (sc.Match('*', '/')) {
  86. sc.Forward();
  87. sc.ForwardSetState(SCE_V_DEFAULT);
  88. }
  89. } else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) {
  90. if (sc.atLineStart) {
  91. sc.SetState(SCE_V_DEFAULT);
  92. }
  93. } else if (sc.state == SCE_V_STRING) {
  94. if (sc.ch == '\\') {
  95. if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
  96. sc.Forward();
  97. }
  98. } else if (sc.ch == '\"') {
  99. sc.ForwardSetState(SCE_V_DEFAULT);
  100. } else if (sc.atLineEnd) {
  101. sc.ChangeState(SCE_V_STRINGEOL);
  102. sc.ForwardSetState(SCE_V_DEFAULT);
  103. }
  104. }
  105. // Determine if a new state should be entered.
  106. if (sc.state == SCE_V_DEFAULT) {
  107. if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
  108. sc.SetState(SCE_V_NUMBER);
  109. } else if (IsAWordStart(sc.ch)) {
  110. sc.SetState(SCE_V_IDENTIFIER);
  111. } else if (sc.Match('/', '*')) {
  112. sc.SetState(SCE_V_COMMENT);
  113. sc.Forward(); // Eat the * so it isn't used for the end of the comment
  114. } else if (sc.Match('/', '/')) {
  115. if (sc.Match("//!")) // Nice to have a different comment style
  116. sc.SetState(SCE_V_COMMENTLINEBANG);
  117. else
  118. sc.SetState(SCE_V_COMMENTLINE);
  119. } else if (sc.ch == '\"') {
  120. sc.SetState(SCE_V_STRING);
  121. } else if (sc.ch == '`') {
  122. sc.SetState(SCE_V_PREPROCESSOR);
  123. // Skip whitespace between ` and preprocessor word
  124. do {
  125. sc.Forward();
  126. } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
  127. if (sc.atLineEnd) {
  128. sc.SetState(SCE_V_DEFAULT);
  129. }
  130. } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
  131. sc.SetState(SCE_V_OPERATOR);
  132. }
  133. }
  134. }
  135. sc.Complete();
  136. }
  137. static bool IsStreamCommentStyle(int style) {
  138. return style == SCE_V_COMMENT;
  139. }
  140. static bool IsCommentLine(int line, Accessor &styler) {
  141. int pos = styler.LineStart(line);
  142. int eolPos = styler.LineStart(line + 1) - 1;
  143. for (int i = pos; i < eolPos; i++) {
  144. char ch = styler[i];
  145. char chNext = styler.SafeGetCharAt(i + 1);
  146. int style = styler.StyleAt(i);
  147. if (ch == '/' && chNext == '/' &&
  148. (style == SCE_V_COMMENTLINE || style == SCE_V_COMMENTLINEBANG)) {
  149. return true;
  150. } else if (!IsASpaceOrTab(ch)) {
  151. return false;
  152. }
  153. }
  154. return false;
  155. }
  156. // Store both the current line's fold level and the next lines in the
  157. // level store to make it easy to pick up with each increment
  158. // and to make it possible to fiddle the current level for "} else {".
  159. static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
  160. Accessor &styler) {
  161. bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
  162. bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
  163. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  164. bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
  165. // Verilog specific folding options:
  166. // fold_at_module -
  167. // Generally used methodology in verilog code is
  168. // one module per file, so folding at module definition is useless.
  169. // fold_at_brace/parenthese -
  170. // Folding of long port lists can be convenient.
  171. bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
  172. bool foldAtBrace = 1;
  173. bool foldAtParenthese = 1;
  174. unsigned int endPos = startPos + length;
  175. int visibleChars = 0;
  176. int lineCurrent = styler.GetLine(startPos);
  177. int levelCurrent = SC_FOLDLEVELBASE;
  178. if (lineCurrent > 0)
  179. levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
  180. int levelMinCurrent = levelCurrent;
  181. int levelNext = levelCurrent;
  182. char chNext = styler[startPos];
  183. int styleNext = styler.StyleAt(startPos);
  184. int style = initStyle;
  185. for (unsigned int i = startPos; i < endPos; i++) {
  186. char ch = chNext;
  187. chNext = styler.SafeGetCharAt(i + 1);
  188. int stylePrev = style;
  189. style = styleNext;
  190. styleNext = styler.StyleAt(i + 1);
  191. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  192. if (foldComment && IsStreamCommentStyle(style)) {
  193. if (!IsStreamCommentStyle(stylePrev)) {
  194. levelNext++;
  195. } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
  196. // Comments don't end at end of line and the next character may be unstyled.
  197. levelNext--;
  198. }
  199. }
  200. if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
  201. {
  202. if (!IsCommentLine(lineCurrent - 1, styler)
  203. && IsCommentLine(lineCurrent + 1, styler))
  204. levelNext++;
  205. else if (IsCommentLine(lineCurrent - 1, styler)
  206. && !IsCommentLine(lineCurrent+1, styler))
  207. levelNext--;
  208. }
  209. if (foldComment && (style == SCE_V_COMMENTLINE)) {
  210. if ((ch == '/') && (chNext == '/')) {
  211. char chNext2 = styler.SafeGetCharAt(i + 2);
  212. if (chNext2 == '{') {
  213. levelNext++;
  214. } else if (chNext2 == '}') {
  215. levelNext--;
  216. }
  217. }
  218. }
  219. if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
  220. if (ch == '`') {
  221. unsigned int j = i + 1;
  222. while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
  223. j++;
  224. }
  225. if (styler.Match(j, "if")) {
  226. levelNext++;
  227. } else if (styler.Match(j, "end")) {
  228. levelNext--;
  229. }
  230. }
  231. }
  232. if (style == SCE_V_OPERATOR) {
  233. if (foldAtParenthese) {
  234. if (ch == '(') {
  235. levelNext++;
  236. } else if (ch == ')') {
  237. levelNext--;
  238. }
  239. }
  240. }
  241. if (style == SCE_V_OPERATOR) {
  242. if (foldAtBrace) {
  243. if (ch == '{') {
  244. levelNext++;
  245. } else if (ch == '}') {
  246. levelNext--;
  247. }
  248. }
  249. }
  250. if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
  251. unsigned int j = i;
  252. if (styler.Match(j, "case") ||
  253. styler.Match(j, "casex") ||
  254. styler.Match(j, "casez") ||
  255. styler.Match(j, "function") ||
  256. styler.Match(j, "fork") ||
  257. styler.Match(j, "table") ||
  258. styler.Match(j, "task") ||
  259. styler.Match(j, "generate") ||
  260. styler.Match(j, "specify") ||
  261. styler.Match(j, "primitive") ||
  262. (styler.Match(j, "module") && foldAtModule) ||
  263. styler.Match(j, "begin")) {
  264. levelNext++;
  265. } else if (styler.Match(j, "endcase") ||
  266. styler.Match(j, "endfunction") ||
  267. styler.Match(j, "join") ||
  268. styler.Match(j, "endtask") ||
  269. styler.Match(j, "endgenerate") ||
  270. styler.Match(j, "endtable") ||
  271. styler.Match(j, "endspecify") ||
  272. styler.Match(j, "endprimitive") ||
  273. (styler.Match(j, "endmodule") && foldAtModule) ||
  274. (styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) {
  275. levelNext--;
  276. }
  277. }
  278. if (atEOL) {
  279. int levelUse = levelCurrent;
  280. if (foldAtElse) {
  281. levelUse = levelMinCurrent;
  282. }
  283. int lev = levelUse | levelNext << 16;
  284. if (visibleChars == 0 && foldCompact)
  285. lev |= SC_FOLDLEVELWHITEFLAG;
  286. if (levelUse < levelNext)
  287. lev |= SC_FOLDLEVELHEADERFLAG;
  288. if (lev != styler.LevelAt(lineCurrent)) {
  289. styler.SetLevel(lineCurrent, lev);
  290. }
  291. lineCurrent++;
  292. levelCurrent = levelNext;
  293. levelMinCurrent = levelCurrent;
  294. visibleChars = 0;
  295. }
  296. if (!isspacechar(ch))
  297. visibleChars++;
  298. }
  299. }
  300. static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
  301. Accessor &styler) {
  302. FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
  303. }
  304. static const char * const verilogWordLists[] = {
  305. "Primary keywords and identifiers",
  306. "Secondary keywords and identifiers",
  307. "System Tasks",
  308. "User defined tasks and identifiers",
  309. "Unused",
  310. 0,
  311. };
  312. LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);