#!/usr/bin/perl
use 5.016;
use warnings;
sub factorial { $_[0] < 1 ? $_[1] : factorial($_[0] - 1, $_[1] * $_[0]) }
sub rest { [ @{$_[0]}[1 .. $#{$_[0]}] ] }
sub term {
my ($t, $args) = @_;
given($t->[0]){
when('log('){
my ($t, $x) = @_;
}->(expr(rest($t), $args));
}
when('sqrt('){
my ($t, $x) = @_;
}->(expr(rest($t), $args));
}
when(/[0-9]+/){
}
when(/[a-z]+/){
return (rest
($t), $args->{$t->[0]}); }
}
}
sub fact {
my ($t, $args) = @_;
my ($t, $x) = @_;
return (($t->[0] eq '!') ? (rest
($t), factorial
($x, 1)) : ($t, $x)); }->(term($t, $args));
}
sub pow {
my ($t, $args) = @_;
my ($t, $x) = @_;
($t->[0] eq '^') ?
sub{ $_[0], $x ** $_[1] }->(fact(rest($t), $args)) :
($t, $x)
);
}->(fact($t, $args));
}
sub expr {
my ($t, $args) = @_;
my ($t, $x) = @_;
($t->[0] eq '*') ?
sub{ $_[0], $x * $_[1] }->(pow(rest($t), $args)) :
($t, $x)
);
}->(pow($t, $args));
}
sub interpret {
my ($code, $args) = @_;
my $t = [ $code =~ m/\G\s*([0-9]+|[\!\)\^\*]|log\(|sqrt\(|[a-z]+)/g, '' ];
}
my @code = split(/\n/, <<'EOF'); 2^n
2^log(n)
4^n
n
n^2
n!
EOF
my $args = {n => 10};
say
map{ "$_->[0] = $_->[1]\n" } sort{ $b->[1] <=> $a->[1] } map{ [ $_ => interpret
($_, $args) ] } @code;
IyEvdXNyL2Jpbi9wZXJsCnVzZSA1LjAxNjsKdXNlIHdhcm5pbmdzOwoKc3ViIGZhY3RvcmlhbCB7ICRfWzBdIDwgMSA/ICRfWzFdIDogZmFjdG9yaWFsKCRfWzBdIC0gMSwgJF9bMV0gKiAkX1swXSkgfQoKc3ViIHJlc3QgeyBbIEB7JF9bMF19WzEgLi4gJCN7JF9bMF19XSBdIH0KCnN1YiB0ZXJtIHsKCW15ICgkdCwgJGFyZ3MpID0gQF87CgoJZ2l2ZW4oJHQtPlswXSl7CgkJd2hlbignbG9nKCcpewoJCQlyZXR1cm4gc3ViIHsKCQkJCW15ICgkdCwgJHgpID0gQF87CgkJCQkoJHQtPlswXSBlcSAnKScpIG9yIGRpZTsKCQkJCXJldHVybiAocmVzdCgkdCksIGxvZygkeCkpOwoJCQl9LT4oZXhwcihyZXN0KCR0KSwgJGFyZ3MpKTsKCQl9CgkJd2hlbignc3FydCgnKXsKCQkJcmV0dXJuIHN1YiB7CgkJCQlteSAoJHQsICR4KSA9IEBfOwoJCQkJKCR0LT5bMF0gZXEgJyknKSBvciBkaWU7CgkJCQlyZXR1cm4gKHJlc3QoJHQpLCBzcXJ0KCR4KSk7CgkJCX0tPihleHByKHJlc3QoJHQpLCAkYXJncykpOwoJCX0KCQl3aGVuKC9bMC05XSsvKXsKCQkJcmV0dXJuIChyZXN0KCR0KSwgJHQtPlswXSk7CgkJfQoJCXdoZW4oL1thLXpdKy8pewoJCQlyZXR1cm4gKHJlc3QoJHQpLCAkYXJncy0+eyR0LT5bMF19KTsKCQl9Cgl9CgoJZGllOwp9CgpzdWIgZmFjdCB7CglteSAoJHQsICRhcmdzKSA9IEBfOwoKCXJldHVybiBzdWJ7CgkJbXkgKCR0LCAkeCkgPSBAXzsKCQlyZXR1cm4gKCgkdC0+WzBdIGVxICchJykgPyAocmVzdCgkdCksIGZhY3RvcmlhbCgkeCwgMSkpIDogKCR0LCAkeCkpOwoJfS0+KHRlcm0oJHQsICRhcmdzKSk7Cn0KCnN1YiBwb3cgewoJbXkgKCR0LCAkYXJncykgPSBAXzsKCglyZXR1cm4gc3ViewoJCW15ICgkdCwgJHgpID0gQF87CgkJcmV0dXJuICgKCQkJKCR0LT5bMF0gZXEgJ14nKSA/CgkJCQlzdWJ7ICRfWzBdLCAkeCAqKiAkX1sxXSB9LT4oZmFjdChyZXN0KCR0KSwgJGFyZ3MpKSA6CgkJCQkoJHQsICR4KQoJCSk7Cgl9LT4oZmFjdCgkdCwgJGFyZ3MpKTsKfQoKc3ViIGV4cHIgewoJbXkgKCR0LCAkYXJncykgPSBAXzsKCglyZXR1cm4gc3ViewoJCW15ICgkdCwgJHgpID0gQF87CgkJcmV0dXJuICgKCQkJKCR0LT5bMF0gZXEgJyonKSA/CgkJCQlzdWJ7ICRfWzBdLCAkeCAqICRfWzFdIH0tPihwb3cocmVzdCgkdCksICRhcmdzKSkgOgoJCQkJKCR0LCAkeCkKCQkpOwoJfS0+KHBvdygkdCwgJGFyZ3MpKTsKfQoKc3ViIGludGVycHJldCB7CglteSAoJGNvZGUsICRhcmdzKSA9IEBfOwoKCW15ICR0ID0gWyAkY29kZSA9fiBtL1xHXHMqKFswLTldK3xbXCFcKVxeXCpdfGxvZ1wofHNxcnRcKHxbYS16XSspL2csICcnIF07CgoJcmV0dXJuIChleHByKCR0LCAkYXJncykpWzFdOwp9CgoKbXkgQGNvZGUgPSBzcGxpdCgvXG4vLCA8PCdFT0YnKTsKMl5uCjJebG9nKG4pCjRebgpuCm5eMgpuIQpuKmxvZyhuKQpsb2cobiEpCmxvZyhsb2cobikpCnNxcnQobG9nKG4pKQpFT0YKCm15ICRhcmdzID0ge24gPT4gMTB9OwoKc2F5IG1hcHsgIiRfLT5bMF0gPSAkXy0+WzFdXG4iIH0KCXNvcnR7ICRiLT5bMV0gPD0+ICRhLT5bMV0gfQoJbWFweyBbICRfID0+IGludGVycHJldCgkXywgJGFyZ3MpIF0gfSBAY29kZTsK