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.
In reply to Re: nested #if directive matching matching
by tobyink
in thread nested #if directive matching matching
by prassi
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |