my %start= qw( [( )] [| |] [{ }] ); my %end= reverse %start; my $expect= ""; # Closing delimiter we expect, if any. my $code; for my $chunk ( split m#( \[ [(|{] | [)|}] \] )#x, $template ) { if( "" eq $expect ) { if( $start{$chunk} ) { $expect= $start{$chunk}; $code= ""; } else { warn "Unmatched $chunk\n" if $end{$chunk}; print $chunk; } } else { if( $chunk eq $expect ) { print expand( $code ); $expect= ""; } else { $code .= $chunk; warn "Found $chunk inside $end{$expect} $expect block\n" if $start{$chunk} || $end{$chunk}; } } }