tagbodyとgo


ジャンプ処理

条件などによらず、特定のタイミングで指定した式に制御を移行させるような処理を行うには tagbodygo 特別式を使います。 これらを用いれば、手続き型言語における goto 文のように、式の中の特定のリストに制御を移すことができるようになります。

tagbody {tag | statement}*

tagbody 特別式の引数には、タグまたは式を指定することができます。 引数にリストが指定されている場合は評価対象の式であると認識され、そうでなければタグであると認識されます。 tag と statement は任意の数だけ指定することができ、最後に評価された式が tagbody の戻り値となります。

tagbody 内では go 特別式を利用することができ、go 特別式が評価されると指定された tag に移動します。 このとき、go で指定するタグは tagbody で指定されていなければなりません。

go tag

例えば (tagbody (go label) (st1) label (st2)) と記述した場合、tagbody は先頭の引数から評価して go 特別式を実行します。 go で指定されているタグは label タグです。 この tagbody では (st1) の直後に label タグが指定されているので、go が評価された時点で制御を label タグの次に移動させます。 その結果、この tagbody 特別式では (st1) が無視され (st2) が実行されます。

tagbody も go も特別式に分類されるため、タグに記号などを表記しても、それは評価されずにそのままタグとして認識されます。 そのため、上記の例のように記号を指定しても、それが評価されて展開されることはありません。 setq 特別式のように、直接記号を指定することができます。

> (setq x 10)
10
> (setq y 100)
100
> (tagbody (go label) (setq y 0) label (setq x 0))
NIL
> x
0
> y
100

このプログラムでは、変数 x に数値 10 を、y に 100 を代入しています。 その状態で (tagbody (go label) (setq y 0) label (setq x 0)) を実行して、式がどのように評価されているかどうかを調べます。 最初に go 特別式で label タグまで移動するように記述しています。 そのため、(setq y 0) は評価されずに label 間で制御が移動し、(setq x 0) だけが実行されます。

その後の x と y の値を調べれば x の値は 0 になっていますが y の値は 100 のままであることが確認できます。


tagbody の入れ子

入れ子になった tagbody のタグと go の関係は、最も内側のスコープにあるタグが優先的に利用されます。 つまり tagbody の式に tagbody がさらに指定されていて、外側の tagbody と内側の tagbody のタグ名が衝突している場合です。

> (setq x 10)
10
> (setq y 100)
100
> (setq z 1000)
1000
> (tagbody
	(tagbody
		(go label)
		(setq x 0)
	label
		(setq y 0)
	)
label 
	(setq z 0)
)
NIL
> x
10
> y
0
> z
0

このプログラムでは、変数 x、y、z にそれぞれ値 10、100、1000 を代入しています。 そして、入れ子構造の tagbody を実行して式が実行されているかどうかを確認しています。

このプログラムの tagbody は label タグが外側と内側で衝突しています。 内側の tagbody で go を用い label までジャンプしようとすると、内側のスコープから順番に label が検索されます。 そのため、内側の label に制御が以降します。



前のページへ戻る次のページへ