Wednesday, August 6, 2008

Debugging

Sooner or later you'll need to do some fairly hairy debugging. It will be later if you are using strict , -w and writing your subroutines properly, but the moment will come.

When it does you'll be poring over code, probably late at night, wondering where the hell the problem is. Some techniques I find useful are:

Print your variables and other information out at frequent intervals.
Split difficult components of the program out into small, throwaway scripts. Get these working, then copy the results back into the main program.
# Comment frequently.
Eventually, you'll be stuck. Such is the price of progress. In this case, Perl's own debugger can be invaluable. Run this code as normal first:
$name=shift;

print "Logon name creation program\n:Converting '$name'\n";

print &logname($name),"\n\n";

print "Program ended at", scalar(localtime),"\n";

sub logname {
my $name=shift;
my @namebits;
my ($logon,$inital);
@namebits=split /\s+/,$name;
($inital)=$name=~/(\w)/;
$logon=$inital.$namebits[$#namebits];
$logon=lc $logon;
return $logon;
}

We'll run it with the debugger so you can watch perl at work while it runs:
perl -d script.pl "Peter Dakin";

and you are into the debugger, which should look something like this:
c:\scripts\db.pl>perl -d db.pl "Peter Dakin"

Loading DB routines from perl5db.pl version 1.0401
Emacs support available.

Enter h or `h h' for help.

main::(db.pl:1): $name=shift;
DB<1>

db.pl Name of script being executed
1 Line number of script that is just about to be executed.
$name=shift; The code that is just about to be executed.


Type s for a single step and press enter. The code $name=shift; will be executed, and perl waits for your next command. Keep inputting s until the program terminates.

This by itself is useful as you see the subroutine flow, but if you enter h for help you'll see a bewildering range of debug options. I won't detail them all here, but some of the ones I find most useful are:
n Executes main program, but skips subroutine calls. The subroutine is executed, but you aren't stepped through it. Try using n instead of s .
/xx/ Searches through program for xx
p Prints, for example p @namebits, p $name
Enter Pressing the Enter key (inputting a carriage return) repeats the last n or s command.
perlcode You can type any perl code in and it will be evaluated, and have a effect on your program. In the example below I remove spaces from $name. Inputs in bold:
main::(db.pl:1): $name=shift;
DB<1> s
main::(db.pl:3): print "Logon name creation program\n:Converting '$name'\n";
DB<1> $name=~s/\s//g;

DB<2> print $name
MarkGray
DB<3>




There are many, many more debugger options which are worth becoming familiar with. Type h for a full list.

No comments: