我正在创建一个支持重要空格的语法(最像是“Z”lisp变种而不是Python或者yaml,但同样的想法)
我遇到了这个article on how to do significant whitespace parsing in a pegasus a PEG parser for C#
但是我把它转换成欧芹并不太成功,看起来Pegasus中的#STATE#变量在某种程度上跟踪了回溯。
这是我最接近一个简单的解析器,如果我使用indent
的版本,看看它不能解析子,如果我使用的版本没有,它无法解析兄弟姐妹。
如果这是欧芹的限制,我需要使用PyPEG或Parsimonious或其他东西,我对此持开放态度,但似乎内部缩进变量可以遵循PEG内部回溯,这一切都可行。
import parsley
def indent(s):
s['i'] += 2
print('indent i=%d' % s['i'])
def deindent(s):
s['i'] -= 2
print('deindent i=%d' % s['i'])
grammar = parsley.makeGrammar(r'''
id = <letterOrDigit+>
eol = '\n' | end
nots = anything:x ?(x != ' ')
node = I:i id:name eol !(fn_print(_state['i'], name)) -> i, name
#I = !(' ' * _state['i'])
I = (' '*):spaces ?(len(spaces) == _state['i'])
#indent = ~~(!(' ' * (_state['i'] + 2)) nots) -> fn_indent(_state)
#deindent = ~~(!(' ' * (_state['i'] - 2)) nots) -> fn_deindent(_state)
indent = -> fn_indent(_state)
deindent = -> fn_deindent(_state)
child_list = indent (ntree+):children deindent -> children
ntree = node:parent (child_list?):children -> parent, children
nodes = ntree+
''', {
'_state': {'i': 0},
'fn_indent': indent,
'fn_deindent': deindent,
'fn_print': print,
})
test_string = '\n'.join((
'brother',
' brochild1',
#' gchild1',
#' brochild2',
#' grandchild',
'sister',
#' sischild',
#'brother2',
))
nodes = grammar(test_string).nodes()