Pull to refresh

Comments 68

Неплохо было бы сделать это все ввиде плагина к браузеру.
Никогда этим не занимался. Но, возможно, стоит попробовать
Что-то я не смог понять почему вас не устроил Pygments для подсветки кода.
Велосипеды делаются по незнанию и, реже, от избытка энтузиазма.
А что плохого в изобретении велосипедов? Фарадей не знал, что электромагнитные явления могут описываться уравнениями и изобрел силовые линии. Так теперь силовым линиям учат школьников, а полные уравнения дают только студентам физмата. И таких примеров полно. Любая задача может быть — и должна! — быть решена несколькими способами. Так что на мой взгляд велосипеды — это хорошо
На мой взгляд лучше, если велосипедостроение начинается после изучения сущесвующих альтернатив.
Обычно такое изучение заканчивается словами «Че я буду париться, все ведь уже придумано». Если конечно это не научная работа. Мое мнение — сначала сформируй идею, а потом ищи альтернативные решения, на случай если такая идея уже была и получила (а если не получила — то почему) развитие.
Понимаете ли, программирование — моя профессия. Я этим себе на хлеб с маслом зарабатываю.
И предпочитаю быть честным с заказчиком. Сначала смотрю, не сделано ли желаемое кем-то другим.
Разбираюсь в имеющихся реализациях (это практически всегда быстрее, чем писать с нуля).
Чтобы можно было выдать какое-то подобие экспертной оценки: есть варианты А и Б, для каждого приложить список достоинств и недостатков. Если свой велосипед выглядит привлекательным решением — он тоже прикладывается. Очевидный недостаток — на изобретение требуется время и, соответственно, деньги. Иногда (не слишком часто) — достоинства перевешивают.

Как-то так. Оба подхода: «чё я буду париться, все ведь уже придумано» или «свой велосипед любой ценой» — выглядят одинаково непрофессионально, вы уж извините. Основывать работу на них не стоит.
Программирование — неотъемлемая часть и моей профессии. И я с Вами согласен — но только для крупных проектов, где собственно успех зависит от качества модели предметной области. А в решении небольших подзадач использование готовых «хороших» или «популярных» решений — это далеко не всегда так хорошо. Да, на изобретение требуется время, но лучше потерять немного времени чем потерять хорошую идею
И уж простите, но честность с заказчиком не исключает возможность предложить свое решение. А если ориентироваться на других — всегда будешь только догонять
Что-то я потерял нить разговора.
Насколько вижу, всё начиналось с максимы: «Перед созданием своего решения изучи существующие альтернативы».
Похоже, вы с этим не согласны — рассматривать готовые решения следует только для мегапроектов, а во всех случаях нужно изобретать колесо с шашкой наголо. Мне такой подход чужд.
Не совсем. Я хочу сказать, что изобретения велосипедов не надо чураться, это не зло в последней ипостаси и уж никак не признак непрофессиализма. Я не знал о существовании pygments. Сейчас знаю — и вижу, что в перспективе он может не дать того результата, который мне нужен. Если бы знал о нем до того, как начал искать решение, вероятно, его бы и использовал. И грабли вылезли бы позже, когда что-то переделывать стало бы влом — программа-то бытовая
Я не пытаюсь навязать свою точку зрения, просто говорю, что если есть библиотека N, которая решает эту задачу (т.н. «существующее решение») — не надо ее закрыв глаза использовать, даже если граблей пока не видно. Может ваш велосипед окажется лучше созданного до тебя
спор ремесленника с исследователем. Так забавно :)
Тут еще такой момент. В мои планы не входило делать описания для всех языков, описываю синтаксические конструкции только тех, которыми владею. А пользователю может потребоваться подсветить код на другом языке, может, даже собственного производства. И этот абстрактный пользователь может и не быть спецом в питоне. Тогда pygments не устроит. А регулярки — вещь известная большинству IT-специалистов
Открываем исходники pygments…
О чудо! Внутри лексеров тоже — регулярки!
Или у вас они какие-то особенные, понятные детям и домашним животным?
Да нет, регулярки самые обычные, я бы даже сказал, банальные. Вот только зачем лишний раз лезть в исходники, особенно в чужие? Это что, фетиш такой? Не нужно писать лишний код, если можно без этого обойтись. В данном случае — можно
За такое высказывание уволил бы сотрудника в ту же минуту.
Чужие исходники — кладезь знаний. И багов. Ради разборок с обоими туда лизать полезно.
у вас ведь опенсорс?
так поместите его в гитхаб!
Сыроват он еще. Как созреет, стилями обрастет — выложу
вот гады какието минусуют!
человеку стыдно за некрасивый код, а вы…

