Perl script to grep for always block and print the specified lines - perl

I need to fetch the files , read line by line and search for always_ff block.
If always_ff is present, then i need to print the specific lines from inside the found always_ff block
use strict;
use warnings;
for my $file ('*.sv')
{
open my $fh, "<", $file or die $!;
while (<$fh>) {
print scalar <$fh> if /begin/;
}
}
The file has :
always_ff #(negedge clk )
begin
if (!clk)
begin
p1 <= 1'b0;
end
else
begin
p1 <= disable_ff;
end
end
always_ff #(negedge clk)
begin
if (!clk)
begin
p2<= enable;
end
else
begin
p2 <= disable_ff;
end
end
Expected result:
p1 <= disable_ff
p2<= enable
p2 <= disable_ff;
Actual result coming :
if (!clk)
p1 <= disable_ff;

You should probably use the range operator with patterns that match the start and the end of the section. Looking at your input data I would suggest:
start: match "always_ff" plus white space, i.e. /always_ff\s+/
end: empty line, i.e. /^\s*$/
in the block: print lines with assignment, i.e. /<=/
Quote from perlop:
In scalar context, .. returns a boolean value. The operator is bistable, like a flip-flop, ... It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true, AFTER which the range operator becomes false again.
Something like this
#!/usr/bin/perl
use warnings;
use strict;
while (<DATA>) {
if (/always_ff\s+/../^\s*$/) {
print if /<=/;
}
}
exit 0;
__DATA__
always_ff #(negedge clk )
begin
if (!clk)
begin
p1 <= 1'b0;
end
else
begin
p1 <= disable_ff;
end
end
always_ff #(negedge clk)
begin
if (!clk)
begin
p2<= enable;
end
else
begin
p2 <= disable_ff;
end
end
Test output:
$ perl dummy.pl
p1 <= 1'b0;
p1 <= disable_ff;
p2<= enable;
p2 <= disable_ff;
For your use case of reading *.sv files replace <DATA> from my test code with <STDIN> and use the following shell command line:
$ cat *.sv | perl script.pl

Related

Global Match Anchors \G: rolling lover over an input file

