Nemerle.Peg как альтернатива Regexp'ам
От: Рысцов Денис  
Дата: 20.04.11 13:09
Оценка:
Я работаю над презентацией про Nemerle.Peg для addconf2 и в процессе обнаружил, что некоторые регулярки со скрипом ложатся на peg нотацию. Это получается из-за того, что PEG (насколько я понял) не поддерживает квантификатор вида '{n}', поэтому простое регулярное выражение '\d{3}-\d{4}' приходиться раскрывать в

[PegGrammar(phone,grammar{
  d     : int    = ['0'..'9'];
  phone : string = d d d '-' d d d d;
})]
class PhoneParser
{
  d(digit : NToken) : int { int.Parse(GetText(digit)) }

  phone(a:int, b:int, c:int, _:NToken, d:int, e:int, f:int, g:int) : string
  { 
    $"+7(812)$a$b$c-$d$e$f$g"
  }
}

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

[PegGrammar(phone,grammar{
  d              = ['0'..'9'];
  phone : string = d{3} '-' d{3};
})]
class PhoneParser
{
  phone(a : NToken, _ : NToken, b : NToken) : string
  { 
    $"+7(812)$(GetText(a))-$(GetText(b))"
  }
}

Мне кажется, что такой подход нужен для того, чтобы заметить почти всюду использование Regex на Nemerle.Peg. К сожалению, для меня сейчас приоритет — подготовить презентацию, поэтому не могу заняться реализацией этого комбинатора, будет здорово, если кто-нибудь возьмется за нее, а смогу с чистой совестью рекламировать Nemerle.Peg на addconf, в том числе и как альтернативу регулярным выражениям.
Re: Nemerle.Peg как альтернатива Regexp'ам
От: hardcase Пират http://nemerle.org
Дата: 20.04.11 13:24
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Мне кажется, что такой подход нужен для того, чтобы заметить почти всюду использование Regex на Nemerle.Peg. К сожалению, для меня сейчас приоритет — подготовить презентацию, поэтому не могу заняться реализацией этого комбинатора, будет здорово, если кто-нибудь возьмется за нее, а смогу с чистой совестью рекламировать Nemerle.Peg на addconf, в том числе и как альтернативу регулярным выражениям.


Чисто технически там трудностей нет (квантификаторы могут быть любыми), я полагаю дело лишь в парсере грамматики и его можно поправить за вечер.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Nemerle.Peg как альтернатива Regexp'ам
От: WolfHound  
Дата: 20.04.11 14:06
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Мне кажется, что такой подход нужен для того, чтобы заметить почти всюду использование Regex на Nemerle.Peg. К сожалению, для меня сейчас приоритет — подготовить презентацию, поэтому не могу заняться реализацией этого комбинатора, будет здорово, если кто-нибудь возьмется за нее, а смогу с чистой совестью рекламировать Nemerle.Peg на addconf, в том числе и как альтернативу регулярным выражениям.

Оно было всегда.
    | RepeatMin      { minCount : int; rule : Rule; }
    | RepeatMinMax   { minCount : int; maxCount : int; rule : Rule; }

Только синтакса нет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.11 18:36
Оценка:
Здравствуйте, WolfHound, Вы писали:

РД>>Мне кажется, что такой подход нужен для того, чтобы заметить почти всюду использование Regex на Nemerle.Peg. К сожалению, для меня сейчас приоритет — подготовить презентацию, поэтому не могу заняться реализацией этого комбинатора, будет здорово, если кто-нибудь возьмется за нее, а смогу с чистой совестью рекламировать Nemerle.Peg на addconf, в том числе и как альтернативу регулярным выражениям.

WH>Оно было всегда.
WH>
WH>    | RepeatMin      { minCount : int; rule : Rule; }
WH>    | RepeatMinMax   { minCount : int; maxCount : int; rule : Rule; }
WH>

WH>Только синтакса нет.

Попробовал прикрутить синтаксис:
Rule '{' IntLiteral (',' IntLiteral)? '}'

но нарвался на проблему. Препарсер сворачивает LooseGroup по окончании '}', так что получается что после '}' как бы начинается новое правило.

