Ria Ria - 1 month ago 9
Perl Question

error while extracting both value and type from lines

This question was asked by me earlier
how to find the lengh of the input in an array and match pattern in perl

Here my input is in decimal format later converting to hex


1.While extracting type I am getting compilation error


" Global symbol "$type" requires explicit package name at test15.pl line 65."
" Global symbol "$type" requires explicit package name at test15.pl line 66."



2.When I have checked the output of vals and type (by commenting last few

lines of the code from my $vals= to $packed)

I am getting both values and type as I have mentioned below


0x01,uint8
1440,Uint16
0xbb3,Uint16
ffffffbf,Sint8
0xa3,uint32



3.My regex not able to extract values from middle of lines


For e.g.
rrc_mac_interface RLC_PDU { 1} rrc_mac_interface #default type is uint8
gsm_lte_interface scell + ncell + gsm cell { 3} gsm_lte_interface #default type is uint8
reserved_for_data{3} { 0, 0, 0 } Uint8,unsigned char



my input lines:


trans_id 1 uint8,unsigned char
Pdu_size 5120 Uint16, unsigned short
sub_sfn 2995 Uint16, unsigned short
rrc_mac_interface RLC_PDU { 1} rrc_mac_interface #default type is uint8
gsm_lte_interface scell + ncell + gsm cell { 3} gsm_lte_interface
#default type is uint8
minvalue -65 Sint8,signed char
numtrx 163 uint32,unsigned short
reserved_for_data{3} { 0, 0, 0 } Uint8,unsigned char
my_st[1] 0 //do not match if the this line has []



code:


use strict;
use warnings;
use feature qw( say );
my $inputfile = 'input.txt';
my $outputfile = 'output.txt';
open my $my_ipfh, "<", $inputfile or die $!;
open my $my_opfh, ">", $outputfile or die $!;

my %packers = (
Uint8 => sub { pack 'C*', @_ },
Sint8 => sub { pack 'c*', @_ },
Uint16 => sub { pack 'S>*', @_ },
Sint16 => sub { pack 's>*', @_ },
Uint32 => sub { pack 'L>*', @_ },
Sint32 => sub { pack 'l>*', @_ },
);

my $packed = '';
while (<$my_ipfh>)
{
if (/([+-]?\d+)\s+ (uint8|sint8|Uint8|Sint8|uint16|sint16|Uint16|Sint16|uint32|sint32|Uint32|Uint32)/xg)
{
my ($vals, $type);
$vals =$1;
$vals =sprintf("0x%02x", $1);
$type =$2;
print "$vals,$type\n";
}
my @vals =
map { unpack 'l', pack 'l', hex $_ } # Convert to number and fix the sign
my $packer = $packers {$type}
or die("Unsupported type \"$type\"\n"); #error in this line
$packed .= $packer->(@vals);

say
join ',',
map { sprintf("0x%02X", $_) }
unpack 'C*',
$packed;
}



some mistakes I am doing which I am not able to catch if somebody can help me would be great ?

Answer

You asked a bunch of questions. I'll cover one.

While extracting type I am getting compilation error

my declares a lexical variable. It exists only for the block it's in.

if( ...whatever... ) {
    my $something = 42;
}

print $something;

This is different from, say, Javascript where var is scoped to the whole function no matter where you declare it.

$something does not exist outside that if block. When use strict is on, Perl does not allow you to use undeclared variables, so that print statement will produce an error at compile time.

Read more about scoping in Perl here.

This is why it's very important to get your indentation right. Being able to clearly and quickly see scopes is one of the most important things in programming. Your code is poorly spaced and indented. Here's how it should look.

my $int_type_re = qr{
    ( [+-]? \d+ )
    \s+
    ( [us]int(?:8|16|32) )
}xi;

my $packed = '';
while (<$my_ipfh>) {
    if ( $_ =~ m{$int_type_re}g; ) {
        my ($vals, $type);
        $vals =$1;
        $vals =sprintf("0x%02x", $1);
        $type =$2;
        print "$vals,$type\n";
    }
    my @vals =
      map { unpack 'l', pack 'l', hex $_ };

    my $packer = $packers {$type} 
      or die("Unsupported type \"$type\"\n");  #error in this line

    $packed .= $packer->(@vals);
}

With proper 4 character indentation and good use of blank lines, it's much clearer what's inside the while loop, what's inside the if and what's a multi-line statement.

I've also moved the complicated regex out of the condition and into its own variable. This both gives it a name to help understand what it's doing, and it makes the condition easier to read.

I made use of the /x regex modifier and newlines to space the regex out clearly. Then, with it pulled apart into smaller pieces, I saw I could collapse the repeated parts.