а вы человек не парьтесь на счет красоты, выложите, а там вам и патчики пойдут
я не парюсь насчет красоты. просто не люблю столь официально (гитхаб для меня какбы авторитетное место) публиковать сырую работу
Еще один одаренный человек пытается делать парсинг кода регулярками.
Описать грамматику в терминах БНФ и сделать нормальный парсер.
Чудесное предложение. ЗАЧЕМ? Вы предлагаете собрать автомобиль только чтоб на радиаторе яичницу пожарить
Парсеров в сети — жопой жуй, описания грамматик тоже можно легко и непринужденно найти. Собрать парсер на генераторе — дело пяти минут, а работать будет быстрее и эффективнее — допустима будет подсветка ключевых слов в контексте (например, в C# value является ключевым словом только в контексте объявления свойства).
Я могу сказать только одно — действуйте. И посмотрим, после скольки языков у вас руки отсохнут. А вот что работать будет эффективнее — это откровенная ложь. Потрудитесь посмотреть сложность алгоритмов синтаксического разбора и сравнить со сложностью сопоставления с регулярным выражением.
А парсеров в сети — много, да. Но вы уверены в их качестве, устойчивости к ошибкам, соответствии стандартам? Я нет. И не для всех языков они есть. Составите, к примеру, по-быстрому за пять минут в генераторе полный парсер для Haskell — лично сниму перед Вами шляпу.
И в основе ЛЮБОГО парсера все те же регулярные выражения. Читайте теорию
В статье после слов «Вспомним теорию». Не верите тому что там написано — Вирт вам в руки, «Построение компиляторов», или Книгу Дракона Ахо и Ульмана
Я не буду Вам цитировать Дракона. Просто ответьте на вопрос: как парсер вытаскивает лексемы языка из исходной последовательности символов. Ну и про иерархию грамматик Хомского хотя бы в Википедии прочитайте
То есть вам все-таки имеет смысл напомнить, что КС-грамматики и автоматные грамматики — это два разных класса грамматик, и большинство языков программирования описываются первой, а не второй?
А слово «иерархия» вам не о чем не говорит? По иерархии Хомского КС-грамматики — 2-й тип, а регулярные — 3-й. Множество грамматик с большим номером по иерархии Хомского входит в множество грамматик с меньшим номером как подмножество. Советую все-таки перечитать теорию.
Именно. Регулярное выражение определяет один-единственный класс лексем. А КС-грамматики описываются в БНФ как раз с использованием этих самых лексем. Посему повторяю вопрос: как парсер вытаскивает лексемы языка из исходной последовательности символов. Если Вы знаете способ без использования регулярных выражений — просветите меня
Эммм… по-моему вы слегка запутались.

Парсер вытаскивает лексемы из исходной последовательности символов простым сравнением текущей лексемы с возможными вариантами. Никаких регулярных выражений здесь никогда и не было, а если бы они были тут — даже простейшая программа компилировалась бы до третьего пришествия.

Следствием большей мощности КС-грамматик относительно автоматным является тот факт, что с помощью КС-грамматик можно описать любые автоматные грамматики, а обратное в свою очередь неверно. Причем тут БНФ, которая является лишь способом задания КС-грамматики?

Видимо, вас запутала фраза из википедии
> Они являются контекстно-свободными, но с ограниченными возможностями.
Так вот, регулярные грамматики не являются контекстно-свободными.
Нет, я не запутался. Похоже, запутались Вы. Поясните пожалуйста фразу «вытаскивает лексемы из исходной последовательности символов простым сравнением текущей лексемы с возможными вариантами». Что за варианты такие?
Приведу пример. Хочу я сделать такой вот странный язык, в котором имена переменных должны соответствовать правилу (20-50 букв, цифра, подчеркивание или символ '$'). Попробуйте описать это в БНФ
а какой из существующих языков имеет такие лексемы?
PS: в статье я описывал хоть простенький лексер, но который может быть легко расширен и до плюсового/java'вского, причём без всяких регулярок. Зачем стрелять из пушки по воробьям?
Из существующих — надеюсь, никакой. Только это значения не имеет. Вот захотелось мне сделать, допустим, диалект того же питона с такими странными идентификаторами переменных. Язык порождается КС-грамматикой. Сможете его описать в БНФ?
смогу. даже не очень трудно.
претензии к тому что выглядит не очень не принимаются, ибо:
1. Сами придумали корявые идентификаторы.
2. В коде это будет довольно просто и компактно из-за использования таблиц парсинга.
3. Грамматика раздута для наглядности, нетерминалы ten, five_less, eleven_less, six_less не нужны.
4. Работать будет скорее всего быстрее чем regexp.

Но я не понимаю зачем вам нужно задавать БНФ для лексем, когда чаще всего достаточно простого анализа входного потока, без заморочек?
Вы наплодили много ненужных продукций. А если я увеличу максимум до 500? Или еще больше? Случай надуманный — бесспорно, но суть показывает. На то, что в общем-то является терминалом языка, у вас ушло 10 продукций
Статью посмотрел, спасибо. И про воробьев правильно — я об этом говорил выше. Только вы несколько не правы в том, что «без всяких регулярок». Простите, если выше я допускал неточность в формулировках, но тут основная мысль в том, что лексемы языка с образующими КС-грамматиками — это не что иное, как регулярные языки. Каждый регулярный язык может быть описан одним регулярным выражением. И строка — это тоже регулярное выражение, просто в вашем случае прямо их использовать не требуется (хотя никто не мешает) — они атомарны, составлены с использованием только одной операции — конкатенации символов алфавита
ну вы смешали в кучу лексер и синтаксический анализатор, насколько я понял к вам претензия в том, что вы используете регулярки при синтаксическом анализе, а вы упираете на то, что они удобны для лексического.
Как бы оба этих утверждения правда — для лексического анализа проще не применять БНФ, а юзать regexp'ы или вовсе без сложных структур обойтись, а работать посимвольно, но и выполнять синтаксический анализ через регекспы — извращение, и лучше использовать КС-грамматики + анализатор.
Вы напрасно столь категорично разделяете лексический и синтаксический анализаторы на два разных класса. Лексический анализатор — это синтаксический анализатор для языков с регулярной грамматикой. А они, как писалось выше, составляют подмножество КС-грамматик
Да и претензии ко мне, собственно, в том, что уважаемый bobermaniac не приемлет регулярные выражения в парсерах КС-грамматик, что, простите, просто глупо если вы строили хоть один транслятор для языка программирования
выполнять синтаксический анализ текста на языке с КС-грамматикой через регексы — не просто извращение. Это в принципе невозможно. Только я упираю на то, что в данном случае вообще не нужен синтаксический анализатор языка программирования. Это как микроскопом гвозди заколачивать
Дело даже не в принципиальной невозможности описать такие изотерические случаи в БНФ. Можно, даже не в расширенной нотации. Только продукция будет километровая — в конце 30 закрывающих квадратных скобок! Вся соль в том, что эта продукция будет описывать один единственный регулярный язык («Язык регулярен, если его синтаксис может быть выражен единственным выражением РБНФ (расширенной нотации Бекуса-Наура)» Н.Вирт «Построение компиляторов»). А если язык регулярен — так и давайте его описывать как регулярное выражение, а не плодить ненужные продукции для терминалов языка
Для подсветки кода достаточно лексического разбора, с которым обычно справляются регулярные выражения. Другое дело, что автор реализовал разбор не самым лучшим образом :)
Посмотрите, как делаются классические лексические анализаторы: после выделения очередной лексемы они сдвигают указатель сразу после выделенной лексемы, так что следующая лексема оказывается в начале буфера. Таким образом before и after становятся не нужны. before не нужен, т.к. мы и так в начале буфера, а after не нужен, если писать «regexpr» правильно.
Насколько я понимаю, Вы имеете ввиду семейство lex-подобных программ. Так там, если я правильно помню, после считывания символа последовательности делается сдвиг по всем конечным автоматам, то бишь проверяются сразу все классы лексем, поэтому когда один из них срабатывает — дает лексему — указатель оказывается у начала следующей. Здесь такая штука не прокатит, поскольку не имеется таких методов у объектов-регулярок стандартной библиотеки
> не имеется таких методов у объектов-регулярок стандартной библиотеки