Сейчас думаю как подправить компилятор чтобы можно было хотя бы понять, что свертка произведена неправильно. Хочу добавить в LooseGroup еще одно поле содержащее токен-разделитель, если он есть. Это позволит понять правомерно ли разорвали группу. За одно у нас будет токен ';', что позволит улучшить комплит в инициализиаторах выражений (надеюсь).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.11 20:50
Оценка: 48 (2)
Здравствуйте, Рысцов Денис, Вы писали:

Сначала о самой задаче. На мой взгляд — это все баловство.

На практике намного правильнее разбирать более общие паттерны вроде: d* ('-' d*)+
Ну, а количество символов уже контролировать в семантике. Это позволит выдать более осмысленное сообщение об ошибке. Типа "Ожидается паттерн ххх-ххххх, а вы ввели 8 цифр вместо 4 послле '-'.".

Что касается использования PegGrammar вместо регексов, то тут есть две проблемки. Во-первых, для использования PEG-а в качестве регесов нужно чтобы их можно было использовать прямо среди выражений, т.е. надо реализовать нечто вроде оператора "peg match". Во вторых PegGrammar довольно не шустро работает. Если в программе будет тысяча его применений, то она может начать сильно тормозить как при компиляции, так в режиме разработки (при работе под IDE). Так что я бы стал использовать PegGrammar только в нетривиальных случаях. Для проверки телефона сгодятся и регекспы.

РД>К сожалению, для меня сейчас приоритет — подготовить презентацию, поэтому не могу заняться реализацией этого комбинатора, будет здорово, если кто-нибудь возьмется за нее, а смогу с чистой совестью рекламировать Nemerle.Peg на addconf, в том числе и как альтернативу регулярным выражениям.


О, хитрец! На меня в два раза длиннее доклад повесили.

В общем, реализовал синтаксис для этого дела. Доступно в последнем комите.

Пример использования:
using System.Console;
using Nemerle.Peg;

[PegGrammar(start,grammar{
  any            = ['\u0000'..'\uFFFF7'];
  d              = ['0'..'9'];
  phone : string = d{3} '-' d{4,5};
  start : string = phone !any;
})]
class PhoneParser
{
  phone(a : NToken, _ : NToken, b : NToken) : string
  { 
    $"+7(812) $(GetText(a))-$(GetText(b))"
  }
}

module Program
{
  Main() : void
  {
    def parser = PhoneParser();
    def print(text)
    {
      match (parser.Parse(text))
      {
        | Some(rest) => WriteLine($"OK! Result is: '$rest'")
        | _          => WriteLine($"Fail source: '$text'")
      }
    }
    
    print("123-4567");
    print("123-45678");
    print("123-456");
    print("123-456789");
  }
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Nemerle.Peg как альтернатива Regexp'ам
От: hardcase Пират http://nemerle.org
Дата: 20.04.11 21:05
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В общем, реализовал синтаксис для этого дела. Доступно в последнем комите.


А частный случай поддерживаются?

d{x,_}  // x и более раз


И еще, а почему бы не захардкодить правило any в генератор? Оно все-таки наиболее употребимо.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Nemerle.Peg как альтернатива Regexp'ам
От: hardcase Пират http://nemerle.org
Дата: 20.04.11 21:09
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В общем, реализовал синтаксис для этого дела. Доступно в последнем комите.


И еще, возможно стоит ли для разбора литералов использовать ConstantFolder?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.11 21:28
Оценка:
Здравствуйте, hardcase, Вы писали:

H>А частный случай поддерживаются?


H>
H>d{x,_}  // x и более раз
H>


Нет. Но добавить не сложно.

H>И еще, а почему бы не захардкодить правило any в генератор? Оно все-таки наиболее употребимо.


Это к Вольфхаунду вопрос. Он что-то сильно возбухал против этого. Типа у нас все чисто и конкретно. Ну, а мне как-то одну строку не в падлу скопипастить .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.11 21:30
Оценка:
Здравствуйте, hardcase, Вы писали:

VD>>В общем, реализовал синтаксис для этого дела. Доступно в последнем комите.


H>И еще, возможно стоит ли для разбора литералов использовать ConstantFolder?


Это и так извращение. Если тебе делать нечего можешь потом прикрутить. Но сначала доделай поддержку языковых плагинов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Nemerle.Peg как альтернатива Regexp'ам
От: Рысцов Денис  
Дата: 21.04.11 06:41
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>На практике намного правильнее разбирать более общие паттерны вроде: d* ('-' d*)+

VD>Ну, а количество символов уже контролировать в семантике. Это позволит выдать более осмысленное сообщение об ошибке. Типа "Ожидается паттерн ххх-ххххх, а вы ввели 8 цифр вместо 4 послле '-'.".

Это верно, но случай, когда допускаются несколько разных форматов, им не обработать, так как внутри обработчика правила невозможно сказать, что оно не верно и нужно переходить к следующему. Например, следующий парсер нельзя было бы написать (в крайней случае, почти вся логика разбора перешла бы в обработчик правила, и он бы по сути превратился бы в рукописный парсер). Если эту задачу решать regexp'ами, то тоже ничего хорошего не выйдет, выйдет мешанина кода и выражений, а с помощью peg получилось очень декларативно.

[PegGrammar(start,grammar{
  d               = ['0'..'9'];
  phoneA : string = d{3} '-' d{4};
  phoneB : string = d{3} '-' d{2} '-' d{2};
  phone  : string = phoneA / phoneB;
})]
class PhoneParser {
  phoneA(a : NToken, _ : NToken, b : NToken) : string { 
    $"+7(812) $(GetText(a))-$(GetText(b))"
  }

