Как стать автором
Обновить

Комментарии 28

ply – один из лучших парсеров, с которыми я работал. Отмечу, что у рубишников есть rly, почти полный порт ply на ruby, с еще более навороченным синтаксисом (благо ruby в плане DSL потолерантнее питона). Он, правда помедленее ply, так как был допилен до уровня, достаточного чтобы я использовал его в своем проекте, но Yacc-составляющаая полноценная.
На фото у всех шорты мокрые, так ли страшен этот ply?
Интересная штука!
А может ли это использоваться вот в таком примере:
<?php
$foo=6;
syntax(var, ":=", val, {
var=val
});//объявили новый синтаксис
//используем
$foo := 10;

То есть в процессе парсинга грамматика может изменяться.
Нет. Грамматика определяется во время компилирования и не изменяется во время выполнения. Такое наверное можно сделать только руками, используя LL(1), и то, будет порождать множество неоднозначностей.
Вспоминается Katahdin.
Да, прикольный язык. О нём даже статья была на хабре. Хотя мне нужно compile-time изменений грамматики.
Спасибо, замечательная статья! Правда есть грамматики, для которых PLY не очень подходит, так что я перешел на простой самопальный парсер :)
Если будете продолжать писать, хотелось бы услышать про обработку ошибок.
хотелось бы услышать про обработку ошибок

Ну вот есть t_error и p_error — через них все и делается. В питоне ведь свойства классов динамические, так что чем больше инфы вы походу парсинга будете запихивать в t.lexer и p.parser, тем лучше будет происходить обработка.
Я в курсе про t_error и p_error, но по-человечески их завести так и не вышло. Так и не понял, как сказать красиво, например, что не закрыта какая-нибудь скобка или еще что. Как в gcc в общем.
А не подходит он для грамматики LOGO, например. Там вот это:

PRINT THING "VAR

означает это:
PRINT (THING "VAR)

Так же, как и PRINT ADD 5 THING "VAR. То есть значение имеет количество аргументов у функций.
По поводу скобок и всего такого, можно делать вставки в грамматику, хотя конечно не самый изящный вариант:
def p_func(p):
    '''func : expect_funcname funcname expect_lbrace LBRACE expect_body body expect_rbrace RBRACE'''
    pass

def p_expect_funcname(p): stack.push('expect funcname')
def p_expect_lbrace(p): stack.push('expect lbrace')



По поводу logo да, там разве что только лексер оттуда брать…
Ну это выглядит как костыль, сами понимаете.
Костыль, да. Но теоретически… в любых других парсерах это должно делаться примерно так же, ну т.е. мы должны как-то дать знать сами себе что ожидаем.
Для каких например грамматик может не подходить ply?
НЛО прилетело и опубликовало эту надпись здесь
Расскажите, пожалуйста, справляется ли PLY со следующими часто встречающимися проблемами парсеров и если да, то как?

  1. В статье написано, что PLY сам сортирует таблицу лексем, чтобы «побеждал длиннейший». В парсере языка C++ была проблема, что код вложенных шаблонных типов (TypeA<TypeB<TypeC>>) разбирался некорректно: две закрывающие треугольные скобки подряд воспринимались за один оператор сдвига (>>) и это приводило к ошибке синтаксиса.
  2. Есть ли возможность разбирать грамматики со значащими отступами, как в самом Python?
  3. Можно ли кастомизировать сообщения об ошибках? Чтобы выдавалось не нечто вроде «Ожидается: идентификатор, или число, или строка, или ...», а более подходящие по контексту: «Возможно, пропущена скобка».
код вложенных шаблонных типов (TypeA<TypeB>) разбирался некорректно: две закрывающие треугольные скобки подряд воспринимались за один оператор сдвига (>>)
Т.е. что-то типа этого?

string<allocator<char>> varname = "foo";


Можно просто не включать в лексер оператор '>>' и обрабатывать его в парсере, как последовательность '>'. Но тогда грамматика усложнится за счет того что придется обрабатывать ненужные пробельные символы.

2. Думаю что можно и с отступами разбирать. Посчитать их количество перед началом первого блока с отступами и считать это длиной оступа по умолчанию. В парсере мы просто считаем количество пробелов перед блоком, а затем делим на отступ по умолчанию и принимаем решение принадлежит ли блок родителю. Ну и действуем соответствующе

3. Можно. Уже ответил выше как. Нужно вставлять действия посередине.
В стандарте С++ уделено внимание этой неоднозначности и решение только одно — ставить пробел, т.е. проблемный код не является валидным для С++. Но вообще С++ нельзя распарсить LALR(1) парсером, это не проблема PLY
Теперь, с С++11, код без пробела между двумя закрывающими > в шаблонах является валидным.
Указание «ставить пробел» в стандарте — это классический пример ситуации «это не баг, это фича» :)
Кто-нибудь из тех, кто шарит в ply, объясните мне, нафига не использовать именные пространства, а вместо этого использовать префиксы к названиям переменных и функций?
Ну, во первых, он по спецификации не обязателен, во вторых он мне был не нужен потому что парсер кроме пыхтачка ничего не понимает.А если бы понимал, то не было бы строгого условия начинать код с <?php (можно ведь текст и вначале файла пихануть какой-то).
Но если хотите, могу написать через день-два, как расширить парсер на использование php как вставок… функции, классы. Хотя на самом деле это уже не будет относиться к ply напрямую, а больше к построению граматики.
Ну… учитывая что есть возможность транслировать python в нативный C, это не кажется оверхедом. Если я правильно помню, то facebook делал интерпретатор php тоже на python (не hiphop, а позже какой-то там), и добились значительного ускорения.
съинтерпретируется

Wut? Сынтерпретируется же :-)
Если не трудно, покажите примеры ветвлений.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации