Обновить
5
21.1
Алексей Миклин@miklin-ag

Разработчик ПО

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

Функция ptr::drop_in_place выполняет деструктор по указанному адресу, по сути освобождая память, на которую указывает num_ptr. После её вызова ресурс уже освобождён, но переменная num по‑прежнему существует и при выходе из области видимости снова попробует освободить тот же самый адрес. Это классическая ситуация double free.

Вовсе не так: у вас же num_ptr: *mut i32, то есть никакого деструктора для числа нет, тем более освобождающего память.

Надо было оперировать указателем на Box, чтобы получить double free.

В данном случае это даже супер, потому что переменная x всё ещё владеет своим старым значением, и его деструктор вызовется автоматически при выходе из функции.

Про это уже сказали выше - здесь будет утечка старого значения.

А, сорри, промахнулся, @Mingun , это не вы предложили комбинатор.

Но в остальном всё похоже для PEG и для комбинатора - лексер, приенённый до них передаст в парсер полный массив токенов, а в парсере всё так же разрешать неоднозначности с помощью упорядоченного выбора. И, соответственно, потенциально получить ухудшение перформанса - по сравнению с CFG (lalrpop), но это будет всё же наверное выгоднее, чем без лексера.

Лексер при этом для слабого слова и для идентификатора выдаст один токен, например, KwOrId("name"), а парсер уже в зависимости от выполненной альтернативы выявит, что это.

Что-то я не понимаю вас. Если выбор единственный, то тем более стоит брать CFG.

Вы же предложили аналог рекурсивного спуска - на парсер-комбинаторе - как раз для разрешения неоднозначностей путем упорядоченного выбора из альтернатив (как и в PEG). А за это свойство расплата в виде замедления - варианты могут перебираться неоптимально.

Вы предложили, как я понял, разрешение в парсере - является ли слово ключевым или идентификатором - просто в зависимости от того, какая альтернатива сработает первой по порядку.

Пришла ещё мысль, что разрешение слабого ключевого слова в CFG вторым способом будет мало отличаться от определения альтернатив для PEG и nom, но CFG более оптимально по-идее.

А, то есть у вас лексер превращает входную строку в вектор токенов, который потом идёт в nom?

Интересная идея, так возможно будет чуть эффективнее - работать в парсере уже с токенами, а не с байтами, хотя и потребует большую аллокацию для всех токенов.

Так можно и для rust-peg, видимо, сделать. И не совсем понятно, в чём принципиальная разница между ними будет, если обходиться стандартными мультипликаторами - rust-peg тогда будет полаконичнее.

Но главное свойство - упорядоченный выбор - остаётся, и его недостатки в виде возможного ухудшения перформанса тоже.

Разные языки используются для разных же целей. А ваша "группа C языков", это кажется вообще что-то из эзотерики - не понятно, почему вы в одну кучу сложили C и C#

Зато вы можете самостоятельно перепарсить это место (т.е. начать разбор с указанного парсером места ошибки) уже другим парсером (даже PEG парсером, т.е. фактически другим правилом из той же грамматики) и получить то, что хотите.

Так перепарсить можно для любого типа парсера, а мы здесь их пытаемся сравнить.

Более того, такие правила (на ошибочный вход), можно сознательно вставлять в грамматику в вероятных местах ошибки и прямо включать в выстраиваемый AST, чтобы потом обработать их на более верхнем уровне.

Множественные ошибки может выдавать и lalrpop.

По вашему примеру с незакрытым строковым литералом - для CFG парсера (например lalrpop) это делается прямо в лексере, и он выдаёт кастомную ошибку.

Я ж говорю, интересно было бы провести исследование и сравнить показатели перформанс-память против удобства и обработки ошибок для PEG (rust-peg) vs CFG (lalrpop) на реально нагромождённом языке типа моего случая.

Будет интересно почитать другие статьи - именно в упор на другие модели механики \ оптимизации существующих (насколько я понимаю перед этим надо задать ограничения).

На сайте про AnyDynamics есть статьи, в которых разобраны некоторые задачи механики с использованием языка.

Про оптимизацию вы, видимо, подразумеваете задачи оптимизации функционалов и систем управления - в языке есть соответствующие конструкции.

В принципе НЕ может бы универсальной системы моделирования или, как вы её называете, одного языка моделирования "на все случаи жизни".

