Здравствуйте, SergeyT., Вы писали:
ST>А чего молчите-то? JetBrains Company Blog — An Introduction to Nitra
Я правильно понимаю, что смогу при помощи этого забабахать свой c# с монадами и операторами и компилировать его в IL?
Здравствуйте, 0x7be, Вы писали:
0>Я правильно понимаю, что смогу при помощи этого забабахать свой c# с монадами и операторами и компилировать его в IL?
Со временем да.
Более того грамматика, типизатор и кодогенератор для C# будут идти в поставке.
Тебе придётся только маленькие кусочки дописать.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, jazzer, Вы писали:
J>>Плюсовые встроенные DSL с вашими по возможностям, включая качество сгенеренного нативного кода и удобство использования из основной программы, если это компонент.
VD>Ты тут путаешь теплое с мягким. Я даже не говорю о сложности сравнения DSL-ей получающихся в С++ и созданных с помощью Nitra, потому как когда я говорю о генерации С-кода, то я говорю о коде парсера, а не о коде который может породить DSL.
Коде парсера DSL? Т.е. у него будет просто API из одной функции типа nitra_parse_result* parseDSL(const char* dsl_text)? Или как? И, главное, что потом? Как взаимодействовать с объектами в основной плюсовой программе?
Например, в Boost.Spirit считывание разделенных чем-нть (в данном случае — запятой) в какой-нть контейнер (в данном случае — вектор даблов) делается так (сам парсер — double_%','):
более того, я даже могу написать auto_%',' — и он вычислит тип парсера, исходя из типа элемента контейнера store.
Допустим, я решаю отказаться от Boost.Spirit в пользу нитры и писать парсер там на красивом DSL-е. Какой интерфейс я получу в результате в С++?
VD>Сейчас у нас схема такая: VD>1. Nitra.exe или компилятор/интеграция Nemerle парсит файл грамматики и генерирует дотнет-сборку (MSIL) парсера. Делается это средствами метапрограммирования Nemerle (хотя это скрыто от пользователя). VD>2. Программа на дотнете запускает парсер путем вызова некоторых API-функций. VD>3. Загруженный на этапе 2 парсер парсит то что ему скормят и выдает некую структуру данных ParseResult. Она на низком уровне описывает результат парсинга. VD>4. Программа на дотнете передает ParseResult в другие API-функции чтобы получить некоторые сервисы (например, объектный AST или для произведения вычислений).
VD>Так вот мы можем генерировать не дотнет-сборку, а нативную DLL или даже ее исходный код. Это позволит на этапах 2-4 пользоваться не только .Net API, но и любым другим (Java или нативным).
Дело в том, что сборка в .Net и сишная DLL в С++ — это огромная разница в возможностях взаимодействия. В .Net она встроится в систему типов, при ошибке выкинет нормальное .Net-исключение, т.е. интегрируется с любым .Net-языком на достаточно высоком уровне. В С++ придется написать гору кода, чтоб предоставить нормальный интерфейс к этой DLL.
VD>Для каждой поддерживаемой платформы придется создать рантайм, но все рантаймы будут работать с единой структурой данных (ParseResult). VD>Это возможно, так как ParseResult — это очень низкоуровневая структура. По сути там только два куска динамически занимаемой памяти и эта память может быть занята средствами ОС. Кое какие сложности возникнут с представлением информации получаемой при восстановлении после ошибок, но ее тоже можно представить в виде простых сишных структур, а память для них выделять из пула (который можно будет освободить одним махом).
VD>В наших алгоритмах почти не нужна динамическая память. Именно по этому их будет относительно легко перенести на С. VD>В природе нет никакого плюсового компилятора. Их множество. Все известные мне умеют компилировать С. Оптимизации при этом будут те же, за исключением число С++-ных оптимизаций которые на просто не нужны. VD>С же банально более переносимый язык.
Да вопросов нет, что Си — самый переносимый и доступен из С++ напрямую. Вопрос в удобстве. Си ни разу не удобен для плюсовика.
J>>Плюс, я так понимаю, то, что сгенерено Нитрой, будет в результате доступно в виде отдельной сишной библиотеки, так?
VD>В принцие, да. Только скорее ее нужно назвать "нативно". С — это только один из вариантов реализации. Но это библиотека содержащая внутри код парсера, а результат компиляции DSL-я. Это нужно отчетливо понимать.
Ну так интерфейс у него по-прежнему будет сишный для моей сиплюсовой программы, так ведь?
J>>Со стандартными сишными проблемами с управлением памятью, передачей параметров только по указателю, отсутствием исключений и прочим...
VD>Проблемы управления память будет нашими проблемами. Мы не предлагаем использовать такие ДЛЛ-и самостоятельно. Они слишком низкоуровенвые для этого.
А как их тогда использовать? Не понимаю.
VD>Плюс в них есть не все что нужно. Кроме генерируемой части у парсеров есть и рукописная. Она находится в рантайме. Некоторые вещи просто нельзя будет написать на С, так как они зависят от платформы. Например, материализация AST должна порождать AST в виде объектов целевой платформы, а не структур С. Хотя если использовать наши AST-методы можно обойтись без материализации AST-а для конкретной платформы.
Да, я о платформе (асме) и не веду пока речь даже. Меня интересует высокоуровневая интеграция с С++.
J>>Не очень понятно, как интерфейситься с теми же плюсами — сишный уровень все-таки очень ограниченнный.
VD>Для плюсов можно создать рантайм который будет прозрачно представлять данные для С++-программиста. Учитывая совместимость С++ и С это будет даже проще реализовать.
Вот с этого места поподробнее хотелось мы. Потому что пока я не вижу, как будет выглядеть эта прозрачность.
VD>Что касается управления памятью, то парсеры используют столь низкоуровневые структуры данных, что это для них не проблема. Куда большей проблемой является кросплатформная реализация АСТ-методов. Во-первых, они пишутся на некотором языке. А во-вторых, оперируют частями грамматики как объектами и могут использовать такие фишки (которые будут предоставляться Nitra) как квази-цитирование. Конечно можно использовать в них язык целевой платформы, но он будет по определению ограничен своими возможностями. Например, в С++ будет невозможно использовать сопоставление с образцом для распознавания сложных сочетаний конструкций в коде. Ну, и опят же управление памятью начинает играть роль.
Ну и как оно все будет работать со сложными конструкциями в С++ коде?
Здравствуйте, jazzer, Вы писали:
J>Допустим, я решаю отказаться от Boost.Spirit в пользу нитры и писать парсер там на красивом DSL-е. Какой интерфейс я получу в результате в С++?
Красивый.
О проектировании интерфейса для С++ мы сейчас даже не думаем.
Сейчас есть масса более приоритетных задач.
J>Дело в том, что сборка в .Net и сишная DLL в С++ — это огромная разница в возможностях взаимодействия. В .Net она встроится в систему типов, при ошибке выкинет нормальное .Net-исключение, т.е. интегрируется с любым .Net-языком на достаточно высоком уровне. В С++ придется написать гору кода, чтоб предоставить нормальный интерфейс к этой DLL.
Не придётся. Всё что нужно сгенерируем. Ваще не проблема.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, catbert, Вы писали:
C>Не знаю куда баги писать,
Попробуй сюда. http://youtrack.jetbrains.com/issues/NTR
Должен быть уже открыт.
C>но на звездочки в ошибочных инпутах эта штука как-то болезненно реагирует.
На ошибочные тексты оно сейчас вообще болезненно реагирует.
Сейчас только этим и занимаемся.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, jazzer, Вы писали:
VD>>Ты тут путаешь теплое с мягким. Я даже не говорю о сложности сравнения DSL-ей получающихся в С++ и созданных с помощью Nitra, потому как когда я говорю о генерации С-кода, то я говорю о коде парсера, а не о коде который может породить DSL.
J>Коде парсера DSL?
Да. Мы создаем tool для разработки языков который можно будет использовать и по частям. Пока готова только первая часть — динамически расширяемый парсер.
J>Т.е. у него будет просто API из одной функции типа nitra_parse_result* parseDSL(const char* dsl_text)? Или как?
Примерно так.
J>И, главное, что потом? Как взаимодействовать с объектами в основной плюсовой программе?
Пожалуй проще "заглянуть под капот", чтобы было понятнее. В этом nitra_parse_result лежит несколько простых переменных (целые, булевы и т.п.) и пара целочисленных массивов. В одном массиве лежит лог парсинга закодированный определенным образом. Во втором информация о мемоизации (ссылки во первый массив). Таким образом AST закодирован этими двумя массивами.
Мы можем посторить эти массив на любом языке./платформе Например на дотнете (как сейчас) или на С/нэитив коде (гипотетически). Этот код (код парсинга) частично универсальный (такого кода очень не много), а частично генерируется по грамматике (вот его много, но он генерируется, а генератор всегда можно поменять).
Далее есть алгоритм обхода этих массивов. Этот алгоритм универсален и его можно перенести на любой язык. На С++ можно написать базовый класс у наследников которого будут вызваться переопределенные методы. Получается нечто вроде SAX-модели для ХМЛ-я в Яве.
Кроме того к грамматике еще имеется так называемая "рефлексия". Это метаданные описанные в виде статических структур данных (для каждого правила). Их можно читать как во время исполнения, так и во время компиляции. Это позволяет написать на любом языке генераторы или интепретаторы. Например, не сложно написать материализатор AST для С++.
Еще один вариант (несколько более сложный, но самый интересный) — генерация С++ (или любого другого языка) по нашим AST-методам. AST-методы — это DSL который позволяет объявить методы прямо внутри правил и оперировать, внутри этих методов, частями грамматики как полями объектов.
Если это сделать, то на С++ можно будет просто взывать AST-метод и получить нужно значение. А С++-код его получающий будет скомпилирован по коду AST-метода.
Прикинь полноценные лямбды и паттерн-матчинг в С++?
J>Допустим, я решаю отказаться от Boost.Spirit в пользу нитры и писать парсер там на красивом DSL-е. Какой интерфейс я получу в результате в С++?
Я вше как раз описал три возможных варианта, по мере сложности их реализации.
Циклы в грамматике у нас тоже автомат в списке преобразуются. В прочем, с использованием AST-методов можно сразу получать конечный результат (в том числе производить нужные вычисления).
J>Дело в том, что сборка в .Net и сишная DLL в С++ — это огромная разница в возможностях взаимодействия.
Взаимодействовать с ней ты будешь через API. Главное, что данные представляются так, что ни на одном языке/платформе с ними проблем не будет (это просто массивы целых чисел).
J>В .Net она встроится в систему типов, при ошибке выкинет нормальное .Net-исключение, т.е. интегрируется с любым .Net-языком на достаточно высоком уровне. В С++ придется написать гору кода, чтоб предоставить нормальный интерфейс к этой DLL.
Если в парсере вылетает исключение — это ошибка и ее нужно чинить. По делу исключений быть не может. Мы их не генерируем и не используем. У на эдакий олскульный С-ишный код (для производительности).
J>Да вопросов нет, что Си — самый переносимый и доступен из С++ напрямую. Вопрос в удобстве. Си ни разу не удобен для плюсовика.
Удобство обеспечивается API и генерацией специализированного для С++ кода. Мы в Nemerle и C# не колупаемся с массивами? Вот, например, код строчного калькулятора написанный на C# с использованием Nitra:
using N2;
using System;
class Program
{
static void Main()
{
var parserHost = new ParserHost();
for(;;)
{
Console.Write("input>");
var input = Console.ReadLine();
// выходим, если пользователь ввел пустую строкуif (string.IsNullOrWhiteSpace(input))
return;
// Парсим строку с помощью стартового правилаvar parseResult = Calc.Start(SourceSnapshot(input), parserHost);
// Создаем материализованный ASTvar ast = CalcAstWalkers.Start(parseResult);
Console.WriteLine("Pretty print: " + ast);
// Выводим сообщения об ошибках, если таковые имеютсяforeach(var error in parseResult.GetErrors())
{
var lineCol = error.Location.StartLineColumn;
Console.WriteLine("(" + lineCol.Line + "," + lineCol.Column + "): " + error.Message);
}
// Вычисляем результат выражения путем вызова
// AST-метода и выводим значение на консоль.
Console.WriteLine("Result: " + ast.Value());
}
}
}
А вот грамматика с AST-методами:
using N2.Runtime;
using System;
syntax module Calc
{
// синтаксические модули из стандартной библиотекиusing PrettyPrint;
using TokenNames;
using StandardSpanClasses;
using Whitespaces;
[StartRule]
syntax Start = Expr !Any
{
Value() : double = Expr.Value();
}
syntax Expr
{
Value() : double;
missing Value = double.NaN;
| [SpanClass(Number)] Number
{
regex Digit = ['0'..'9'];
regex Number = Digit+ ('.' Digit+)?;
override Value = double.Parse(GetText(Number));
}
| ParenthesesParentheses = '(' Expr ')'
{
override Value = Expr.Value();
}
| Add = Expr '+' Expr precedence 10
{
override Value = Expr1.Value() + Expr2.Value();
}
| Sub = Expr '-' Expr precedence 10
{
override Value = Expr1.Value() - Expr2.Value();
}
| Mul = Expr '*' Expr precedence 20
{
override Value = Expr1.Value() * Expr2.Value();
}
| Div = Expr '/' Expr precedence 20
{
override Value = Expr1.Value() / Expr2.Value();
}
| Pow = Expr '^' Expr precedence 30 right-associative
{
override Value =
Math.Pow(Expr1.Value(), Expr2.Value());
}
| Neg = '-' Expr precedence 100
{
override Value = -Expr.Value();
}
}
}
J>Ну так интерфейс у него по-прежнему будет сишный для моей сиплюсовой программы, так ведь?
Нет. Не так. Интерфейс можно сделать специализированным для конкретного языка.
J>А как их тогда использовать? Не понимаю.
Я уже несколько раз говорил — через API и генерированный специально для конкретного языка код.
J>Да, я о платформе (асме) и не веду пока речь даже. Меня интересует высокоуровневая интеграция с С++.
Под алатфоромой я скорее .Net/Java/native имею в виду.
J>Вот с этого места поподробнее хотелось мы. Потому что пока я не вижу, как будет выглядеть эта прозрачность.
Вот для дотнета мы предоставляет разного рода базовые классы обходчиков, атериализованный AST (классы/объекты дотнета) и AST-методы — DSL скрывающий от пользователя детали реализации и позволяющий писать методы производящие вычисления как бы над грамматикой.
Тоже самое можно сделать и для С++. Проще всего сделать обходчик дергающий методы. Чуть сложнее наладить генерацию AST-а для С++. Значительно сложнее генерировать по AST-методам С++-код. Но все вполне реально. Было бы желание, время и необходимость.
J>Ну и как оно все будет работать со сложными конструкциями в С++ коде?
Это вопрос преобразования данных. В парсингде речь всегда идет о разборе отрезков строк.
ЗЫ
Ты еще забываешь, что сравнивать Nita и Boost.Spirit не вполне корректно.
Мы, в отличии от Boost.Spirit-а, предоставляем кучу гарантированно качественных севрисов:
1. Сам парсер быстр и имеет вычислительную сложность порядка O(n) (при отсутствии ошибок в разбираемом коде).
2. Алгоритм разбирает все однозначные контекстно-свободные грамматики и многие неоднозначные.
3. Предоставляется автоматическая поддержка в IDE (подсветка, фолдинг, диагностика ошибок).
4. В будущем это будет законченное решение предоставляющее полный набор IDE-сервисов и позволяющее создавать автономные компилятора. Тут тебе будет и связывание имен, и вывод типов, и сменяемые бэкэнды.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Аноним, Вы писали:
А>Что то Влада нет в скайпе....
Мой старый скайп протух. Пользуйтесь новым скайповским экаунтом — vc.rsdn.ru
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: An Introduction to Nitra
От:
Аноним
Дата:
16.11.13 18:58
Оценка:
Есть проект в котором нужно парсить C# и Delphi файлы, как раз бы нитра и пригодился, для шарпа использую Roslyn, а для дельфи регексы.
А планируется ли какая-та тулза для конвертации синтакса из других известных парсеров в синтакс нитры?