As of version 0.99.7, Free Pascal supports exceptions. Exceptions provide a convenient way to program error and error-recovery mechanisms, and are closely related to classes.
Exception support is based on 3 constructs:
The raise statement is as follows:
Raise [ExceptionInstance [at Address]];This statement will raise an exception. If specified, ExceptionInstance must be an initialized instance of a class, which is the raise type. If specified, Address must be an expression that returns an address.
If ExceptionInstance is omitted, then the Current exception is re-raised. This construct can only be used in an exception handling block.
As an example: The following division checks whether the denominator is zero, and if so, raises an exception of type EDivException
Type EDivException = Class(Exception); Function DoDiv (X,Y : Longint) : Integer; begin If Y=0 then Raise EDivException.Create ('Division by Zero would occur'); Result:=X Div Y; end;The class Exception is defined in the Sysutils unit of the rtl.
An exception handling block is of the following form :
Try ...Statement List... Except [On [E:] ExceptionClass do CompoundStatement;] [ Default exception handler] end;If an exception occurs during the execution of the statement list, the program flow fill be transferred to the except block. There, the type of the exception is checked, and if there is a On ExcType statement where ExcType matches the exception object type, or is a parent type of the exception object type, then the statements follwing the corresponding Do will be executed. The first matching type is used. After the Do block was executed, the program continues after the End statement.
The identifier E is optional, and declares an exception object. It can be used to manipulate the exception object in the exception handling code. The scope of this declaration is the statement block foillowing the Do keyword.
If none of the On handlers matches the exception object type, then the Default exception handler is executed. If no such default handler is found, then the exception is automatically re-raised. This process allows to nest try...except blocks.
As an example, given the previous declaration of the DoDiv function, consider the following
Try Z:=DoDiv (X,Y); Except On EDivException do Z:=0; end;If Y happens to be zero, then the DoDiv function code will raise an exception. When this happens, program flow is transferred to the except statement, where the Exception handler will set the value of Z to zero. If no exception is raised, then program flow continues past the last end statement.
To allow error recovery, the Try ... Finally block is supported. A Try...Finally block ensures that the statements following the Finally keyword are guaranteed to be executed, even if an exception occurs.
A Try..Finally block has the following form:
Try ...Statement List... Finally [ Finally Statements ] end;If no exception occurs inside the Statement List, then the program runs as if the Try, Finally and End keywords were not present.
If, however, an exception occurs, the program flow is immediatly transferred to the first statement of the Finally statements. All statements of the Finally Statements will be executed, and then the exception will be automatically re-raised. Any statements between the place where the exception was raised and the first statement of the Finally Statements are skipped.
As an example consider the following routine:
Procedure Doit (Name : string); Var F : Text; begin Try Assign (F,Name); Rewrite (name); ... File handling ... Finally Close(F); end;If during the execution of the file handling an excption occurs, then program flow will continue at the close(F) statement, skipping any file operations that might follow between the place where the exception was raised, and the Close statement.
If no exception occurred, all file operations will be executed, and the file will be closed at the end.
It is possible to nest Try...Except blocks with Try...Finally blocks. Program flow will be done according to a lifo (last in, first out) principle: The code of the last encountered Try...Except or Try...Finally block will be executed first. If the exception is not caught, or it was a finally statement, program flow will we transferred to the last but-one block, ad infinitum.
If an exception occurs, and there is no exception handler present, then a runerror 217 will be generated. If you use the sysutils unit, a default handler is installed which ioll show the exception object message, and the address where the exception occurred, after which the program will exit with a Halt instruction.