Не стал особо разбираться с препроцессором и с глюками. Того тупого распознавания, которое я сделал, вполне хватит для колорера для сайта. А если глюки исправлю, то надо будет высылать новую версию, чего мне делать не хочется. Вот если перенести проект на местный svn, то с этим будет гораздо проще.
Короче,
здесь лежит простенький колорер для C#. Чтобы сбилдить, опять же, понадобится Nemerle.MSBuild.targets
отсюда, т.к. стандартный targets-файл не поддерживает ресурсы. Колорер использует преобразование xslt, потому работает не очень быстро. Можно в принципе прикрутить бенчмарк, который меряет время именно распарсивания. Хотя общую картину будет портить работа с DOM XML. В общем, у меня не стояло цели сделать быстрый колорер, а просто показать, как такое в принципе делается.
Так что теперь можно писать подсветку для других языков. Правда, для некоторых вещей понадобятся недокументированные (

) возможности. Опишу их вкратце.
Если внимательно приглядеться к файлу BnfParser/bnf-macro.bnf из исходников генератора, то можно заметить, что лексеров можно описать несколько. Я добавил такую фичу, когда писал лексер для XML. Там нельзя бить на непересекающиеся классы все лексемы — какое именно из разбиений используется, определяется контекстом. Короче, используется 6 лексеров, между которыми идёт переключение при поступлении тех или иных лексем. Все лексеры помещены в один класс, а переключение между ними выполняется с помощью свойства Mode.
Чтобы не повторять описания, можно до первого раздела lexer добавить раздел subst, в котором описать все нужные вспомогательные правила, а из лексеров ссылаться на них. Выглядеть это может так:
subst
{
AuxRule1 ::= ...;
AuxRule2 ::= ...;
}
lexer (name = "First")
{
Rule1 ::= AuxRule1 | AuxRule2;
Rule2 ::= AuxRule1 "," AuxRule2;
}
lexer (name = "Second")
{
Rule1 ::= AuxRule1;
Rule3 ::= AuxRule2+ AuxRule1;
}
Эквивалентно:
lexer (name = "First")
{
subst AuxRule1 ::= ...;
subst AuxRule2 ::= ...;
Rule1 ::= AuxRule1 | AuxRule2;
Rule2 ::= AuxRule1 "," AuxRule2;
}
lexer (name = "Second")
{
subst AuxRule1 ::= ...;
subst AuxRule2 ::= ...;
Rule1 ::= AuxRule1;
Rule3 ::= AuxRule2+ AuxRule1;
}
Если лексеров больше одного, то нужно обязательно указывать для них имена. Пока свойство Mode имеет тип int. Но в будущем я это исправлю.
... << RSDN@Home 1.2.0 alpha rev. 672>>