See:
https://www.oreilly.com/library/view/mastering-perl/9780596527242/ch02.html
I'm having some trouble getting the perl Global Match Anchors \G to work with my input file proved below with my perl code... I would have thought \G keeps picking up where it left off in the previous match and matches from that position in the string?
note, if i uncomment these two line it works:
#!/bin/perl
$vlog = "out/tb_asc.sv";
open(my $F, "$vlog") || die("cannot open file: $vlog\n");
#lines = <$F>;
chomp(#lines);
$bigline = join("\n", #lines);
close($F);
$movingline = $bigline;
print ">> << START\n";
$moving = $bigline;
$moving =~ s|//.*$||mg;
$moving =~ s|\s+$||mg;
while(1) {
# Blank Linke
if ($moving =~ /\G\n/g) {
#$moving = substr $moving, $+[0]+1; # <= doesn't \G anchor imply this line?
next;
}
# Precompiler Line
if ($moving =~ /\G\s*`(\w+)(\s+(.*))?\n/g) {
$vpccmd = $1;
$vpcarg1 = $3;
#$moving = substr $moving, $+[0]+1;
print "vpc_cmd($vpccmd) vpc_arg1($vpcarg1)\n";
next;
}
$c = nextline($moving);
print "\n=> processing:[$c]\n";
die("parse error\n");
}
sub nextline($) {
#c = split(/\n/, $moving);
$c = $c[0];
chomp($c);
return $c;
}
sample input file: out/tb_asc.sv
`timescale 1ns / 1ps
`define DES tb_asc.DES.HS86.CORE
`ifdef HS97_MODE
`define SER_DUT HS97
`ifndef HS78_MODE
`define SER_DUT HS78
`else //1:HS78_MODE
`define SER_DUT HS89
`define SER tb_asc.SER.`SER_DUT.CORE
`ifdef MULTIPLE_SERS
`define SER_1 tb_asc.SER_1.`SER_DUT.CORE
`define SER_2 tb_asc.SER_2.`SER_DUT.CORE
`define SER_3 tb_asc.SER_3.`SER_DUT.CORE
`else //1:MULTIPLE_SERS
`define SER_1 tb_asc.SER.`SER_DUT.CORE
`define SER_2 tb_asc.SER.`SER_DUT.CORE
`define SER_3 tb_asc.SER.`SER_DUT.CORE
`define REPCAPCAL DIGITAL_TOP.RLMS_A.REPCAL.U_REPCAPCAL_CTRL
`define MPU_D POWER_MGR.Ism.por_pwdnb_release
`define DFE_OUT RXD.EC.Eslicer.QP
`define DFE_OUT_SER RXD.EC.Eslicer.QP
//beg-include-1 ser_reg_defs_macros.sv
//FILE: /design/proj/hs89/users/HS89D-0A/digital/modules/cc/src/ser_reg_defs_macros.sv
`define CFG_BLOCK "CFG_BLOCK"
`define DEV_ADDR "DEV_ADDR"
`define RX_RATE "RX_RATE"
`define TX_RATE "TX_RATE"
`define DIS_REM_CC "DIS_REM_CC"
`define DIS_LOCAL_CC "DIS_LOCAL_CC"
NOTE: this version works but doesn't use \G:
while(1) {
# Blank Linke
if ($moving =~ /\A$/m) {
$moving = substr $moving, $+[0]+1;
next;
}
# Precompiler Line
if ($moving =~ /\A\s*`/) {
$moving =~ /\A\s*`(\w+)(\s+(.*))?$/m;
$vpccmd = $1;
$vpcarg1 = $3;
$moving = substr $moving, $+[0]+1;
print "vpc_cmd($vpccmd) vpc_arg1($vpcarg1)\n";
next;
}
$c = nextline($moving);
print "\n=> processing:[$c]\n";
die("parse error\n");
}
I prefer to do this using \G because substr uses a lot of CPU time with a large input file.
The bit you're missing is that is that an unsuccessful match resets the position.
$ perl -Mv5.14 -e'$_ = "abc"; /./g; /x/g; say $& if /./g;'
a
Unless you also use /c, that is.
$ perl -Mv5.14 -e'$_ = "abc"; /./gc; /x/gc; say $& if /./gc;'
b
When your match fails, In the link to Mastering Perl that you provide, I wrote:
I have a way to get around Perl resetting the match position. If I want to try a match without resetting the starting point even if it fails, I can add the /c flag, which simply means to not reset the match position on a failed match. I can try something without suffering a penalty. If that doesn’t work, I can try something else at the same match position. This feature is a poor man’s lexer.
My example that I think you are trying to use has /gc on all the matches using \G.

perl - Trying to use a while loop to ask the user if they want to do that again

(New to perl)
I have a small perl program that calculates factorials. I'd like to use a while loop so that after the user gets a result, they will be asked "Calculate another factorial? Y/N" and have Y run the code again & have N end the program.
Here's my code:
print"Welcome! Would you like to calculate a factorial? Y/N\n";
$decision = <STDIN>;
while $decision == "Y";
{
print"Enter a positive # more than 0: \n";
$num = <STDIN>;
$fact = 1;
while($num>1)
{
$fact = $fact * $num;
$num $num - 1;
}
print $fact\n;
print"Calculate another factorial? Y/N\n";
$decision = <STDIN>;
}
system("pause");
What's giving me trouble is where to put the while loop and how to make the Y/N option work. I'm also unclear about system("pause") and sleep functions. I do know that system("pause") makes my programs work though.
Your program is almost right, just a few issues:
Please get used to always add use strict; and use warnings; to your scripts. They will
(beyond other things) force you to declare all the variables you use (with my $num=…;)
and warn you about common errors (like typos). Some people consider it a bug that
use strict; and use warnings; aren't turned on by default.
When reading a line from STDIN (or some other filehandle) the read line will contain the
trailing newline character "\n". For your comparison to work you must get rid of that using
the chomp function.
There are two different sets of comparison operators in Perl: one for strings and one for numbers.
Numbers are compared with <, >, <=, >=, ==, and !=. For strings you must use
lt (less-than), gt, le (less-or-equal), ge, eq, and ne. If you use one of the number
operators on strings Perl will try to interpret your string as a number, so $decision == "Y"
would check whether $decision is 0. If you had use warnings; Perl would have noticed you.
Use $decision eq "Y" instead.
The outer while loop had a trailing ; just after the comparison which will give you an endless
loop or a no-op (depending on the content of $decision).
You forgot the = in $num = $num - 1;.
You forgot the quotes " around print "$fact\n";
system("pause") only works on Windows where pause is an external command. On Linux (where
I just tested) there is no such command and system("pause") fails with command not found.
I replaced it with sleep(5); which simply waits 5 seconds.
.
#!/usr/bin/env perl
use strict;
use warnings;
print "Welcome! Would you like to calculate a factorial? Y/N\n";
my $decision = <STDIN>;
chomp($decision); # remove trailing "\n" from $decision
while ( $decision eq 'Y' ) {
print "Enter a positive # more than 0: \n";
my $num = <STDIN>;
chomp($num);
my $fact = 1;
while ( $num > 1 ) {
$fact = $fact * $num;
$num = $num - 1;
}
print "$fact\n";
print "Calculate another factorial? Y/N\n";
$decision = <STDIN>;
chomp($decision);
}
print "ok.\n";
sleep(5); # wait 5 seconds
Always add use warnings and use strict to the beginning of your program.
There are a number of typos in your code that would have been caught by this.
#!/usr/bin/perl
use warnings;
use strict;
print "Welcome! Would you like to calculate a factorial? Enter 'Y' or 'N': ";
my $answer = <STDIN>;
chomp($answer);
while($answer =~ /^[Yy]$/){
my $fact = 1;
print"Enter a positive number greater than 0: ";
my $num = <STDIN>;
chomp($num);
my $number_for_printing = $num;
while($num > 0){
$fact = $fact * $num;
$num--;
}
print "The factorial of $number_for_printing is: $fact\n";
print"Calculate another factorial? Enter 'Y' or 'N': ";
$answer = <STDIN>;
chomp($answer);
}
print "Goodbye!\n";

How to get the max value from an array in Perl?

I have an input source as follows. What I want to do is capture the numeric value on each of the Layer lines into an array and then print out the maximum value.
input
MACRO cell_1
size 0.1 by 0.1 ;
pin a
(....same topology as pin vcc)
END a
pin b
(.....same topology as pin vcc)
END b
Pin vcc
aaaa
bbbb
Port
Layer m2 ;
END
CCC
DDD
Port
Layer m1 ;
END
EEE
FFF
Port
Layer m0 ;
END
END vcc
pin d
(....same topology as pin vcc)
END d
END cell_1
MACRO cell_2
(repeated)
END cell_2
my code:
foreach my $file ( #files ) { # #files = multiple path of abc/def/fgh/cell_lef
open( INFILE, "<$file" ) || die "Can not open stdcell_file\n";
my #lines = <INFILE>;
close INFILE;
$init = 1;
$delimiter =~ /^$/; # between each MACRO. haven't utilize this yet
foreach (#lines) {
if ( $init ) {
$path = 1;
$init = 0;
#num = ();
}
if ( $path ) {
if ( /MACRO\s+(\S+) /) {
$cellname = $1; print "$cellname\n";
}
if ( /SIZE\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
$footprint_x = $1;
$footprint_y = $3;
print "$footprint_x $footprint_y\n";
}
if ( /PIN vcc/ .. /END vcc/ ) {
#grab the highest value from layer (m*)
#print "max layer = m*"
}
$init = 1;
}
}
}
intended output
cell_1
0.1 0.1
m2
cell_2
0.2 0.2
m3
The code I am attempting to use:
if ( /PIN vcc/../END vcc/ ) {
if ( /LAYER\s+m(\S+) / ) {
push(#num, $1);
print "#num";
}
}
The problem with my code so far is that when I print the value of #num, all the values are joined together as a string (210) instead of individual elements: 2 1 0 — so I am not able to do the sorting to get the max value.
Update: I am not sure how to integrate the while into my code as I'm using foreach as my main loop
Your code is capturing the numbers ok, it's just that you're printing the whole array. Perl's default separator for array elements when you print an array is "" ie, nothing - so, it looks like a single string but it's three (or however many) elements printed next to each other without a separator.
You can iterate over input line by line in Unix filter style with while (<>) {. You can switch on a "scanning mode" flag when "PIN vcc" is found and switch it off when "END vcc" is found. After that, use a regex to search for the layer line but always use 'extended mode' /x so you can use whitespace in your regex.
As the regex's for switching modes and capturing the layer number are mutually exclusive, you can let the other checks happen after a check succeeds - just be aware that if future changes result in overlapping cases, you need to do a next when one of the regex succeeds.
Finally, List::Util is a core module so, you might as well grab the max function from it;
use v5.12;
use warnings;
use List::Util qw( max );
my #num ;
my $scanning = 0;
while (<>) {
$scanning = 1 if /PIN vcc/ ;
$scanning = 0 if /END vcc/ ;
next unless $scanning ;
push #num, $1 if /Layer \s+ m (\d+) /x ;
}
say "Max layer number found: ", max(#num) ;
Or simply use sort function for to do it.
my #values ;
while (<DATA>)
{
push (#values , $1) if (/Layer\s+m(\d+)\s;/);
}
my ($max) = sort{$b <=> $a} #values ;
print "$max\n";
__DATA__
Pin vcc
aaaa
bbbb
Port
Layer m3 ;
END
CCC
DDD
Port
Layer m1 ;
END
EEE
FFF
Port
Layer m0 ;
END
use sort function and store the first result into list contain the variable $max.
my #data = <DATA> ;
my #num ;
foreach (#data) {
push #num, $1 if /Layer\s+m(\S+)/ ;
}
# home made max() - sorts an anonymous array and prints the last element
print [ sort { $a <=> $b } #num ]->[-1] , "\n" ;
__DATA__
Pin vcc
aaaa
bbbb
Port
Layer m2 ;
END
CCC
DDD
Port
Layer m1 ;
END
EEE
FFF
Port
Layer m0 ;
END
END vcc
Using map to fetch numbers from file. sort the number and get maximum number.
#!/usr/bin/perl
use strict;
use warnings;
my $max = (sort{$b <=> $a }map{/Layer\s+m(\d+)/} <DATA>)[0];
print $max,"\n";
__DATA__
Pin vcc
aaaa
bbbb
Port
Layer m3 ;
END
CCC
DDD
Port
Layer m1 ;
END
EEE
FFF
Port
Layer m0 ;
END
First, you don't need to store all values if you're looking only for max value; and second, print the max value after the loop is over,
my $max = "-inf";
if (/PIN vcc/ .. /END vcc/) {
$max = $1 if /LAYER\s+m(\S+)/ and $max < $1;
}
# ..
print $max, "\n";

perl while loop iterates through a variable.

This little snippet is from the first chapter of the LWP perl oreilly book.
This line
$count++ while $catalog =~ m/Perl/gi;
perplexes me
I do not understand how the while statement iterates through the lines in the $catalog variable to find the matched, I don't even know how to explain what that line does in english much less perl
#!/usr/bin/perl -w
use strict ;
use LWP::Simple ;
my $catalog = get("http://www.oreilly.com/catalog");
my $count = 0;
$count++ while $catalog =~ m/Perl/gi;
print "$count\n";
so I have tried writing it out long hand to no avail.
#!/usr/bin/perl -w
use strict ;
use LWP::Simple ;
my $catalog = get("http://www.oreilly.com/catalog");
open( my $fh_catalog ,"<" , $catalog) || die "cant open $!";
while (<$fh_catalog>) {
print $_ ;
sleep 1;
}
I even tried
#!/usr/bin/perl -w
use strict ;
use LWP::Simple ;
my $catalog = get("http://www.oreilly.com/catalog");
while (<$catalog>) {
print $_ ;
sleep 1;
}
$catalog contains the string <!DOCTYPE HTML PUB[...][newline][newline]<html>[...].
Your first snippet fails because $catalog doesn't contain a file name.
Your second snippet fails because $catalog doesn't contain a file handle.
When a match operator with the /g modifier is used scalar context, it searches from where the last search left off.
The analog would be
use Time::HiRes qw( sleep ); # Support sleeping fractions of seconds.
$| = 1; # Turn off STDOUT's output buffering.
for my $i (0..length($content)-1) {
print(substr($content, $i, 1));
sleep 0.1;
}
Let's use a simpler string as an example.
my $s = "a000a000a000";
++$count while $s =~ /a/g;
Here's what happens:
The match operator is executed. It finds the first a, sets pos($s) = 1;, and returns true.
The loop body is entered, and $count is incremented.
The match operator is executed. It behaves as if the string started as pos($s) (1), finds the second a, sets pos($s) = 5;, and returns true.
The loop body is entered, and $count is incremented.
The match operator is executed. It behaves as if the string started as pos($s) (5), finds the third a, sets pos($s) = 9;, and returns true.
The loop body is entered, and $count is incremented.
The match operator is executed. It behaves as if the string started as pos($s) (9), fails to find a match, clears pos($s), and returns false. The loops exits.
Nothing changes if some of the characters of the string are newlines.

Perl uninitialized warnings

I've got my program keymap (it is not yet actually mapping any keys yet and is currently only printing out what it sees in hex) here:
#!/usr/bin/env perl
use strict;
use warnings;
use Term::ReadKey;
ReadMode 4;
END {
ReadMode 0; # Reset tty mode before exiting
}
if ($ARGV[0] ~~ ["h", "-h", "--help", "help"]) {
print "Usage: (h|-h|--help|help)|(code_in codes_out [code_in codes_out]+)\nNote: output codes can be arbitrary length";
exit;
}
$#ARGV % 2 or die "Even number of args required.\n";
$#ARGV >= 0 or warn "No args provided. Output should be identical to input.\n";
my $interactive = -t STDIN;
my %mapping = #ARGV;
{
local $| = 1;
my $key;
while (ord(($key = ReadKey(0))) != 0) {
printf("saw \\x%02X\n",ord($key));
if ($interactive and ord($key) == 4) {
last;
}
}
}
Here's what happens:
slu#new-host:~/util 20:50:20
❯ keymap a b
saw \x61
saw \x62
saw \x04
There I had typed on my keyboard abCtrl+D.
slu#new-host:~/util 20:50:24
❯ echo "^D^Da" | keymap
No args provided. Output should be identical to input.
saw \x04
saw \x04
saw \x61
saw \x0A
Use of uninitialized value $key in ord at /Users/slu/util/keymap line 30.
I'm wondering what the meaning of this is. Is it simply a case of Perl "not counting" the loop condition as "setting" $key? Is there some sort of thing I can do to suppress the warning here? I know about no warnings "uninitialized";, I don't want that.
There's a known bug that warnings issued by the condition expression of a while loop can be misattributed to the statement in the loop evaluated just before the while condition.
The code issuing the warning is actually the condition of the while loop, ord(($key = ReadKey(0))) != 0.
ReadKey(0) is returning undef, and you are trying to get the ord or it.
while (1) {
my $key = ReadKey(0);
last if !defined($key) || ord($key) == 0;
printf("saw \\x%02X\n",ord($key));
last if $interactive and ord($key) == 4;
}