会議についての会議の結果、羊が足りないという結論に達した。
実際を考えると生の構文木よりも
「マークの付いている『重要な』要素だけのツリー」
が得られた方がありがたいと思うのだけど、
とりあえず生の構文木。
>>> MUL.match("123*45")
'123*45'/6
>>> r = _
>>> r.children
['123*'/4, '45'/2]
>>> r.children[0].children
['123'/3, '*'/1]
Pythonの構文は、トークナイザの部分がインデント・デデントを判断しているみたいなのだけども、
トークナイザをパーサを分けるのは美しくないのでどうするか考え中。
=
アンサイクロペディアのPythonの項目が面白い。Python - アンサイクロペディア
パールのようなもの - アンサイクロペディア
=
見た目は唐辛子、ししとうなんだけどー。
=
AA-lib。CACA-lib。CUCU-lib。BB
=
ずっと黒い画面のターン
=
あああ。Matzにっき(2007-09-12)より:
Logix
Pythonの文法を自由に再定義できるようにした新言語。またはPythonバイトコードを吐くマクロ処理系。
これはPEGじゃないけど、やりたかったのはまさにこういうことだったんだ。先にやられたorz
Pythonの構文木も、生の構文木を綺麗な抽象構文木にするためには
別途トランスフォーマってのを走らせる必要がある。
僕のPEGでは簡単な数式がこんな複雑な構文木になってしまうので何か間違っているのではないかと悩んだが、
>>> MATH.match("2*(1+3)+5")
'2*(1+3)+5'/9
>>> tree(_)
'2*(1+3)+5'/9
'2*(1+3)'/7
'2'/1
'2'/1
''/0
'*(1+3)'/6
'*(1+3)'/6
'*'/1
'*'/1
''/0
'*'/1
''/0
'(1+3)'/5
'(1+3'/4
'(1+3'/4
'('/1
'('/1
''/0
'1+3'/3
'1'/1
'1'/1
'1'/1
''/0
''/0
'+3'/2
'+3'/2
'+'/1
'+'/1
''/0
'+'/1
''/0
'3'/1
'3'/1
'3'/1
''/0
''/0
''/0
')'/1
'+5'/2
'+5'/2
'+'/1
'+'/1
''/0
'+'/1
''/0
'5'/1
'5'/1
'5'/1
''/0
''/0
Pythonでも生の構文木はかなりぐちゃぐちゃ
>>> pprint.pprint(parse("2*(1+5)-3"))
['eval_input',
['testlist',
['test',
['or_test',
['and_test',
['not_test',
['comparison',
['expr',
['xor_expr',
['and_expr',
['shift_expr',
['arith_expr',
['term',
['factor', ['power', ['atom', ['NUMBER', '2']]]],
['STAR', '*'],
['factor',
['power',
['atom',
['LPAR', '('],
['testlist_gexp',
['test',
['or_test',
['and_test',
['not_test',
['comparison',
['expr',
['xor_expr',
['and_expr',
['shift_expr',
['arith_expr',
['term',
['factor',
['power',
['atom',
['NUMBER', '1']]]]],
['PLUS', '+'],
['term',
['factor',
['power',
['atom',
['NUMBER', '5']]]]]]]]]]]]]]]],
['RPAR', ')']]]]],
['MINUS', '-'],
['term',
['factor', ['power', ['atom', ['NUMBER', '3']]]]]]]]]]]]]]]],
['NEWLINE', ''],
['ENDMARKER', '']]
Pythonの方はトークナイザが走った後の「空白とかインデントとか処理済みのトークン列」を処理していることを考えれば、
PEGの方は(まだ盛り込んだ機能が少ないこともあるけど)比較的シンプル。
トランスフォーマが作る抽象構文木はこんな感じ
>>> compiler.parse("2*(1+5)-3", "eval")
Expression(Sub((Mul((Const(2), Add((Const(1), Const(5))))), Const(3))))
これは美しい。しかしこの美しい構文木に変換するためには
下のような超泥臭い作業が必要。
def for_stmt(self, nodelist):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
listNode = self.com_node(nodelist[3])
bodyNode = self.com_node(nodelist[5])
if len(nodelist) > 8:
elseNode = self.com_node(nodelist[8])
else:
elseNode = None
return For(assignNode, listNode, bodyNode, elseNode,
lineno=nodelist[0][2])
文法定義と抽象構文木化で似たような内容を書くのはばかげていると思うのだけども、どうすれば可読性を損ねたりせずに文法定義だけでこういうきれいなツリーを作れるだろうか。
とりあえず1+3だけで下のような木になってしまうのは、PEGのSequenceを二項関係だけで定義しているから。
僕のsimple_pegは本当にシンプルに作ってあるけど、Matcherを追加することで拡張できるようにしてあるから「任意のn個のSequence」を表現するMatcherを作ればいいと思う。
'1+3'/3
'1'/1
'1'/1
'1'/1
''/0
''/0
'+3'/2
'+3'/2
'+'/1
'+'/1
''/0
'+'/1
''/0
'3'/1
'3'/1
'3'/1
''/0
''/0
すごく続きをしたいところではあるけども、
頑張って147行の英文メールを投げたおかげで(?)
日本語の化けないJython2.2.1rc1が出たので、
本当に化けないのかを確認するのが先。