http://qs1969.pair.com?node_id=1168641

rkabhi has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perl Monks !!

I came across a really unexpected issue while developing a code to read a netlist file containing just few lines. I have written down system details, the code and input file and finally I describe the problem at the end

System and Setup Info: Linux RHEL6 Perl Version 5.10.1

***************************************************

Code:

#!/usr/bin/perl use strict; use warnings; use Switch; #Common Variable Initialization my %DeviceList = (); my $netlist_file = "/home/abhishek_r/Tool_Development/Voltrace/Perl/ne +tlist.scs"; my @InbuiltDeviceList = ('resistor','capacitor','inductor','vsource',' +isource'); my @subcktslist = getSubcktList($netlist_file); print @subcktslist; TraceSubcktDevices($netlist_file); sub getSubcktList{ my $netlist = $_[0]; my @subckts = (); open(READ_NETLIST, "<$netlist") or die "Couldn't open netlist file + for read, $!"; while(<READ_NETLIST>){ chomp; s/^\s+//; #To remove leading blanks (if any) in the line #ignore line if it contains comments or initializing words for + spectre switch() { case /^[*\/]/i {next;} case /simulator\s+lang/i {next;} case /^include/i {next;} } if(/subckt/i) { my $line = $_; my @words = split(/\s+/,$line); #Split the read line in $_ + with white spaces as delimiter my $nameindex = 1; #Default index where subckt name i +s usally found if(/inline/i){ #To change name index if subckt de +finition includes inline $nameindex = 2; } push @subckts,$words[$nameindex]; } } close(READ_NETLIST); return @subckts; } sub TraceSubcktDevices{ #Input: (netlist_file, subcktname, key +_init) where subcktname is the name of subckt that needs to be traced + in the netlist my $netlist = $_[0]; my $subcktname = "hello"; $subcktname =~ s/^\s*|\s*$//g; #To remove all leading and trainin +g blanks from input subckt name my $key_init = $_[2]; my $skip=0; #Default Skip status for netlist l +ine. 0 indicates "don't skip" and is set for TOPLEVEL if($subcktname){ #Set skip flag if input subckt name is not + blank i.e. the tracing is not required at TOPLEVEL $skip = 1; } open(READ_NETLIST, "<$netlist") or die "Couldn't open netlist file + for read, $!"; while(<READ_NETLIST>){ $skip = $skip + 1; print "Hello"; } close(READ_NETLIST); }

Input File: netlist.scs

// Generated for: spectre // Generated on: Jul 26 15:10:24 2016 // Design library name: custom // Design cell name: TOPLEVEL // Design view name: schematic simulator lang=spectre global 0 //--------------------------------// // Library name: custom // Cell name: inv // View name: schematic subckt inv IN OUT VDD VSS M0 (OUT IN VSS VSS) nch l=60n w=200n m=1 nf=1 sd=200n ad=3.5e-14 \ as=3.5e-14 pd=750n ps=750n nrd=0.5 nrs=0.5 sa=175n sb=175n sca +=0 \ scb=0 scc=0 M2 (OUT IN VDD VDD) pch l=60n w=200n m=1 nf=1 sd=200n ad=3.5e-14 \ as=3.5e-14 pd=750n ps=750n nrd=0.5 nrs=0.5 sa=175n sb=175n sca +=0 \ scb=0 scc=0 ends inv // End of subcircuit definition. // Library name: custom // Cell name: BUF_DELAY // View name: schematic subckt BUF_DELAY IN OUT VDD VSS I1 (net11 OUT VDD VSS) inv I0 (IN net11 VDD VSS) inv ends BUF_DELAY // End of subcircuit definition. // Library name: custom // Cell name: INV_DELAY // View name: schematic subckt INV_DELAY IN OUT VDD VSS I2 (net08 OUT VDD VSS) inv I1 (net11 net08 VDD VSS) inv I0 (IN net11 VDD VSS) inv ends INV_DELAY // End of subcircuit definition. // Library name: custom // Cell name: TOPLEVEL // View name: schematic I2 (BUF_IN BUF_OUT VDD VSS) BUF_DELAY I3 (INV_IN INV_OUT VDD VSS) INV_DELAY I4 (INV_IN net8) isource type=pwl wave=[ 1u 1 2u 2 ] V3 (VSS 0) vsource dc=0 type=dc V2 (INV_IN 0) vsource dc=0 type=dc V1 (BUF_IN 0) vsource dc=5 type=dc V0 (VDD 0) vsource dc=5 type=dc R0 (net8 VSS) rm1w l=10u w=2u mf=1 C0 (net8 0) capacitor c=1p //----------------- Entering Netlist Footer -------------------//

The Problem: In the code, there are two subroutines getSubcktList() and TraceSubcktDevices(). The former subroutine works fine. The latter subroutine (i.e. TraceSubcktDevices()) is showing a very unexpected behavior. I have listed my observations below:

1) If the above code is run "as is" making sure that correct path of netlist.scs file is supplied at the beginning, the code gets stuck (I use Linux command line to run the code) with no response

2) If I swap the subroutines, i.e. define TraceSubcktDevices() first and getSubcktList(), the code works fine printing "Hello" as many times as the number of lines in input file netlist.scs

Can anyone please let me know why this is unexpected behavior being observed?

Thanks !!

Abhishek

update: edited/code tags by stevieb

