Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Parsing Ada Based Constants

by RonW (Parson)
on May 06, 2024 at 11:27 UTC ( [id://11159301]=CUFP: print w/replies, xml ) Need Help??

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: +-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 +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> >> =head1 BUGS Please report any bugs or feature requests to C<bug-ada-const at rt.cp>, or through the web interface at L< +=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<> =item * CPAN Ratings L<> =item * Search CPAN L<> =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)

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://11159301]
Approved by marto
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-06-16 21:22 GMT
Find Nodes?
    Voting Booth?

    No recent polls found

    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.