PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Tools/MaterialEditor/wxscintilla_1.69.2/src/scintilla/src/LexAda.cxx

https://bitbucket.org/CaptainOz/ogre
C++ | 520 lines | 391 code | 87 blank | 42 comment | 141 complexity | 765fcd786995ac3ea50e97a0a0598ec6 MD5 | raw file
Possible License(s): LGPL-2.1, MIT
  1. // Scintilla source code edit control
  2. /** @file LexAda.cxx
  3. ** Lexer for Ada 95
  4. **/
  5. // Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
  6. // The License.txt file describes the conditions under which this software may be distributed.
  7. #include <stdlib.h>
  8. #include <ctype.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include "Platform.h"
  12. #include "Accessor.h"
  13. #include "StyleContext.h"
  14. #include "PropSet.h"
  15. #include "KeyWords.h"
  16. #include "SciLexer.h"
  17. #include "SString.h"
  18. /*
  19. * Interface
  20. */
  21. static void ColouriseDocument(
  22. unsigned int startPos,
  23. int length,
  24. int initStyle,
  25. WordList *keywordlists[],
  26. Accessor &styler);
  27. static const char * const adaWordListDesc[] = {
  28. "Keywords",
  29. 0
  30. };
  31. LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);
  32. /*
  33. * Implementation
  34. */
  35. // Functions that have apostropheStartsAttribute as a parameter set it according to whether
  36. // an apostrophe encountered after processing the current token will start an attribute or
  37. // a character literal.
  38. static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
  39. static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
  40. static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
  41. static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
  42. static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
  43. static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
  44. static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
  45. static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
  46. static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
  47. static inline bool IsDelimiterCharacter(int ch);
  48. static inline bool IsNumberStartCharacter(int ch);
  49. static inline bool IsNumberCharacter(int ch);
  50. static inline bool IsSeparatorOrDelimiterCharacter(int ch);
  51. static bool IsValidIdentifier(const SString& identifier);
  52. static bool IsValidNumber(const SString& number);
  53. static inline bool IsWordStartCharacter(int ch);
  54. static inline bool IsWordCharacter(int ch);
  55. static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
  56. apostropheStartsAttribute = true;
  57. sc.SetState(SCE_ADA_CHARACTER);
  58. // Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
  59. // is handled correctly)
  60. sc.Forward();
  61. sc.Forward();
  62. ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
  63. }
  64. static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
  65. while (!sc.atLineEnd && !sc.Match(chEnd)) {
  66. sc.Forward();
  67. }
  68. if (!sc.atLineEnd) {
  69. sc.ForwardSetState(SCE_ADA_DEFAULT);
  70. } else {
  71. sc.ChangeState(stateEOL);
  72. }
  73. }
  74. static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
  75. // Apostrophe meaning is not changed, but the parameter is present for uniformity
  76. sc.SetState(SCE_ADA_COMMENTLINE);
  77. while (!sc.atLineEnd) {
  78. sc.Forward();
  79. }
  80. }
  81. static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
  82. apostropheStartsAttribute = sc.Match (')');
  83. sc.SetState(SCE_ADA_DELIMITER);
  84. sc.ForwardSetState(SCE_ADA_DEFAULT);
  85. }
  86. static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
  87. apostropheStartsAttribute = false;
  88. sc.SetState(SCE_ADA_LABEL);
  89. // Skip "<<"
  90. sc.Forward();
  91. sc.Forward();
  92. SString identifier;
  93. while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
  94. identifier += static_cast<char>(tolower(sc.ch));
  95. sc.Forward();
  96. }
  97. // Skip ">>"
  98. if (sc.Match('>', '>')) {
  99. sc.Forward();
  100. sc.Forward();
  101. } else {
  102. sc.ChangeState(SCE_ADA_ILLEGAL);
  103. }
  104. // If the name is an invalid identifier or a keyword, then make it invalid label
  105. if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
  106. sc.ChangeState(SCE_ADA_ILLEGAL);
  107. }
  108. sc.SetState(SCE_ADA_DEFAULT);
  109. }
  110. static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
  111. apostropheStartsAttribute = true;
  112. SString number;
  113. sc.SetState(SCE_ADA_NUMBER);
  114. // Get all characters up to a delimiter or a separator, including points, but excluding
  115. // double points (ranges).
  116. while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
  117. number += static_cast<char>(sc.ch);
  118. sc.Forward();
  119. }
  120. // Special case: exponent with sign
  121. if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
  122. (sc.ch == '+' || sc.ch == '-')) {
  123. number += static_cast<char>(sc.ch);
  124. sc.Forward ();
  125. while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
  126. number += static_cast<char>(sc.ch);
  127. sc.Forward();
  128. }
  129. }
  130. if (!IsValidNumber(number)) {
  131. sc.ChangeState(SCE_ADA_ILLEGAL);
  132. }
  133. sc.SetState(SCE_ADA_DEFAULT);
  134. }
  135. static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
  136. apostropheStartsAttribute = true;
  137. sc.SetState(SCE_ADA_STRING);
  138. sc.Forward();
  139. ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
  140. }
  141. static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
  142. // Apostrophe meaning is not changed, but the parameter is present for uniformity
  143. sc.SetState(SCE_ADA_DEFAULT);
  144. sc.ForwardSetState(SCE_ADA_DEFAULT);
  145. }
  146. static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
  147. apostropheStartsAttribute = true;
  148. sc.SetState(SCE_ADA_IDENTIFIER);
  149. SString word;
  150. while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
  151. word += static_cast<char>(tolower(sc.ch));
  152. sc.Forward();
  153. }
  154. if (!IsValidIdentifier(word)) {
  155. sc.ChangeState(SCE_ADA_ILLEGAL);
  156. } else if (keywords.InList(word.c_str())) {
  157. sc.ChangeState(SCE_ADA_WORD);
  158. if (word != "all") {
  159. apostropheStartsAttribute = false;
  160. }
  161. }
  162. sc.SetState(SCE_ADA_DEFAULT);
  163. }
  164. //
  165. // ColouriseDocument
  166. //
  167. static void ColouriseDocument(
  168. unsigned int startPos,
  169. int length,
  170. int initStyle,
  171. WordList *keywordlists[],
  172. Accessor &styler) {
  173. WordList &keywords = *keywordlists[0];
  174. StyleContext sc(startPos, length, initStyle, styler);
  175. int lineCurrent = styler.GetLine(startPos);
  176. bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
  177. while (sc.More()) {
  178. if (sc.atLineEnd) {
  179. // Go to the next line
  180. sc.Forward();
  181. lineCurrent++;
  182. // Remember the line state for future incremental lexing
  183. styler.SetLineState(lineCurrent, apostropheStartsAttribute);
  184. // Don't continue any styles on the next line
  185. sc.SetState(SCE_ADA_DEFAULT);
  186. }
  187. // Comments
  188. if (sc.Match('-', '-')) {
  189. ColouriseComment(sc, apostropheStartsAttribute);
  190. // Strings
  191. } else if (sc.Match('"')) {
  192. ColouriseString(sc, apostropheStartsAttribute);
  193. // Characters
  194. } else if (sc.Match('\'') && !apostropheStartsAttribute) {
  195. ColouriseCharacter(sc, apostropheStartsAttribute);
  196. // Labels
  197. } else if (sc.Match('<', '<')) {
  198. ColouriseLabel(sc, keywords, apostropheStartsAttribute);
  199. // Whitespace
  200. } else if (IsASpace(sc.ch)) {
  201. ColouriseWhiteSpace(sc, apostropheStartsAttribute);
  202. // Delimiters
  203. } else if (IsDelimiterCharacter(sc.ch)) {
  204. ColouriseDelimiter(sc, apostropheStartsAttribute);
  205. // Numbers
  206. } else if (IsADigit(sc.ch) || sc.ch == '#') {
  207. ColouriseNumber(sc, apostropheStartsAttribute);
  208. // Keywords or identifiers
  209. } else {
  210. ColouriseWord(sc, keywords, apostropheStartsAttribute);
  211. }
  212. }
  213. sc.Complete();
  214. }
  215. static inline bool IsDelimiterCharacter(int ch) {
  216. switch (ch) {
  217. case '&':
  218. case '\'':
  219. case '(':
  220. case ')':
  221. case '*':
  222. case '+':
  223. case ',':
  224. case '-':
  225. case '.':
  226. case '/':
  227. case ':':
  228. case ';':
  229. case '<':
  230. case '=':
  231. case '>':
  232. case '|':
  233. return true;
  234. default:
  235. return false;
  236. }
  237. }
  238. static inline bool IsNumberCharacter(int ch) {
  239. return IsNumberStartCharacter(ch) ||
  240. ch == '_' ||
  241. ch == '.' ||
  242. ch == '#' ||
  243. (ch >= 'a' && ch <= 'f') ||
  244. (ch >= 'A' && ch <= 'F');
  245. }
  246. static inline bool IsNumberStartCharacter(int ch) {
  247. return IsADigit(ch);
  248. }
  249. static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
  250. return IsASpace(ch) || IsDelimiterCharacter(ch);
  251. }
  252. static bool IsValidIdentifier(const SString& identifier) {
  253. // First character can't be '_', so initialize the flag to true
  254. bool lastWasUnderscore = true;
  255. size_t length = identifier.length();
  256. // Zero-length identifiers are not valid (these can occur inside labels)
  257. if (length == 0) {
  258. return false;
  259. }
  260. // Check for valid character at the start
  261. if (!IsWordStartCharacter(identifier[0])) {
  262. return false;
  263. }
  264. // Check for only valid characters and no double underscores
  265. for (size_t i = 0; i < length; i++) {
  266. if (!IsWordCharacter(identifier[i]) ||
  267. (identifier[i] == '_' && lastWasUnderscore)) {
  268. return false;
  269. }
  270. lastWasUnderscore = identifier[i] == '_';
  271. }
  272. // Check for underscore at the end
  273. if (lastWasUnderscore == true) {
  274. return false;
  275. }
  276. // All checks passed
  277. return true;
  278. }
  279. static bool IsValidNumber(const SString& number) {
  280. int hashPos = number.search("#");
  281. bool seenDot = false;
  282. size_t i = 0;
  283. size_t length = number.length();
  284. if (length == 0)
  285. return false; // Just in case
  286. // Decimal number
  287. if (hashPos == -1) {
  288. bool canBeSpecial = false;
  289. for (; i < length; i++) {
  290. if (number[i] == '_') {
  291. if (!canBeSpecial) {
  292. return false;
  293. }
  294. canBeSpecial = false;
  295. } else if (number[i] == '.') {
  296. if (!canBeSpecial || seenDot) {
  297. return false;
  298. }
  299. canBeSpecial = false;
  300. seenDot = true;
  301. } else if (IsADigit(number[i])) {
  302. canBeSpecial = true;
  303. } else {
  304. break;
  305. }
  306. }
  307. if (!canBeSpecial)
  308. return false;
  309. } else {
  310. // Based number
  311. bool canBeSpecial = false;
  312. int base = 0;
  313. // Parse base
  314. for (; i < length; i++) {
  315. int ch = number[i];
  316. if (ch == '_') {
  317. if (!canBeSpecial)
  318. return false;
  319. canBeSpecial = false;
  320. } else if (IsADigit(ch)) {
  321. base = base * 10 + (ch - '0');
  322. if (base > 16)
  323. return false;
  324. canBeSpecial = true;
  325. } else if (ch == '#' && canBeSpecial) {
  326. break;
  327. } else {
  328. return false;
  329. }
  330. }
  331. if (base < 2)
  332. return false;
  333. if (i == length)
  334. return false;
  335. i++; // Skip over '#'
  336. // Parse number
  337. canBeSpecial = false;
  338. for (; i < length; i++) {
  339. int ch = tolower(number[i]);
  340. if (ch == '_') {
  341. if (!canBeSpecial) {
  342. return false;
  343. }
  344. canBeSpecial = false;
  345. } else if (ch == '.') {
  346. if (!canBeSpecial || seenDot) {
  347. return false;
  348. }
  349. canBeSpecial = false;
  350. seenDot = true;
  351. } else if (IsADigit(ch)) {
  352. if (ch - '0' >= base) {
  353. return false;
  354. }
  355. canBeSpecial = true;
  356. } else if (ch >= 'a' && ch <= 'f') {
  357. if (ch - 'a' + 10 >= base) {
  358. return false;
  359. }
  360. canBeSpecial = true;
  361. } else if (ch == '#' && canBeSpecial) {
  362. break;
  363. } else {
  364. return false;
  365. }
  366. }
  367. if (i == length) {
  368. return false;
  369. }
  370. i++;
  371. }
  372. // Exponent (optional)
  373. if (i < length) {
  374. if (number[i] != 'e' && number[i] != 'E')
  375. return false;
  376. i++; // Move past 'E'
  377. if (i == length) {
  378. return false;
  379. }
  380. if (number[i] == '+')
  381. i++;
  382. else if (number[i] == '-') {
  383. if (seenDot) {
  384. i++;
  385. } else {
  386. return false; // Integer literals should not have negative exponents
  387. }
  388. }
  389. if (i == length) {
  390. return false;
  391. }
  392. bool canBeSpecial = false;
  393. for (; i < length; i++) {
  394. if (number[i] == '_') {
  395. if (!canBeSpecial) {
  396. return false;
  397. }
  398. canBeSpecial = false;
  399. } else if (IsADigit(number[i])) {
  400. canBeSpecial = true;
  401. } else {
  402. return false;
  403. }
  404. }
  405. if (!canBeSpecial)
  406. return false;
  407. }
  408. // if i == length, number was parsed successfully.
  409. return i == length;
  410. }
  411. static inline bool IsWordCharacter(int ch) {
  412. return IsWordStartCharacter(ch) || IsADigit(ch);
  413. }
  414. static inline bool IsWordStartCharacter(int ch) {
  415. return (isascii(ch) && isalpha(ch)) || ch == '_';
  416. }