Perl's declared constants (using "use constant") are implemented as subroutines. Although it is entirely possible to do what you're asking (and I'll show you how in a minute) generating Perl constants (subroutines) means that you run the risk of your enums clashing with subs already in the program as you pull every enum in from some header file. It might be less offensive to pull all of the enum members into a single hash, and make the hash itself immutable. I'll show you the hash technique first.

There is a really useful module on CPAN called Convert::Binary::C. Its name doesn't seem to really convey the breadth of its utility. Combine that with Hash::Util's lock_hash() function, and you can have a constant hash built out of your enumerations.

Here's an example of how that could work:

A sample header file:

/* mytest.h */ enum { a = 10, b, c, d, efg, hijk }; /* unnamed */ enum Temperature { temp_low, temp_medium, temp_high }; enum Othertest { frank, john, kurt, jason };

A Perl program to parse that file

#!/usr/bin/env perl use strict; use warnings; use v5.12; use Convert::Binary::C; use Hash::Util qw/lock_hash/; my %C_ENUMS; { my $c = Convert::Binary::C->new->parse_file( 'mytest.h' ); %C_ENUMS = map %{ $_->{enumerators} || {} }, $c->enum; lock_hash( %C_ENUMS ); } say "'efg' is $C_ENUMS{efg}"; say "'kurt' is $C_ENUMS{kurt}"; eval{ $C_ENUMS{kurt} = 15; }; print $@ if $@; say "'kurt' is $C_ENUMS{kurt}";

The output:

'efg' is 14 'kurt' is 2 Modification of a read-only value attempted at mytest.pl line 22. 'kurt' is 2

This is a pretty simple example where all enum fields are just dumped into a single hash. If you need to keep track of the enum names, for example, Temperature and Othertest the Convert::Binary::C module has methods for that too, and you could build a hash of multiple dimensions that way.

Also, by going with the hash approach your "constants" can still interpolate easily into quoted strings.

Update:

As Perl use constants:

I mentioned before I would show how to turn your enums into Perl constants. If you really want to risk subroutine name collisions you can do exactly what you're asking for by using the same Convert::Binary::C module like this:

use strict; use warnings; use v5.12; BEGIN{ use Convert::Binary::C; my $c = Convert::Binary::C->new->parse_file( 'mytest.h' ); my %c_enums = map %{ $_->{enumerators} || {} }, $c->enum; eval "use constant $_ => $c_enums{$_};" for keys %c_enums; } say "efg => ", efg; say "kurt => ", kurt;

The output will be:

efg => 14 kurt => 2

Fun stuff!


Dave


In reply to Re: Using C-style .h as constants by davido
in thread Using C-style .h as constants by gri6507

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



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.