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

Hi Monks, My issue revolves around going back to a do{}while loop in my code, I thought I had figured out how to label it and perlsyn corroborated my theory I thought, but I still can't get it to work, as I get the error: {0}: perl putLinesBackInVCF4.pl -1kg CEU.head.txt -knome wo127.head.txt -o output.txt Label not found for "redo LOOP" at putLinesBackInVCF4.pl line 96, <KGFILE> line 20. Here's my code, I've tried to comment it pretty extensively.
#!/usr/bin/perl use strict; use warnings; use Pod::Usage; use Getopt::Long; my $KG_FILE; my $OUTFILE; my $KNOME_FILE; GetOptions( '1kg=s' =>\$KG_FILE, 'knome=s' =>\$KNOME_FILE, 'o=s' =>\$OUTFILE, 'help' =>sub{pod2usage(1);} ) or pod2usage(2); =head SYNOPSIS putLinesBackinVCF.pl Options: -1kg 1000 genomes input vcf file -knome knome file with sites -o output file -help display this message =cut if (!$KG_FILE){ pod2usage(2); die "Please supply an input 1000 genomes file\n"; } if(!$KNOME_FILE){ pod2usage(2); die "Please supply our sites file\n"; } if(!$OUTFILE){ pod2usage(2); die "Please supply an output file\n"; } unless(open( KGFILE, $KG_FILE)){ die "Couldn't create link to 1kg file: $!\n"; } unless(open( KNOME, $KNOME_FILE)){ die "Couldn't create link to knome input file: $!\n"; } unless (open( OUTFILE,">", $OUTFILE)){ die "Couldn't create link to output file: $!\n"; } my $pos = 0; while (<KGFILE>){ if ($_ =~ /^#/){ next; } # skip header lines... my ($kgLine) = $_; chomp $kgLine; my @kgArr = (split("\t", $kgLine))[0,1]; #grab the chrom and posit +ion columns my $chr; my @arr; LOOP: { do{ # go through the KNOME file; # print out the positions till we reach (or exceed) the position f +rom the KGFILE my $line = <KNOME>; if (not defined $line) { last; } chomp $line; @arr = (split("\t", $line))[0,1]; $arr[0] =~ s/^0//; $chr = $arr[0]; #remove leading 0's from chromosome number $pos = $arr[1]+1; #to adjust positions to base 1 rather than + base 0 if ($pos < $kgArr[1]){ print OUTFILE "$chr\t$pos\n"; #probably unncessary if sta +tement but shouldn't hurt anything even if so } } while $pos < $kgArr[1]; } if($kgArr[1] < $pos){ #at this point the position from KNOME is + no longer LESS THAN position from KGFILE print OUTFILE $kgLine,"\n"; while ($kgArr[1] < $pos){ #if last position from KNOME is GREATER THAN position from KGFILE we n +ow need to loop through #and print all the lines from KGFILE until we catch back up to KNOME's + position! my $catchup = (<KGFILE>); chomp $catchup; @kgArr = (split("\t", $catchup))[0,1]; if ($kgArr[1] == $pos){ #If we get to the point where th +ey're equal, good... just print, this while loop will end, and we'll +start the whole process over print OUTFILE $catchup,"\n"; } elsif($kgArr[1] > $pos){ print OUTFILE "$chr\t$pos\n"; redo LOOP ; last; #print OUTFILE "$catchup\n"; #if KGFILE's position has become GREATER than the KNOME $pos again, ho +wever, it gets tricky... # but now we need to go through KNOME file positions again and see if +that position matches later on... # can't just quit the loop or this line will be lost, but we don't rea +lly want to print it here either... # } } } elsif($kgArr[1] == $pos){ print OUTFILE $kgLine,"\n"; } } #if we get to the end of the KGFILE and there's still lines left in th +e KNOME file, just print the rest of those lines chr and pos values; while (<KNOME>){ chomp; my @remainingArr = (split("\t", $_))[0,1]; $remainingArr[0] =~ s/^0//; my $remChr = $remainingArr[0]; my $remPos = $remainingArr[1]+1; print OUTFILE "$remChr\t$remPos\n"; }

Replies are listed 'Best First'.
Re: Trouble with do{}while LABELS
by ikegami (Patriarch) on Aug 09, 2011 at 22:09 UTC
    do BLOCK while COND;
    is just a combination of
    do BLOCK
    and
    EXPR while COND;

    The combination is special cased to not check the while condition the first time through, but that's it.

    Note that it's do that's executed repeatedly, not the block. That means the curlies aren't a loop block, so next and the like don't work.

    $ perl -E'last while 1;' Can't "last" outside a loop block at -e line 1. $ perl -E'do { last; };' Can't "last" outside a loop block at -e line 1. $ perl -E'do { last; } while 1;' Can't "last" outside a loop block at -e line 1.

    Yeah, it should be "proper" loop. But it's not.


    I usually just use an infinite loop:

    for (;;) { my $line = <KNOME>; last if not defined $line; chomp $line; my ($chr, $pos) = split(/\t/, $line); $chr += 0; # Numify. $pos += 1; # Make 1-based last if $pos >= $kgArr[1]; print OUTFILE "$chr\t$pos\n"; }

    although it can be collapsed a bit:

    while (defined( my $line = <KNOME> )) { chomp $line; my ($chr, $pos) = split(/\t/, $line); $chr += 0; # Numify. $pos += 1; # Make 1-based last if $pos >= $kgArr[1]; print OUTFILE "$chr\t$pos\n"; }
      Ah... I don't know why I didn't think of that. it's so much simpler. I guess all that remains is to see if it will actually work :)
Re: Trouble with do{}while LABELS
by duyet (Friar) on Aug 09, 2011 at 20:11 UTC
    You can also put the code between LOOP: { ... } into a sub and call it when ever needed.
      putting it in a sub and telling the code to back to LABEL: { sub } calls the same error, no Label found for "redo LABEL"
      I'm trying to put it into a sub right now to see if I can go to a LABEL with a sub in the block, but I still need to go back to that LABEL: position in the original code I can't call the sub where I have "next LABEL" because I need the program to continue from that point onward.
Re: Trouble with do{}while LABELS
by cjb (Friar) on Aug 09, 2011 at 21:56 UTC

    You should be able to label the do loop rather than enclosing it with named loop.

    LOOP: do {

    rather than:

    LOOP: { do{