1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
27:
28:
29:
30: define ('TEXT_HIGHLIGHTER_EMPTY_RE', 1);
31: define ('TEXT_HIGHLIGHTER_INVALID_RE', 2);
32: define ('TEXT_HIGHLIGHTER_EMPTY_OR_MISSING', 3);
33: define ('TEXT_HIGHLIGHTER_EMPTY', 4);
34: define ('TEXT_HIGHLIGHTER_REGION_REGION', 5);
35: define ('TEXT_HIGHLIGHTER_REGION_BLOCK', 6);
36: define ('TEXT_HIGHLIGHTER_BLOCK_REGION', 7);
37: define ('TEXT_HIGHLIGHTER_KEYWORD_BLOCK', 8);
38: define ('TEXT_HIGHLIGHTER_KEYWORD_INHERITS', 9);
39: define ('TEXT_HIGHLIGHTER_PARSE', 10);
40: define ('TEXT_HIGHLIGHTER_FILE_WRITE', 11);
41: define ('TEXT_HIGHLIGHTER_FILE_READ', 12);
42:
43:
44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66:
67:
68: class Text_Highlighter_Generator extends XML_Parser
69: {
70:
71: 72: 73: 74: 75: 76: 77:
78: var $folding = false;
79:
80: 81: 82: 83: 84: 85:
86: var $_syntaxFile;
87:
88: 89: 90: 91: 92: 93:
94: var $_element;
95:
96: 97: 98: 99: 100: 101:
102: var $_regions = array();
103:
104: 105: 106: 107: 108: 109:
110: var $_blocks = array();
111:
112: 113: 114: 115: 116: 117:
118: var $_keywords = array();
119:
120: 121: 122: 123: 124: 125:
126: var $_authors = array();
127:
128: 129: 130: 131: 132: 133:
134: var $language = '';
135:
136: 137: 138: 139: 140: 141:
142: var $_code = '';
143:
144: 145: 146: 147: 148: 149:
150: var $_defClass = 'default';
151:
152: 153: 154: 155: 156: 157:
158: var = '';
159:
160: 161: 162: 163: 164: 165:
166: var = false;
167:
168: 169: 170: 171: 172: 173:
174: var $_blockOrder = 0;
175:
176: 177: 178: 179: 180: 181:
182: var $_errors;
183:
184:
185:
186:
187: 188: 189: 190: 191: 192: 193: 194:
195:
196: function __construct($syntaxFile = '')
197: {
198: XML_Parser::XML_Parser(null, 'func');
199: $this->_errors = array();
200: $this->_declareErrorMessages();
201: if ($syntaxFile) {
202: $this->setInputFile($syntaxFile);
203: }
204: }
205:
206:
207:
208:
209: 210: 211: 212: 213: 214: 215: 216: 217: 218:
219: function _formatError($code, $params, $fileName, $lineNo)
220: {
221: $template = $this->_templates[$code];
222: $ret = call_user_func_array('sprintf', array_merge(array($template), $params));
223: if ($fileName) {
224: $ret = '[' . $fileName . '] ' . $ret;
225: }
226: if ($lineNo) {
227: $ret .= ' (line ' . $lineNo . ')';
228: }
229: return $ret;
230: }
231:
232:
233:
234:
235: 236: 237: 238: 239:
240: function _declareErrorMessages()
241: {
242: $this->_templates = array (
243: TEXT_HIGHLIGHTER_EMPTY_RE => 'Empty regular expression',
244: TEXT_HIGHLIGHTER_INVALID_RE => 'Invalid regular expression : %s',
245: TEXT_HIGHLIGHTER_EMPTY_OR_MISSING => 'Empty or missing %s',
246: TEXT_HIGHLIGHTER_EMPTY => 'Empty %s',
247: TEXT_HIGHLIGHTER_REGION_REGION => 'Region %s refers undefined region %s',
248: TEXT_HIGHLIGHTER_REGION_BLOCK => 'Region %s refers undefined block %s',
249: TEXT_HIGHLIGHTER_BLOCK_REGION => 'Block %s refers undefined region %s',
250: TEXT_HIGHLIGHTER_KEYWORD_BLOCK => 'Keyword group %s refers undefined block %s',
251: TEXT_HIGHLIGHTER_KEYWORD_INHERITS => 'Keyword group %s inherits undefined block %s',
252: TEXT_HIGHLIGHTER_PARSE => '%s',
253: TEXT_HIGHLIGHTER_FILE_WRITE => 'Error writing file %s',
254: TEXT_HIGHLIGHTER_FILE_READ => '%s'
255: );
256: }
257:
258:
259:
260:
261: 262: 263: 264: 265: 266: 267:
268: function setInputFile($file)
269: {
270: $this->_syntaxFile = $file;
271: $ret = parent::setInputFile($file);
272: if (PEAR::isError($ret)) {
273: $this->_error(TEXT_HIGHLIGHTER_FILE_READ, $ret->message);
274: return false;
275: }
276: return true;
277: }
278:
279:
280:
281:
282: 283: 284: 285: 286:
287:
288: function generate()
289: {
290: $this->_regions = array();
291: $this->_blocks = array();
292: $this->_keywords = array();
293: $this->language = '';
294: $this->_code = '';
295: $this->_defClass = 'default';
296: $this->_comment = '';
297: $this->_inComment = false;
298: $this->_authors = array();
299: $this->_blockOrder = 0;
300: $this->_errors = array();
301:
302: $ret = $this->parse();
303: if (PEAR::isError($ret)) {
304: $this->_error(TEXT_HIGHLIGHTER_PARSE, $ret->message);
305: return false;
306: }
307: return true;
308: }
309:
310:
311:
312:
313: 314: 315: 316: 317: 318:
319:
320: function getCode()
321: {
322: return $this->_code;
323: }
324:
325:
326:
327:
328: 329: 330: 331: 332: 333: 334: 335: 336:
337:
338: function saveCode($filename)
339: {
340: $f = @fopen($filename, 'wb');
341: if (!$f) {
342: $this->_error(TEXT_HIGHLIGHTER_FILE_WRITE, array('outfile'=>$filename));
343: return false;
344: }
345: fwrite ($f, $this->_code);
346: fclose($f);
347: return true;
348: }
349:
350:
351:
352:
353: 354: 355: 356: 357: 358:
359:
360: function hasErrors()
361: {
362: return count($this->_errors) > 0;
363: }
364:
365:
366:
367:
368: 369: 370: 371: 372: 373:
374:
375: function getErrors()
376: {
377: return $this->_errors;
378: }
379:
380:
381:
382:
383: 384: 385: 386: 387:
388:
389: function _sortBlocks($b1, $b2) {
390: return $b1['order'] - $b2['order'];
391: }
392:
393:
394:
395: 396: 397: 398: 399: 400:
401: function _sortLookFor($b1, $b2) {
402: $o1 = isset($this->_blocks[$b1]) ? $this->_blocks[$b1]['order'] : $this->_regions[$b1]['order'];
403: $o2 = isset($this->_blocks[$b2]) ? $this->_blocks[$b2]['order'] : $this->_regions[$b2]['order'];
404: return $o1 - $o2;
405: }
406:
407:
408:
409:
410: 411: 412: 413: 414: 415: 416:
417: function _makeRE($text, $case = false)
418: {
419: if (!strlen($text)) {
420: $this->_error(TEXT_HIGHLIGHTER_EMPTY_RE);
421: }
422: if (!strlen($text) || $text{0} != '/') {
423: $text = '/' . $text . '/';
424: }
425: if (!$case) {
426: $text .= 'i';
427: }
428: $php_errormsg = '';
429: @preg_match($text, '');
430: if ($php_errormsg) {
431: $this->_error(TEXT_HIGHLIGHTER_INVALID_RE, $php_errormsg);
432: }
433: preg_match ('#^/(.+)/(.*)$#', $text, $m);
434: if (@$m[2]) {
435: $text = '(?' . $m[2] . ')' . $m[1];
436: } else {
437: $text = $m[1];
438: }
439: return $text;
440: }
441:
442:
443:
444:
445: 446: 447: 448: 449: 450: 451:
452: function _exportArray($array)
453: {
454: $array = var_export($array, true);
455: return trim(preg_replace('~^(\s*)~m',' \1\1',$array));
456: }
457:
458:
459:
460: 461: 462: 463: 464:
465: function _countSubpatterns($re)
466: {
467: preg_match_all('/' . $re . '/', '', $m);
468: return count($m)-1;
469: }
470:
471:
472:
473: 474: 475: 476: 477: 478:
479:
480:
481:
482: 483: 484:
485: function xmltag_Default($xp, $elem, $attribs)
486: {
487: $this->_aliasAttributes($attribs);
488: if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
489: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
490: }
491: $this->_defClass = @$attribs['innerGroup'];
492: }
493:
494:
495:
496:
497: 498: 499:
500: function xmltag_Region($xp, $elem, $attribs)
501: {
502: $this->_aliasAttributes($attribs);
503: if (!isset($attribs['name']) || $attribs['name'] === '') {
504: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region name');
505: }
506: if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
507: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
508: }
509: $this->_element = array('name' => $attribs['name']);
510: $this->_element['line'] = xml_get_current_line_number($this->parser);
511: if (isset($attribs['case'])) {
512: $this->_element['case'] = $attribs['case'] == 'yes';
513: } else {
514: $this->_element['case'] = $this->_case;
515: }
516: $this->_element['innerGroup'] = $attribs['innerGroup'];
517: $this->_element['delimGroup'] = isset($attribs['delimGroup']) ?
518: $attribs['delimGroup'] :
519: $attribs['innerGroup'];
520: $this->_element['start'] = $this->_makeRE(@$attribs['start'], $this->_element['case']);
521: $this->_element['end'] = $this->_makeRE(@$attribs['end'], $this->_element['case']);
522: $this->_element['contained'] = @$attribs['contained'] == 'yes';
523: $this->_element['never-contained'] = @$attribs['never-contained'] == 'yes';
524: $this->_element['remember'] = @$attribs['remember'] == 'yes';
525: if (isset($attribs['startBOL']) && $attribs['startBOL'] == 'yes') {
526: $this->_element['startBOL'] = true;
527: }
528: if (isset($attribs['endBOL']) && $attribs['endBOL'] == 'yes') {
529: $this->_element['endBOL'] = true;
530: }
531: if (isset($attribs['neverAfter'])) {
532: $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']);
533: }
534: }
535:
536:
537:
538:
539: 540: 541:
542: function xmltag_Block($xp, $elem, $attribs)
543: {
544: $this->_aliasAttributes($attribs);
545: if (!isset($attribs['name']) || $attribs['name'] === '') {
546: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'block name');
547: }
548: if (isset($attribs['innerGroup']) && $attribs['innerGroup'] === '') {
549: $this->_error(TEXT_HIGHLIGHTER_EMPTY, 'innerGroup');
550: }
551: $this->_element = array('name' => $attribs['name']);
552: $this->_element['line'] = xml_get_current_line_number($this->parser);
553: if (isset($attribs['case'])) {
554: $this->_element['case'] = $attribs['case'] == 'yes';
555: } else {
556: $this->_element['case'] = $this->_case;
557: }
558: if (isset($attribs['innerGroup'])) {
559: $this->_element['innerGroup'] = @$attribs['innerGroup'];
560: }
561: $this->_element['match'] = $this->_makeRE($attribs['match'], $this->_element['case']);
562: $this->_element['contained'] = @$attribs['contained'] == 'yes';
563: $this->_element['multiline'] = @$attribs['multiline'] == 'yes';
564: if (isset($attribs['BOL']) && $attribs['BOL'] == 'yes') {
565: $this->_element['BOL'] = true;
566: }
567: if (isset($attribs['neverAfter'])) {
568: $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']);
569: }
570: }
571:
572:
573:
574:
575: 576: 577:
578: function cdataHandler($xp, $cdata)
579: {
580: if ($this->_inComment) {
581: $this->_comment .= $cdata;
582: }
583: }
584:
585:
586:
587:
588: 589: 590:
591: function ($xp, $elem, $attribs)
592: {
593: $this->_comment = '';
594: $this->_inComment = true;
595: }
596:
597:
598:
599:
600: 601: 602:
603: function xmltag_PartGroup($xp, $elem, $attribs)
604: {
605: $this->_aliasAttributes($attribs);
606: if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
607: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
608: }
609: $this->_element['partClass'][$attribs['index']] = @$attribs['innerGroup'];
610: }
611:
612:
613:
614:
615: 616: 617:
618: function xmltag_PartClass($xp, $elem, $attribs)
619: {
620: $this->xmltag_PartGroup($xp, $elem, $attribs);
621: }
622:
623:
624:
625:
626: 627: 628:
629: function xmltag_Keywords($xp, $elem, $attribs)
630: {
631: $this->_aliasAttributes($attribs);
632: if (!isset($attribs['name']) || $attribs['name'] === '') {
633: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'keyword group name');
634: }
635: if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
636: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
637: }
638: if (!isset($attribs['inherits']) || $attribs['inherits'] === '') {
639: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'inherits');
640: }
641: $this->_element = array('name'=>@$attribs['name']);
642: $this->_element['line'] = xml_get_current_line_number($this->parser);
643: $this->_element['innerGroup'] = @$attribs['innerGroup'];
644: if (isset($attribs['case'])) {
645: $this->_element['case'] = $attribs['case'] == 'yes';
646: } else {
647: $this->_element['case'] = $this->_case;
648: }
649: $this->_element['inherits'] = @$attribs['inherits'];
650: if (isset($attribs['otherwise'])) {
651: $this->_element['otherwise'] = $attribs['otherwise'];
652: }
653: if (isset($attribs['ifdef'])) {
654: $this->_element['ifdef'] = $attribs['ifdef'];
655: }
656: if (isset($attribs['ifndef'])) {
657: $this->_element['ifndef'] = $attribs['ifndef'];
658: }
659: }
660:
661:
662:
663:
664: 665: 666:
667: function xmltag_Keyword($xp, $elem, $attribs)
668: {
669: if (!isset($attribs['match']) || $attribs['match'] === '') {
670: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'match');
671: }
672: $keyword = @$attribs['match'];
673: if (!$this->_element['case']) {
674: $keyword = strtolower($keyword);
675: }
676: $this->_element['match'][$keyword] = true;
677: }
678:
679:
680:
681:
682: 683: 684:
685: function xmltag_Contains($xp, $elem, $attribs)
686: {
687: $this->_element['contains-all'] = @$attribs['all'] == 'yes';
688: if (isset($attribs['region'])) {
689: $this->_element['contains']['region'][$attribs['region']] =
690: xml_get_current_line_number($this->parser);
691: }
692: if (isset($attribs['block'])) {
693: $this->_element['contains']['block'][$attribs['block']] =
694: xml_get_current_line_number($this->parser);
695: }
696: }
697:
698:
699:
700:
701: 702: 703:
704: function xmltag_But($xp, $elem, $attribs)
705: {
706: if (isset($attribs['region'])) {
707: $this->_element['not-contains']['region'][$attribs['region']] = true;
708: }
709: if (isset($attribs['block'])) {
710: $this->_element['not-contains']['block'][$attribs['block']] = true;
711: }
712: }
713:
714:
715:
716:
717: 718: 719:
720: function xmltag_Onlyin($xp, $elem, $attribs)
721: {
722: if (!isset($attribs['region']) || $attribs['region'] === '') {
723: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region');
724: }
725: $this->_element['onlyin'][$attribs['region']] = xml_get_current_line_number($this->parser);
726: }
727:
728:
729:
730:
731: 732: 733:
734: function xmltag_Author($xp, $elem, $attribs)
735: {
736: if (!isset($attribs['name']) || $attribs['name'] === '') {
737: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'author name');
738: }
739: $this->_authors[] = array(
740: 'name' => @$attribs['name'],
741: 'email' => (string)@$attribs['email']
742: );
743: }
744:
745:
746:
747:
748: 749: 750:
751: function xmltag_Highlight($xp, $elem, $attribs)
752: {
753: if (!isset($attribs['lang']) || $attribs['lang'] === '') {
754: $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'language name');
755: }
756: $this->_code = '';
757: $this->language = strtoupper(@$attribs['lang']);
758: $this->_case = @$attribs['case'] == 'yes';
759: }
760:
761:
762:
763:
764:
765:
766:
767: 768: 769: 770: 771: 772: 773: 774:
775: function _error($code, $params = array(), $lineNo = 0)
776: {
777: if (!$lineNo && !empty($this->parser)) {
778: $lineNo = xml_get_current_line_number($this->parser);
779: }
780: $this->_errors[] = $this->_formatError($code, $params, $this->_syntaxFile, $lineNo);
781: }
782:
783:
784:
785:
786: 787: 788: 789: 790:
791: function _aliasAttributes(&$attrs)
792: {
793: if (isset($attrs['innerClass']) && !isset($attrs['innerGroup'])) {
794: $attrs['innerGroup'] = $attrs['innerClass'];
795: }
796: if (isset($attrs['delimClass']) && !isset($attrs['delimGroup'])) {
797: $attrs['delimGroup'] = $attrs['delimClass'];
798: }
799: if (isset($attrs['partClass']) && !isset($attrs['partGroup'])) {
800: $attrs['partGroup'] = $attrs['partClass'];
801: }
802: }
803:
804:
805:
806: 807: 808: 809: 810:
811:
812:
813:
814: 815: 816:
817: function ($xp, $elem)
818: {
819: $this->_inComment = false;
820: }
821:
822:
823:
824:
825: 826: 827:
828: function xmltag_Region_($xp, $elem)
829: {
830: $this->_element['type'] = 'region';
831: $this->_element['order'] = $this->_blockOrder ++;
832: $this->_regions[$this->_element['name']] = $this->_element;
833: }
834:
835:
836:
837:
838: 839: 840:
841: function xmltag_Keywords_($xp, $elem)
842: {
843: $this->_keywords[$this->_element['name']] = $this->_element;
844: }
845:
846:
847:
848:
849: 850: 851:
852: function xmltag_Block_($xp, $elem)
853: {
854: $this->_element['type'] = 'block';
855: $this->_element['order'] = $this->_blockOrder ++;
856: $this->_blocks[$this->_element['name']] = $this->_element;
857: }
858:
859:
860:
861:
862: 863: 864:
865: function xmltag_Highlight_($xp, $elem)
866: {
867: $conditions = array();
868: $toplevel = array();
869: foreach ($this->_blocks as $i => $current) {
870: if (!$current['contained'] && !isset($current['onlyin'])) {
871: $toplevel[] = $i;
872: }
873: foreach ((array)@$current['onlyin'] as $region => $lineNo) {
874: if (!isset($this->_regions[$region])) {
875: $this->_error(TEXT_HIGHLIGHTER_BLOCK_REGION,
876: array(
877: 'block' => $current['name'],
878: 'region' => $region
879: ));
880: }
881: }
882: }
883: foreach ($this->_regions as $i=>$current) {
884: if (!$current['contained'] && !isset($current['onlyin'])) {
885: $toplevel[] = $i;
886: }
887: foreach ((array)@$current['contains']['region'] as $region => $lineNo) {
888: if (!isset($this->_regions[$region])) {
889: $this->_error(TEXT_HIGHLIGHTER_REGION_REGION,
890: array(
891: 'region1' => $current['name'],
892: 'region2' => $region
893: ));
894: }
895: }
896: foreach ((array)@$current['contains']['block'] as $region => $lineNo) {
897: if (!isset($this->_blocks[$region])) {
898: $this->_error(TEXT_HIGHLIGHTER_REGION_BLOCK,
899: array(
900: 'block' => $current['name'],
901: 'region' => $region
902: ));
903: }
904: }
905: foreach ((array)@$current['onlyin'] as $region => $lineNo) {
906: if (!isset($this->_regions[$region])) {
907: $this->_error(TEXT_HIGHLIGHTER_REGION_REGION,
908: array(
909: 'region1' => $current['name'],
910: 'region2' => $region
911: ));
912: }
913: }
914: foreach ($this->_regions as $j => $region) {
915: if (isset($region['onlyin'])) {
916: $suits = isset($region['onlyin'][$current['name']]);
917: } elseif (isset($current['not-contains']['region'][$region['name']])) {
918: $suits = false;
919: } elseif (isset($current['contains']['region'][$region['name']])) {
920: $suits = true;
921: } else {
922: $suits = @$current['contains-all'] && @!$region['never-contained'];
923: }
924: if ($suits) {
925: $this->_regions[$i]['lookfor'][] = $j;
926: }
927: }
928: foreach ($this->_blocks as $j=>$region) {
929: if (isset($region['onlyin'])) {
930: $suits = isset($region['onlyin'][$current['name']]);
931: } elseif (isset($current['not-contains']['block'][$region['name']])) {
932: $suits = false;
933: } elseif (isset($current['contains']['block'][$region['name']])) {
934: $suits = true;
935: } else {
936: $suits = @$current['contains-all'] && @!$region['never-contained'];
937: }
938: if ($suits) {
939: $this->_regions[$i]['lookfor'][] = $j;
940: }
941: }
942: }
943: foreach ($this->_blocks as $i=>$current) {
944: unset ($this->_blocks[$i]['never-contained']);
945: unset ($this->_blocks[$i]['contained']);
946: unset ($this->_blocks[$i]['contains-all']);
947: unset ($this->_blocks[$i]['contains']);
948: unset ($this->_blocks[$i]['onlyin']);
949: unset ($this->_blocks[$i]['line']);
950: }
951:
952: foreach ($this->_regions as $i=>$current) {
953: unset ($this->_regions[$i]['never-contained']);
954: unset ($this->_regions[$i]['contained']);
955: unset ($this->_regions[$i]['contains-all']);
956: unset ($this->_regions[$i]['contains']);
957: unset ($this->_regions[$i]['onlyin']);
958: unset ($this->_regions[$i]['line']);
959: }
960:
961: foreach ($this->_keywords as $name => $keyword) {
962: if (isset($keyword['ifdef'])) {
963: $conditions[$keyword['ifdef']][] = array($name, true);
964: }
965: if (isset($keyword['ifndef'])) {
966: $conditions[$keyword['ifndef']][] = array($name, false);
967: }
968: unset($this->_keywords[$name]['line']);
969: if (!isset($this->_blocks[$keyword['inherits']])) {
970: $this->_error(TEXT_HIGHLIGHTER_KEYWORD_INHERITS,
971: array(
972: 'keyword' => $keyword['name'],
973: 'block' => $keyword['inherits']
974: ));
975: }
976: if (isset($keyword['otherwise']) && !isset($this->_blocks[$keyword['otherwise']]) ) {
977: $this->_error(TEXT_HIGHLIGHTER_KEYWORD_BLOCK,
978: array(
979: 'keyword' => $keyword['name'],
980: 'block' => $keyword['inherits']
981: ));
982: }
983: }
984:
985: $syntax=array(
986: 'keywords' => $this->_keywords,
987: 'blocks' => array_merge($this->_blocks, $this->_regions),
988: 'toplevel' => $toplevel,
989: );
990: uasort($syntax['blocks'], array(&$this, '_sortBlocks'));
991: foreach ($syntax['blocks'] as $name => $block) {
992: if ($block['type'] == 'block') {
993: continue;
994: }
995: if (is_array(@$syntax['blocks'][$name]['lookfor'])) {
996: usort($syntax['blocks'][$name]['lookfor'], array(&$this, '_sortLookFor'));
997: }
998: }
999: usort($syntax['toplevel'], array(&$this, '_sortLookFor'));
1000: $syntax['case'] = $this->_case;
1001: $this->_code = <<<CODE
1002: <?php
1003: /**
1004: * Auto-generated class. {$this->language} syntax highlighting
1005: CODE;
1006:
1007: if ($this->_comment) {
1008: $comment = preg_replace('~^~m',' * ',$this->_comment);
1009: $this->_code .= "\n * \n" . $comment;
1010: }
1011:
1012: $this->_code .= <<<CODE
1013:
1014: *
1015: * PHP version 4 and 5
1016: *
1017: * LICENSE: This source file is subject to version 3.0 of the PHP license
1018: * that is available through the world-wide-web at the following URI:
1019: * http://www.php.net/license/3_0.txt. If you did not receive a copy of
1020: * the PHP License and are unable to obtain it through the web, please
1021: * send a note to license@php.net so we can mail you a copy immediately.
1022: *
1023: * @copyright 2004-2006 Andrey Demenev
1024: * @license http://www.php.net/license/3_0.txt PHP License
1025: * @link http://pear.php.net/package/Text_Highlighter
1026: * @category Text
1027: * @package Text_Highlighter
1028: * @version generated from: $this->_syntaxFile
1029:
1030: CODE;
1031:
1032: foreach ($this->_authors as $author) {
1033: $this->_code .= ' * @author ' . $author['name'];
1034: if ($author['email']) {
1035: $this->_code .= ' <' . $author['email'] . '>';
1036: }
1037: $this->_code .= "\n";
1038: }
1039:
1040: $this->_code .= <<<CODE
1041: *
1042: */
1043:
1044: /**
1045: * Auto-generated class. {$this->language} syntax highlighting
1046: *
1047:
1048: CODE;
1049: foreach ($this->_authors as $author) {
1050: $this->_code .= ' * @author ' . $author['name'];
1051: if ($author['email']) {
1052: $this->_code .= ' <' . $author['email']. '>';
1053: }
1054: $this->_code .= "\n";
1055: }
1056:
1057:
1058: $this->_code .= <<<CODE
1059: * @category Text
1060: * @package Text_Highlighter
1061: * @copyright 2004-2006 Andrey Demenev
1062: * @license http://www.php.net/license/3_0.txt PHP License
1063: * @version Release: 0.7.1
1064: * @link http://pear.php.net/package/Text_Highlighter
1065: */
1066: class Text_Highlighter_{$this->language} extends Text_Highlighter
1067: {
1068:
1069: CODE;
1070: $this->_code .= 'var $_language = \'' . strtolower($this->language) . "';\n\n";
1071: $array = var_export($syntax, true);
1072: $array = trim(preg_replace('~^(\s*)~m',' \1\1',$array));
1073:
1074: $this->_code .= <<<CODE
1075:
1076: /**
1077: * Constructor
1078: *
1079: * @param array \$options
1080: * @access public
1081: */
1082: function __construct(\$options=array())
1083: {
1084:
1085: CODE;
1086: $this->_code .= <<<CODE
1087:
1088: \$this->_options = \$options;
1089: CODE;
1090: $states = array();
1091: $i = 0;
1092: foreach ($syntax['blocks'] as $name => $block) {
1093: if ($block['type'] == 'region') {
1094: $states[$name] = $i++;
1095: }
1096: }
1097: $regs = array();
1098: $counts = array();
1099: $delim = array();
1100: $inner = array();
1101: $end = array();
1102: $stat = array();
1103: $keywords = array();
1104: $parts = array();
1105: $kwmap = array();
1106: $subst = array();
1107: $re = array();
1108: $ce = array();
1109: $rd = array();
1110: $in = array();
1111: $st = array();
1112: $kw = array();
1113: $sb = array();
1114: foreach ($syntax['toplevel'] as $name) {
1115: $block = $syntax['blocks'][$name];
1116: if ($block['type'] == 'block') {
1117: $kwm = array();
1118: $re[] = '(' . $block['match'] . ')';
1119: $ce[] = $this->_countSubpatterns($block['match']);
1120: $rd[] = '';
1121: $sb[] = false;;
1122: $st[] = -1;
1123: foreach ($syntax['keywords'] as $kwname => $kwgroup) {
1124: if ($kwgroup['inherits'] != $name) {
1125: continue;
1126: }
1127: $gre = implode('|', array_keys($kwgroup['match']));
1128: if (!$kwgroup['case']) {
1129: $gre = '(?i)' . $gre;
1130: }
1131: $kwm[$kwname][] = $gre;
1132: $kwmap[$kwname] = $kwgroup['innerGroup'];
1133: }
1134: foreach ($kwm as $g => $ma) {
1135: $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/';
1136: }
1137: $kw[] = $kwm;
1138: } else {
1139: $kw[] = -1;
1140: $re[] = '(' . $block['start'] . ')';
1141: $ce[] = $this->_countSubpatterns($block['start']);
1142: $rd[] = $block['delimGroup'];
1143: $st[] = $states[$name];
1144: $sb[] = $block['remember'];
1145: }
1146: $in[] = $block['innerGroup'];
1147: }
1148: $re = implode('|', $re);
1149: $regs[-1] = '/' . $re . '/';
1150: $counts[-1] = $ce;
1151: $delim[-1] = $rd;
1152: $inner[-1] = $in;
1153: $stat[-1] = $st;
1154: $keywords[-1] = $kw;
1155: $subst[-1] = $sb;
1156:
1157: foreach ($syntax['blocks'] as $ablock) {
1158: if ($ablock['type'] != 'region') {
1159: continue;
1160: }
1161: $end[] = '/' . $ablock['end'] . '/';
1162: $re = array();
1163: $ce = array();
1164: $rd = array();
1165: $in = array();
1166: $st = array();
1167: $kw = array();
1168: $pc = array();
1169: $sb = array();
1170: foreach ((array)@$ablock['lookfor'] as $name) {
1171: $block = $syntax['blocks'][$name];
1172: if (isset($block['partClass'])) {
1173: $pc[] = $block['partClass'];
1174: } else {
1175: $pc[] = null;
1176: }
1177: if ($block['type'] == 'block') {
1178: $kwm = array();;
1179: $re[] = '(' . $block['match'] . ')';
1180: $ce[] = $this->_countSubpatterns($block['match']);
1181: $rd[] = '';
1182: $sb[] = false;
1183: $st[] = -1;
1184: foreach ($syntax['keywords'] as $kwname => $kwgroup) {
1185: if ($kwgroup['inherits'] != $name) {
1186: continue;
1187: }
1188: $gre = implode('|', array_keys($kwgroup['match']));
1189: if (!$kwgroup['case']) {
1190: $gre = '(?i)' . $gre;
1191: }
1192: $kwm[$kwname][] = $gre;
1193: $kwmap[$kwname] = $kwgroup['innerGroup'];
1194: }
1195: foreach ($kwm as $g => $ma) {
1196: $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/';
1197: }
1198: $kw[] = $kwm;
1199: } else {
1200: $sb[] = $block['remember'];
1201: $kw[] = -1;
1202: $re[] = '(' . $block['start'] . ')';
1203: $ce[] = $this->_countSubpatterns($block['start']);
1204: $rd[] = $block['delimGroup'];
1205: $st[] = $states[$name];
1206: }
1207: $in[] = $block['innerGroup'];
1208: }
1209: $re = implode('|', $re);
1210: $regs[] = '/' . $re . '/';
1211: $counts[] = $ce;
1212: $delim[] = $rd;
1213: $inner[] = $in;
1214: $stat[] = $st;
1215: $keywords[] = $kw;
1216: $parts[] = $pc;
1217: $subst[] = $sb;
1218: }
1219:
1220:
1221: $this->_code .= "\n \$this->_regs = " . $this->_exportArray($regs);
1222: $this->_code .= ";\n \$this->_counts = " .$this->_exportArray($counts);
1223: $this->_code .= ";\n \$this->_delim = " .$this->_exportArray($delim);
1224: $this->_code .= ";\n \$this->_inner = " .$this->_exportArray($inner);
1225: $this->_code .= ";\n \$this->_end = " .$this->_exportArray($end);
1226: $this->_code .= ";\n \$this->_states = " .$this->_exportArray($stat);
1227: $this->_code .= ";\n \$this->_keywords = " .$this->_exportArray($keywords);
1228: $this->_code .= ";\n \$this->_parts = " .$this->_exportArray($parts);
1229: $this->_code .= ";\n \$this->_subst = " .$this->_exportArray($subst);
1230: $this->_code .= ";\n \$this->_conditions = " .$this->_exportArray($conditions);
1231: $this->_code .= ";\n \$this->_kwmap = " .$this->_exportArray($kwmap);
1232: $this->_code .= ";\n \$this->_defClass = '" .$this->_defClass . '\'';
1233: $this->_code .= <<<CODE
1234: ;
1235: \$this->_checkDefines();
1236: }
1237:
1238: }
1239: CODE;
1240: }
1241:
1242:
1243: }
1244:
1245:
1246: 1247: 1248: 1249: 1250: 1251: 1252:
1253:
1254: ?>
1255: