いろきゅう.jp 〜Programmable maiden〜 Tech side このページをアンテナに追加 RSSフィード

2016-12-16

yaccで死亡

| 17:59

正確には ply の yacc ですけどももも

…いやぁ全然概念が判らなくて大苦戦ですわ(苦笑




学習がてら、以下に合致するパーサーを作ろうかと思ったわけです。ドット区切りで要素3つまで。

  • a
  • b.a
  • c.b.a
  • 正規表現的にはこんな感じ → ((\w+\.)?\w\.)?\w+

イメージ的には foo.ir9.jp / ir9.jp / jp を解析するパーサーを作りたい的な。 で、こんな感じなの書きました

## lex
tokens = (
	"NAME",
	"PERIOD",
)

t_NAME   = r"\w+"
t_PERIOD = r"\."

## yacc
def p_host(p):
	"""
	host : NAME PERIOD NAME PERIOD NAME
	     | NAME PERIOD NAME
	     | NAME
	"""

	p[0] = ''.join(p[1:])

yacc.yacc()
print(yacc.parse("c.b.a"))	# c.b.a
print(yacc.parse("b.a"))	# b.a
print(yacc.parse("a"))		# a

動きました。良かったよかった!

…ではあるんですが、各NAMEの要素に名前というか意味合いを付けたほうがよいのかなと。今後各要素に適用できる文字の定義を変えるかもしれないし! …ってことで、次のように改修してみました。 "[ [sub . ] domain .] cont" というイメージ。

## lex
tokens = (
	"NAME",
	"PERIOD",
)

t_NAME   = r"\w+"
t_PERIOD = r"\."

## yacc
def p_host(p):
	"""
	host : domain PERIOD cunt
	     | NAME
	"""

	p[0] = ''.join(p[1:])

def p_cunt(p) :
	"""
	cunt : NAME
	"""
	p[0] = p[1]

def p_domain(p) :
	"""
	domain : sub PERIOD NAME
	       | NAME
	"""
	p[0] = ''.join(p[1:])

def p_sub(p) :
	"""
	sub : NAME
	"""
	p[0] = p[1]

yacc.yacc()
print(yacc.parse("c.b.a"))	# a // Syntax error at line 1, token=PERIOD
print(yacc.parse("b.a"))	# b.a
print(yacc.parse("a"))		# a

# WARNING: 1 reduce/reduce conflict
# WARNING: reduce/reduce conflict in state 3 resolved using rule (domain -> NAME)
# WARNING: rejected rule (sub -> NAME) in state 3
# WARNING: Rule (sub -> NAME) is never reduced

ダメだってさ!



…って所でめっちゃ詰まってます。 おそらく「スタックに NAME 積んだ後 PERIOD 来ると、domain なんだか sub なんだか判断つかねぇんだよ!2回死ね!それと便座カバー」って事だとは思っているんですが、いかんせん yacc の挙動・動作・考え方が解っていないため全く確信が持てず。 ついでに解決方法も良くわからん… そもそもコレ「右結合」なんじゃないのと思いつつ、それがどう記述に影響してくるのか・考え方にどう影響してくるのかとかもよくわからず… ぐぬぬ……

構文解析難しいわ…

トラックバック - http://d.hatena.ne.jp/ir9Ex/20161216/1481878767