SAL аннотации.
В последнее время я немного забросил Win32.Utf8 – на работе завал, так что, приходя домой, делать ничего особенного не хочется. Тем не менее, проект потихоньку движется и, на сегодняшний день, я добрался до разбора SAL аннотаций.
В последнее время я немного забросил Win32.Utf8 – на работе завал, так что, приходя домой, делать ничего особенного не хочется. Тем не менее, проект потихоньку движется и, на сегодняшний день, я добрался до разбора SAL аннотаций.
Продолжаю возиться с синтаксическим анализом.
Основное преимущество, которое даёт использование AST по сравнению с техникой разбора снизу вверх (bottom-up parsing) – это возможность отложить анализ разобранного текста «на потом». Это может быть удобно по разным причинам. В случае Win32.Utf8 это удобно тем, что требования к анализатору формируются прямо в процессе работы над проектом. По большому счёту я понятия не имею, что получиться в конечном итоге.
Во время работы над парсером постоянно возникала необходимость посмотреть как выглядит тот или иной кусок дерева или все дерево целиком. Недолго думая, я попробовал выводить его в виде XML, – получилось довольно неплохо.
Исходный код на C:
typedef void *LPVOID;
Дерево, полученное после синтаксического разбора:
<translation_unit>
<external_declaration>
<declaration>
<init_list_declaration>
<declaration_specifiers>
<declaration_specifier>
<storage_class_specifier>
typedef
</storage_class_specifier>
</declaration_specifier>
<declaration_specifier>
<type_specifier>
<builtin_type>
void
</builtin_type>
</type_specifier>
</declaration_specifier>
</declaration_specifiers>
<init_declarator>
<declarator>
<pointer>
*
</pointer>
<direct_declarator>
LPVOID
</direct_declarator>
</declarator>
</init_declarator>
</init_list_declaration>
;
</declaration>
</external_declaration>
</translation_unit>
Алгоритм работы Win32.Utf8 состоит из трех основных шагов:
На данный момент я работаю над вторым этапом. Цель – построенное дерево должно быть компактным, его структура должна облегчать последующий анализ во время генерации кода. В тоже время дерево должно включать всю информацию необходимую для генерации корректного кода.
Существует два способа собрать DParser for Python под Windows:
Естественно, что я выбрал второй вариант.
(На самом деле причина довольно прозаична – не хотелось собирать один проект двумя разными компиляторами).
Стандартный обработчик пробелов в DParser распознаёт пробелы, табуляцию, переводы строк, C-подобные комментарии и директивы “#line”. Мне нужно было отсеивать ещё и “#pragma” директивы, которые препроцессор от Visual C++ любезно оставляет в коде. Для этого понадобилось определить свой обработчик пробельных символов:
re_whitespace =
re.compile(r'(\\s+|/\\*(.|\\n)*?\\*/|//.*\\n|(^\\s*\\#.*$((?<=\\\\)\\n.*$)*))+', re.M)
def whitespace(loc):
m = re_whitespace.match(loc.buf, loc.s)
if m:
loc.s = m.end()
loc.line += m.group().count('\\n')
Из интересного тут только само регулярное выражение. Мне понадобилось н-дцать попыток, чтобы довести его до ума.
Переделал разбор С заголовков на DParser – получил ускорение в 10 раз. Мелочь, а приятно.

PS. Под профайлером разница меньше, – раз шесть всего, но тоже впечатляет.
Recent Comments