Groupを使用して、解析されたトークンに階層を作成します。次に、グループのリストをナビゲートし、グループ内の名前付きフィールドにアクセスできます。このようなもの:
from pyparsing import *
LPAR,RPAR,COMMA,HASH,COLON = map(Suppress, '(),#:')
ident = Word(alphas+'_', alphanums+'_')
fnumber = Regex(r'[+-]?\d+\.\d*').setParseAction(lambda t:float(t[0]))
inumber = Regex(r'[+-]?\d+').setParseAction(lambda t:int(t[0]))
number = fnumber | inumber
ref_name = Combine("$" + delimitedList(ident, delim=oneOf(". ->"), combine=True))
named_ref = Group(ident("name") + COLON + ref_name("ref"))
unnamed_ref = Group(ref_name("ref"))
IF, ELSE = map(Keyword, "if else".split())
stmt = Forward()
decl = named_ref | unnamed_ref
def setType(typ):
def parseAction(tokens):
tokens['type'] = typ
return parseAction
cond = operatorPrecedence(ref_name | number,
[
(oneOf("< == > <= >= !="), 2, opAssoc.LEFT),
])
if_else = Group(HASH + IF + LPAR + cond("condition") + RPAR +
LPAR + stmt("then") + RPAR +
Optional(HASH + ELSE + LPAR + stmt("else") + RPAR))
if_else.setParseAction(setType("IF_ELSE"))
decl.setParseAction(setType("DECL"))
stmt << Group(decl | if_else | (HASH + LPAR + delimitedList(stmt) + RPAR))
section = Group(ident("section_name") + LPAR + Group(ZeroOrMore(stmt))("section_body") + RPAR)
parser = OneOrMore(section)
source = """
preview
(
#if ($e.d.stateFlags == 0) (
$e.d
) #else (
#( $e.d->scheme, $e.d->host, $e.d->path )
)
)
children
(
#(
scheme: $c.d->scheme,
host: $c.d->host,
path: $c.d->path,
username: $c.d->userName,
password: $c.d->password,
encodedOriginal: $c.d->encodedOriginal,
query: $c.d->query,
fragment: $c.d->fragment
)
)"""
def dump_stmt(tokens, depth=0):
if 'type' in tokens:
print tokens.type
print tokens[0].dump(depth=depth)
else:
for stmt in tokens:
dump_stmt(stmt, depth=depth+1)
for sec in parser.parseString(source):
print sec.dump()
print sec.section_name
for statement in sec.section_body:
dump_stmt(statement)
print
プリント:
['preview', [[['if', ['$e.d.stateFlags', '==', 0], [['$e.d']], 'else', [[['$e.d->scheme']], [['$e.d->host']], [['$e.d->path']]]]]]]
- section_body: [[['if', ['$e.d.stateFlags', '==', 0], [['$e.d']], 'else', [[['$e.d->scheme']], [['$e.d->host']], [['$e.d->path']]]]]]
- section_name: preview
preview
IF_ELSE
['if', ['$e.d.stateFlags', '==', 0], [['$e.d']], 'else', [[['$e.d->scheme']], [['$e.d->host']], [['$e.d->path']]]]
- condition: ['$e.d.stateFlags', '==', 0]
- else: [[['$e.d->scheme']], [['$e.d->host']], [['$e.d->path']]]
- then: [['$e.d']]
- type: DECL
['children', [[[['scheme', '$c.d->scheme']], [['host', '$c.d->host']], [['path', '$c.d->path']], [['username', '$c.d->userName']], [['password', '$c.d->password']], [['encodedOriginal', '$c.d->encodedOriginal']], [['query', '$c.d->query']], [['fragment', '$c.d->fragment']]]]]
- section_body: [[[['scheme', '$c.d->scheme']], [['host', '$c.d->host']], [['path', '$c.d->path']], [['username', '$c.d->userName']], [['password', '$c.d->password']], [['encodedOriginal', '$c.d->encodedOriginal']], [['query', '$c.d->query']], [['fragment', '$c.d->fragment']]]]
- section_name: children
children
DECL
['scheme', '$c.d->scheme']
- name: scheme
- ref: $c.d->scheme
DECL
['host', '$c.d->host']
- name: host
- ref: $c.d->host
DECL
['path', '$c.d->path']
- name: path
- ref: $c.d->path
DECL
['username', '$c.d->userName']
- name: username
- ref: $c.d->userName
DECL
['password', '$c.d->password']
- name: password
- ref: $c.d->password
DECL
['encodedOriginal', '$c.d->encodedOriginal']
- name: encodedOriginal
- ref: $c.d->encodedOriginal
DECL
['query', '$c.d->query']
- name: query
- ref: $c.d->query
DECL
['fragment', '$c.d->fragment']
- name: fragment
- ref: $c.d->fragment