Описание всех функций генератора
CLL - Common Language Logic.
Что это
При создании парсера семантические действия часто важны для правильной конструкции AST. CLL - это возможность вставлять семантические действия в парсер генераторе. Отличается удобным синтаксисом, достаточной абстракцией и конвертацией в большинство, если не во все языки.
Принцип роботы
CLL объявляеться с помощью $. В дальнейшем планирую сделать опциональным. После $ идет объявление переменной, условие, цикл и т.д.
Объявление переменных
num floating = 1.4;
num integral = 1;
str string = "Hello, World!";
bool boolean = true;
arr<str> array = ["a", "b", "c"];
obj<str, bool> object1 = { a: true, b: false, c: true };
obj<num, bool> object2 = { 1: true, 2: false, 3: true };
var any_type = "Hello, World!";
any_type = 45;
Типы:
num - номер с плавающей запятой
str - строка
bool - булиновое значение
arr<type> - массив определенного типа
obj<typen type> - объект (ключ-значение)
Token - тип токена.
Rule - тип правила
var - переменная любого типа
Пример перевода в С++:
double floating = 1.4;
double integral = 1;
std::string string = "Hello, World!";
bool boolean = true;
std::vector<std::string> array = {"a", "b", "c"};
std::unordered_map<std::string, bool> object1 = {
{"a", true},
{"b", false},
{"c": true}
};
std::unordered_map<long long, bool> object2 = {
{1, true},
{2, false},
{3, true}
};
std::any any_type = "Hello, World!";
any_type = 45;
Объявление условий
NUMBER:
@( @ [+-]? @ ( [0-9]+ ) @ ([.,] [0-9]+)? )
@{full, sign, main, dec}
;
simple_expr:
&a NUMBER &sign PLUS | MINUS | DIVIDE | MULTIPLE &b NUMBER
$if (sign.name() == :PLUS) {
$return a.full.to_double() + b.full.to_double();
} else if (sign.name() == :MINUS) {
$return a.full.to_double() - b.full.to_double();
} // ...
;
&a NUMBER - объявление переменной "а" с значением результата матчинга токена NUMBER
sign.name() - для правил или токенов доступны методы, этот возвращает имя токена/правила
:PLUS - имя токена или правила. Для вложеных правил используеться "."
TO_DOUBLE - встроенная функция конвертирования
Пример перевода C++:
template<typename IT>
Rule_res simple_expr(IT pos) {
Token a;
Token sign;
Tokne b;
if (pos->name() != Tokens::NUMBER) {
// throw an error
}
a = *pos++;
// ...
if (sign.name() == Tokens::PLUS) {
return {true, Rule(/*...*/, stod(a.data().full) + stod(b.data().full))};
} else {
if (sign.name() == Tokens::MINUS) {
return {true, Rule(/*...*/, stod(a.data().full) - stod(b.data().full))};
}
}
return {true, {}};
}
Объявление циклов
object:
&key NUMBER | STRING ':' &val rvalue (&keys NUMBER | STRING ':' &values rvalue)*
$obj<num, var> ints;
$obj<str, var> strings;
$if (key.name() == :NUMBER) {
ints[key.full.to_int()] = rvalue;
} else {
strings[key] = rvalue;
}
$for (num i = 0; i < keys.size(); i++) {
$if (key.name() == :NUMBER) {
ints[keys[i].full.to_int()] = values[i];
} else {
strings[keys[i]] = values[i];
}
}
// create AST node
{
ints: ints
strings: strings
}
;
Пример перевода в C++:
std::unordered_map<int, std::any> ints;
std::unordered_map<std::string, std::any> strings;
if (key.name() == Tokens::NUMBER) {
ints[stoi(key.data())] = rvalue;
} else {
strings[key.data()] = rvalue
}
for (double i = 0; i < keys.size(); i++) {
if (key.name() == Tokens::NUMBER) {
ints[stoi(key.data())] = rvalue;
} else {
strings[key.data()] = rvalue
}
}
object_data data;
data.ints = ints;
data.strings = strings;
return {true, Rule(/*...*/, data)};
Поддерживаеться также while, синтаксис как в других языках:
while(cond) { statement }
Встроенные методы
Этот список может изменяться
num - to_str
str - find, slice, substr, insert, erase, to_double, to_int
arr - find, slice, insert, erase, push, pop
obj - keys, values
Token, Rule - startpos, endpos, clear, empty, line, column, length, name, data
Объявление типов и функций
сам CLL пока что не позволяет добавлять свои функции и типы, но он позволяет определить их из другого источника чтобы далее использовать в CLL. Например
extern type uint8_t;
extern void log(str message);
Сравнение с ANTRL, Bison
-
Вставка кода и абстракция.
В ANTRL и Bison код вставляеться напрямую, без абстракций. Это сразу делает грамматику специфичной для конкретного языка.
В CLL код конвертируеться в любой язык, давая возможность создавать общие структуры как переменные, циклы
-
Типизация
ANTRL использует типизацию целевого языка
В Bison типизация может быть частичной через%type
, но сложной в управлении.
CLL имеет встроенные типы, ошибки проверяються во время компиляции -
Читаемость
Семантические действия мешают читаемости в ANTRL, Bison, но не так существенно с CLL
Итог
CLL это мощный инструмент для добавления различных семантических действий в грамматику. Он позовляет создавать переменные, условия, циклы не делая эти добавления специфичными для языка. Его абстракция упрощает взаимодействие с разпарсенными данными, делая этот инструмент нужным для правильной конструкции AST.