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

Hello Monks

I have written a perl code which is able to search and delete a line from a file (IN_FILE) which contains "max_transition",when "direction : output" condition will satisfy. After deleting the line the code writes the modified file into a different location.

Now I need to delete the line "max_transition" when the "direction : output" condition will satisfy as well as where it will find word "timing" in that particular pin group.

IN_FILE, has output pin "HIZIBI_79", HIZIBI_78 and HIZIBI. After running the script "max_transition" line should not be deleted from pin "HIZIBI_79", HIZIBI_78", because this pin group do not have "timing". Only "max_transition" line would be deleted from pin "HIZIBI", it has a "timing" group.

Any idea how to implement it?

Output file should be look like OUT_FILE

perl file use warnings; use strict; my $inputfile = $ARGV[0]; # input lib FILE if ($#ARGV!=0) { print "USAGE :: perl max_tran_update.pl <<LIB_FILE>> \n\n" ; exit(1); } my $cmd = "mkdir tmpdir;"; system ($cmd); my $iline; my $flag_outpin=0; my $out_pin_flag=0; open (INFILE,"<","$inputfile") || die "Can not open Input LIB File"; open (my $OPFILE,">","tmpdir/input_lib.lib") || die "Can not open Inpu +t Text File"; while ($iline = <INFILE>) { chomp $iline; print $OPFILE "$iline\n"; if (($iline =~m/^\s*direction\s*:\s*output\s*;/g)) { $flag_outpin=1; while ($iline = <INFILE>) { if (($iline =~m/^\s*direction\s*:\s*input\s*;/g)) { $flag_outpin=0; } if (($iline =~m/^\s*direction\s*:\s*output\s*;/g)) { $flag_outpin=1; } if (($iline =~m/^\s*max_transition\s*:/g) && ($flag_outpin == 1 +)) { $iline =~ s/$iline//g ; } else { print $OPFILE "$iline"; } } } } close INFILE; close $OPFILE;

IN_FILE cell (lib_1) { dont_use : true ; dont_touch : true ; pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 12 ; } pin ("HIZIBI_79") { direction : output ; max_transition : 10; min_capacitance : 3 ; } pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 1 ; } pin ("HIZIBI_78") { direction : output ; max_transition : 10; min_capacitance : 34 ; capacitance : 34 ; } pin ("HIZIBI") { direction : output ; clock : true ; max_transition : 20; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } } } }

OUT_FILE cell (lib_1) { dont_use : true ; dont_touch : true ; pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 12 ; } pin ("HIZIBI_79") { direction : output ; max_transition : 10; min_capacitance : 3 ; } pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 1 ; } pin ("HIZIBI_78") { direction : output ; max_transition : 10; min_capacitance : 34 ; capacitance : 34 ; } pin ("HIZIBI") { direction : output ; clock : true ; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } } } }

