Perl5 の適当な手書きパーザで、簡単な数式をパースしてみる
パーザジェネレータを使うのは情弱だ、そんな風なことをいう kazuho さんもいる今日このごろなので、手書きでパーズしてみようとおもってみました。
Perl5 で適当にパースしたい場合は、こんな風に書くのが楽なのではないでしょうか。もっとスマートに書く方法もあるかもしらんですが。
my $src = "11*3+2/2";
use Data::Dumper;
say Dumper(parse($src));
exit;
sub parse {
my $src = shift;
my ($rest, $ret) = expression($src);
if ($rest) {
die "Parse failed: $rest";
}
$ret;
}
sub expression {
my $src = $_[0];
{
my $c = $src;
($c, my $lhs) = term($c) or goto n1;
($c) = match($c, '+') or goto n1;
($c, my $rhs) = expression($c) or goto n1;
return ($c, [$lhs, '+', $rhs]);
}
n1:
{
my $c = $src;
($c, my $lhs) = term($c) or goto n2;
($c) = match($c, '-') or goto n2;
($c, my $rhs) = expression($c) or goto n2;
return ($c, [$lhs, '-', $rhs]);
}
n2:
{
my $c = $src;
($c, my $ret) = term($c) or goto err;
return ($c, $ret);
}
err:
die "Parse Error";
}
sub term {
my $src = shift;
{
my $c = $src;
($c, my $lhs) = primary($c) or goto n1;
($c) = match($c, '*') or goto n1;
($c, my $rhs) = term($c) or goto n1;
return ($c, [$lhs, '*', $rhs]);
}
n1:
{
my $c = $src;
($c, my $lhs) = primary($c) or goto n2;
($c) = match($c, '/') or goto n2;
($c, my $rhs) = term($c) or goto n2;
return ($c, [$lhs, '/', $rhs]);
}
n2:
{
my $c = $src;
($c, my $ret) = primary($c) or goto err;
return ($c, $ret);
}
err:
die "Parse failed";
}
sub match {
my ($c, $word) = @_;
$word = quotemeta($word);
$c =~ s/^\s*//;
$c =~ s/^$word//
or return ();
warn "O";
return ($c);
}
sub primary {
local $_ = shift;
s/^([1-9][0-9]*)//;
($_, $1);
}
【追記】
このコードは - とかが左結合になってなくてダメです。
Published: 2012-04-13(Fri) 01:56