我正在创建一种支持重要空格的语法(最像 Python 或 yaml 的“Z”lisp 变体,但相同的想法)
我遇到了这篇关于如何在 pegasus 中进行重要的空白解析的文章,这是 C# 的 PEG 解析器
但是我在将其转换为欧芹方面不太成功,看起来 Pegasus 中的#STATE# 变量以某种方式跟随回溯。
这是我最接近简单解析器的方法,如果我使用indent
with look ahead 的版本,它就无法解析孩子,如果我使用没有的版本,它就无法解析兄弟姐妹。
如果这是欧芹的限制并且我需要使用 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()