Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

comment on

( [id://3333]=superdoc: 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)

In reply to Parsing Ada Based Constants by RonW

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-06-16 22:37 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.