Обновить
3
0

Пользователь

Отправить сообщение

Сейчас компиляторы строят таблицу символов при парсинге и смотрят в неё для правильного создания дерева. Так работает как GCC, так и clang. Ваш подход похож на GLR, который хранит обе возможные части дерева и дает решить что из этого откинуть позже

T * T - в завимимости от T это объявление поинтера или умножение
с T::something проблем меньше, но все равно нужно знать это переменная или тип для более правильного lookup.

а как вы парсили templates, <, <<, >, >>, или например T * T, или T::something. Это все требует семантику

Да, этот язык я придумал сам. То, что вы предалагаете делает ANTRL, но для парсинга сложных языков как C++ семантические действия в генераторе необходимы.

можете еще кстати почитать недавно опубликованную статью о CLL

Мой генератор делает токенизацию, что в этом случае не всегда еффективно. Прямой матчинг может быть лучше чем использование DFA таблиц. Низкоуровневый контроль часто необходим чтобы построить лучшее дерево. А так да, можно

Помочь мне можно именно с backend, frontend уже сделан. Но для этого нужно разбирать мой код. Поэтому я просто предлагаю)

Спасибо, мы кстати можем работать над этим генератором вместе. Мне хотелось бы найти команду т.к проект стает достаточно большим для реализации в одиночку. Тем не менее ваш генератор по описанию не плох как я упоминал для JSON, XML. Если бы мне нужно было парсить эти структуры, я бы либо писал парсер вручную либо использовал подобный вашему генератор.

Я думаю в следующей статье описать СLL подробно, укажу больше хабов (думал в начале здесь как на редите нельзя постить если пост не подходит под тему поэтому указал только подходящие хабы)

AST храниться с помощью структуры node (уже считаю устаревшим). Состоит из информации о позиции в тексте и std::any data. Этот дата хранит саму информацию правила, что обычно или структура или прямой тип данных. Сами типы находяться здесь.

Вывод достаточно сложный, полный макросов, но ок для авто генерированного кода. Сам DSL я тоже не понимаю :)

на генерацию старой версии уходило около 700 мс, на генерацию новой версии около 1с

Это старая реализация, но сгенерированная этим парсером и сейчас используеться для парсинга грамматики. Новая реализация использует DFA для лексера и парсера в месте опциональных правил

Parser.h

Parser.cpp

Мой парсер генератор использует также структуры а не обьекты если только пользователь самостоятельно не создаст обьект как тип данных:

some_rule:
  @ key ';' @ value
  $obj<str, var> obj;
  $obj[@] = @;
  {obj}
;

Если сохранить это следующим образом то будет структура:

some_rule:
  @ key ';' @ value
  @{key, value}
;

То-есть это создаёт структуру:

{
  a: a
  b: b
}

Это создает обьект:

obj<str, str> obj
{obj}

Переписывать мой парсер на QapDSL мне не поможет т.к я уже успешно сделал bootstrap своей грамматики.

Да, думаю переходить с этой структуры на другую (основанную на std::variant и структурах для каждого правила/токена) или возможно полностью на структуру из классов но она вроде бы считаеться устаревшой.
Вообще в своем проекте я сделал TreeAPI (сейчас AST.API), который определяет дерево в удобной, фиксированной структуре, которая не будет изменяться и конвертирует дерево из парсера в эту структуру. Это даёт возможность редактировать вывод дерева парсера с минимальными затратами т.к таких изменений будет много в будущем

У меня все также open source, проект на C++20/C++23 с использованием модулей

Сам принцип парсера - низкоуровненове взаимодействие (низкоуровневое в нашем случае будет означать прямое обьявление переменных, условий и т.д). ISPA парсер даёт этому абстракцию давая добавлять низкоуровневые елементы только когда это необходимо. Именно в этом и преимущество. Это не значит, что какой-то из вариантов лучше, просто каждый подходит больше под свою задачу. Например QapDSL лучше подходит для парсинга JSON, XML, INI, где прямое взаимодействие обычно необходимо, а EBNF для новых языков или других комплексных текстов.

Насчет самостотельного создания дерева, это правда для ANTRL, но не для ISPA. В ISPA вы просто выделяете что захватить, а далее определяете каким типом данных оно будет (int, bool, string, array, object) и что из захваченного туда поместить. Хотя можно и редактировать данные перед созданием дерева посредством CLL.

Ещё одна важная проблема для парсер генераторов это ошибки. Я стараюсь её решить посредством fail блоков. В QapDSL это опять же низкоуровневое (что вообще может быть и отлично)

В целом QapDSL имеет смысл и вам нужно над этим работать.

с QapDSL я не знаком совсем, но по тому, что я вижу могу сказать следующее:
он достаточно низкоуровневый по сравнению с EBNF. Пример правила в ispa:

condition: // name "if" for rule is prohibited
  'if' '(' @ expr ')' @ stmt 'else' @ stmt
  @{expression, true_stmt, false_stmt}
;
expr:
  logical

  #logical:
      @ compare (@ LOGICAL_OP @ compare)*

      @{left, op, right}
  ;

  #compare:
      @ arithmetic (@ COMPARE_OP @ arithmetic)*

      @{first, operators, sequence}
  ;
  // ... see https://github.com/Sinfolke/ispa-parser/blob/main/parser/parser/cll.isc
  #value:
      @ group | _variable | function_call | method_call | rvalue
      {@}
  ;
;
stmt:
  ( '{' @ #value '}' ) | @ #value
  {@}
  #value:
  // here what stmt could contain
  ;
;

Похоже на ANTRL.

  1. Этот парсер генератор может генерировать LR парсеры. Конструкция дерева может не отличаться с LL парсером как только я реализую PLL алгоритм (мой собственный алгоритм который добавляет левую рекурсию в LL парсерах)

  2. Все достаточно абстрактно, хотя вообще вы можете матчить текст самостоятельно в СLL. Достаточно просто добавить для этого возможность читать текущий символ и токен. То-есть абстракция есть, но можно делать что-то специфичное если нужно. Именно поэтому я хочу сделать возможность создавать свое дерево на конкретном языке (пункт 3 в посте).

  3. В QapDSL похоже нету токенизации

  4. ISPA как отдельный язык, в то время как QapDSL больше похож на утилиту для существующего языка

  5. ISPA пока что поддерживает только C++, но его архитектура позволяет генерацию на несколько языков.

    QapDSL как ассемблер, гибкий, низкоуровневый, но из-за этого сложный.

    Bison как C с инлайн ассемблером - декларативный, с возможностью низкоуровневого контроля

    ISPA, ANTRL как C++ - высокоуровневые, удобные, но не теряющие контроль

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность