Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, netch80, Вы писали:
N>>Если смотреть на правила какого-нибудь C#, в каком случае > будет считаться знаком сравнения, а в каких — закрывающей скобкой шаблона, то это уже заметно напоминает естественные языки. А C++ так вообще превращается в один из них со своей зависимостью от контекста, который ещё не задан
Pzz>Язык, на котором нельзя сказать обидную гадость, не может считаться естественным
А это уже от семантики зависит. Аналогом "обидной гадости" из одного слова может быть вызов вредной функции.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Если говорить о программировании, для языка это особенно важно. И если для библиотеки еще можно как то пережить кривой API, то в случае с языком это фактически уничтожает его целевую функцию.
А бы отчасти поспорил.
Для какой-нибудь небольшой библиотеки, решающей какую-то конкретную проблему да, я с тобой соглашусь. Но если библиотека претендует на "фундаментальную" роль в программе, как стандартная библиотека языка, как стандартная библиотека операционной системы, как какой-то большой и всеобъемлющий framework, неудачный API может наделать много бед.
Здравствуйте, netch80, Вы писали:
A>>А что там такого? Покупать книжку за 50 долларов, чтобы убедиться, что там лажа я не буду. A>>Это лучше или хуже, чем вот это? Тут вся грамматика английского языка умещается на одной странице:
N>Грамматика английского в принципе не может быть умещена на одной странице, если описывать в достаточных деталях. Например, в каких сочетаниях допускаются need или dare в качестве вспомогательных глаголов, или с какими глаголами допустим инфинитив в качестве прямого дополнения, с какими — герундий, а с какими — оба, но с разным смыслом.
У этого мужика это в словаре. Это параметр "тип глагола".
Валентность глагола — это такой же параметр как грамматический род, и он используется в третьей таблицы.
Словарь — это не грамматика. Он может быть очень большим, но он регулярный.
То есть, увеличение объёма (данных) не приводит к увеличению сложности для автора программы.
Здравствуйте, netch80, Вы писали:
N>Регэкспы — давно не вкладываются в регулярные грамматики.
Регеспы POSIX в точности описывают регулярную грамматику.
Может ты имел ввиду расширенные варианты, типа https://ru.wikipedia.org/wiki/PCRE?
Да, в Перле регекспы расширили обратными ссылками и те перестали быть регулярными выражениями.
По-хорошему, термин тоже надо было изменить...
N>PEG используется каждым вторым.
Тю!
Когда-то область компиляторостроения и вообще парсинга была "необъезженной", по ней неплохо готовили специалистов, бо отрасль нуждалась.
С приходом XML, JSON, YAML и прочих структурированных форматов практическая надобность в большом кол-ве специалистов по парсерам иссякла.
Отсюда те частые наблюдения, что когда необученные программеры начинают лабать нисходящие парсеры на коленке, т.е. методом проб и ошибок, получается банальный PEG.
A>>И этот тэг определяет в какой массив и какую структуру AST ты его записываешь. N>Есть такие языки, но в целом это неудобно.
В целом это сводит парсер по сложности примерно к хеш-таблице. ))
Первый Фортран не далеко от такого ушел (до введения типизации):
переменные, имена которых начинаются с одной из шести букв I, J, K, L, M, N (например: IGREK5, LA, М, K2N3AB и т.д.), являются величинами целого типа, а с любой другой буквы (AL, X, DELTA и т.д.) — величинами вещественного типа.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, alpha21264, Вы писали:
A>>Я нашёл полный pdf этой книжки. Если кому-то нужно, могу выслать.
N>Это находится легко. Вот рецензию по смыслу было бы полезнее. Пока что увидел, что там подходы заметно отличаются от типовых направлений "драконщины", но с обилием математики — продираться будет долго.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Хватать то хватает. Но ты продолжаешь делать ту же ошибку. Экономя человекодни на разработке инструмента теряешь человекогоды на его использовании. Активно используемый DSL (а делать его имеет смысл только при активном использовании) на много порядков умножает любое, даже копеечное удобство.
Случайно зашёл в дискуссию и, будучи не в теме, стало любопытно. Можно в двух словах, в каких случаях оптимально создание нового дсл? Почему-то казалось, что в большинстве случаев проще взять готовый язык (который большинству людей априори знаком), вроде python, lua, typescript/js, и на его основе городить скриптовый движок, чем изобретать новое «наречие».
Здравствуйте, Ночной Смотрящий, Вы писали: M>>Ну, ок, возможно. Где бы еще посмотреть на что-то такое готовое, чтобы понять, как оно делается НС>Примеры к antlr? Можно начать с калькулятора.
Я пока не буду целиком на всё отвечать, пока ещё раз решил попробовать antlr (кстати, javacc/sablecc лучше/хуже/удобнее/быстрее, не в курсе, не пробовал? JavaCC вроде в сипипи умеет, про саблю особо не искал), поднять свой технологический уровень, так сказать, и найти базу для дальнейшей дискуссии.
По умолчанию генерится в джаву. Как через мавен сделать, чтобы генерился плюсовый код, пока не понял. Решил пойти по простому пути — https://en.wikipedia.org/wiki/ANTLR#Example
Тут, внезапно
"generator=cpp:struct как бы намекает, что вместе с целевой областью тут какая то мешанина инструкций для процессинга, зачем оно там?"
Изначально у меня генераторы для типов задавались из командной строки. Потом я прикрутил в язык атрибуты, после чего (потому что могу) прикрутил атрибут generator с возможностью задания генератора для разных target-языков. Мне такое зашло, как и части коллег. Остальные, по старинке, используют командную строку. Не знаю, в какой последовательности аналогичные фичи (и когда — думаю, давно уже, но я не подглядывал) появились в ANTLR, но они есть. Но там ведь умные люди сидят, зачем эта мешанина?
// Common options, for example, the target language
options
{
language = "CSharp";
}
Присунул, куда показалось, надо, но что-то пошло не так
Здравствуйте, Михaил, Вы писали:
М>Случайно зашёл в дискуссию и, будучи не в теме, стало любопытно. Можно в двух словах, в каких случаях оптимально создание нового дсл? Почему-то казалось, что в большинстве случаев проще взять готовый язык (который большинству людей априори знаком), вроде python, lua, typescript/js, и на его основе городить скриптовый движок, чем изобретать новое «наречие».
Если коротенько — ненужный мусор из конструкций языка. Так-то и на плюсиках в рамках плюсиков можно любой DSL написать, но плюсиковые конструкции будут заслонять DSL. Для других языков ровно то же самое вполне актуально.
Расскажу свою историю успехаза себя.
Давным давно, в одном НИИодной далёкой галактике, в рамках реализации проекта для вояк кто-то из разработчиков потыкал палочкой OPENcan. Присовывать какую-либо открытую реализацию OPENcan для микроконтроллеров в проект для вояк никто не решился, и по мотивам был создан свой стек протоколов для CAN, RS-232/UART и RS-485.
В протоколе (протокол не командный — типа — послать команду — получить ответ, а статусный — установить командный регистр/получить статусный региср) были предусмотрены ReadOnly регистры и ReadWrite регистры (на самом деле RW регистры — write-only, но в целях отладки их можно читать) — статусные регистры, когда устройство сообщает о своём состоянии, и управляющие RW-регистры, когда мастер начинает командовать.
Потом понадобилось передавать значения, ширшие, чем 1 байт. Их стали мапить на пачку однобайтных регистров. Константы для дефайнов и смещения вычислялись руками (и никто ни разу не облажался, ага).
Эта шляпа начала уже напрягать всех, и начальнеги отделов начали собираться пару раз в неделю перетереть на тему как нам реорганизовать рабкриннашу шляпу.
И тут появляюсь я. Я уже несколько месяцев работал в конторе, и так получилось, что тёрки происходили у меня под ухом (не опен спейс, но большое помещение с кучей народа. И свой уголок есть, и не скучно. Потом нас рассадили по отдельным кабинетам — стало реально скучно и уныло).
Погрел я уши, и запилил за пару вечеров инишку с генератором в C++. Народу понравилось, а потом понеслось
Здравствуйте, alpha21264, Вы писали:
A>>>Я нашёл полный pdf этой книжки. Если кому-то нужно, могу выслать.
N>>Это находится легко. Вот рецензию по смыслу было бы полезнее. Пока что увидел, что там подходы заметно отличаются от типовых направлений "драконщины", но с обилием математики — продираться будет долго.
A>А "драконщина" — это что?
Драгон бук — Ахо, Ульман и прочие, не? На самом деле, хоть и толстая, но так себе книжонка
Здравствуйте, Marty, Вы писали:
M>Здравствуйте!
M>Точнее — парсинг и построение AST
Тут надо понимать, что AST для вашего DSL никто автоматом не сгенерит (ну, или я что-то реально пропустил). Его надо проектировать самому,
Как-то все очень сложно и непонятно. Нафига "проектировать AST" ?
Может, имелось в виду "создать грамматику DSL-я" ?
Наоборот, все очень последовательно и довольно просто:
1. Описываешь грамматику под, например HimeCC — там же расставляешь экшоны (обычно на правилах с участием терминалов)
2. После проверки и обработки имеешь набор классов и ресурсов, и работа сводится к наполнению кодом конкретных экшнов.
... (компилируешь)
3. Запускаешь в прод вкус — лепишь тесткейсов чтобы проверить что все плюс-минус работает ожидаемо, и — вперде.
Самое сложное и творческое — собственно выделенное жирным: иметь грамматику и перевести ее под конкретный генератор.
Здравствуйте, Михaил, Вы писали:
М>Случайно зашёл в дискуссию и, будучи не в теме, стало любопытно. Можно в двух словах, в каких случаях оптимально создание нового дсл? Почему-то казалось, что в большинстве случаев проще взять готовый язык (который большинству людей априори знаком), вроде python, lua, typescript/js, и на его основе городить скриптовый движок, чем изобретать новое «наречие».
Возьмём в качестве знаменитого примера SQL. Это уже заметно формализованный язык со своей логикой, но уже нормально, что непрограммистов пускают исполнять SQL-запросы напрямую через клиента типа SQL*Plus или из каких-нибудь экселевских таблиц. И пусть у нас есть:
1) select m.name as name, sum(s.amount) as total from managers m, sells s where m.id = s.manager_id group by m.id order by total desc
да, формализованно и требует понимания логики базы, но уже не программа по выборке;
2) какое-нибудь
var m = db.table("managers");
var s = db.table("sells");
var query = db.newQueryFromInnerJoin(m, s, onEqual(m.field("id"), s.field("manager_id")));
query
.sortBy(m, "id")
.addOutputColumn("name", m, "name")
.addOutputColumn("total", groupFunction("sum", s, "amount", groupBy: name))
.sortBy("total", -1);
result = query.execute();
3) то же уже в виде операций доступа к конкретным таблицам (даже если план исполнения запроса однозначен), облом расписывать... попробуйте сами представить себе это, если таблицы сделаны в виде, например, map (C++) с отдельными индексами и структурами полей.
В варианте 2 ещё более-менее понятно (а можно было вообще LINQ вспомнить, но я с ним не работал), но уже опасность — так как это исполняемый код, как защититься от вредных воздействий автора запроса? Исполнять всё в специальной песочнице? Не всегда возможно, почти всегда дорого.
А если допускать к конкретному API — вот мы завтра решили, что нам вместо последовательности addOutputColumn нужен отдельный объект шапки, который одновременно даёт ссылки на поля для упоминания в тексте (чтобы можно было один раз вместо всех этих m, "name" получать объект ссылки) — все должны переписывать свои запросы?
Ну и снова вопрос секьюрити.
При создании DSL крайне важным является не то, что язык может, а то, чего язык не даёт сделать, и как описываются определённые вещи. Писать юзеру на языке программирования может быть:
— неудобно, потому что ему нужно каждый раз преобразовывать свои мысли в другую форму, с которой он незнаком, а при чтении — и обратно. Причём его форма может быть даже не текстовой(!) — DSL может быть, например, графическим.
— страшно, потому что он будет бояться зацепить что-то не то и создать нежелательный побочный эффект. (а
админы системы будут бояться пускать его код даже в песочнице, потому что мало ли что напишет.)
— плохо при замене особенностей реализации (внутреннее API может меняться хоть каждый месяц, зачем юзерам
всё переписывать под него?)
Разумеется, при создании DSL что-то теряется — затраты человека (поддерживать внутренний язык), машины (его разбирать и переводить в свою логику, при компиляции или в рантайме), но это окупается целевым результатом.
Здравствуйте, alpha21264, Вы писали:
N>>Это находится легко. Вот рецензию по смыслу было бы полезнее. Пока что увидел, что там подходы заметно отличаются от типовых направлений "драконщины", но с обилием математики — продираться будет долго.
A>А "драконщина" — это что?
Вот это.
Есть три издания (на этом почему-то пишут, что второе, хотя по факту третье — может, потому, что состав авторов менялся).
В Сети находится, если поискать.
Теме парсинга посвящено страниц 200 с хвостом (там не только это — ещё кодогенерации, оптимизации и пр.), но большинство это доказательства применимости разных хитрых формализмов. Прочитать один раз — однозначно стоит; решать задачи — уже по вкусу; верить важности — нет, по крайней мере пока основные проблемы с реальными языками программирования это не как соблюсти типовой теоретизм, а как быть, если он уже нарушен (как в C++).
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, netch80, Вы писали:
N>>Регэкспы — давно не вкладываются в регулярные грамматики.
V>Регеспы POSIX в точности описывают регулярную грамматику. V>Может ты имел ввиду расширенные варианты, типа https://ru.wikipedia.org/wiki/PCRE?
В первую очередь их, да. Но про POSIX ты неправ, или отстал. POSIX допускает так называемые back-references:
For example, the expression "^\(.*\)\1$" matches strings consisting of two adjacent appearances of the same substring
на регулярную грамматику ты такое не уложишь, это уже context dependent.
Там есть таракан, что по POSIX они допустимы только в basic regexps, но не extended — а расширения все делаются поверх extended (кроме vim с его спецификой), но это не отменяет их присутствия.
V>Да, в Перле регекспы расширили обратными ссылками и те перестали быть регулярными выражениями. V>По-хорошему, термин тоже надо было изменить...
Не они первые начали. Термин, да, размылся.
N>>PEG используется каждым вторым.
V>Тю! V>Когда-то область компиляторостроения и вообще парсинга была "необъезженной", по ней неплохо готовили специалистов, бо отрасль нуждалась. V>С приходом XML, JSON, YAML и прочих структурированных форматов практическая надобность в большом кол-ве специалистов по парсерам иссякла.
V>Отсюда те частые наблюдения, что когда необученные программеры начинают лабать нисходящие парсеры на коленке, т.е. методом проб и ошибок, получается банальный PEG.
Момент, когда "отрасль нуждалась", я пропустил, видимо. Я наблюдаю, да, невысокий, но постоянный спрос и всё равно при этом решения на PEG занимают заметную нишу.
Может быть, как раз потому, что они естественно ложатся на мышление того, кто ещё не загнан правилами LL/LR на конкретные рельсы мышления и/или не понимает важности их ограничений (а, может, это одно и то же условие).
A>>>И этот тэг определяет в какой массив и какую структуру AST ты его записываешь. N>>Есть такие языки, но в целом это неудобно. V>В целом это сводит парсер по сложности примерно к хеш-таблице. ))
Увы, ещё нет. Посмотри на Perl
там теги типа $ — скаляр, @ — список, % — хэш, но "к хэш-таблице" его парсер несводим (не буду вдаваться в то, насколько несводим)
Ладно, на старый BASIC с его A! — целое, A$ — строка, A% — вещественное. Всё равно выражения надо парсить.
V>Первый Фортран не далеко от такого ушел (до введения типизации): V>
V>переменные, имена которых начинаются с одной из шести букв I, J, K, L, M, N (например: IGREK5, LA, М, K2N3AB и т.д.), являются величинами целого типа, а с любой другой буквы (AL, X, DELTA и т.д.) — величинами вещественного типа.
Нет, это не "первый" Fortran. Это уже правила Fortran II.
Более того, в нём это были типы по умолчанию, и их можно было заменять явным определением типа конкретной переменной.
Fortran I имел другое правило — целое при первой букве X, все остальные буквы означают вещественные.
Но у раннего Фортрана интереснее даже не это, а фокус, как там решали проблему приоритетов.
Любое выражение обрамлялось (( )).
* и / заменялись на )*( и )/(, + и — — на ))+(( и ))-((.
Дальше логика работала только учётом скобок.
Такой себе древний самопальный аналог правил Пратта с приоритетами.
Здравствуйте, netch80, Вы писали:
V>>Отсюда те частые наблюдения, что когда необученные программеры начинают лабать нисходящие парсеры на коленке, т.е. методом проб и ошибок, получается банальный PEG. N>Момент, когда "отрасль нуждалась", я пропустил, видимо.
До последней четверти 90-х примерно.
У меня курсовик в 94-м был — свой парсеропостроитель из своего метаописания (на второй итерации это метаописание читалось уже сгенерированным кодом), потом он пошёл как часть диплома.
Тогда это был пик востребованности.
Плюс ограничения тогдашней техники на объемы памяти и быстродействия тоже требовали далеко не наколенных решений, типа PEG (вернее, более общего класса наколенных парсеров — комбинаторных).
А потом появились (скорее созрели) достаточно развитые ср-ва построения парсеров, и вкупе с Java+XML, плюс развитие интернета — всё это стало видоизменять IT, придавать всё больший уклон от фундаментальных вещей к прикладным. Сверху усилилось "память больше не ресурс" и т.д.
N>Я наблюдаю, да, невысокий, но постоянный спрос
Увы, спрос не постоянен.
Я одно время искал себя именно по этой теме, бо в "просто программеры" идти было скучновато...
Выяснилось, что каждая такая задача — "одноразовая".
Т.е., всё время держать штат подготовленных по этой области спецов любой отдельно взятой конторе бессмысленно.
И обратное тоже верно — достаточному кол-ву спецов сложно найти полную занятость именно по этой области.
N>и всё равно при этом решения на PEG занимают заметную нишу.
Вряд ли именно строгий PEG, просто PEG — это уже мем над целым направлением комбинаторных потуг.
Да, любой доведенный до практического применения комбинаторный парсер будет в существенной части своей реализации PEG, но не обязательно весь.
На то он и комбинаторный парсер. ))
N>Может быть, как раз потому, что они естественно ложатся на мышление того, кто ещё не загнан правилами LL/LR на конкретные рельсы мышления и/или не понимает важности их ограничений (а, может, это одно и то же условие).
Ну да, принцип разработки незамысловат: "водим пальчиком по разбираемому тексту и прикидываем — как бы это можно было зачитать".
При таком подходе работает "тесты вперёд", бо все конфликты могут быть обнаружены только на реальных данных, т.е. вопрос широты тестирования и банального везения тут не праздный.
Формальные грамматики, наоборот, могут судить о непротиворечивости грамматики еще на этапе её анализа (или построения по ней парсера).
В общем, это примерно как отличие статической типизации от динамической.
Второй я никогда не доверял.
A>>>>И этот тэг определяет в какой массив и какую структуру AST ты его записываешь. N>>>Есть такие языки, но в целом это неудобно. V>>В целом это сводит парсер по сложности примерно к хеш-таблице. ))
N>Ладно, на старый BASIC с его A! — целое, A$ — строка, A% — вещественное. Всё равно выражения надо парсить.
Но тип выражения выводить не надо, я это имел ввиду.
N>Нет, это не "первый" Fortran. Это уже правила Fortran II.
Здравствуйте, Marty, Вы писали:
M>Я пока не буду целиком на всё отвечать, пока ещё раз решил попробовать antlr (кстати, javacc/sablecc лучше/хуже/удобнее/быстрее, не в курсе, не пробовал?
Саблю смотрел, благо исходники вполне читаемы. Проще antlr, но для DSL наверняка сойдет.
M>Хочу сгенерить парсер плюсиков.
А чего сразу не естественного языка? Ну а чего мелочиться.
Я ж говорю — начни с калькулятора, потом паскаль.
M>Если не жалко, помоги мне поднять мой технологический уровень
Тут я тебе вряд ли чем смогу помочь, я 4 версию уже не смотрел, задачи по теме закончились году в 16.
Здравствуйте, Михaил, Вы писали:
М>Случайно зашёл в дискуссию и, будучи не в теме, стало любопытно. Можно в двух словах, в каких случаях оптимально создание нового дсл?
Когда приходится писать много однообразного кода, большая часть которого тупая копипаста. Причем для написания этого кода требуется хорошее знание не программирования, я предметной области. И когда у тебя есть бюджет на написание DSL.
М> Почему-то казалось, что в большинстве случаев проще взять готовый язык (который большинству людей априори знаком), вроде python, lua, typescript/js, и на его основе городить скриптовый движок, чем изобретать новое «наречие».
Не всегда проще. И для таких языков нельзя задавать ограничения, чего делать нельзя. DSL обычно ближе не к скриптам, а к конфигам. Собственно, DSL, как правило, это сложные конфиги и есть.
Здравствуйте, Marty, Вы писали:
M>Давным давно, в одном НИИодной далёкой галактике, в рамках реализации проекта для вояк кто-то из разработчиков потыкал палочкой OPENcan. Присовывать какую-либо открытую реализацию OPENcan для микроконтроллеров в проект для вояк никто не решился, и по мотивам был создан свой стек протоколов для CAN, RS-232/UART и RS-485.
Если "плюсики" это C++ — то, надеюсь, это шутка. Потому что плюсы сделаны так, чтобы парсить их было не просто, а очень сложно. Это типа результат естественного развития, но результат от этого не лучше.
Для начала Most vexing parse. Точное понимание конструкции зависит от определений, которые на этот момент могли ещё не быть прочитаны из файла (они появятся позже в том же классе).
Оно же сбоку: функция или переменная на разных платформах.
В C++11 (и позже), последовательность >> — или сдвиг вправо, или два закрытия шаблона.
В C++20, те же проблемы с spaceship operator ("<=>").
И прочая и прочая (тысячи их).
В ANTLR, конечно, какой-то пример, но минимальный; полный парсер, чтобы получить хотя бы AST, должен включать в себя из-за описанных свойств интерпретатор логики шаблонов (а вслед этим и значительного подмножества языка).
Здравствуйте, Ночной Смотрящий, Вы писали:
M>>Хочу сгенерить парсер плюсиков.
НС>А чего сразу не естественного языка? Ну а чего мелочиться. НС>Я ж говорю — начни с калькулятора, потом паскаль.
Ну, например, потому, что калькулятор я и в рукопашную за полдня напишу рекурсивным спуском, а плюсики хочу парсить для своего пет-проекта, руками уже писал, хочу по науке попробовать.
Тем более, что грамматика уже умными людьми описана
Здравствуйте, netch80, Вы писали:
N>В ANTLR, конечно, какой-то пример, но минимальный; полный парсер, чтобы получить хотя бы AST, должен включать в себя из-за описанных свойств интерпретатор логики шаблонов (а вслед этим и значительного подмножества языка).
Похоже, что ручной работы что так, что эдак — куча. Оставить что ли изучение ANTLR до тех времён, когда надо будет калькулятор написать