sub dec2bin { sprintf "%04b", shift }
sub bin2dec { oct "0b".shift }
sub bin2bits { reverse split(//, substr(shift,0,shift)); }
sub bits2bin { join "", map { 0+$_ } reverse @_ }

sub bxor {
  my($a, $b) = @_;
  (!$a & $b) | ($a & !$b);
}

sub half_adder {
  my($a, $b) = @_;
  ( bxor($a,$b), $a & $b );
}

sub full_adder {
  my($a, $b, $c) = @_;
  my($s1, $c1) = half_adder($a, $c);
  my($s2, $c2) = half_adder($s1, $b);
  ($s2, $c1 | $c2);
}

sub four_bit_adder {
  my($a, $b) = @_;
  my @abits = bin2bits($a,4);
  my @bbits = bin2bits($b,4);

  my($s0,$c0) = full_adder($abits[0], $bbits[0], 0);
  my($s1,$c1) = full_adder($abits[1], $bbits[1], $c0);
  my($s2,$c2) = full_adder($abits[2], $bbits[2], $c1);
  my($s3,$c3) = full_adder($abits[3], $bbits[3], $c2);
  (bits2bin($s0, $s1, $s2, $s3), $c3);
}

print " A    B      A      B   C    S  sum\n";
for my $a (0 .. 15) {
  for my $b (0 .. 15) {
    my($abin, $bbin) = map { dec2bin($_) } $a,$b;
    my($s,$c) = four_bit_adder( $abin, $bbin );
    printf "%2d +%2d =%s +%s =%s%s =%2d\n",
           $a, $b, $abin, $bbin, $c, $s, bin2dec($c.$s);
  }
}