in reply to nested #if directive matching matching

You want to use a stack.

A stack is an abstract concept in programming. It is basically a list that you can only access from the tail end. You can push things onto the stack, and pop the item on the top off the stack, and you can detect when the stack is empty.

As I said, stacks are an abstract concept; you need a concrete realisation of them. In Perl, that's an array. Perl helpfully provides built-in push and pop functions, and makes it easy to check if an array is empty.

This is the basic technique you want...

my @if_stack; while (<$input>) { if (/$start/) { push @if_stack, $_; next; } if (/$stop/) { die unless @if_stack; pop @if_stack; next; } if (@if_stack) { # got a line which is inside a conditional } else { # got a line which is not inside a conditional print $output $_; } }

In fact, in this case you could get away with using a data structure even simpler than a stack - a counter will do. You simply pretend you've got an imaginary stack, and use a counter that keeps track of how many items are on the stack. Instead of pushing onto the stack, increment the counter; instead of popping, decrement.

my $if_stack; while (<$input>) { if (/$start/) { $if_stack++; next; } if (/$stop/) { die unless $if_stack; $if_stack--; next; } if ($if_stack) { # got a line which is inside a conditional } else { # got a line which is not inside a conditional print $output $_; } }

I maintain that the stack is the better solution because you can, for example, print a dump of the current stack when you detect an error, which can help in identifying where things have gone wrong. That said, if you're crunching though vast quantities of text, the counter will probably perform slightly faster.

perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

Replies are listed 'Best First'.
Re^2: nested #if directive matching matching
by prassi (Acolyte) on Jun 26, 2012 at 12:51 UTC
    Hi Tobyink,

    your code fails if the code encounters #else

    Regards,

    -Prassi

      No it doesn't. I just neglected to post my version of $start and $stop.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'