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

  • Автор темы Автор темы MORGAN
  • Дата начала Дата начала

MORGAN

Активный пользователь
Регистрация
04.06.2025
Сообщения
1 179
Реакции
1 068
Баллы
113

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


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


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


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


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


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

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);
M+=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(";");
}
}



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


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


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

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;
M+=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;
}
};


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


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


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

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



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


QapDSLANTLRYacc/Bisonprotobuf
Тип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!



upd:
QapDSL:

t_var_decl{
string type_name;
string var_name;
{
M+=go_str<t_type>(type_name);
M+=go_const(" ");
M+=go_str<t_name>(var_name);
M+=go_const(";");
}
}
 
Назад
Верх