in reply to Using C-style .h as constants
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
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Using C-style .h as constants
by gri6507 (Deacon) on Oct 26, 2011 at 20:29 UTC |