Можете указать, где я такое писал? Вы как будто прочитали другой текст и спорите не понятно с кем.

И в основном тексте, и в ответах к вам указаны конкретные сферы и примеры применения языка, где он неплохо подходит.

в пределах того же уровня (лексер \ парсер ) - откат при обнаруженной ошибке делается из коробки (*) сколько угодно раз

вроде из коробки в nom этого нет - придётся учить (делать дополнительные обёртки, которые умеют пробрасывать в лексер ошибки парсера)

Почитал про nom - с ним действительно должно быть нетрудно справляться со слабыми ключевыми словами - судя по описанию, ведь в нём есть возможность использовать выбор из упорядоченного списка альтернатив. Соответственно всё тот же набор trade-off по скорости, памяти и удобству относительно использованного мной CFG парсера, как и для PEG парсера, что приведены в ответе выше.

Использование nom кажется будет ещё более многословнее, чем rust-peg, но зато через него можно протянуть кастомные ошибки, как и с lalrpop, что использовал я.

А лексера в nom (и rust-peg) никакого специально не выделяется, поиск идёт по диапазону байтов, в отличие от CFG парсера (lalrpop), где лексер выдаёт более крупные токены.

почему уже в самом описании парсера нельзя указать, тут name ключевое слово или нет. Ну то есть если в парсере в этом месте написано "name", то явно именна такая последовательность тут и ожидается и это ключевое слово. При этом оно ведь ожидается только в этом месте, в других местах вы спокойно в грамматике пишите <kw_name:id> и если там разбираемом тексте встретится name, оно будет как идентификатор распознано, а не ключевое слово. Или я тут чего-то не понимаю? Кстати, не смотрели на rust-peg?

Почитав про rust-peg, я понял вашу мысль. Действительно, PEG парсер позволяет разрешать слабые ключевые слова довольно легко, за счёт своего базового свойства - в нём описываемые в грамматике альтернативы упорядочены, и конфликтов поэтому быть не может, в отличие от контекстно-свободного (CFG) парсера, который использовал я и для которого приходится ухищряться (в статье приводятся способы) при разрешении таких слабых слов. (В прежнем моём ответе выше есть объяснение, почему ваше предложение не работает для моего случая).

Навскидку кажется, что грамматика для rust-peg будет чуть более многословна - нужно везде использовать whitespace символы (различные пробельные символы и переводы строки) в качестве возможных разделителей для остальных токенов.

А также из-за указанного выше базового свойства (ordered choice) ожидается ухудшение перформанса и увеличение использования памяти, что требует в ручном режиме выставлять оптимальный порядок для таких альтернатив, если хочется улучшить перформанс.

Ещё видимо следует делать правила достаточно лёгкими или использовать их кэширование - так как правило может быть вызвано несколько раз на том же месте.

В дополнение можно указать, что ошибка, выдаваемая rust-peg, более простая, в сравнении с lalrpop - а именно, первый выдаёт только позицию и список ожидаемых токенов, тогда как второй дополнительно выдаёт и встреченный по факту токен с его началом и концом и ещё есть ошибка про неизвестный токен уже от лексера.

В общем, это было бы интересное исследование - сравнить оба подхода и выяснить, насколько PEG парсер проиграет в скорости и памяти использованному CFG парсеру - для моего или подобного случая нагроможденного языка. Если разница несущественна, то можно рассматривать rust-peg как неплохую альтернативу, но надо ещё смотреть на удобство и внятность ошибок. И наверняка есть ситуации, где удобно приоритетнее скорости.

Понятия, структура и описание обьектов относящихся к СМ в принципе ни коим образом НЕ соотносятся и НЕ пересекаются с понятиями и объектами в универсальных языков програмирования, как упорно пытается сделать автор статьи

Прежде всего в статье упор делается на реализации языка, но можем с вами подискутировать и про понятия и сущности: я бы не был столь категоричен как вы, напрочь отвергая возможность похожести элементов языка программирования и моделирования.

Ведь в физическом мире присутствуют объекты и у них есть некоторые свойства и параметры, которые участвуют в моделировании - что довольно похоже на сущности в обычном программировании. Сложную составную физическую систему удобно представлить в виде многокомпонентной модели, где каждая её составляющая описана как какой-то объект с набором состояний со своим поведением, и эти составляющие объекты соединены между собой.

