sh_pas.pp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. {
  2. "SHEdit" - Text editor with syntax highlighting
  3. Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. }
  10. // Syntax highlighting class for Pascal sources
  11. // !!! Slightly modified version for fpDoc !!!
  12. {$MODE objfpc}
  13. {$H+}
  14. {$IFDEF Debug}
  15. {$ASSERTIONS On}
  16. {$ENDIF}
  17. unit sh_pas;
  18. interface
  19. const
  20. LF_SH_Valid = $01;
  21. LF_SH_Multiline1 = $02;
  22. LF_SH_Multiline2 = $04;
  23. LF_SH_Multiline3 = $08;
  24. LF_SH_Multiline4 = $10;
  25. LF_SH_Multiline5 = $20;
  26. LF_SH_Multiline6 = $40;
  27. LF_SH_Multiline7 = $80;
  28. LF_Escape = #10;
  29. shDefault = 1;
  30. shInvalid = 2;
  31. shSymbol = 3;
  32. shKeyword = 4;
  33. shComment = 5;
  34. shDirective = 6;
  35. shNumbers = 7;
  36. shCharacters = 8;
  37. shStrings = 9;
  38. shAssembler = 10;
  39. procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
  40. implementation
  41. uses Strings;
  42. const
  43. LF_SH_Comment1 = LF_SH_Multiline1; { Normal braced Comments}
  44. LF_SH_Comment2 = LF_SH_Multiline2; { (* *) Comments}
  45. LF_SH_Asm = LF_SH_Multiline3;
  46. MaxKeywordLength = 15;
  47. MaxKeyword = 60;
  48. KeywordTable: array[0..MaxKeyword] of String =
  49. ('AND', 'ARRAY', 'ASM', 'ASSEMBLER',
  50. 'BEGIN', 'BREAK',
  51. 'CASE', 'CONST', 'CONSTRUCTOR', 'CLASS',
  52. 'DEFAULT', 'DESTRUCTOR', 'DIV', 'DO', 'DOWNTO',
  53. 'ELSE', 'END', 'EXCEPT', 'EXIT',
  54. 'FINALIZATION', 'FINALLY', 'FOR', 'FUNCTION',
  55. 'GOTO',
  56. 'IF', 'IMPLEMENTATION', 'IN', 'INHERITED', 'INITIALIZATION', 'INTERFACE',
  57. 'NIL', 'NOT',
  58. 'OBJECT', 'OF', 'ON', 'OR', 'OVERRIDE',
  59. 'PACKED', 'PRIVATE', 'PROCEDURE', 'PROGRAM', 'PROPERTY', 'PROTECTED',
  60. 'PUBLIC', 'PUBLISHED',
  61. 'RAISE', 'RECORD', 'REPEAT', 'RESOURCESTRING',
  62. 'SET',
  63. 'THEN', 'TRY', 'TYPE',
  64. 'UNIT', 'UNTIL', 'USES',
  65. 'VAR', 'VIRTUAL',
  66. 'WHILE', 'WITH',
  67. 'XOR');
  68. KeywordAsmIndex = 2;
  69. procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
  70. var
  71. dp: Integer; // Destination position - current offset in dest
  72. LastSHPos: Integer; // Position of last highlighting character, or 0
  73. procedure AddSH(sh: Byte);
  74. begin
  75. ASSERT(sh > 0);
  76. if (LastSHPos > 0) and (dp = LastSHPos + 1) then Dec(dp, 2);
  77. dest[dp] := LF_Escape; Inc(dp);
  78. LastSHPos := dp;
  79. dest[dp] := Chr(sh); Inc(dp);
  80. end;
  81. procedure PutChar;
  82. begin
  83. dest[dp] := source[0]; Inc(dp); Inc(source);
  84. end;
  85. procedure PutChars(S : String);
  86. Var
  87. C : char;
  88. begin
  89. for C in S do
  90. begin
  91. dest[dp] := c;
  92. Inc(dp);
  93. Inc(source);
  94. end;
  95. end;
  96. procedure ProcessComment1;
  97. begin
  98. while source[0] <> #0 do begin
  99. if source[0] = '}' then begin
  100. PutChar;
  101. flags := flags and not LF_SH_Comment1;
  102. AddSH(shDefault);
  103. break;
  104. end;
  105. PutChar;
  106. end;
  107. end;
  108. procedure ProcessComment2;
  109. begin
  110. while source[0] <> #0 do begin
  111. if (source[0] = '*') and (source[1] = ')') then begin
  112. PutChar; PutChar;
  113. flags := flags and not LF_SH_Comment2;
  114. AddSH(shDefault);
  115. break;
  116. end;
  117. PutChar;
  118. end;
  119. end;
  120. { Checks if we are at the beginning of a comment (or directive) and processes
  121. all types of comments and directives, or returns False }
  122. function CheckForComment: Boolean;
  123. begin
  124. Result := True;
  125. if source[0] = '{' then begin
  126. if source[1] = '$' then
  127. AddSH(shDirective)
  128. else
  129. AddSH(shComment);
  130. PutChar;
  131. flags := flags or LF_SH_Comment1;
  132. ProcessComment1;
  133. end else if (source[0] = '(') and (source[1] = '*') then begin
  134. AddSH(shComment);
  135. PutChar; PutChar;
  136. flags := flags or LF_SH_Comment2;
  137. ProcessComment2;
  138. end else if (source[0] = '/') and (source[1] = '/') then begin
  139. AddSH(shComment);
  140. repeat PutChar until source[0] = #0;
  141. AddSH(shDefault);
  142. end else
  143. Result := False;
  144. end;
  145. procedure ProcessAsm;
  146. var
  147. LastChar: Char;
  148. begin
  149. LastChar := ' ';
  150. while source[0] <> #0 do begin
  151. if (LastChar in [' ', #9, #10, #13]) and
  152. (UpCase(source[0]) = 'E') and (UpCase(source[1]) = 'N') and
  153. (UpCase(source[2]) = 'D') then begin
  154. AddSH(shKeyword);
  155. PutChar; PutChar; PutChar;
  156. flags := flags and not LF_SH_Asm;
  157. AddSH(shDefault);
  158. break;
  159. end else
  160. if CheckForComment then LastChar := ' '
  161. else begin
  162. LastChar := source[0];
  163. PutChar;
  164. end;
  165. end;
  166. end;
  167. procedure ProcessSymbol;
  168. begin
  169. AddSH(shSymbol);
  170. if (source[0] = ':') and (source[1] = '=') then
  171. PutChar;
  172. PutChar;
  173. AddSH(shDefault);
  174. end;
  175. function CheckForKeyword: Boolean;
  176. var
  177. keyword, ukeyword: string;
  178. i, j: Integer;
  179. begin
  180. i := 1;
  181. SetLength(KeyWord,MaxKeywordLength);
  182. SetLength(UKeyWord,MaxKeywordLength);
  183. while (source[i] <> #0) and (i <= MaxKeywordLength) and
  184. (source[i] in ['0'..'9', 'A'..'Z', 'a'..'z']) do begin
  185. keyword[i] := source[i];
  186. ukeyword[i] := UpCase(source[i]);
  187. Inc(i);
  188. end;
  189. SetLength(keyword,I-1);
  190. SetLength(ukeyword,I-1);
  191. Result := False;
  192. if i < MaxKeywordLength then
  193. for j := 0 to MaxKeyword do
  194. if KeywordTable[j]=ukeyword then begin
  195. Result := True; break;
  196. end;
  197. if not Result then exit;
  198. Inc(source, i);
  199. AddSH(shKeyword);
  200. PutChars(keyword);
  201. if j <> KeywordAsmIndex then
  202. AddSH(shDefault)
  203. else begin
  204. AddSH(shAssembler);
  205. flags := flags or LF_SH_Asm;
  206. ProcessAsm;
  207. end;
  208. end;
  209. var
  210. StringLength: Integer;
  211. begin
  212. dp := 0;
  213. LastSHPos := 0;
  214. if (flags and LF_SH_Comment1) <> 0 then begin
  215. AddSH(shComment);
  216. ProcessComment1;
  217. end;
  218. if (flags and LF_SH_Comment2) <> 0 then begin
  219. AddSH(shComment);
  220. ProcessComment2;
  221. end;
  222. if (flags and LF_SH_Asm) <> 0 then begin
  223. AddSH(shAssembler);
  224. ProcessAsm;
  225. end;
  226. while source[0] <> #0 do begin
  227. if CheckForComment then continue;
  228. case source[0] of
  229. ',', ';', ':', '.', '(', ')', '[', ']', '<', '>', '=',
  230. '*', '/', '+', '-', '^', '&', '@': ProcessSymbol;
  231. '#': begin
  232. AddSH(shCharacters);
  233. PutChar;
  234. if source[0] = '$' then PutChar;
  235. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  236. AddSH(shDefault);
  237. end;
  238. '$': begin
  239. AddSH(shNumbers);
  240. PutChar;
  241. while source[0] in ['0'..'9', 'A'..'F', 'a'..'f'] do PutChar;
  242. AddSH(shDefault);
  243. end;
  244. '0'..'9': begin
  245. AddSH(shNumbers);
  246. PutChar;
  247. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  248. AddSH(shDefault);
  249. end;
  250. '''': begin
  251. AddSH(shStrings);
  252. PutChar;
  253. StringLength := 0;
  254. while source[0] <> #0 do begin
  255. if source[0] = '''' then
  256. if source[1] = '''' then PutChar
  257. else begin
  258. PutChar; break;
  259. end;
  260. Inc(StringLength);
  261. PutChar;
  262. end;
  263. if StringLength = 1 then
  264. dest[LastSHPos] := Chr(shCharacters);
  265. if (source[0] = #0) and (dest[dp - 1] <> '''') then
  266. dest[LastSHPos] := Chr(shInvalid);
  267. AddSH(shDefault);
  268. end;
  269. '_', 'A'..'Z', 'a'..'z': begin
  270. if not CheckForKeyword then
  271. repeat
  272. PutChar
  273. until not (source[0] in ['0'..'9', '_', 'A'..'Z', 'a'..'z']);
  274. end;
  275. ' ': PutChar;
  276. else begin
  277. AddSH(shInvalid);
  278. PutChar; // = found an invalid char!
  279. AddSH(shDefault);
  280. end;
  281. end;
  282. end;
  283. dest[dp] := #0;
  284. end;
  285. end.