Replies are listed 'Best First'.
Re: Perl Code Changes Behavior if Two Subroutine definitions are swapped
by Athanasius (Archbishop) on Jul 27, 2016 at 16:05 UTC

    Hello rkabhi,

    As haukex says, the Switch module is deprecated and therefore best avoided. But the problem here is not with the module, but rather with the way it is being used.

    First, by giving the switch statement an empty argument, you are matching against the empty string:

    use strict; use warnings; use Switch; for ('abc', 'def', 'ghi') { switch () { case /bc/ { print "$_: matches 'bc'\n"; } case /de/ { print "$_: matches 'de'\n"; } case '' { print "EMPTY STRING\n"; } else { print "$_: no match found\n"; } } }

    Output:

    1:51 >perl 1675_SoPW.pl EMPTY STRING EMPTY STRING EMPTY STRING 1:51 >

    You need to specify the string to be matched against: in this case, switch ($_) {.

    Second, the next statements in your case clauses do not force another iteration of the enclosing while loop, as you expect. That’s because the Switch module uses next to implement fall-through, as explained in the “Allowing fall-through” section of the Switch documentation. You could avoid this by specifying an explicit target for the next statements; for example (untested):

    MAIN_LOOP: while (<READ_NETLIST>) { chomp; s/^\s+//; # Remove leading blanks (if any) in the line # ignore line if it contains comments or initializing words for sp +ectre switch ($_) { case /^[*\/]/i { next MAIN_LOOP; } case /simulator\s+lang/i { next MAIN_LOOP; } case /^include/i { next MAIN_LOOP; } } ... }

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Hi Athanasius,

      Thanks for your response.

      Regarding the empty string. I tried running your example code using perl 5.10.1 and got following output:

      OUTPUT WITH EXAMPLE CODE:
      abc: matches 'bc' def: matches 'de' ghi: no match found

      So, somehow we get different outputs. Not sure why. Since in my case it tries to match with $_ when nothing is specified in switch(), I could not identify any issue with such use of switch and therefore I continued using it.

      Thanks for mentioning things to take care as best practice about using empty arguments and next statements. I will try your suggestions and get back if the main issue persists. For now I am not going to use switch as it is not necessary for my code.

      Best Regards,
      Abhishek
        I tried running your example code using perl 5.10.1 and got following output...

        Interesting. Experimenting with the Strawberry Perl versions I have on my system, it appears the change occurred between Perl 5.12.3 and 5.14.4. Running with -MO=Deparse reveals only one difference:

        &Switch::switch(); # v5.12.3 vs. &Switch::switch(()); # v5.14.4

        And calling switch explicitly with an empty list — switch(()) — under 5.12.3 gives the same result as calling switch() under 5.14.4.

        I’ve skimmed through the deltas, but so far haven’t found a plausible explanation. Possibly related to the change in handling the (;$) prototype,1 since that is the prototype of sub switch in the Switch module, but I don’t see how that would account for the observed behaviour. :-/

        1See “Change in parsing of certain prototypes” in perl5140delta.

        Cheers,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Welcome, rkabhi.

        Is there any particular reason why you are not running the latest version of Perl?

Re: Perl Code Changes Behavior if Two Subroutine definitions are swapped
by haukex (Archbishop) on Jul 27, 2016 at 14:20 UTC

    Hi Abhishek,

    Please use <code> tags to format your code and example input. See also How do I post a question effectively?

    A first quick analysis is that your problem seems to stem from the use of the Switch module - its use is discouraged, please see the section "Limitations" in its documentation. If I replace the switch statement with next if /^[*\/]|simulator\s+lang|^include/i;, your code appears to run the same no matter the order of the subroutines.

    There may be other possible places for improvement, I haven't read the code in detail yet, but that seems to be the main problem.

    Hope this helps,
    -- Hauke D

      Hi Hauke,
      Thanks a lot for quick response !!
      Your response really helped.

      I am actually writing few perl codes for the first time for a project and want to be cautious with use of such modules. Is there any way I can get to know those basic modules whose use is not suggested?

      Thanks once again for your help!!

      --
      Abhishek

        Hi Abhishek,

        Modules whose use is discouraged is often noted in the module's documentation itself (for example, the top of the Switch page says "do not use if you can use given/when"). Otherwise, by looking at a distribution's CPAN page (this is the one for Switch), there are other clues as to when a module might not be good to use: if it has bad reviews, if it only had one release and/or hasn't had releases for many years, if its test statistics show a lot of failures, and/or if it has a lot of unresolved bugs. None of these things by themselves make a module bad, they are only clues, but if a module has a lot of these issues then you may want to stay away from it. The same clues can of course be used to tell if a module is "good": good reviews, several releases over several years, a low bug count, and good test results are all signs of a module being "good quality".

        Off the top of my head, some modules that are often used even though their use is nowadays discouraged: XML::Simple (is only useful for a very narrow range of tasks, there are better modules like XML::Twig, XML::Rules, or XML::LibXML), Switch (a few alternatives), and CGI (there are more modern web frameworks, such as Catalyst, Dancer/Dancer2, and Mojolicious). <update> File::Slurp has a lot of issues, better to slurp manually or use one of the other modules. </update>

        On the other hand, you can get a lot of good module suggestions from this site itself by reading threads with questions that relate to your tasks, or there is also Task::Kensho, a list of recommended modules for various tasks.

        Hope this helps,
        -- Hauke D