Здравствуйте, Петрухин Эдуард, Вы писали:
ПЭ>Я тебя уверяю — регулярные выражения тебе не помогут, только зря потратишь время. Для примера: ты в исходном посте упомянул о вложенных классах. Это называется «самовложением». Самовложение — характерный признак контекстно-свободных грамматик (если бы отсутствовали самовложения, грамматика была бы автоматной). Никаким регулярным выражением самовложения тебе не одолеть.
Я уточню один важный момент. Я могу более-менее произвольно отделить подмножество языка и работать только с ним. Например, ограничить самовложения одним уровнем (вполне достаточно, я считаю).
Для "математика" это может звучать дико, как любой случай коверканья задачи под инструмент, но я оценил количество работы с парсером и сразу решил, что сделаю как можно более работоспособный регэксп, но не больше.
Здравствуйте, Аноним, Вы писали:
А>>Никто не находил хороший регэксп для парсинга C#?
А>>Конкретно интересует разбор кода одного-единственного класса на методы, но со всеми потрохами, в т.ч. вложенными классами. Написал свой, но не уверен в качестве, лучше всего бы какой-нибудь активно используемый.
А>Мое любимое регулярное выражение на этот случай — такое. Код компилируется, результурующая сборка поднимается через reflection и исследуется.
Ну и много вы наисследуете, если получите пачку ошибок от компайлера? Где можно, я использую отражение, но это не панацея.
Ладно, не в этом дело. Задача (выделенная болдом) через отражение не решается.
Здравствуйте, Niemand, Вы писали:
N>подобную фичу сделал пару недель назад на своем проекте, могу вот поделиться (чуть подредактировал):
N>
N> public static SomeDataClass[] CompileContext(string filename)
N> {
N> try
N> {
N> // устанавливаем в режим c# 3.0, BCL 3.5, чтобы кушало лябмды и другое
N> CSharpCodeProvider codeProvider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion",
N>"v3.5" } });
N> var result = codeProvider.CompileAssemblyFromFile(new CompilerParameters(new[] {
N> // какие либы здесь надо, а какие не надо - это индивидуйно, меняйте под себя
N> "System.dll",
N> "System.Data.dll",
N> "System.Core.dll",
N> "System.Web.Services.dll"}, Guid.NewGuid() + ".dll"), // конечно тут надо написать Path.GetTempFile()+".dll", но в моей задаче сойдет и так
N> filename);
N> var assembly = result.CompiledAssembly; // получаем сборку (или исключение)
N> var contextType = assembly.GetTypes().FirstOrDefault(t => t.BaseType == typeof(SomeMyBaseType));
N> // если класс всего один можно заменить на
N> // var contextType = assembly.GetTypes().FirstOrDefault();
N> // дальше вытягиваем список методов (у меня там идет другая логика, потому скопипастил с http://www.csharp-examples.net/get-method-names/ )
N> MethodInfo[] methodInfos = typeof(MyClass).GetMethods(); // и добавляем .Select(m=>m.Name).ToList() или как-то так если надо только имена методов
N> // ... ну и так дальше
N>
Извините, это поделка. Я выше приводил пример регэкспа — вот он как раз был написан по аналогичному случаю: для поиска в исходном коде референсов (заданных через атрибуты). Собственно, в плюсах есть аналог — прагма lib (ЕМНИП).
Однако, не в этом дело. Дело в том, что мне нужно
>Конкретно интересует разбор кода одного-единственного класса на методы
Здравствуйте, _DAle_, Вы писали:
_DA>Строго говоря, "регулярные выражения" в том виде, в котором они реализованы в большинстве языков/библиотек, выходят за рамки автоматных грамматик, но эта тема не для "Коллеги, улыбнитесь"
Здравствуйте, regexp, Вы писали: R>Парсер-шмарсер... Хотелось бы взять одно готовое выражение, отформатировать его (string.Format()) согласно прилагающейся инструкции и получить искомое.
Ты задачу штоле поподробнее опиши.
Но скорее всего регулярные выражения не самый удачный вариант — быстро накатаешь половину рабочей программы — потом напорешься на несколько хитрых частных случаев и будешь их до посинения отлаживать.
Здравствуйте, regexp, Вы писали:
_DA>>Строго говоря, "регулярные выражения" в том виде, в котором они реализованы в большинстве языков/библиотек, выходят за рамки автоматных грамматик, но эта тема не для "Коллеги, улыбнитесь"
R>Спьяну ее сюда засунули, что ли? Весельчаки
Исключительно от радости за невинность коллеги.
Однако, исправляю.
Здравствуйте, Аноним, Вы писали:
А>Ну, вот такой регэксп успешно ищет все атрибуты:
А также всё, что похоже на атрибуты, но закомментировано. А также — всё, что находится внутри методов и является не атрибутами, а вызовами оператора []... и так далее, и тому подобное.
Здравствуйте, _DAle_, Вы писали:
_DA>Строго говоря, "регулярные выражения" в том виде, в котором они реализованы в большинстве языков/библиотек, выходят за рамки автоматных грамматик, но эта тема не для "Коллеги, улыбнитесь"
Вот, кстати, давно хотел выяснить: регекспы с расширениями (perl-compatible) дотягивают до КС-грамматики, или образуют какой-то промежуточный класс грамматик между КС и регулярными (автоматными)?
И если дотягивают — как можно построить регексп из, например, БНФ?
У меня есть подозрение, что в любом случае размер регекспа очень нелинейно (вплоть до экспоненты) зависит от размера БНФ.
Поэтому, даже если автор и родит регексп, он либо не влезет в память, либо наглухо загрузит интерпретатор.
Здравствуйте, Кодт, Вы писали:
К>но закомментировано.
Уже было.
>А также — всё, что находится внутри методов и является не атрибутами, а вызовами оператора []...
Это предусмотренный случай ССЗБ. Ничто, конечно, не мешает передать атрибут в индексер, но он не для этого предназначен.
>и так далее, и тому подобное.
Здравствуйте, Mr.Cat, Вы писали:
MC>Здравствуйте, regexp, Вы писали: R>>Парсер-шмарсер... Хотелось бы взять одно готовое выражение, отформатировать его (string.Format()) согласно прилагающейся инструкции и получить искомое. MC>Ты задачу штоле поподробнее опиши.
Да ерунда, обычный редактор:
[+] [foo]
[-] void bar(object o)
| {
| int i = 0;
| }
С некоторой спецификой, правда, не имеющей отношения к теме.
MC>Но скорее всего регулярные выражения не самый удачный вариант — быстро накатаешь половину рабочей программы — потом напорешься на несколько хитрых частных случаев и будешь их до посинения отлаживать.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _DAle_, Вы писали:
_DA>>Строго говоря, "регулярные выражения" в том виде, в котором они реализованы в большинстве языков/библиотек, выходят за рамки автоматных грамматик, но эта тема не для "Коллеги, улыбнитесь"
К>Вот, кстати, давно хотел выяснить: регекспы с расширениями (perl-compatible) дотягивают до КС-грамматики, или образуют какой-то промежуточный класс грамматик между КС и регулярными (автоматными)?
Немножко про это есть в википедии http://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages
К>И если дотягивают — как можно построить регексп из, например, БНФ? К>У меня есть подозрение, что в любом случае размер регекспа очень нелинейно (вплоть до экспоненты) зависит от размера БНФ. К>Поэтому, даже если автор и родит регексп, он либо не влезет в память, либо наглухо загрузит интерпретатор.
Здравствуйте, regexp, Вы писали:
R>я оценил количество работы с парсером и сразу решил, что сделаю как можно более работоспособный регэксп, но не больше.
Начать работать с парсерами легко! На примере C# версии 2.0:
2. Редактируешь файл CSharp2.ATG (сделай копию на всякий случай) — это описание грамматики
Первая треть файла — между COMPILER CS2 и CHARACTERS (SCANNER DESCRIPTION) — обычный C# код, можешь заводить там свои переменные, списки и методы.
Вторая часть — между CHARACTERS и PRODUCTIONS — описание терминалов — меняй, только если у тебя язык отличается от C#
Третья часть — после PRODUCTIONS — собственно грамматика. Свой C# код надо писать в блоках (. .), после соответствующих частей правил разбора.
Для нашего примера:
Описание StructMemberDeclaration<Modifiers m> дополняешь (мои правки выделены курсивом):
Тут мы указываем парсеру при каждой встрече элемента MemberName сохранять (out) его имя в переменную memberName (объявлена в самом начале правила) и выводить ее в консоль
Меняешь описание MemberName на такое:
MemberName<out string name>
= ident (. name = t.val; .)
[ "::" ident (. name += "::"+t.val; .) ]
[ IF (la.kind == _lt && IsPartOfMemberName()) TypeArgumentList ]
{ IF (la.kind == _dot && Peek(1).kind == _ident)
"." ident (. name += "."+t.val; .)
[ IF (la.kind == _lt && IsPartOfMemberName()) TypeArgumentList ]
}
.
Тут мы просим MemberName накопить в строку то, что нашел парсер (t.val — это текущий найденный парсером токен,
то есть для строки "Buffer.Close" будут последовательно найдены "Buffer", ".", "Close", соответственно сработают первая и последняя части правил)
3. Генерируешь исходники сканера/парсера (я делал в командной строке):
coco.exe CSharp2.ATG
(должно быть сообщение parser + scanner generated, 0 errors detected)
4. Собираешь все это вместе (как вызывать парсер из своего кода, смотри в CS2Parser.cs)
csc.exe CS2Parser.cs Scanner.cs Parser.cs
5. Проверяешь
CS2Parser.exe somesourcefile.cs
Должна получиться распечатка имен методов.
Когда разберешься, можешь переходить к сигнатурам (TypeArgumentList), конструкторам и тому подобному, потом к квалифицированным именам.
Для последнего придется написать в первой части файла какой-то простенький стек, который хранит имя класса на текущей глубине разбора.
Здравствуйте, regexp, Вы писали: R>Да ерунда, обычный редактор: R>
R>[+] [foo]
R>[-] void bar(object o)
R>| {
R>| int i = 0;
R>| }
R>
Ну если нужны только подсветка, фолдинг и прочие нехитрые вещи — тогда погляди, как это сделано в vim или notepad++. Думаю, в итоге там все сводится к прогону разными регулярными выражениями с разными приоритетами: сперва комментарии выявляются (и внутри них больше ничего не подсвечивается), потом строки и т.п.
Здравствуйте, _DAle_, Вы писали:
К>>Вот, кстати, давно хотел выяснить: регекспы с расширениями (perl-compatible) дотягивают до КС-грамматики, или образуют какой-то промежуточный класс грамматик между КС и регулярными (автоматными)?
_DA>Немножко про это есть в википедии http://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages
Как-то уж очень немножко
Я так понял, регекспы с обратными отсылками описывают контекстно-зависимые грамматики (наверно, не всевозможные, а некое подмножество?)
Например,
/ alfa (beta) gamma \1 delta /
Соответствуют правила вывода
Regex -> Use beta
Use X -> alfa X gamma X delta
Кстати, неутешительно для топикстартера: сопоставление регекспа с бэкреференсами — NP-полная задача, т.е. парсер выжрет время-память.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _DAle_, Вы писали:
К>>>Вот, кстати, давно хотел выяснить: регекспы с расширениями (perl-compatible) дотягивают до КС-грамматики, или образуют какой-то промежуточный класс грамматик между КС и регулярными (автоматными)?
_DA>>Немножко про это есть в википедии http://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages
К>Как-то уж очень немножко К>Я так понял, регекспы с обратными отсылками описывают контекстно-зависимые грамматики (наверно, не всевозможные, а некое подмножество?)
Я тут сразу рванул писать, что Back references не спасают даже от классического контекстно-свободного языка AnBn (ну в смысле ab, aabb, aaabbb, ...). Но потом, погуглив и поспрашивав в IRC, нашел, что, например, в perl 5.10 можно сейчас вроде бы написать /^(a(?1)?b)$/, и таким образом используя рекурсию победить эту проблему. Но с другой стороны контекстно-зависимый AnBnCn уже так с помощью backreferences и recursion не воспроизведешь.
В общем, вроде бы получается так..
Множество языков, которые описывают regexp c Back references, пересекается с контекстно-свободными языками.
Множество языков, которые описывают regexp с Back references и recursion, содержат в себе все контекстно-свободные, и сами содержатся в множестве контекстно-зависимых.
Это все может оказаться неправдой, но похоже на нее
Здравствуйте, _DAle_, Вы писали:
_DA>Я тут сразу рванул писать, что Back references не спасают даже от классического контекстно-свободного языка AnBn (ну в смысле ab, aabb, aaabbb, ...). Но потом, погуглив и поспрашивав в IRC, нашел, что, например, в perl 5.10 можно сейчас вроде бы написать /^(a(?1)?b)$/, и таким образом используя рекурсию победить эту проблему. Но с другой стороны контекстно-зависимый AnBnCn уже так с помощью backreferences и recursion не воспроизведешь.
_DA>Множество языков, которые описывают regexp c Back references, пересекается с контекстно-свободными языками.
А не с КЗ? /([A-Z]+)_(?1)_(?1)/ как представить в КС?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _DAle_, Вы писали:
_DA>>Я тут сразу рванул писать, что Back references не спасают даже от классического контекстно-свободного языка AnBn (ну в смысле ab, aabb, aaabbb, ...). Но потом, погуглив и поспрашивав в IRC, нашел, что, например, в perl 5.10 можно сейчас вроде бы написать /^(a(?1)?b)$/, и таким образом используя рекурсию победить эту проблему. Но с другой стороны контекстно-зависимый AnBnCn уже так с помощью backreferences и recursion не воспроизведешь.
_DA>>Множество языков, которые описывают regexp c Back references, пересекается с контекстно-свободными языками.
К>А не с КЗ? /([A-Z]+)_(?1)_(?1)/ как представить в КС?
Под пересекается я имел ввиду, что ни одно из множеств не содержит другое.
MC>Ну если нужны только подсветка, фолдинг и прочие нехитрые вещи — тогда погляди, как это сделано в vim или notepad++. Думаю, в итоге там все сводится к прогону разными регулярными выражениями с разными приоритетами: сперва комментарии выявляются (и внутри них больше ничего не подсвечивается), потом строки и т.п.
Не прокатит по причине возможной вложенности одного в другое. Например:
/* ......... " ..../*...*/.... " ....... */..........."
и
".........../*...*/...".....".....*/........"
как ни парси регекспами, контрпример можно будет построить в общем случае.
Здравствуйте, Au1, Вы писали: Au1>Не прокатит по причине возможной вложенности одного в другое. Например: Au1>/* ......... " ..../*...*/.... " ....... */..........." Au1>и Au1>".........../*...*/...".....".....*/........"
В чем конкретно ты тут видишь проблему? Как, на твой взгляд, это распарсится регекспами? И как оно, на твой взгляд, должно распарситься? Я проблемы не вижу. Вот как парсит тутошний регексповый форматтер.
VS парсит точно так же.
Au1>как ни парси регекспами, контрпример можно будет построить в общем случае.
Если речь идет о подсветке и фолдинге редакторе, то 100% корректной работы не нужно. Достаточно покрытия определенного процента ситуаций, я считаю.
MC>VS парсит точно так же.
Au1>>как ни парси регекспами, контрпример можно будет построить в общем случае. MC>Если речь идет о подсветке и фолдинге редакторе, то 100% корректной работы не нужно. Достаточно покрытия определенного процента ситуаций, я считаю.
Возможно, пример не очень удачный. Давай попробую так:
MC>
Если не трудно, приведи кусок местного кода, который различает эти ситуации. А именно, умеет понимать разницу между первыми тремя ситуациями. Может я не умею готовить регекспы, но с ходу не могу придумать, как различить эти ситуации. Зато умею это делать без регекспов — проходом по коду и запоминанием уровня вложенности и типа парной конструкции для каждого символа.