Описание всех функций генератора
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.