Replies are listed 'Best First'.
Re: Need to save a single line from delete on some special condition
by Eily (Monsignor) on Mar 26, 2019 at 10:30 UTC

    Hello anirbanphys. Is the format of your file some kind of standard? If so, I'd recommend trying to find a module that does what you want. Parsing that kind of data (nested) is complex if you want to do it correctly. Otherwise you have to assume some things to "cheat". For example ways you could divide your file into pins would be to either:

    • consider that the indentation is always correct
    • consider that there won't be another type of objects beside the pins
    • consider that other objects don't have any of the attributes you are working with
    There are probably other possibilities, but the implementation I can think of that are simple could be broken by having one of those assumptions proven wrong.

      Thank you Eily for looking and understanding the issue.

      Yes the three assumptions you mentioned are accurate. I am trying a simple solution "read a line, don't print it when conditions are met" won't work with my new requirement, as "timing(" occurs after the line I want to delete. I'll have to rewrite the code to read one whole " pin(..) { ... }" section in, decide which lines to delete and then dump it to the output. As I have several block-type statements I will either need to count the open brackets or write a real parser for the given syntax. And This is getting complex

      I am using the code, but every time I am getting the issue "timing event not found", what is wrong here?

      perl -0777 -ne ' s/(pin\s*\(".+?"?\)\s+\{.+?\})/$x=$1;if($x=~m!timing +\s*\(\)! and $x=~m!direction : output!){$x=~s!^\s*max_transition.+?\n +!!mg};$x/gse ; print ' <INPUT_FILE>

        the three assumptions you mentioned are accurate
        If you're really sure about the indentation something like that can help :
        use strict; use warnings; use v5.10; my $data = do { local $/; <DATA> }; my @sections = split /(\s{4}pin.*?\s{4}\})/s, $data; for (@sections) { say; say '-' x 24; } __END__ cell (lib_1) { dont_use : true ; dont_touch : true ; pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 12 ; } pin ("HIZIBI_79") { direction : output ; max_transition : 10; min_capacitance : 3 ; } pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 1 ; } pin ("HIZIBI_78") { direction : output ; max_transition : 10; min_capacitance : 34 ; capacitance : 34 ; } pin ("HIZIBI") { direction : output ; clock : true ; max_transition : 20; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } } } }
        It's very rough, and assumes a very consistent indentation. It divides the input into section (even empty ones between the pins but that shouldn't be an issue):
        cell (lib_1) { dont_use : true ; dont_touch : true ; ------------------------ pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 12 ; } ------------------------ ------------------------ pin ("HIZIBI_79") { direction : output ; max_transition : 10; min_capacitance : 3 ; } ------------------------ ------------------------ pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 1 ; } ------------------------ ------------------------ pin ("HIZIBI_78") { direction : output ; max_transition : 10; min_capacitance : 34 ; capacitance : 34 ; } ------------------------ ------------------------ pin ("HIZIBI") { direction : output ; clock : true ; max_transition : 20; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } ------------------------ } } } ------------------------

        Edit: it also assumes that the file is not so big that you can't read it all at once.