Есть большой класс задач, где такой подход работает и является удобным для моделирования - например, гидравлические и электрические сети, механические системы.

Интересно, посмотрю на Dyad, спасибо. Если там та же Modelica, то в статье я привёл сравнение с ней - вкратце, она имеет меньше возможностей по сравнению с MVL и поэтому проще в реализации.

что представляют собой физические движки, какие типы бывают (вы же наверняка один из существующих типов реализовали - но почему выбрали этот тип).

Язык предполагает описание поведения объекта в виде алгебро-дифференциальной системы уравнений пользователем, так что нет никакого физического движка, а есть движок, компонующий совокупную систему уравнений в текущем композитном состоянии модели и решающий её.

Т.е. моделист-пользователь может описать требуемые физические законы для какого-то объекта с нужной для него детализацией в виде набора состояний с разным поведением.

Наличие специфических (кажется нет) оптимизаций.....

Оптимизации, как я указал в статье, в моей реализации будут позже (а в оригинальной некоторые уже есть). Они включают как алгоритмические, так и аналитические, такие как: манипуляции с графом зависимостей для уравнений (конденсация графа), выявление уравнений с константной правой частью, выявление явных формул, символьное дифференцирование, и т.п.

Что с точностью? Есть ли анализ точности? Как делается?(глаз зацепился, что вы в примерах не задумываясь double пишите).

А нужно single float? Не уверен, хватит ли его при требуемой точности в 1e-6 например. Вообще, точность задаётся в файле проекта, и если её выставить малой, то может быть можно и single float использовать внутри реализации, это интересная мысль.

То есть язык мог бы предоставлять абстрактный float тип, а его реальная точность и представление зависит от требуемой.

Сейчас же и в моей, и в оригинальной реализации используется double float, в последней точность учитывается, а я ещё не дошёл до этого.

Могу ли я (кажется нет - но поправьте) нарисовать "рельеф" и запустить по нему кататься шарик? Чем закончится? Накапливаемая ошибка?

Вы можете описать это поведение в виде уравнения динамики шарика на поверхности, которую зададите в виде функции координат например. Все описания уравнений в ваших руках и из вашей головы.

Ошибка может накапливаться, но вы задаёте требуемую точность. А возможно вы можете применить какую-то эвристику и сбрасывать эту ошибку при каких-то событиях или условиях.

Сам бы взял парсер-комбинатор

Да, можно наверное и так. А пробовали ли вы для реально нагромождённых языков со слабыми ключевыми словами?

Мне проще было в это войти через генератор парсера, когда грамматика довольно компактно описывается и вся перед глазами - по крайней мере до слабых ключевых слов всё идёт относительно легко, а дальше требуется изголяться - но это скорее всего везде так.

Рад, что статья зашла! По поводу комментариев в виде двойного даша в исходном коде - это не моё детище, я взялся за свою реализацию языка, т.к. хотел сделать её лучше и кроссплатформенной. Я бы сделал двойной слэш, хотя и в двойном даше не вижу страшной крамолы.

Но синтаксис это дело наживное - в частности, авторы языка используют и C# подобный, наряду с Ada-подобным, как приведено в статье. Я так вообще хотел бы другой сделать, более современный - но это уже можно потом.

Просто как я понял, сейчас вы запускаете генератор, он делает файлы, а потом эти файлы идут на вход компилятору Rust. Компилятор Rust вынужден эти исходники парсить, чтобы получить список токенов, которые потом он обрабатывает. А можно на вход компилятору сразу подавать список токенов.

Ваша идея понятна и имеет право на жизнь - но для гораздо более простых случаев.

Вы фактически предлагаете использовать лексер от Rust, но дело в том, что он выдаёт токены для лексики Rust, а не моего исходного языка - т.е. например, он выдаст как литералы 1u8 и b"something", что не являются валидными литералами в моём случае. Не говоря уже о том, что в качестве идентификаторов он выдаст и ключевые слова, которые потребуются всё равно отделять.

И ещё при этом нет возможности взаимодействия с лексером - что требуется для третьего способа обработки слабых ключевых слов.

И к тому же в случае отдельного транслятора, в качестве промежуточного языка можно взять не обязательно Rust, или вообще можно реализовать интерпретатор, обойдясь без компиляции на стороне пользователя.

