休息了大半個月,沒寫自己的代碼了。國慶過了,再不為自己寫寫代碼就有負罪感了。這篇文章所提到的所有工具的代碼都可以在
Vczh Library++ 3.0的頁面找到。
上一篇文章提到了一個狀態機繪圖工具,直到最近我終于把他的第一個部分給做好了。現在可以畫圖之后產生一個可以供
這里所描述的高亮控件所使用的著色器了。第一步我們要使用TokenizerBuilder繪制一個狀態機:
然后點擊“Generate to Clipboard”按鈕,就會要求你輸入一個類名然后產生著色器插件的代碼了。上面這個是一個簡化過的C#代碼著色狀態機,其中Id有個星號代表不是所有走到這個狀態的東西都可以叫Id(其實是關鍵字,懶得改了)。中括號里面的是顏色的名稱。這些名稱最終是要拿來生成代碼的,所以必須是C#接受的可以拿來做變量名的東西,不過我也沒檢查,只管拼接字符串生成。
我把生成后的代碼貼在了CodeForm工程的CSharpTokenizer.Generated.cs里:
第三步就是要自己建立一個CSharpColorizer.Configuration.cs了。C#的partial class真是偉大,簡直就是為了代碼生成而設計出來的。在這里我們看看生成后的CSharpColorizer.Generated.cs的代碼:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using CodeBoxControl;
6 using System.Drawing;
7
8 namespace CodeForm
9 {
10 partial class CSharpColorizer : ITextEditorColorizer
11 {
12 //public const int NormalColorId = 0;
13 public const int IdColorId = NormalColorId + 1;
14 public const int StringColorId = NormalColorId + 2;
15 public const int CommentColorId = NormalColorId + 3;
16
17 //private readonly Color HighlightColor = Color.FromArgb(173, 214, 255);
18 //private readonly Color NormalColor = Color.FromArgb(0, 0, 0);
19 //private readonly Color IdColor = Color.FromArgb(0, 0, 0);
20 //private readonly Color StringColor = Color.FromArgb(0, 0, 0);
21 //private readonly Color CommentColor = Color.FromArgb(0, 0, 0);
22
23 private const int StartState = 0;
24 private const int NormalState = 1;
25 private const int IdStateId = 2;
26 private const int InStringStateId = 3;
27 private const int InStringEscapingStateId = 4;
28 private const int InCharStateId = 5;
29 private const int InCharEscapingStateId = 6;
30 private const int StringStateId = 7;
31 private const int CommentStartStateId = 8;
32 private const int SingleLineCommentStateId = 9;
33 private const int InMultipleLineCommentStateId = 10;
34 private const int InMultipleLineCommentWaitingToFinishStateId = 11;
35 private const int MultipleLineCommentStateId = 12;
36
37 private TextEditorColorItem[] colorItems = new TextEditorColorItem[NormalColorId + 4];
38 private int[] charset = new int[65536];
39 private int[,] transitions = new int[13, 11];
40 private bool[] finalStates = new bool[13];
41 private int[] stateColors = new int[13];
42
43 public TextEditorColorItem[] ColorItems
44 {
45 get
46 {
47 return this.colorItems;
48 }
49 }
50
51 public CSharpColorizer()
52 {
53 this.colorItems[NormalColorId] = new TextEditorColorItem()
54 {
55 Text = NormalColor,
56 HighlightText = NormalColor,
57 Highlight = HighlightColor
58 };
59 this.colorItems[IdColorId] = new TextEditorColorItem()
60 {
61 Text = IdColor,
62 HighlightText = IdColor,
63 Highlight = HighlightColor
64 };
65 this.colorItems[StringColorId] = new TextEditorColorItem()
66 {
67 Text = StringColor,
68 HighlightText = StringColor,
69 Highlight = HighlightColor
70 };
71 this.colorItems[CommentColorId] = new TextEditorColorItem()
72 {
73 Text = CommentColor,
74 HighlightText = CommentColor,
75 Highlight = HighlightColor
76 };
77 // You should write your own CreateAdditionalColors() implementation to add additional colors.
78 // You can modify the NormalColorId and put all additional colors ids before NormalColorId.
79 // It is recommended to use another partial class to store all customized code.
80 CreateAdditionalColors();
81 CreateStateMachine();
82 }
83 public int ColorizeLine(char[] items, int length, int initialState, int[] colors)
84 {
85 int state = initialState;
86 int itemStart = 0;
87 int lastFinalState = StartState;
88
89 for (int i = 0; i <= length; i++)
90 {
91 if (i != length)
92 {
93 state = transitions[state, charset[items[i]]];
94 if (state == StartState)
95 {
96 state = transitions[state, charset[items[i]]];
97 }
98 }
99 else
100 {
101 lastFinalState = state;
102 }
103
104 if (i == length || lastFinalState != state && lastFinalState != StartState)
105 {
106 int color = stateColors[lastFinalState];
107 switch (lastFinalState)
108 {
109 case IdStateId:
110 // You should write your own IsValidId implementation.
111 color = IsValidId(new string(items, itemStart, Math.Min(i, length) - itemStart)) ? stateColors[lastFinalState] : NormalColorId;
112 break;
113 }
114 for (int j = itemStart; j < i; j++)
115 {
116 colors[j] = color;
117 }
118 itemStart = i;
119 }
120 lastFinalState = finalStates[state] ? state : StartState;
121 }
122
123 return transitions[state, charset['\n']];
124 }
125
126 private void CreateStateMachine()
127 {
128 for (int i = 0; i < 10; i++)
129 charset[i] = 0;
130 for (int i = 10; i < 11; i++)
131 charset[i] = 1;
132 for (int i = 11; i < 34; i++)
133 charset[i] = 0;
134 for (int i = 34; i < 35; i++)
135 charset[i] = 2;
136 for (int i = 35; i < 36; i++)
137 charset[i] = 3;
138 for (int i = 36; i < 39; i++)
139 charset[i] = 0;
140 for (int i = 39; i < 40; i++)
141 charset[i] = 4;
142 for (int i = 40; i < 42; i++)
143 charset[i] = 0;
144 for (int i = 42; i < 43; i++)
145 charset[i] = 5;
146 for (int i = 43; i < 47; i++)
147 charset[i] = 0;
148 for (int i = 47; i < 48; i++)
149 charset[i] = 6;
150 for (int i = 48; i < 58; i++)
151 charset[i] = 7;
152 for (int i = 58; i < 65; i++)
153 charset[i] = 0;
154 for (int i = 65; i < 91; i++)
155 charset[i] = 8;
156 for (int i = 91; i < 92; i++)
157 charset[i] = 0;
158 for (int i = 92; i < 93; i++)
159 charset[i] = 9;
160 for (int i = 93; i < 95; i++)
161 charset[i] = 0;
162 for (int i = 95; i < 96; i++)
163 charset[i] = 8;
164 for (int i = 96; i < 97; i++)
165 charset[i] = 0;
166 for (int i = 97; i < 123; i++)
167 charset[i] = 8;
168 for (int i = 123; i < 65536; i++)
169 charset[i] = 0;
170
171 finalStates[0] = false;
172 finalStates[1] = true;
173 finalStates[2] = true;
174 finalStates[3] = false;
175 finalStates[4] = false;
176 finalStates[5] = false;
177 finalStates[6] = false;
178 finalStates[7] = true;
179 finalStates[8] = false;
180 finalStates[9] = true;
181 finalStates[10] = false;
182 finalStates[11] = false;
183 finalStates[12] = true;
184
185 stateColors[0] = NormalColorId + 0;
186 stateColors[1] = NormalColorId + 0;
187 stateColors[2] = NormalColorId + 1;
188 stateColors[3] = NormalColorId + 2;
189 stateColors[4] = NormalColorId + 2;
190 stateColors[5] = NormalColorId + 2;
191 stateColors[6] = NormalColorId + 2;
192 stateColors[7] = NormalColorId + 2;
193 stateColors[8] = NormalColorId + 0;
194 stateColors[9] = NormalColorId + 3;
195 stateColors[10] = NormalColorId + 3;
196 stateColors[11] = NormalColorId + 3;
197 stateColors[12] = NormalColorId + 3;
198
199 transitions[0, 0] = 1;
200 transitions[0, 1] = 1;
201 transitions[0, 2] = 3;
202 transitions[0, 3] = 2;
203 transitions[0, 4] = 5;
204 transitions[0, 5] = 1;
205 transitions[0, 6] = 8;
206 transitions[0, 7] = 1;
207 transitions[0, 8] = 2;
208 transitions[0, 9] = 1;
209 transitions[0, 10] = 1;
210 transitions[1, 0] = 0;
211 transitions[1, 1] = 0;
212 transitions[1, 2] = 0;
213 transitions[1, 3] = 0;
214 transitions[1, 4] = 0;
215 transitions[1, 5] = 0;
216 transitions[1, 6] = 0;
217 transitions[1, 7] = 0;
218 transitions[1, 8] = 0;
219 transitions[1, 9] = 0;
220 transitions[1, 10] = 0;
221 transitions[2, 0] = 0;
222 transitions[2, 1] = 0;
223 transitions[2, 2] = 0;
224 transitions[2, 3] = 0;
225 transitions[2, 4] = 0;
226 transitions[2, 5] = 0;
227 transitions[2, 6] = 0;
228 transitions[2, 7] = 2;
229 transitions[2, 8] = 2;
230 transitions[2, 9] = 0;
231 transitions[2, 10] = 0;
232 transitions[3, 0] = 3;
233 transitions[3, 1] = 0;
234 transitions[3, 2] = 7;
235 transitions[3, 3] = 3;
236 transitions[3, 4] = 3;
237 transitions[3, 5] = 3;
238 transitions[3, 6] = 3;
239 transitions[3, 7] = 3;
240 transitions[3, 8] = 3;
241 transitions[3, 9] = 4;
242 transitions[3, 10] = 0;
243 transitions[4, 0] = 3;
244 transitions[4, 1] = 0;
245 transitions[4, 2] = 3;
246 transitions[4, 3] = 3;
247 transitions[4, 4] = 3;
248 transitions[4, 5] = 3;
249 transitions[4, 6] = 3;
250 transitions[4, 7] = 3;
251 transitions[4, 8] = 3;
252 transitions[4, 9] = 3;
253 transitions[4, 10] = 0;
254 transitions[5, 0] = 5;
255 transitions[5, 1] = 0;
256 transitions[5, 2] = 5;
257 transitions[5, 3] = 5;
258 transitions[5, 4] = 7;
259 transitions[5, 5] = 5;
260 transitions[5, 6] = 5;
261 transitions[5, 7] = 5;
262 transitions[5, 8] = 5;
263 transitions[5, 9] = 6;
264 transitions[5, 10] = 0;
265 transitions[6, 0] = 5;
266 transitions[6, 1] = 0;
267 transitions[6, 2] = 5;
268 transitions[6, 3] = 5;
269 transitions[6, 4] = 5;
270 transitions[6, 5] = 5;
271 transitions[6, 6] = 5;
272 transitions[6, 7] = 5;
273 transitions[6, 8] = 5;
274 transitions[6, 9] = 5;
275 transitions[6, 10] = 0;
276 transitions[7, 0] = 0;
277 transitions[7, 1] = 0;
278 transitions[7, 2] = 0;
279 transitions[7, 3] = 0;
280 transitions[7, 4] = 0;
281 transitions[7, 5] = 0;
282 transitions[7, 6] = 0;
283 transitions[7, 7] = 0;
284 transitions[7, 8] = 0;
285 transitions[7, 9] = 0;
286 transitions[7, 10] = 0;
287 transitions[8, 0] = 1;
288 transitions[8, 1] = 1;
289 transitions[8, 2] = 1;
290 transitions[8, 3] = 1;
291 transitions[8, 4] = 1;
292 transitions[8, 5] = 10;
293 transitions[8, 6] = 9;
294 transitions[8, 7] = 1;
295 transitions[8, 8] = 1;
296 transitions[8, 9] = 1;
297 transitions[8, 10] = 1;
298 transitions[9, 0] = 9;
299 transitions[9, 1] = 0;
300 transitions[9, 2] = 9;
301 transitions[9, 3] = 9;
302 transitions[9, 4] = 9;
303 transitions[9, 5] = 9;
304 transitions[9, 6] = 9;
305 transitions[9, 7] = 9;
306 transitions[9, 8] = 9;
307 transitions[9, 9] = 9;
308 transitions[9, 10] = 0;
309 transitions[10, 0] = 10;
310 transitions[10, 1] = 10;
311 transitions[10, 2] = 10;
312 transitions[10, 3] = 10;
313 transitions[10, 4] = 10;
314 transitions[10, 5] = 11;
315 transitions[10, 6] = 0;
316 transitions[10, 7] = 10;
317 transitions[10, 8] = 10;
318 transitions[10, 9] = 10;
319 transitions[10, 10] = 0;
320 transitions[11, 0] = 10;
321 transitions[11, 1] = 10;
322 transitions[11, 2] = 10;
323 transitions[11, 3] = 10;
324 transitions[11, 4] = 10;
325 transitions[11, 5] = 10;
326 transitions[11, 6] = 12;
327 transitions[11, 7] = 10;
328 transitions[11, 8] = 10;
329 transitions[11, 9] = 10;
330 transitions[11, 10] = 0;
331 transitions[12, 0] = 0;
332 transitions[12, 1] = 0;
333 transitions[12, 2] = 0;
334 transitions[12, 3] = 0;
335 transitions[12, 4] = 0;
336 transitions[12, 5] = 0;
337 transitions[12, 6] = 0;
338 transitions[12, 7] = 0;
339 transitions[12, 8] = 0;
340 transitions[12, 9] = 0;
341 transitions[12, 10] = 0;
342 }
343 }
344 }
345
這是一個典型的狀態機,里面定義了所有狀態、顏色和對外可見的顏色標號。這里使用partial class是因為顏色是要你自己填寫的,因此你可以看見我在代碼的一開始注釋掉了幾行,所以他們就會出現在CSharpColorizer.Configuration.cs里:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using CodeBoxControl;
6 using System.Drawing;
7
8 namespace CodeForm
9 {
10 partial class CSharpColorizer
11 {
12 public const int BreakPointColorId = 0;
13 public const int BlockPointColorId = 1;
14 public const int NormalColorId = 2;
15
16 private readonly Color HighlightColor = Color.FromArgb(173, 214, 255);
17 private readonly Color NormalColor = Color.FromArgb(0, 0, 0);
18 private readonly Color IdColor = Color.FromArgb(0, 0, 255);
19 private readonly Color StringColor = Color.FromArgb(163, 21, 21);
20 private readonly Color CommentColor = Color.FromArgb(0, 128, 0);
21
22 private readonly Color BreakPointColor = Color.FromArgb(255, 255, 255);
23 private readonly Color BreakPointHighlightColor = Color.FromArgb(123, 119, 166);
24 private readonly Color BlockPointColor = Color.Gray;
25
26 private void CreateAdditionalColors()
27 {
28 this.colorItems[BreakPointColorId] = new TextEditorColorItem()
29 {
30 Text = BreakPointColor,
31 HighlightText = BreakPointColor,
32 Highlight = BreakPointHighlightColor
33 };
34 this.colorItems[BlockPointColorId] = new TextEditorColorItem()
35 {
36 Text = BlockPointColor,
37 HighlightText = BlockPointColor,
38 Highlight = HighlightColor
39 };
40 }
41
42 private bool IsValidId(string token)
43 {
44 return token[0] == '#' || Array.BinarySearch(keywords, token) >= 0;
45 }
46
47 private static string[] keywords ={
48 "abstract",
49 "as",
50 "base",
51 "bool",
52 "break",
53 "byte",
54 "case",
55 "catch",
56 "char",
57 "checked",
58 "class",
59 "const",
60 "continue",
61 "decimal",
62 "default",
63 "delegate",
64 "do",
65 "double",
66 "else",
67 "enum",
68 "event",
69 "explicit",
70 "extern",
71 "false",
72 "finally",
73 "fixed",
74 "float",
75 "for",
76 "foreach",
77 "goto",
78 "if",
79 "implicit",
80 "in",
81 "int",
82 "interface",
83 "internal",
84 "is",
85 "lock",
86 "long",
87 "namespace",
88 "new",
89 "null",
90 "object",
91 "operator",
92 "out",
93 "override",
94 "params",
95 "private",
96 "protected",
97 "public",
98 "readonly",
99 "ref",
100 "return",
101 "sbyte",
102 "sealed",
103 "short",
104 "sizeof",
105 "stackalloc",
106 "static",
107 "string",
108 "struct",
109 "switch",
110 "this",
111 "throw",
112 "true",
113 "try",
114 "typeof",
115 "unit",
116 "ulong",
117 "unchecked",
118 "unsafe",
119 "ushort",
120 "using",
121 "virtual",
122 "void",
123 "volatile",
124 "while"
125 };
126 }
127 }
128
這個Configuration做了三件事情。第一、定義了額外的顏色。在這里我們修改了NormalColorId,這是系統顏色的第一個顏色序號。我們只需要修改了它,然后把自己的顏色加在它前面就行了。第二件事情是定義了什么是Id。我們在Id狀態里打了個星號,那么生成的代碼就會要求我們實現一個IsValidId函數。第三件事情就是我們指定了所有記號的真正的顏色。
為什么要做成partial class呢?我們可以很容易看出來,每一次生成代碼的時候,我們只需要修改namespace和類名以及注釋掉NormalColorId和所有顏色的聲明,就可以讓我們的自定義部分得到保留。這無疑很方便我們對著色器進行修改。只需要修改一下狀態機,生成一份代碼,再做一點很小的改動就行了。
最重要的是,這個著色器的性能跟
手寫的基本一樣優秀,因此從現在開始,我們開發一個上下文無關的著色器控件就基本不需要寫代碼了,只要是用Vczh Library++ 3.0實驗庫里面的TextEditorControl,再用這個TokenizerBuilder畫個狀態機生成個著色器的代碼就搞定了,哇哈哈。下面要做的就是增強TokenizerBuilder,從狀態機生成詞法分析器了,然后就可以繼續智能提示的實驗了。
posted on 2010-10-08 06:05
陳梓瀚(vczh) 閱讀(6780)
評論(8) 編輯 收藏 引用 所屬分類:
開發自己的IDE