in reply to Comment a block that match a keyword

This is very dependant upon the correct and logical formatting of the input. It could probably be simplified through refactoring and needs a lot of testing, but the principles it uses might help:

##! perl -slw use strict; while( <DATA> ) { chomp; print, next unless m[TIMINGCHECK]; my $count = tr[(][(] - tr[)][)]; { s[^][//]; print; last unless defined( $_ = <DATA> ); chomp; $count += tr[(][(] - tr[)][)]; redo unless $count < 0; } print; } __DATA__ ... (CELL ... (TIMINGCHECK .... .... ) ) (CELL (CELLTYPE "SEDFQD1") (INSTANCE uTrigger/TrcInclCtrlReg_reg[13]) (DELAY (ABSOLUTE (IOPATH CP Q (0.10:0.15:0.25)(0.09:0.15:0.24)) ) ) (TIMINGCHECK (SETUP (posedge SI) (posedge CP) (0.14:0.23:0.41)) (SETUP (negedge SI) (posedge CP) (0.09:0.16:0.30)) ....(random lines) (HOLD (negedge SI) (posedge CP) (0.00:0.00:0.00)) (HOLD (negedge D) (posedge CP) (0.00:0.00:0.00)) ) )

Output:

c:\test>junk6 ... (CELL ... // (TIMINGCHECK // .... // .... // ) ) (CELL (CELLTYPE "SEDFQD1") (INSTANCE uTrigger/TrcInclCtrlReg_reg[13]) (DELAY (ABSOLUTE (IOPATH CP Q (0.10:0.15:0.25)(0.09:0.15:0.24)) ) ) // (TIMINGCHECK // (SETUP (posedge SI) (posedge CP) (0.14:0.23:0.41)) // (SETUP (negedge SI) (posedge CP) (0.09:0.16:0.30)) // ....(random lines) // (HOLD (negedge SI) (posedge CP) (0.00:0.00:0.00)) // (HOLD (negedge D) (posedge CP) (0.00:0.00:0.00)) // ) )

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Comment a block that match a keyword (did)
by tye (Sage) on Aug 17, 2007 at 02:51 UTC

    Here is a simple demonstration that Perl does indeed have a "post-condition loop construct" (contrary to the claim nearby in this thread), and that it is useful. Here is a trivial refactoring of the above code to make use of that. I don't repeat the input nor output, but if you provide it with the former, then it will duplicate the latter.

    #!/usr/bin/perl -lw use strict; while( <DATA> ) { chomp; if( ! m[TIMINGCHECK] ) { print; next; } my $count= tr[(][(] - tr[)][)]; do { s[^][//]; print; last # Leaves the while( <DATA> ) loop if ! defined( $_= <DATA> ); chomp; $count += tr[(][(] - tr[)][)]; } while( 0 <= $count ); print; }

    Note that the last jumps out of both "loops", which can be considered an improvement since the original code would warn about trying to print an undefined value (when given incomplete input).

    And, here is one way I might refactor this (in order to avoid repeating the code used to read input and the code to count parens):

    #!/usr/bin/perl -lw use strict; my $count= -1; while( <DATA> ) { chomp; $count= 0 if m[TIMINGCHECK]; $count += tr[(][(] - tr[)][)] if 0 <= $count; s[^][//] if 0 <= $count; print; }

    Which also duplicates the above output, though it might not always agree on all inputs (it doesn't warn on incomplete input, certainly).

    - tye        

Re^2: Comment a block that match a keyword
by FunkyMonk (Bishop) on Aug 17, 2007 at 00:01 UTC
    There's a couple of things That smell bad to me about this. They're personal things; I don't have any doubts that the code works. It's just things that trouble me:
    • a block pretending to be a loop, and the use of redo and last therein.
    • (this is definatley just me) chomp that isn't the first thing done in the "loop". I'd have put it first, even if any subsequent print (etc) had to include \n.

    I'd be happier with a do block, rather than a bare block. Perhaps it's just me :)

    Like I said, personal things.

    update: added stuff about do after further thought

      I wasn't particularly enamoured with it, hence my "could be refactored" comment. The reason I didn't refactor it at the time was I couldn't see a nice way how to.

      Noting your "personal preferences" emphasis, I hope you don't mind if I respond with my take on things?

      1. a block pretending to be a loop, and the use of redo and last therein.

        Update: Everything in here is wrong. See the responces below

        The real problem here is Perl's lack of a post-condition loop construct.

        As was pointed out to me here a couple of years ago, unlike pascal's repeat ... until cond();, Perl's do{ ... } while/until cond(); construct tests the condition before entry to the loop body, and will prevent entry ever happening if the condition isn't met. That leaves us with the unfortunate situation, when we need to execute the loop body at least once, of duplicating that loop body:

        # do stuff do { # the same 'do stuff' as above. } while cond;

        And that repetition of 'do stuff' is a problem. In this case, having read a line at the top of the while loop, we need to

        • do some stuff (initialise out parens count from the first line)
        • enter the loop construct
        • do some more stuff (prepend the comment card and print)
        • read the next line, check for eof.
        • chomp the line we just read.
        • Do some more stuff (adjust the parens count from the new line)
        • decide whether to loop or not

        And the only way I know how to do that in perl (without artificial means like setting flags and/or double condition tests) is redo.

        You said: I'd be happier with a do block, rather than a bare block., but that doesn't work:

        #! perl -slw use strict; my $i =0; do{ print ++$i; redo if $i < 5; }; __END__ c:\test>junk2 1 Can't "redo" outside a loop block at c:\test\junk2.pl line 7.

        You'd have to do

        #! perl -slw use strict; my $i =0; do{{ print ++$i; redo if $i < 5; }}; __END__ c:\test>junk2 1 2 3 4 5

        That is, embed a bare block within the do block, and that is redundant and very obscure.

        You could adopt a Perl 6 like construct:

        LOOP:{ ... redo LOOP; }

        which could be construed as clearer. But frankly, redo in a bare block is a perfectly valid and useful construct and, I think, it is better to just become familiar with it than to obscure it. Indeed, it is actually the most flexible looping construct. It can be used to construct all many other looping constructs Perl has. Even the much decried but extremely flexible C-style for loop with its otherwise unique ability to vary multiple indexes concurrently.

        ## draw the diagonals for( my $x=0, my $y=0; $i < $xMax; $x++, $y++ ) { draw( $x, $y ); +} for( my $x=0, my $y=$yMax; $i < $xMax; $x++, $y-- ) { draw( $x, $y ); +}

        It's a little used feature, but when you need it, you need it:

      2. chomp that isn't the first thing done in the "loop". I'd have put it first, even if any subsequent print (etc) had to include \n.

        Hm. I'm not sure what the position of chomp has to do with the loop construct. The chomp has to follow the readline. The readline has to occur in the middle of the loop.

      I'm still not happy with the construction I posted, but I haven't come up with a better one.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        You might want to test your ideas about do{ STMTs }while( EXPR );. The while() condition actually is tested at the end of the loop, ensuring that the body of the loop is always run at least once.

        The 'problem' with it is that it isn't a "loop" as far as next, redo, and last are concerned (due to somewhat obscure implementation details).

        But it is a construct I find useful, not just some redundant alternative to while( EXPR ){ STMTs } and STMT while EXPR; (which both test before each iteration).

        - tye        

        Whadda yer know. I made this same error 3 years ago, and despite being corrected, and accepting that correction from the ultimate authority, I'm still making it.

        Does that say something about me? Or just confirm TimToady's reasoning for ditching the do{ ... } while construct.

        For those not following along.

        This

        my $i = 0; while( $i < 5 ) { print ++$i; } 1 2 3 4 5

        And this

        my $i = 0; print ++$i while $i < 5; 1 2 3 4 5

        Produce the same output.

        And so do $i = 0; until( $i >= 5 ) { print ++$i }

        And $i = 0; print ++$i until $i >= 5;

        And $i=0; ++$i and print( $i ) while $i < 5;

        And $i=0; ++$i, print( $i ) while $i < 5;

        And even this $i=0; do{ ++$i; print( $i ) } while $i < 5;

        But then suddenly, whilst $i=0; print( $i ) while $i++ < 5; this does.

        This

        $i=0; do{ print( $i ) } while $i++ < 5; 0 1 2 3 4 5

        doesn't.


        So, somewhere back there I've reached the conclusion that do{  } while is too subtle even for my tastes and stopped using it. As a result, I convinced myself that "Perl doesn't have a post-condition loop".

        As you can see, I'm wrong. But for good reasons, and in line with those of some other people I respect, I'll continue to mentally deprecate it's usage.

        With luck, this will act as an aide memoire to cause me not to voice my internal deprecation Perl does not have a post-condition loop out loud.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re^2: Comment a block that match a keyword
by yorkwu (Novice) on Aug 16, 2007 at 13:51 UTC
    Wow! what a cool way to find out the balanced bracketed block.
    Thank you, BrowserUK! I really learn a lot. York
Re^2: Comment a block that match a keyword
by moritz (Cardinal) on Aug 17, 2007 at 10:52 UTC
    I quite like that solution, but it will fail if there are unbalanced brackets in quoted strings, like "foo(".

    If you want to consider that, you have to purge all quoted strings first. You can achieve this with the regexes from Regexp::Common::delimited.

      Yes. Hence my "This is very dependant upon the correct and logical formatting of the input." caveat.

      If there are any errors in the balancing of parens, it will fail horribly, but as the text is obviously source to some parser somewhere, it's a reasonable, pragmatic, economic ROI decision to say: This 'comment out timing checks script' is only usable on source that parses correctly using a.n.other tool. A pragmatic decision to save having to reverse engineer that a.n.other tool's parser from scratch and without the originial specs.

      It will also fail in many cases that would (probably; no spec!) be successfully parsed by that other parser. For example, if the close parens placements are coalesed on a single line, rather than laid out in a logically structured way as per the OPs example:

      (CELL (TIMINGCHECK (SETUP (posedge SI) (posedge CP) (0.14:0.23:0.41)) (SETUP (negedge SI) (posedge CP) (0.09:0.16:0.30)) ....(random lines) (HOLD (negedge SI) (posedge CP) (0.00:0.00:0.00)) (HOLD (negedge D) (posedge CP) (0.00:0.00:0.00)) ))

      In this case, the close paren of the (CELL block will also be commented out and the result will fail to parse with that other tool.

      In an ideal world one would go back to the authors of a.n.other tool, request a copy of their parser, or the specifications from which it was drawn, and produce a 'proper parser' script that understood all the rules of the input language and performed the required operation.

      But this isn't an ideal world, and time is money, and performing ad-hoc text munging tasks like this are exactly what Perl was invented for. (Amongst other things. :)

      But then again, it seems that the authors of a.n.other tool were either on-the-ball or responsive to in-use experience of using their tool, because it seems they already may have provided an option that make this entire thread redundant.

      It's just a shame that post hasn't received the attention and votes it deserves. It's a non-perl solution, but, assuming the poster has correctly recognised the nature of the data and OP is using the correct a.n.other tool, by far the best solution to the OPs problem.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        A number of additional points:

        I added some keywords to the title of this node because it is quite relevant to my line of work, and I know I will want to refer back to it in the future. When I ran a SuperSearch on "Verilog" and/or "SDF", this node was not located. Of course, I linked to this node, but maybe others will be able to locate it more easily now.

        The syntax of the code in the OP is specified in the IEEE Standard 1497-2001 document, titled:

        IEEE Standard for Standard Delay Format (SDF) for the Electronic Design Process
        I'm mentioning this just in case anyone following this stream was wondering what this strange syntax was. It is used by digital IC hardware designers who use the Verilog language.

        I like BrowserUK's solution. In the SDF syntax, to quote the spec: "White space is never significant except when used within quoted strings or to separate lexical tokens." So, end parentheses need not be on separate lines. We have had the need to hack an SDF file, similar to what the OP poster has done, but our solution is pretty nasty. At some point, I will probably give this a try.

        I am one of those who upvoted shoness's node because that may well be the best solution for the OP. It is too bad the the OP has not responded to this node, because there may be additional solutions which could be offered if these few basic questions were answered.

        That being said, we have decided that hacking our SDF file is the most cost-effective solution, given our circumstances. We do disable timing checks using simulator options, but we have other constraints which make it difficult to disable them for all cells. We should extend our own cell library to handle this case, but that takes more time and resources than hacking the SDF file.

        Thanks to all for contributing to this very useful (at least to me) thread. I'm usually not this long-winded, so I'll shut up now.