Article 8165 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:8165
Newsgroups: comp.lang.perl
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!eff!news.kei.com!ub!csn!iem!husni
From:
[email protected] (Husni Sayed)
Subject: TRY/RECOVER in Perl
Message-ID: <
[email protected]>
Date: Sat, 20 Nov 1993 03:24:58 GMT
Organization: IEM, Inc.
X-Newsreader: Tin 1.1 PL4
Lines: 206
Perl has great constructs, but it is weak when it comes to handling
errors, run-time, and compile time. In my past life (at HP), I worked
with another engineer on implementing a structured error handling into
Pascal. The language was used extensively in the late 70's and early
80's. It was called Modcal or (HP Pascal). A huge amount of code has
been written using this language.
The contruct we used was:
TRY
try block
RECOVER
recover block
The idea is that if an error took place in the try block, then the
code in the recover block was executed. I would like to propose the
same contruct for Perl. Larry will have to implement it in his code
to make it efficient.
I have implemented a perl pre-processor called 'perlpp' that will,
using Perl push, pop, and goto, implement the same. Howver, I can
only catch errors that I detect and force and ESCAPE to the recover
block. It is better than nothing. SIGNALS do not work very well
here.
'perlpp' is fully deecribed in the following man page. Notice how I
had to use ENDRECOVER to signify the end of the RECOVER block. You
will also find my implementation at the end of tha man page. The
program and the concept is very simple, but it makes life real easy.
================= perlpp.1 ====================================
perlpp(1)
Perl pre-processor. Processes special syntax such as TRY RECOVER.
SYNTAX
perlpp [infile | - [outfile | -]]
DESCRIPTION:
This filter will take any perl program and look for special syntax,
such as TRY RECOVER and translate it into actual perl statement.
Perl programs can now handle error recovery gracefully and in a
structured manner. All you have to do is inert the new TRY/RECOVER
syntax and process your perl program using this filter 'perlpp' to
translate the new syntax into regular perl statements. The
following is how to use this construct:
Insert the following lines in your perl code:
TRY
perl lines of code. Somewhere in here or in any sub called from
here, you should include ESCAPE or ESCAPE(escapecode).
RECOVER
error handling for ESCAPES from the previous TRY block
ENDRECOVER
You can nest as many TRY RECOVER ENDRECOVER blocks as you wish.
Just make sure that they are all nest properly. In other words,
each TRY must be matched with a corresponding RECOVER, and each
RECOVER must be matched with a corresponding ENDRECOVER.
The following global 'main' variables will also be defined, so to
dot tamper with them:
@GERROR_BLK: TRY RECOVER stack
$ESCAPECODE: Value of escape code, if set by ESCAPE(code)
$TRYLEVEL: Nest level of the TRY blocks, starting with 0.
EXAMPLES:
#!/usr/contrib/bin/perl
sub one
{
print "In one\n";
ESCAPE(10);
}
sub two
{
print "In TWO\n";
&one;
print "In TWO Back from one. This should not print\n";
}
TRY
print "in Main\n";
&two;
print "After two in main. This should not print\n";
RECOVER
print "MAIN: First recover level\n";
TRY
&one;
RECOVER
print "MAIN: Second recover level\n";
print "In error block of main ESCAPECODE = $ESCAPECODE\n";
print "About to get done TRYLEVEL $TRYLEVEL\n";
ENDRECOVER
print "MAIN: First recover level, bye\n";
ENDRECOVER
IMPLEMENTATION DETAILS:
The perlpp uses a label stack called @GERROR_BLK to keep track of
the current TRY block. Here is how it translates the various new
statements:
TRY ==>
$TRYLEVEL=current_try_level;
push(@GERROR_BLK, RECOVER_LABEL);
RECOVER ==>
pop(@GERROR_BLK);
goto AFTER_ENDRECOVER;
recover_label: {
ENDRECOVER ==>
}
AFTER_ENDRECOVER:
ESCAPE(code) ==>
$ESCAPECODE=code;
$GERRLBL=pop(@GERROR_BLK);
eval "goto $GERRLBL";
AUTHOR:
Husni S. Sayed (
[email protected])
MANPAGE REVISION:
@(#)$Header: perlpp.1,v 1.1 93/11/19 20:03:53 husni Exp $
================= perlpp program source ============================
#!/usr/contrib/bin/perl
# *********************************************************************
# $Header: perlpp.pp,v 1.1 93/11/19 20:03:58 husni Exp $
# *********************************************************************
sub revision{
'$Revision: 1.1 $' =~ /Revision:\s*(\d+\.\d+)/o;
return $1;
}
if ($ARGV[0] eq '-?'){
}
if ($ARGV[0]){$inf=$ARGV[0];}else{$inf="<-";}
if ($ARGV[1]){$onf=$ARGV[1];}else{$onf=">-";}
open(IN,$inf);
open(OUT,$onf);
$gerrlbl=0;
while (<IN>){
/^\s*TRY/o && do {
print OUT " # TRY $gerrlbl\n";
print OUT " \$TRYLEVEL=$gerrlbl;\n";
print OUT " push(\@GERROR_BLK,'lbl_$gerrlbl');\n";
$gerrlbl++;
next;
};
/^\s*RECOVER/o && do {
print OUT " # END TRY $gerrlbl\n";
print OUT " pop(\@GERROR_BLK); goto lbl_$gerrlbl;\n";
print OUT " # RECOVER $GERRLBL\n";
$lbl=$gerrlbl-1;
print OUT "lbl_$lbl: {\n";
next;
};
/^\s*ENDRECOVER/o && do {
print OUT " }\n";
print OUT " # ENDRECOVER $gerrlbl\n";
print OUT "lbl_$gerrlbl: ";
$gerrlbl--;
next;
};
/^\s*ESCAPE(\((.*)\))?/o && do {
if ($2) {$err=$2} else {$err=0}
print OUT " # ESCPE($err)\n";
print OUT " \$ESCAPECODE=$err;\n";
print OUT " \$GERRLBL=pop(\@GERROR_BLK);\n";
print OUT " eval \"goto \$GERRLBL\";\n";
next;
};
print OUT $_;
}
if ($gerrlbl){
print STDERR "perlpp: Problem with TRY RECOVER nesting level $gerrlbl\n";
}