sh_pas.pp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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 PChar =
  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 ProcessComment1;
  86. begin
  87. while source[0] <> #0 do begin
  88. if source[0] = '}' then begin
  89. PutChar;
  90. flags := flags and not LF_SH_Comment1;
  91. AddSH(shDefault);
  92. break;
  93. end;
  94. PutChar;
  95. end;
  96. end;
  97. procedure ProcessComment2;
  98. begin
  99. while source[0] <> #0 do begin
  100. if (source[0] = '*') and (source[1] = ')') then begin
  101. PutChar; PutChar;
  102. flags := flags and not LF_SH_Comment2;
  103. AddSH(shDefault);
  104. break;
  105. end;
  106. PutChar;
  107. end;
  108. end;
  109. { Checks if we are at the beginning of a comment (or directive) and processes
  110. all types of comments and directives, or returns False }
  111. function CheckForComment: Boolean;
  112. begin
  113. Result := True;
  114. if source[0] = '{' then begin
  115. if source[1] = '$' then
  116. AddSH(shDirective)
  117. else
  118. AddSH(shComment);
  119. PutChar;
  120. flags := flags or LF_SH_Comment1;
  121. ProcessComment1;
  122. end else if (source[0] = '(') and (source[1] = '*') then begin
  123. AddSH(shComment);
  124. PutChar; PutChar;
  125. flags := flags or LF_SH_Comment2;
  126. ProcessComment2;
  127. end else if (source[0] = '/') and (source[1] = '/') then begin
  128. AddSH(shComment);
  129. repeat PutChar until source[0] = #0;
  130. AddSH(shDefault);
  131. end else
  132. Result := False;
  133. end;
  134. procedure ProcessAsm;
  135. var
  136. LastChar: Char;
  137. begin
  138. LastChar := ' ';
  139. while source[0] <> #0 do begin
  140. if (LastChar in [' ', #9, #10, #13]) and
  141. (UpCase(source[0]) = 'E') and (UpCase(source[1]) = 'N') and
  142. (UpCase(source[2]) = 'D') then begin
  143. AddSH(shKeyword);
  144. PutChar; PutChar; PutChar;
  145. flags := flags and not LF_SH_Asm;
  146. AddSH(shDefault);
  147. break;
  148. end else
  149. if CheckForComment then LastChar := ' '
  150. else begin
  151. LastChar := source[0];
  152. PutChar;
  153. end;
  154. end;
  155. end;
  156. procedure ProcessSymbol;
  157. begin
  158. AddSH(shSymbol);
  159. if (source[0] = ':') and (source[1] = '=') then
  160. PutChar;
  161. PutChar;
  162. AddSH(shDefault);
  163. end;
  164. function CheckForKeyword: Boolean;
  165. var
  166. keyword, ukeyword: array[0..MaxKeywordLength] of Char;
  167. i, j: Integer;
  168. begin
  169. i := 0;
  170. while (source[i] <> #0) and (i < MaxKeywordLength) and
  171. (source[i] in ['0'..'9', 'A'..'Z', 'a'..'z']) do begin
  172. keyword[i] := source[i];
  173. ukeyword[i] := UpCase(source[i]);
  174. Inc(i);
  175. end;
  176. keyword[i] := #0; ukeyword[i] := #0;
  177. Result := False;
  178. if i < MaxKeywordLength then
  179. for j := 0 to MaxKeyword do
  180. if StrIComp(KeywordTable[j], ukeyword) = 0 then begin
  181. Result := True; break;
  182. end;
  183. if not Result then exit;
  184. Inc(source, i);
  185. AddSH(shKeyword);
  186. StrCopy(dest + dp, keyword);
  187. Inc(dp, i);
  188. if j <> KeywordAsmIndex then
  189. AddSH(shDefault)
  190. else begin
  191. AddSH(shAssembler);
  192. flags := flags or LF_SH_Asm;
  193. ProcessAsm;
  194. end;
  195. end;
  196. var
  197. StringLength: Integer;
  198. begin
  199. dp := 0;
  200. LastSHPos := 0;
  201. if (flags and LF_SH_Comment1) <> 0 then begin
  202. AddSH(shComment);
  203. ProcessComment1;
  204. end;
  205. if (flags and LF_SH_Comment2) <> 0 then begin
  206. AddSH(shComment);
  207. ProcessComment2;
  208. end;
  209. if (flags and LF_SH_Asm) <> 0 then begin
  210. AddSH(shAssembler);
  211. ProcessAsm;
  212. end;
  213. while source[0] <> #0 do begin
  214. if CheckForComment then continue;
  215. case source[0] of
  216. ',', ';', ':', '.', '(', ')', '[', ']', '<', '>', '=',
  217. '*', '/', '+', '-', '^', '&', '@': ProcessSymbol;
  218. '#': begin
  219. AddSH(shCharacters);
  220. PutChar;
  221. if source[0] = '$' then PutChar;
  222. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  223. AddSH(shDefault);
  224. end;
  225. '$': begin
  226. AddSH(shNumbers);
  227. PutChar;
  228. while source[0] in ['0'..'9', 'A'..'F', 'a'..'f'] do PutChar;
  229. AddSH(shDefault);
  230. end;
  231. '0'..'9': begin
  232. AddSH(shNumbers);
  233. PutChar;
  234. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  235. AddSH(shDefault);
  236. end;
  237. '''': begin
  238. AddSH(shStrings);
  239. PutChar;
  240. StringLength := 0;
  241. while source[0] <> #0 do begin
  242. if source[0] = '''' then
  243. if source[1] = '''' then PutChar
  244. else begin
  245. PutChar; break;
  246. end;
  247. Inc(StringLength);
  248. PutChar;
  249. end;
  250. if StringLength = 1 then
  251. dest[LastSHPos] := Chr(shCharacters);
  252. if (source[0] = #0) and (dest[dp - 1] <> '''') then
  253. dest[LastSHPos] := Chr(shInvalid);
  254. AddSH(shDefault);
  255. end;
  256. '_', 'A'..'Z', 'a'..'z': begin
  257. if not CheckForKeyword then
  258. repeat
  259. PutChar
  260. until not (source[0] in ['0'..'9', '_', 'A'..'Z', 'a'..'z']);
  261. end;
  262. ' ': PutChar;
  263. else begin
  264. AddSH(shInvalid);
  265. PutChar; // = found an invalid char!
  266. AddSH(shDefault);
  267. end;
  268. end;
  269. end;
  270. dest[dp] := #0;
  271. end;
  272. end.