- PVSM.RU - https://www.pvsm.ru -

QapDSL — это специализированный язык (DSL), который позволяет описывать абстрактные синтаксические деревья (AST) и правила их разбора для языков программирования, прежде всего C++. Такая формализация помогает автоматизировать построение парсеров, генерацию кода, анализ исходников и даже рефакторинг.
Рассмотрим, как описывается объявление класса 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).Вот пример 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;
}
};
go реализует правила разбора для каждого поля — как и в QapDSL.QapGenStructNoTemplate.inl добавляет автогенерированные методы для RTTI/визиторов/сериализации. В проекте Sgon [1] можно встретить QapDSL-описание, закодированное в base64 или encodeURIComponent внутри комментария — это целостная схема AST и грамматики.
Пример живого проекта: cpp_ast_scheme.cpp в QapGen [2] и репозиторий QapGen [3].
| QapDSL | ANTLR | Yacc/Bison | protobuf | |
|---|---|---|---|---|
| Тип | DSL для AST+грамматики | Генератор парсеров | Генератор парсеров | DSL для сериализации |
| AST | Автоматически | Через actions | Ручное | Только структуры данных |
| Язык генерации | C++ | Java, C++, Python и др. | C/C++ | C++, Python и др. |
| Поддержка C++-синтаксиса | Глубокая | Возможно | Возможно | Нет |
| Порог вхождения | Средний | Средний/Высокий | Средний/Высокий | Низкий |
QapDSL — мощный инструмент для тех, кто работает с AST, парсерами и анализом кода C++. Он позволяет компактно описывать самые сложные конструкции C++ и автоматизировать рутинные задачи, связанные с синтаксисом. Если вы любите декларативные подходы и часто пишете компиляторы или анализаторы — обязательно попробуйте 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(";");
}
}
Что даётся на вход Лексеру:
Строка программы, например:
int x;
Лексер разбивает текст на лексемы (токены):
int // лексема типа
// пробел (разделитель)
x // идентификатор (имя переменной)
; // символ конца объявления
Какой AST получается на выходе:
После разбора получится структура:
t_var_decl{
type_name = "int"
var_name = "x"
}
То есть, поле type_name содержит строку «int», а var_name — строку «x».
Автор: Adler3d [5]. Статья подготовлена при поддержке GitHub Copilot.
Автор: Adler3D
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ast/421812
Ссылки в тексте:
[1] проекте Sgon: https://github.com/adler3d/unordered/tree/master/code/uidevs_from_nout_d_temp/uidev_one/Sgon
[2] cpp_ast_scheme.cpp в QapGen: https://github.com/Adler3d/QapGen/blob/master/samples/cpp_ast_scheme.cpp#L1
[3] репозиторий QapGen: https://github.com/Adler3d/QapGen
[4] samples в репозитории: https://github.com/Adler3d/QapGen/tree/master/samples
[5] Adler3d: https://github.com/Adler3d
[6] Источник: https://habr.com/ru/articles/916006/?utm_campaign=916006&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.