--- /dev/null
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp(my $data = <>);
+# Accept also a binary string instead of hexadecimal one:
+$data =~ s/./sprintf("%04b", hex $&)/ge if $data =~ /[2-9A-F]/;
+
+sub chop_bits {
+ my ($bits) = @_;
+ my $rv;
+ $data =~ s/.{$bits}/$rv = eval "0b$&"; ''/e;
+ # say "chop_bits($bits) = $rv";
+ return $rv;
+}
+
+my $ver_sum;
+my $result;
+
+sub parse {
+ $ver_sum += chop_bits(3);
+ my $type = chop_bits(3);
+
+ if ($type == 4) {
+ my $num = 0;
+ my $more;
+ do {
+ $more = chop_bits(1);
+ $num *= 16;
+ $num += chop_bits(4);
+ } while ($more);
+ $result .= "$num,";
+ } else {
+ $result .= "op$type(";
+ if (chop_bits(1)) {
+ my $subparts = chop_bits(11);
+ parse() for 1 .. $subparts;
+ } else {
+ my $sublen = chop_bits(15);
+ my $len = length $data;
+ parse() while $len - length($data) < $sublen;
+ }
+ $result .= "),";
+ }
+}
+
+use List::Util qw(sum product min max);
+
+sub op0 { sum @_; }
+sub op1 { product @_; }
+sub op2 { min @_; }
+sub op3 { max @_; }
+sub op5 { $_[0] > $_[1] ? 1 : 0 }
+sub op6 { $_[0] < $_[1] ? 1 : 0 }
+sub op7 { $_[0] == $_[1] ? 1 : 0 }
+
+parse();
+
+say "versions = $ver_sum";
+say $result, ' = ', eval $result;
+