QapDSL — декларативное описание AST и парсеров для C++

от автора

QapDSL — декларативное описание AST и парсеров для C++

QapDSL — это специализированный язык (DSL), который позволяет описывать абстрактные синтаксические деревья (AST) и правила их разбора для языков программирования, прежде всего C++. Такая формализация помогает автоматизировать построение парсеров, генерацию кода, анализ исходников и даже рефакторинг.

Зачем нужен QapDSL?

  • Компактно и наглядно описывать структуру и грамматику языка.
  • Автоматически генерировать C++-структуры, парсеры, сериализаторы и визиторы.
  • Ускорять эксперименты с языками, создавая прототипы компиляторов и анализаторов.
  • Упрощать анализ и рефакторинг сложных языков, в т.ч. C++.

Пример QapDSL-описания

Рассмотрим, как описывается объявление класса на C++:

<code>t_class{   string keyword;   t_sep sep0;   string name;   t_sep sep1;   TAutoPtr<t_parents> parents;   t_sep sep2;   TAutoPtr<t_class_body> body;   t_sep sep3;   {     M+=go_any_str_from_vec(keyword,split("struct,class,union",","));     O+=go_auto(sep0);     O+=go_str<t_name>(name);     O+=go_auto(sep1);     O+=go_auto(parents);     O+=go_auto(sep2);     O+=go_auto(body);     O+=go_auto(sep3);     M+=go_const(";");   } }</code>

  • Поле keyword — ключевое слово (struct, class, union).
  • name — имя класса, parents — список базовых классов.
  • В фигурных скобках — правила разбора для каждого поля (обязательно/опционально, тип парсинга).

Пример сгенерированного C++-кода

Вот пример C++-структуры, которую может сгенерировать QapGen по приведённому выше QapDSL-описанию:

<code>class t_class{   #define DEF_PRO_STRUCT_INFO(NAME,PARENT,OWNER)NAME(t_class)OWNER(t_inl_file)   #define DEF_PRO_VARIABLE(ADDBEG,ADDVAR,ADDEND)\   ADDBEG()\   ADDVAR(string,keyword,DEF,$,$)\   ADDVAR(t_sep,sep0,DEF,$,$)\   ADDVAR(string,name,DEF,$,$)\   ADDVAR(t_sep,sep1,DEF,$,$)\   ADDVAR(TAutoPtr<t_parents>,parents,DEF,$,$)\   ADDVAR(t_sep,sep2,DEF,$,$)\   ADDVAR(TAutoPtr<t_class_body>,body,DEF,$,$)\   ADDVAR(t_sep,sep3,DEF,$,$)\   ADDEND()   //=====+>>>>>t_class   #include "QapGenStructNoTemplate.inl"   //<<<<<+=====t_class   public:     bool go(i_dev&dev){       t_fallback scope(dev,__FUNCTION__);       auto&ok=scope.ok;       auto&D=scope.mandatory;       auto&M=scope.mandatory;       auto&O=scope.optional;       static const auto g_static_var_0=QapStrFinder::fromArr(split("struct,class,union",","));       M+=dev.go_any_str_from_vec(keyword,g_static_var_0);       if(!ok)return ok;       O+=dev.go_auto(sep0);       if(!ok)return ok;       O+=dev.go_str<t_name>(name);       if(!ok)return ok;       O+=dev.go_auto(sep1);       if(!ok)return ok;       O+=dev.go_auto(parents);       if(!ok)return ok;       O+=dev.go_auto(sep2);       if(!ok)return ok;       O+=dev.go_auto(body);       if(!ok)return ok;       O+=dev.go_auto(sep3);       if(!ok)return ok;       M+=dev.go_const(";");       if(!ok)return ok;       return ok;     }   }; </code>

  • Структура полностью повторяет схему из QapDSL и содержит макросы для генерации кода и сериализации.
  • Метод go реализует правила разбора для каждого поля — как и в QapDSL.
  • Включение QapGenStructNoTemplate.inl добавляет автогенерированные методы для RTTI/визиторов/сериализации.

QapDSL в действии: как это работает?

  1. Пишем QapDSL-описание грамматики.
  2. Автогенератор создает C++-структуры и код парсера.
  3. Получаем AST, по которому можно строить анализаторы, рефактореры, сериализаторы и т.д.

В проекте можно встретить QapDSL-описание, закодированное в base64 или encodeURIComponent внутри комментария — это целостная схема AST и грамматики.
Пример живого проекта: cpp_ast_scheme.cpp в QapGen и репозиторий QapGen.

Сравнение с аналогами

QapDSL ANTLR Yacc/Bison protobuf
Тип DSL для AST+грамматики Генератор парсеров Генератор парсеров DSL для сериализации
AST Автоматически Через actions Ручное Только структуры данных
Язык генерации C++ Java, C++, Python и др. C/C++ C++, Python и др.
Поддержка C++-синтаксиса Глубокая Возможно Возможно Нет
Порог вхождения Средний Средний/Высокий Средний/Высокий Низкий

QapDSL: плюсы и минусы

  • + Одна схема — и AST, и парсер.
  • + Просто расширять и поддерживать новые конструкции C++ (шаблоны, пространства имён, препроцессор).
  • + Автоматическая генерация кода, сериализация, визиторы.
  • Меньше документации и сообщества, чем у ANTLR/Yacc.
  • Ориентация прежде всего на C++ и AST-heavy задачи.

Где посмотреть/попробовать?

Заключение

QapDSL — мощный инструмент для тех, кто работает с AST, парсерами и анализом кода C++. Он позволяет компактно описывать самые сложные конструкции C++ и автоматизировать рутинные задачи, связанные с синтаксисом. Если вы любите декларативные подходы и часто пишете компиляторы или анализаторы — обязательно попробуйте QapDSL!


Автор: Adler3d. Статья подготовлена при поддержке GitHub Copilot.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Понятно?

0% Да0
0% Нет0
0% Посчитайте как полчеловека0

Никто еще не голосовал. Воздержавшихся нет.

ссылка на оригинал статьи https://habr.com/ru/articles/916006/