Re: Need to save a single line from delete on some special condition
by clueless newbie (Curate) on Mar 26, 2019 at 16:41 UTC
    Maybe you want to look at Regexp::Common::balanced. Using it I get this: Updated and cleaned up in response to anirbanphy's post which follows:
    use Data::Dumper; use Regexp::Common; use strict; use warnings; my $pin_group_re=qr{ pin\ + # "pin" followed by sp +aces ( # $1 capture $RE{balanced}{-parens=>'()'} # balanced parenthesis \ + # followed by spaces $RE{balanced}{-parens=>'{}'} # balanced braces ) # end $1 capture }x; my $timing_group_re=qr{ timing\ + # "timing" followed by + spaces ( # $1 capture $RE{balanced}{-parens=>'()'} # balanced parenthesis \ + # followed by spaces $RE{balanced}{-parens=>'{}'} # balanced braces ) # end $1 capture }x; sub do_something_with_a_pin { # To see what we got we'll dump @_ warn Data::Dumper->Dump([\@_],[qw(*_)]),' '; my $string=shift; if ($string =~ m{direction : input}) { # Has a "direction : in +put" so no modification warn "has 'direction : input'"; } elsif ($string =~ m{$timing_group_re}) { # has a timing group warn "has 'timing'"; # kill the max_transition line -- $string =~ s{^.*max_transition.*\r?\n}{}m; # Let's see what the string looks like now }; warn Data::Dumper->Dump([\$string],[qw(*string)]),' '; return $string; }; my $string; { # Because we want all of the data as a single string local $/; # Deal with string, which will be the entire file, replacing each +of pin groups ($string=<DATA>) =~ s{$pin_group_re}{"pin\ ".do_something_with_a_p +in($1)}gex; } print $string; __DATA__ IN_FILE cell (lib_1) { dont_use : true ; dont_touch : true ; pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 12 ; } pin ("HIZIBI_79") { direction : output ; max_transition : 10; min_capacitance : 3 ; } pin ("HIZIBI_IN_1") { direction : input ; clock : true ; max_transition : 1 ; capacitance : 1 ; } pin ("HIZIBI_78") { direction : output ; max_transition : 10; min_capacitance : 34 ; capacitance : 34 ; } pin ("HIZIBI") { direction : output ; clock : true ; max_transition : 20; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } } } }
    Now the last pin group looks like
    pin ("HIZIBI") { direction : output ; clock : true ; related_power_pin : VDD ; related_ground_pin : VSS ; timing () { cell_fall (into_f1) { index_1("1,2,3,4,5") ; index_2("1,2,3,4,5") ; values("13, 13, 14, 16, 18",\ "13, 14, 15, 16, 19",\ "14, 15, 16, 17, 20",\ "15, 15, 16, 18, 20",\ "15, 16, 17, 18, 21") ; } }

      Hello clueless newbie, I was using your code and trying to include one more if condition.

      As you already included the logic if "timing" (balanced parenthesized delimiter) present then only by searching the pattern "max_transition", it will delete the line.

      Now I need to add one more condition, you might observed that if "direction : input" (for any pin group) condition arise, it will never delete "max_transition" line. And according to the given code, it will delete "max_transition" line for a input pin group where "timing" is present, which I do not want.

      So I tried to include this

      sub do_something_with { #warn Data::Dumper->Dump([\@_],[qw(*_)]),' '; my $string=shift; if ( $RE{some}{pattern}->matches(~m/^\s*direction\s*:\s*output +\s*;/) ) { if ($string =~ m{timing +($RE{balanced}{-parens=>'()'} +$RE{ba +lanced}{-parens=>'{}'})}) { # has a timing group # kill the max_transition line $string =~ s{^.*max_transition.*\r?\n}{}m; #warn Data::Dumper->Dump([\$string],[qw(*string)]),' '; }; #return $string; }; return $string; };

      But while I am trying to execute I am getting error.

Re: Need to save a single line from delete on some special condition
by tybalt89 (Monsignor) on Mar 26, 2019 at 17:38 UTC

    Just redefine what a line is.

    local $/ = '}'; while( <INFILE> ) { /timing/ and s/^.*max_transition.*\n//m; print $OPFILE $_; }

    Semi-tested :)

Re: Need to save a single line from delete on some special condition
by bliako (Abbot) on Mar 27, 2019 at 10:09 UTC

    It may be worth investing a few days to write a script to parse any file in this format if it is a standard and you are going to work on it for some time. The product should be Perl nested hashtables to represent entities in your file, for example:

    $lib1 = { 'pins' => { 'HIZIBI' => { 'timing' => { ...

    Then you simply navigate to the pin you want and change whatever attributes you like. Finally, write the opposite of the parser, the dumpers so to speak and use it to save the file to disk in any file format you wish. If you want to go the extra mile, then create classes to represent each entity type in your files. If you are not acquainted with Perl classes, they are similar to hashes but with their own functions/methods/subs. You can even delegate the parsing/saving logic to each class.

    Of course the parsing issue will still need to be dealt with but it's trivial once you forget about reading the entities and finding that specific attribute. The suggestion by clueless newbie can be of help in parsing the file: Re: Need to save a single line from delete on some special condition

    If you want to go this direction just show some code and I can be of assistance.

    bw, bliako

      I got a lot of reply/help from all of you. After going thorough your comments I am now able to solve my problem. Thank you folks for showing me some light when I really need it :). Special thanks to Eily, clueless newbie, tybalt89 and Veltro. May god Bless you..... :)

Re: Need to save a single line from delete on some special condition
by Veltro (Hermit) on Mar 26, 2019 at 23:40 UTC

    A couple of months back I was working on something similar here

    This is all highly experimental and completely untested, but I decided to add your use-cases. Especially the idea of being able to search for pins, not depending on name specifically I thought was interesting, so I fiddled around with the wildcard idea.

    The original idea for this code was the ability to specify a filter and changes and try to alter a file of any unspecified 'structured' format and leaving any lines not changed 'untouched'. Such a filter would look like this:

    [ # Filter { "cell \(lib_1\)" => { "pin (\"*\")" => { "timing ()" => 1, # 'max_transition' => [ 20 ], }, }, }, # Changes { "cell \(lib_1\)" => { "pin (\"*\")" => { 'max_transition' => { action => 'delete' }, }, }, } ],

    Have fun!

    edit: Added fix, see comments in code