  phoneB(a : NToken, _ : NToken, b : NToken, _ : NToken, c : NToken) : string { 
    $"+7(812) $(GetText(a))-$(GetText(b))$(GetText(c))"
  }
}


VD>О, хитрец! На меня в два раза длиннее доклад повесили.


да, я такой

VD>В общем, реализовал синтаксис для этого дела. Доступно в последнем комите.

круто, спасибо
Re[3]: Nemerle.Peg как альтернатива Regexp'ам
От: WolfHound  
Дата: 21.04.11 07:31
Оценка:
Здравствуйте, hardcase, Вы писали:

H>И еще, а почему бы не захардкодить правило any в генератор? Оно все-таки наиболее употребимо.

Я думал об этом.
Его можно захардкодить в качестве еще одной юникодной категории.
И тогда можно будет писать так [Any]
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Nemerle.Peg как альтернатива Regexp'ам
От: hardcase Пират http://nemerle.org
Дата: 21.04.11 07:57
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>И тогда можно будет писать так [Any]


А может просто использовать wildcard "_"?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.11 15:18
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Это верно, но случай, когда допускаются несколько разных форматов, им не обработать,


Ну, почему же? При разборе запихиваешь все в АСТ, а потом анализируешь его с помощью паттерн-матчинга.

РД>так как внутри обработчика правила невозможно сказать, что оно не верно и нужно переходить к следующему. Например, следующий парсер нельзя было бы написать (в крайней случае, почти вся логика разбора перешла бы в обработчик правила, и он бы по сути превратился бы в рукописный парсер). Если эту задачу решать regexp'ами, то тоже ничего хорошего не выйдет, выйдет мешанина кода и выражений, а с помощью peg получилось очень декларативно.


Декларативно — это здорово! Если играться в игрушки, то это конечно отличное решение. Но на практике зачастую нужна более качественная диагностика ошибок или еще что-то. А парсер он ведь тупой автотмат. Он не может сказать, что не так. Он может только сказать, что текст не соответствует грамматике.

По этому на практике зачастую бывает выгоднее разбирать более общую грамматику чем требуется. А проверки осуществлять в семантическом анализе. Ведь при сложных задачах стадия семантического анализа будет на верняка. А раз так, то пара лишних проверок картины не испортит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Nemerle.Peg как альтернатива Regexp'ам
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.11 16:53
Оценка: 1 (1)
Здравствуйте, hardcase, Вы писали:

H>А может просто использовать wildcard "_"?


Да как угодно будет по любому лучше чем сейчас. Сейчас приходится лазить по проектам и копипастить правило которое по любому нужно в любой грамматике.

По уму нужно и для других часто встречающихся задач пресетов наделать. Но это уже лучше было бы сделать в виде библиотек. А для этого нам нужно что? Правильно — расширяемость. Предлагаю еще раз попросить нашего уважаемого WolfHound-а таки добить расширяемость.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.