Comments 28
ply – один из лучших парсеров, с которыми я работал. Отмечу, что у рубишников есть rly, почти полный порт ply на ruby, с еще более навороченным синтаксисом (благо ruby в плане DSL потолерантнее питона). Он, правда помедленее ply, так как был допилен до уровня, достаточного чтобы я использовал его в своем проекте, но Yacc-составляющаая полноценная.
На фото у всех шорты мокрые, так ли страшен этот ply?
Интересная штука!
А может ли это использоваться вот в таком примере:
То есть в процессе парсинга грамматика может изменяться.
А может ли это использоваться вот в таком примере:
<?php
$foo=6;
syntax(var, ":=", val, {
var=val
});//объявили новый синтаксис
//используем
$foo := 10;
То есть в процессе парсинга грамматика может изменяться.
Нет. Грамматика определяется во время компилирования и не изменяется во время выполнения. Такое наверное можно сделать только руками, используя LL(1), и то, будет порождать множество неоднозначностей.
Спасибо, замечательная статья! Правда есть грамматики, для которых PLY не очень подходит, так что я перешел на простой самопальный парсер :)
Если будете продолжать писать, хотелось бы услышать про обработку ошибок.
Если будете продолжать писать, хотелось бы услышать про обработку ошибок.
хотелось бы услышать про обработку ошибок
Ну вот есть t_error и p_error — через них все и делается. В питоне ведь свойства классов динамические, так что чем больше инфы вы походу парсинга будете запихивать в t.lexer и p.parser, тем лучше будет происходить обработка.
Я в курсе про t_error и p_error, но по-человечески их завести так и не вышло. Так и не понял, как сказать красиво, например, что не закрыта какая-нибудь скобка или еще что. Как в gcc в общем.
А не подходит он для грамматики LOGO, например. Там вот это:
означает это:
Так же, как и
А не подходит он для грамматики LOGO, например. Там вот это:
PRINT THING "VAR
означает это:
PRINT (THING "VAR)
Так же, как и
PRINT ADD 5 THING "VAR
. То есть значение имеет количество аргументов у функций.По поводу скобок и всего такого, можно делать вставки в грамматику, хотя конечно не самый изящный вариант:
…
По поводу logo да, там разве что только лексер оттуда брать…
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 со следующими часто встречающимися проблемами парсеров и если да, то как?
- В статье написано, что PLY сам сортирует таблицу лексем, чтобы «побеждал длиннейший». В парсере языка C++ была проблема, что код вложенных шаблонных типов (
TypeA<TypeB<TypeC>>
) разбирался некорректно: две закрывающие треугольные скобки подряд воспринимались за один оператор сдвига (>>
) и это приводило к ошибке синтаксиса. - Есть ли возможность разбирать грамматики со значащими отступами, как в самом Python?
- Можно ли кастомизировать сообщения об ошибках? Чтобы выдавалось не нечто вроде «Ожидается: идентификатор, или число, или строка, или ...», а более подходящие по контексту: «Возможно, пропущена скобка».
код вложенных шаблонных типов (TypeA<TypeB>) разбирался некорректно: две закрывающие треугольные скобки подряд воспринимались за один оператор сдвига (>>)
Т.е. что-то типа этого?
string<allocator<char>> varname = "foo";
Можно просто не включать в лексер оператор '>>' и обрабатывать его в парсере, как последовательность '>'. Но тогда грамматика усложнится за счет того что придется обрабатывать ненужные пробельные символы.
2. Думаю что можно и с отступами разбирать. Посчитать их количество перед началом первого блока с отступами и считать это длиной оступа по умолчанию. В парсере мы просто считаем количество пробелов перед блоком, а затем делим на отступ по умолчанию и принимаем решение принадлежит ли блок родителю. Ну и действуем соответствующе
3. Можно. Уже ответил выше как. Нужно вставлять действия посередине.
В стандарте С++ уделено внимание этой неоднозначности и решение только одно — ставить пробел, т.е. проблемный код не является валидным для С++. Но вообще С++ нельзя распарсить LALR(1) парсером, это не проблема PLY
Кто-нибудь из тех, кто шарит в ply, объясните мне, нафига не использовать именные пространства, а вместо этого использовать префиксы к названиям переменных и функций?
Зачем вы потеряли PHP_END?
Ну, во первых, он по спецификации не обязателен, во вторых он мне был не нужен потому что парсер кроме пыхтачка ничего не понимает.А если бы понимал, то не было бы строгого условия начинать код с <?php (можно ведь текст и вначале файла пихануть какой-то).
Парсер PHP на Питоне, конечно, тооонко))
Ну… учитывая что есть возможность транслировать python в нативный C, это не кажется оверхедом. Если я правильно помню, то facebook делал интерпретатор php тоже на python (не hiphop, а позже какой-то там), и добились значительного ускорения.
съинтерпретируется
Wut? Сынтерпретируется же :-)
Если не трудно, покажите примеры ветвлений.
Sign up to leave a comment.
Разбор кода и построение синтаксических деревьев с PLY. Основы