А если найду? :)

Продвигать «указатель» (просто целое число) можно и руками. Перебирать регулярки — тоже. А поиск от нужного места делается методом match класса re.RegexObject:
>>> rr = re.compile('[0-9]+')
>>> rr.match('aa00', 0)  # ничего
>>> rr.match('aa00', 1)  # ничего
>>> rr.match('aa00', 2)
<_sre.SRE_Match object at 0x7fb315eb66b0>
Вы считаете этот выход оптимальным? Я искренне удивлен. Ваша регулярка длиной 4 символа, т.е. каждый вызов match заглядывает вперед от текущей позиции (во втором аргументе) на 4 символа. Т.е. для строки в 20 символов вам нужно будет прочитать (20-4)*4 символа. Это для каждого выражения. В Вашем примере реализован самый дорогой алгоритм сопоставления с шаблоном с асимптотической сложностью N^2 для каждого регулярного выражения.
В lex-подобных анализаторах считывается символ и производится сдвиг (там где это возможно) на одно СОСТОЯНИЕ конечного автомата.
Для подсветки кода я считаю это вполне оптимальным. Для компилятора — конечно, нет.
Странное понимание оптимальности. Вы предлагаете увеличить сложность алгоритма непонятно зачем. В Вашем варианте в сравнении с тем, что уже реализован, сложность будет в лучшем случае такая же, а в худшем на один порядок выше. Простите, но Вы не правы
Для упрощения описания языка. Разве один regexpr не проще regexpr+before+after?
Не лучше. Они просто не подходят, и этот случай описан под словами «Блин первый». Ваше предложение неприемлемо для данной ситуации по следующим причинам:
1. Предложенный метод — самый дорогой из всех возможных, его сложность оценивается как O(n^2) для строки длины n. Не могу сказать точно (не глядел исходники модуля re), но поиск соответствия регулярному выражению в строке в стандартной библиотеке всяко лучше Вашего метода посимвольного сдвига по строке. Во всяком случае он не хуже — потому что хуже некуда.
2. Этот способ вообще не подходит, потому что данная программа, в общем, не является лексическим анализатором (и тем более, синтаксическим) в полном смысле этого слова. Лексический анализатор преобразует исходную последовательность символов в список символов словаря абстрактных терминальных символов языка. Именно поэтому в «классических» лексических анализаторах после прочтения одной лексемы начинается другая. В данной задаче между выделяемыми словами может стоять любое количество символов, которые не составляют лексему, а значит, устойчивый к ошибкам лексический анализатор их просто пропускает. В данном случае (и это написано в статье), такой подход приведет к нахождению лексемы там, где ее на самом деле нет — например, внутри слова. Так что без описания предстоящих и постстоящих символов просто не обойтись. Или потребуется описание всех существующих в конкретном языке лексем — а это уже задача на порядок выше и для данного случая решать ее не вижу смысла.
Если Вы с этим не согласны — напишите свой вариант и докажите, что Ваша идея жизнеспособна. Тогда буду рад признать свою неправоту
кстати, эка незадача, в Вашем примере нашлось число внутри строки. Будем подсвечивать?
Это match, а не find, так что подсвечивать не будем.
Я все напутал и это плохая ссылка. :-(
Sign up to leave a comment.

Articles