A while back, the materials lab got some surplus instruments for materials testing. Interestingly, the data files produced have a mix of base 10, base 16 and base 2 numbers in Ada based numeric constant format:

10#86# 16#FA61# 2#10010110#

After they tried using LabView and Excel to covert the numbers, they came to us software engineers.

My (3/32 baked) solution was using a regular expression to parse out the base and number, then convert using hex and oct as appropriate.

While this worked fine for what was needed, some one asked "Why didn't you make a proper implementation?" My reply, of course, was "This serves our needs" and left it as is. For about a week. My thoughts kept drifting back to it, so I gave in and said "Challenge accepted."

So, I made the "proper implementation" per the Ada standard, including floating point conversion. There is a base converter in CPAN I might have used, but Horner's Method is simple and efficient - and almost habitual to use. I haven't tested whether using a hash or using index (with lc or uc) would be more efficient. I used a hash.

Looking at the CPAN listings, I think Language::Ada is the right namespace. (Though I noticed that C, for example, is top level, rather than Language::C)

`package Language::Ada::Const;
our $VERSION = 0.001;
our $BRIEF = 'Parse Ada based numeric literals';
=head1 SYNOPSIS
use Language::Ada::Const qw(AdaConst);
my $MagicNumber = AdaConst '7#61#e8';
# For convenience, the following is also supported
use Language::Ada::Const qw(AdaConst);
use constant AdaConst aMagicNumber => '3#12#';
# The following work, but produce warnings
use constant AdaConst qw(MoreMagic 5#42# Magical 13#AC#);
my @ArrayOfMagic = AdaConst qw(3#21# 14#D7# 5#43#e6);
=head1 DESCRIPTION
Process a list, converting items that look like Ada based numeric lite
+rals to
Perl numeric literals. Non-conforming items are passed through as-is.
In Ada, based numeric literals are the radix, in decimal, followed by
+a #. Then
the based digits, followed by another #. Then there is an optional exp
+onent, in
decimal. If the exponent is present, the converted value is multipled
+by the
base to the power of the exponent.
5#24#e3 == (2*5 + 4) * 5**3 == 1750
Ada based, numeric literals are described in:
https://www.adaic.org/resources/add_content/standards/05aarm/html/AA-2
+-4-2.html
=head1 CAVEATS
Per the standard, the base and exponent parts are in base 10.
Ada based numeric literals must be quoted or perl will parse them as c
+omments.
Note that in the standard, Ada based-literals are unsigned. As such, t
+his module
treats - as "unary -". Therefore, the literal is converted, then, if -
+ present,
the unary - operation is performed. For example, -16#C8# is interprete
+d as
-hex('C8').
=head1 FUNCTIONS
=cut
use 5.006;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT_OK = qw(AdaConst Horners);
my $acre = qr/(-?)([_0-9]+)#([_0-9a-fA-F.]+)#(?:[eE]([+-]?[_0-9]+))?/;
my %acmap = qw(0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12
+d 13 e 14 f 15 A 10 B 11 C 12 D 13 E 14 F 15);
sub _croak ($)
{
require Carp;
Carp::croak($_[0]);
}
## Convert list items that look like Ada based literals to decimal.
# Other items are returned as-is.
# See https://www.adaic.org/resources/add_content/standards/05aarm/ht
+ml/AA-2-4-2.html
# @note Only integer values of the mantissa are supported.
# @return In list context, list of items. Otherwise, first item.
# @param list
sub AdaConst
{
return unless defined wantarray;
my $v;
my @consts = map
{
$v = $_;
if (/$acre/)
{
$v = Horners($2, $3, $4);
$v = - $v if ((defined $1) and ($1 eq '-'));
}
$v;
} @_;
return @consts if (wantarray != 0);
$consts[0];
}
# Thought about Math::NumberBase, but needed different error handling
# and to handle '_' and '.'. Also, Horner's Algorithm is more eficient
+.
## Algorithm to convert $base number to decimal.
# @return Result of conversion.
# @note Only converts positive values.
sub Horners
{
my ($base, #< Radix of numeric literal
$in, #< Numeric literal
$exp #< (optional) Power of $base to multiply result
) = @_;
$base =~ s/_//g;
_croak "Base ($base) must be in range 2...16" if (($base < 2) || (
+$base > 16));
my $val = 0;
for (split //, $in)
{
next if ($_ eq '_');
if ($_ eq '.')
{
$val += Horners_Fraction($base, substr($in,index($in,'.')+
+1));
last;
}
$val *= $base;
my $d = $acmap{$_};
_croak "Invalid character in $in" if ((!defined $d) || ($d >=
+$base));
$val += $d;
}
if (defined $exp)
{
$exp =~ s/_//g;
$exp =~ s/^[eE]//;
$val *= $base ** $exp;
}
return $val;
}
## Algorithm to convert fraction part of $base number to decimal.
# Adapted from Horners, using division instead of multiplication.
# @return Result of conversion.
# @note Only converts positive values.
sub Horners_Fraction
{
my ($base, #< Radix of numeric literal
$in #< Numeric literal
) = @_;
my $val = 0;
while (my $c = chop $in)
{
next if ($c eq '_');
_croak "Extra radix point detected in $_[1]." if $c eq '.';
my $d = $acmap{$c};
_croak "Invalid character ($c) in $_[1]." if ((!defined $d) ||
+ ($d >= $base));
$val += $d;
$val /= $base;
}
return $val;
}
1;
=head1 AUTHOR
ronw, C<< <ronw at cpan.org> >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-ada-const at rt.cp
+an.org>, or through
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue
+=ada-const>. I will
be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Language::Ada::Const
You can also look for information at:
=over 4
=item * RT: CPAN's request tracker (report bugs here)
L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=ada-const>
=item * CPAN Ratings
L<https://cpanratings.perl.org/d/ada-const>
=item * Search CPAN
L<https://metacpan.org/release/ada-const>
=back
=head1 ACKNOWLEDGEMENTS
=head1 LICENSE AND COPYRIGHT
This software is Copyright (c) 2023 by ronw.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
`

Comment onParsing Ada Based ConstantsDownloadCode