Т.о. заворачивать парсинг в процедурный макрос только из-за использования лексера Rust кажется слишком несоразмерным и не подходит для моего случая.

К тому же иметь транслятор, а значит и возможность генерировать код, вне рантайма позволяет сделать эту генерацию на другой промежуточный язык или вообще реализовать интерпретатор

Как использовать в сборке зависимости через rlib-файлы без исходников

Было бы интересно почитать

Принято, постараюсь изложить

почему уже в самом описании парсера нельзя указать, тут name ключевое слово или нет. Ну то есть если в парсере в этом месте написано "name", то явно именна такая последовательность тут и ожидается и это ключевое слово. При этом оно ведь ожидается только в этом месте, в других местах вы спокойно в грамматике пишите <kw_name:id> и если там разбираемом тексте встретится name, оно будет как идентификатор распознано, а не ключевое слово.

Так не выйдет, ведь слово "name" в грамматике обозначает токен, который выдает лексер - либо встроенный, либо внешний. А токен для идентификатора описывается регулярным выражением, конфликтующим с простым вышеуказанным словом "name" (как и с любым другим словом) и по умолчанию лексер выбирает выдать токен простого (ключевого) слова, а не токен описанный регулярным выражением. Выбор по-умолчанию наоборот был бы ещё хуже, ведь тогда никаких ключевых слов вообще было бы не ввести.

Поэтому-то приходится изголяться с такими слабыми ключевыми словами - ведь лексер ничего не знает о контексте, надо ему о нём сообщить, как в третьем способе (в статье), либо как-то иначе обмануть или свести к общему правилу, соответственно как в первом и втором.

Кстати, не смотрели на rust-peg?

Не помню даже, может глянул мельком, надо взглянуть ещё раз, спасибо.

Еще у вас получилось как-то странно: я так понял, вы написали парсер языка MVL, чтобы сгенерировать Rust-код на макросах, примерно повторяющем структуру исходного MVL, а в реализации макросов уже все делается. А почему бы просто не написать процедурный макрос, который принимает на вход MVL, а на выход дает Rust код, который это реализует?

Ваша идея довольно экстремальная - это ж придётся в процедурном макросе фактически произвести весь парсинг, разрешение идентификаторов, упорядочивание переменных по их зависимостям, аналитические и алгоритмические преобразования и оптимизации, и прочие операции. А потом ещё генерировать там же руками код, который не посмотреть в высокоуровневом макро-коде на Rust.

Это при условии, что вообще такой макрос может съесть исходный код - там же совсем непривычный может быть синтаксис и к тому же не UTF-8 кодировка.

И плюс бонусом медленная работа процедурного макроса, да ещё на большом объеме исходного кода.

А ещё исходный код может обладать несколькими синтаксисами, в моём случае это Ada и C# подобные (я поддерживаю пока только первый).

Интересный опыт!

проще оживить ассемблер виртуальный

А что такое виртуальный ассемблер?

Соответственно, вопрос, как насчет GUI, в вашем новом, любимом языке?

Сам язык чисто для моделирования и без GUI, а его результат в виде разделяемой библиотеки (dll) можно подключить в своё приложение.

Но в его родной IDE AnyDynamics (указан в первой же главе статьи) - волне есть графический редактор для схем и карт поведения, а также возможность накидать примитивную графическую панель с управляющими контролами и индикаторами для работы в “визуальной модели“.

Язык придумал не я и IDE не моя - не имя отношения к авторам языка я взялся за более эффективную и кроссплатформенную реализацию языка самостоятельно. А дальше можно пофантазировать и о своей IDE, если взлетит.

Желаю удачи! От бесплатного пет-проекта, к финансово окупаемому стартапу!

Спасибо, такие пожелания очень греют!

Действую по принципу: «Публикация бесплатной программы на бесплатном сайте и, если «взлетит», попросить донатов». 

Стратегия продвижения это отдельное искусство, которое приходится постигать. Это действительно не просто понять, как лучше действовать соло-разработчику

Моя базовая программа описана в статье: «Уроки французского и пересоздание данных для изучения иностранного языка с помощью обучающей программы «L'école» 

И вам тоже удачи с продвижением вашей задумки!)

1

Информация

В рейтинге
315-й
Зарегистрирован
Активность

Специализация

Десктоп разработчик, Разработчик приложений
Старший