Разработка простого синтаксического анализатора, страница 5

if (isParsing)

return;

break;

case WM_KEYDOWN:

if (открыто окно подсказки)

{

switch ((int) m.WParam)

{

case VK_DOWN:

if (в окне подсказки есть, что показывать)

// Изменяйте индекс выбранного элемента

return;

case VK_UP:

// Изменяйте индекс выбранного элемента

return;

case VK_RETURN:

case VK_SPACE: AcceptPrompt (); return;

case VK_ESCAPE: // Спрячьте окно подсказки return;

}

}

else if ((GetKeyState (VK_CONTROL) & 0x80) != 0)

{

switch ((int) m.WParam)

{

case VK_SPACE: CompleteWord (); return; // Ctrl+Space 

case 0x5A: Undo (); return;       // Ctrl+Z

case 0x59: Redo (); return;       // Ctrl+Y

}

}

else

{

// Работа со стеками undo и redo

}

break;

case WM_CHAR:

switch ((int) m.WParam)

{

case VK_SPACE: // Ctrl+Space

if ((GetKeyState (VK_CONTROL) & 0x80) != 0)

return;

break;

case VK_RETURN: if (открыто окно подсказки) return;

break;

. . .

default:

. . .

}

break;

}

base.WndProc (ref m);

}

Разработка алгоритма анализа текста

Перейдем к разработке методов класса SyntaxBox. Главная идея алгоритма разбора (метода Parse) состоит в том, что в процессе анализа текущего текста элемента SyntaxBox (его свойства Text), надо генерировать цветной (форматированный) текст (его же свойство Rtf). Для этого в классе SyntaxBox объявлена переменная rtf типа StringBuilder. В ней мы собираемся накопить форматированный текст (или текст разметки) и затем перенести его в RTF-документ. Перенос состоит в установке свойства Rtf. Схема метода Parse может выглядеть таким образом:

private void Parse ()

{

InitRtf (); // Установка RTF-заголовка

for (pos = 0; pos < TextLength; )// Объявление переменной pos (текущей позиции текста) удобно вынести в класс

{

AppendToken ();          // Здесь выявляется и обрабатывается одно из ключевых слов

if (pos < TextLength)  // Если после него что-то есть, то оно может быть комментарием

{

Comment com = FindComment (pos);    // Здесь выявляются комментарии

if (найден)

// Здесь обрабатывается (форматируются) комментарий (Позиция pos сдвигается нужным образом)

else

{

AppendChar ();     // Если ни ключевое слово, ни комментарий не найдены, вставляем простой текст

pos++;

}

}

}

Rtf = rtf.ToString ();  // Накопленный в StringBuilder форматированный текст переносится в RTF-документ

}

Подскажу, как создать заголовок текста разметки RTF. Добавьте следующий метод в класс SyntaxBox.

private void InitRtf ()

{

rtf = new StringBuilder (150 + 2 * TextLength); // Это Capacity контейнера

rtf.Append (@"{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{"); // RTF header

rtf.Append (@"\f0\fnil\fcharset0" + Font.Name + ";}}\n");  // Установка шрифта

AppendColors ();   // Добавьте таблицу цветов

// Этот фрагмент завершает заголовок RTF. После него можно вставлять наш форматированный текст.

rtf.Append (@"}\n\viewkind4\uc1\pard\ltrpar\cf" + colorTable[ForeColor] + " ");

}

Метод AppendColors добавляет в формат rtf таблицу цветов. Их надо взять из наших ключевых слов и комментариев, то есть из объектов вспомогательных классов (структур), которые вы разработали ранее. Как было сказано, все цвета надо пронумеровать. В процессе создания таблицы цветов (попутно) создим динамическую коллекцию Dictionary<Color, int> и используем ее в дальнейшем для окрашивания текста.

private void AppendColors ()

{

colorTable = new Dictionary<Color, int> ();

int id = 1;

colorTable.Add (ForeColor, id++);   colorTable.Add (BackColor, id++);

rtf.Append (@"{\colortbl ;" +

@"\red" + ForeColor.R + @"\green" + ForeColor.G + @"\blue" + ForeColor.B + ";" +

@"\red" + BackColor.R + @"\green" + BackColor.G + @"\blue" + BackColor.B + ";");

foreach (для каждого ключевого слова в коллекции highlighter.Keywords)

{

if (такого цвета нет)

{

Color c = возьмите его из текущей структуры Keyword;

colorTable.Add (c, id++);