]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/sourcepainter.cpp
1. Parser improvements
[wxWidgets.git] / utils / HelpGen / src / sourcepainter.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 22/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleskandars Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #if defined( wxUSE_TEMPLATE_STL )
24
25 #include <map>
26 #else
27
28 #include <wxstlac.h>
29
30 #endif
31
32 #include "sourcepainter.h"
33
34 const int MAX_KEYWORD_LEN = 16;
35
36 struct KeywordT
37 {
38 char keyWord[MAX_KEYWORD_LEN];
39 int rank;
40 };
41
42 // source fragment ranks :
43
44 // 0 - nomral text
45 // 1 - basic types
46 // 2 - reserved words
47
48 // multil-language keywords map
49
50 static KeywordT __gKeyWords[] =
51 {
52 { "for", 1 },
53 { "FOR", 1 },
54 { "For", 1 },
55
56 { "next", 1 },
57 { "Next", 1 },
58 { "NEXT", 1 },
59
60 { "if", 1 },
61 { "If", 1 },
62 { "IF", 1 },
63
64 { "then", 1 },
65 { "Then", 1 },
66 { "THEN", 1 },
67
68 { "else", 1 },
69 { "Else", 1 },
70 { "ELSE", 1 },
71
72 { "do", 1 },
73 { "Do", 1 },
74 { "DO", 1 },
75
76
77 { "break", 1 },
78 { "Break", 1 },
79 { "BREAK", 1 },
80
81 { "continue", 1 },
82
83 { "goto", 1 },
84 { "Goto", 1 },
85 { "GOTO", 1 },
86
87 { "switch", 1 },
88 { "default", 1 },
89 { "case", 1 },
90
91 { "repeat", 1 },
92 { "Repeat", 1 },
93 { "REPEAT", 1 },
94
95 { "until", 1 },
96 { "Until", 1 },
97 { "UNTIL", 1 },
98
99 { "return", 1 },
100 { "Return", 1 },
101 { "RETURN", 1 },
102
103 { "unit", 1 },
104 { "Unit", 1 },
105 { "UNIT", 1 },
106
107 { "procedure", 1 },
108 { "Procedure", 1 },
109 { "PROCEDURE", 1 },
110
111 { "function", 1 },
112 { "Function", 1 },
113 { "FUNCTION", 1 },
114
115 { "begin", 1 },
116 { "Begin", 1 },
117 { "BEGIN", 1 },
118
119 { "End", 1 },
120 { "END", 1 },
121
122 ////////////////////////////////////////////////////
123
124 { "enum", 1 },
125 { "static", 1 },
126 { "const", 1 },
127 { "mutable", 1 },
128 { "volatile", 1 },
129 { "__asm", 1 },
130 { "asm", 1 },
131
132 { "typeid", 1 },
133 { "sizeof", 1 },
134 { "typeof", 1 },
135
136
137 { "native", 1 },
138
139 { "#include", 1 },
140 { "#define", 1 },
141 { "#def", 1 },
142 { "#undef", 1 },
143 { "#ifdef", 1 },
144 { "#ifndef", 1 },
145 { "#if", 1 },
146 { "#endif", 1 },
147 { "#elif", 1 },
148 { "#else", 1 },
149 { "#pragma", 1 },
150 { "#line", 1 },
151
152 { "package", 1 },
153 { "import", 1 },
154 { "export", 1 },
155
156 ////////////////////////////////////////////////////
157
158 { "dynamic_cast", 1 },
159 { "const_cast", 1 },
160
161 //////// some hacks for VB /////////
162
163 { "sub", 1 },
164 { "Sub", 1 },
165 { "SUB", 1 },
166 { "as", 1 },
167 { "As", 1 },
168 { "AS", 1 },
169
170 /////// data types ///////
171
172 { "int" , 1 },
173 { "integer", 1 },
174 { "Integer", 1 },
175 { "INTEGER", 1 },
176
177 { "real", 1 },
178 { "Real", 1 },
179 { "REAL", 1 },
180
181 { "float", 1 },
182 { "Float", 1 },
183 { "FLOAT", 1 },
184
185 { "char", 1 },
186 { "Char", 1 },
187 { "CHAR", 1 },
188
189 { "register", 1 },
190
191 { "string", 1 },
192 { "String", 1 },
193 { "STRING", 1 },
194
195 { "array", 1 },
196 { "Array", 1 },
197 { "ARRAY", 1 },
198
199 { "packed", 1 },
200 { "Packed", 1 },
201 { "PACKED", 1 },
202
203 { "property", 1 },
204 { "Property", 1 },
205 { "PROPERTY", 1 },
206
207 { "unsigned", 1 },
208
209 { "long", 1 },
210 { "double", 1 },
211 { "short", 1 },
212 { "bool", 1 },
213
214 { "longint", 1 },
215 { "Longint", 1 },
216 { "LONGINT", 1 },
217
218 { "extended", 1 },
219 { "Extended", 1 },
220 { "EXTENTED", 1 },
221
222 { "pointer", 1 },
223 { "Pointer", 1 },
224 { "POINTER", 1 },
225
226 { "and", 1 },
227 { "And", 1 },
228 { "AND", 1 },
229 { "or", 1 },
230 { "Or", 1 },
231 { "OR", 1 },
232 { "xor", 1 },
233 { "Xor", 1 },
234 { "XOR", 1 },
235
236 { "void", 1 },
237 { "__stdcall", 1 },
238 { "__declspec", 1 },
239 { "extern", 1 },
240 { "stdcall", 1 },
241 { "dllimport", 1 },
242 { "dllexport", 1 },
243 { "__cdecl", 1 },
244 { "cdecl", 1 },
245 { "template", 1 },
246 { "typedef", 1 },
247 { "naked", 1 },
248
249 { "try", 1 },
250 { "catch", 1 },
251 { "throw", 2 }, // C++
252 { "throws", 1 }, // Java
253
254
255 { "finalize", 1 },
256
257 // "STL-suport"
258
259 { "size_t", 1 },
260 { "NPOS", 1 },
261 { "vector", 1 },
262 { "list", 1 },
263 { "map", 1 },
264 { "multimap", 1 },
265
266 { "external", 1 },
267 { "External", 1 },
268 { "EXTERNAL", 1 },
269
270 //////////// meta-information //////////////
271
272 { "virtual", 2 },
273 { "Virtual", 2 },
274
275 { "override", 2 },
276 { "Override", 2 },
277
278 { "class", 2 },
279 { "Class", 2 },
280 { "CLASS", 2 },
281
282 { "struct", 2 },
283 { "union", 2 },
284
285 { "record", 2 },
286 { "Record", 2 },
287 { "RECORD", 2 },
288
289 { "form", 1 },
290 { "Form", 1 },
291 { "FORM", 1 },
292
293 { "namespace", 2 },
294
295 { "interface" , 2 },
296 { "abstract", 2 },
297
298 { "Interface" , 2 },
299 { "INTERFACE" , 2 },
300
301 { "implementation", 2 },
302 { "Implementation", 2 },
303 { "IMPLEMENTATION", 2 },
304
305 { "label", 2 },
306 { "Label", 2 },
307 { "LABEL", 2 },
308
309 { "implements", 2 },
310
311 { "public", 2 },
312 { "private", 2 },
313 { "protected", 2 },
314
315 { "this", 2 },
316 { "This", 2 },
317 { "THIS", 2 },
318
319 { "new", 2 },
320 { "New", 2 },
321 { "NEW", 2 },
322
323 { "delete", 2 },
324 { "inline", 2 },
325
326 { "operator", 2 },
327
328 { "Inherited", 2 },
329 { "Inherited", 2 },
330
331 { "final", 2 },
332 { "implements", 2 },
333 { "super", 2 },
334
335 // even more...
336 { "java", 2 },
337 { "Java", 2 },
338 { "JAVA", 2 },
339 { "delphi", 2 },
340 { "Delphi", 2 },
341 { "SmallTalk", 2 },
342 { "Smalltalk", 2 },
343 { "smalltalk", 2 },
344 { "assembler", 2 },
345 { "Assembler", 2 },
346 { "Basic", 2 },
347 { "BASIC", 2 },
348 { "basic", 2 },
349 { "CORBA", 2 },
350 { "COBOL", 2 },
351 { "ADA", 2 },
352 { "LISP", 2 },
353
354 // just for fun...
355 { "life", 2 },
356 { "sucks", 2 },
357 { "rules", 2 },
358 { "Quake", 2 },
359 { "QuakeWorld", 2 },
360 { "[ag_slammer]",2 },
361 { "Aleksandras", 2 },
362 { "Gluchovas" , 2 },
363 { "Alex", 2 },
364 { "alex", 2 },
365 { "aleks", 2 },
366 { "aleksas", 3 },
367 { "AlexSoft", 2 },
368 { "Alexsoft", 2 },
369 { "SpringSky", 2 },
370 { "SK_Team", 2 },
371 { "soften", 2 },
372 { "UB40", 2 },
373 { "U96", 2 }
374 };
375
376 struct less_c_str
377 {
378 inline bool operator()( char* x, char* y) const
379 { return ( strcmp( x,y ) < 0 );
380 }
381 };
382
383 #if defined( wxUSE_TEMPLATE_STL )
384
385 typedef map< char*, char*, less_c_str > KeywordMapT;
386
387 #else
388
389 typedef char* CharPtrT;
390 typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT;
391
392 #endif
393
394 static KeywordMapT __gMultiLangMap;
395 static int __gMapReady = 0;
396
397 void check_keyword_map( int keywordMapNr )
398 {
399 if ( !__gMapReady )
400 {
401 __gMapReady = 1;
402
403 // "make sure" the address of the first member of non-polimorphic class
404 // coinsides with the address of the instance
405
406 KeywordT dummy;
407
408 if ( (char*)& dummy != &dummy.keyWord[0] )
409 throw;
410
411 int size = sizeof(__gKeyWords) / sizeof( KeywordT );
412
413 for( int i = 0; i != size; ++i )
414
415 __gMultiLangMap.insert(
416 KeywordMapT::value_type( (char*)&__gKeyWords[i],
417 (char*)&__gKeyWords[i]
418 )
419 );
420 }
421 }
422
423 int get_rank( char* start, char* end )
424 {
425 // FIXME:: what if end is no longer leagal adress?
426
427 char tmp = *end;
428 *end = '\0'; // put temporary terminator
429
430 KeywordMapT::iterator i;
431
432 if ( (i = __gMultiLangMap.find( start ) ) != __gMultiLangMap.end() )
433 {
434 KeywordT* pKey = (KeywordT*)(*i).second;
435
436 *end = tmp;
437
438 return pKey->rank;
439 }
440 else
441 {
442 *end = tmp;
443 return 0;
444 }
445 }
446
447 static inline void store_range( SPBlockListT& results, int rank, int range_len )
448 {
449 if ( !range_len ) return;
450
451 results.push_back ( ( rank << 16 ) | ( range_len ) );
452 }
453
454
455 #define STORE_RANGE store_range( results, cur_rank, cur_range_len );\
456 cur_rank = cur_range_len = 0;
457
458 #define NEXT_CHAR cur_range_len++; \
459 ++cur; \
460 continue;
461
462 static inline int is_alpha( char ch )
463 {
464 return ( (( ch >= '_' ) && ( ch <= 'z' )) ||
465 (( ch >= 'A' ) && ( ch <= 'Z' ))
466 );
467 }
468
469 // _ . .
470 // Ziema atEjo netikEtai
471
472 static void heighlight_syntax( char* str, int strLen,
473 SPBlockListT& results, bool& isComment )
474 {
475 bool isMultiline = 0;
476 char* cur = str;
477 char* end = str + strLen;
478
479 int cur_rank = ( isComment == 1 ) ? RANK_GREEN : RANK_BLACK;
480 int cur_range_len = 0;
481
482 while ( cur != end )
483 {
484 int has_next = ( cur+1 != end );
485
486 if ( isComment )
487 {
488 if ( *cur == '*' )
489 if ( has_next && *(cur+1) == '/' )
490 {
491 // turn off multiline comment mode
492 cur += 2;
493 cur_range_len += 2;
494 isComment = 0;
495 isMultiline = 0;
496 STORE_RANGE;
497
498 continue;
499 }
500
501 ++cur_range_len;
502 ++cur;
503 continue;
504 }
505
506 /*
507 if ( *cur == 10 )
508 if ( isComment )
509 if ( isMultiline )
510 {
511 cur_rank = RANK_GREEN;
512 cur_range_len = end - cur;
513 STORE_RANGE;
514 isComment = 0;
515 isMultiline = 0;
516 continue;
517 }*/
518
519 if ( *cur == '/' )
520 {
521 if ( has_next )
522 {
523 if ( *(cur+1) == '/' )
524 {
525 STORE_RANGE;
526
527 char* eol = cur;
528 while ( eol < end && *eol != 10 )
529 ++eol;
530
531 cur_rank = RANK_GREEN;
532 cur_range_len = eol - cur;
533 cur = eol;
534 STORE_RANGE;
535
536 continue;
537 }
538
539 if ( *(cur+1) == '*' )
540 {
541 STORE_RANGE;
542 cur_rank = RANK_GREEN;
543 cur_range_len = 2;
544 isComment = 1;
545 cur += 2;
546 isMultiline = 1;
547 continue;
548 }
549 }
550
551 NEXT_CHAR;
552 }
553
554 if ( ( is_alpha( *cur ) || *(cur) == '#' )
555 && has_next
556 )
557 {
558 if ( is_alpha( *(cur+1) ) )
559 {
560 char* start = cur;
561 cur += 2;
562
563 while ( cur != end && is_alpha(*cur) ) ++cur;
564
565 int wordRank;
566
567 if ( (wordRank = get_rank( start, cur )) > 0 )
568 {
569 STORE_RANGE;
570
571 store_range( results, wordRank, int(cur-start) );
572 cur_rank = cur_range_len = 0;
573 continue;
574 }
575
576 cur_range_len += ( cur-start );
577 continue;
578 }
579 else
580 NEXT_CHAR;
581 }
582
583 NEXT_CHAR;
584 }
585
586 if ( cur_range_len > 0 ) STORE_RANGE;
587 }
588
589 /***** Implementation for class SourcePainter ******/
590
591 SourcePainter::SourcePainter( bool assembleResultString )
592 : mCollectResultsOn( assembleResultString ),
593 mIsInComment( FALSE ),
594 mCommentIsMultiline( FALSE )
595 {
596 check_keyword_map(0);
597 }
598
599 void SourcePainter::ProcessSource( char* src, int srcLen )
600 {
601 // TBD:: multilne state...
602
603 heighlight_syntax( src, srcLen, mBlocks, mIsInComment );
604
605 if ( mCollectResultsOn )
606
607 mResultStr += string( src, srcLen );
608 }
609
610 void SourcePainter::SetState( bool isInComment,
611 bool commentIsMultiline )
612 {
613 mIsInComment = isInComment;
614 mCommentIsMultiline = commentIsMultiline;
615 }
616
617 void SourcePainter::Init(bool assembleResultString)
618 {
619 mIsInComment = 0;
620 mCommentIsMultiline = 0;
621 mCollectResultsOn = assembleResultString;
622
623 mResultStr = "";
624
625 mBlocks.erase( mBlocks.begin(), mBlocks.end() );
626 }
627
628 static int rank_tags_map[] =
629 {
630 TAG_BLACK_FONT,
631 TAG_BLUE_FONT,
632 TAG_RED_FONT,
633 TAG_GREEN_FONT
634 };
635
636 void SourcePainter::GetResultString(string& result, MarkupTagsT tags)
637 {
638 // this method works, only if results of processing
639 // are collected
640 ASSERT( mCollectResultsOn );
641 result = "";
642
643 int pos = 0;
644
645 for( size_t i = 0; i != mBlocks.size(); ++i )
646 {
647 int desc = mBlocks[i];
648
649 int len = desc & 0xFFFF;
650 int rank = (desc >> 16) & 0xFFFF;
651
652 result += tags[ rank_tags_map[rank] ].start;
653
654 for( int n = 0; n != len; ++n )
655
656 result += mResultStr[pos+n];
657
658 pos += len;
659
660 result += tags[ rank_tags_map[rank] ].end;
661 }
662 }
663
664 SPBlockListT& SourcePainter::GetBlocks()
665 {
666 return mBlocks;
667 }
668
669 bool SourcePainter::IsKeyword( char* word, int wordLen )
670 {
671 check_keyword_map(0);
672
673 int rank = get_rank( word, word + wordLen );
674
675 return ( rank == RANK_BLUE || rank == RANK_RED );
676 }