1)
変数 $a は do ブロックの中で my 宣言されているので、while の条件式では参照できないからです。
2)
結論だけ言うと、last 文では do-while を抜けられない仕様だからです。
細かい話をすると、Perl にはそもそも do-while 文という構文は存在しません。do-while 文のように見えるのは、do ブロックと while の組み合わせです。last 文は繰り返しを抜ける機能であるため、do ブロックを繰り返しと認識できず、抜けることができません。
do ブロックと while の組み合わせというのは、以下の様なことです。
do ブロックは、do {A} と書くと A の部分をブロック化して実行します。
while 修飾子は、A while B と書くと B が真である限り A を繰り返し実行します。
例えば、print 'a' while 1; と書くと無限に a を出力します。
似たものに if 修飾子などがあり、例えば print "error" if $a eq ''; と書くと $a が空のときに "error" と出力するという意味になります。
これを組み合わせることによって、do {A} while B と書くと、あたかもC言語の do-while 文のように実行することができるわけです。
ただし、C言語の do-while 文に合わせるため、do ブロックは while または until と組み合わせたときにだけ、条件式より先にブロックを実行するという特殊動作が入っています。
そのくせ last で抜けることはできないとは、まったく無茶苦茶な仕様ですね。素直に do-while 文を構文にしておけばいいのに…。
$a や $b の変数名は sort で使うために用意されているものなので、できる限り避けたほうがよいです。次のようなコードなら、致命的なエラーになって実行できません。
use strict;
do {
my $foo = <STDIN>;
chomp $foo;
print "$foo\n";
} while ($foo ne 'e');
お礼
1)ブロックの外で宣言することによりeで抜け出せるようになりました。 2)do-while文ではlastで抜けられない仕様だったんですね。 詳しい解説ありがとうござました。