Programmausnahmen können nur automatisch vom jeweiligen Pascal-Laufzeitsystem behandelt werden.
Delphi
Der Anweisungsblock, in dem Ausnahmen abgefangen werden sollen, wird wie folgt notiert:
TRY
anweisungsfolge { Normalteil }
EXCEPT
ausnahmebehandlung { Ausnahmeteil }
END;
anweisungfolge sind die im Normalfall auszuführenden Anweisungen.
Tritt bei der Abarbeitung einer Anweisung des Normalteils eine Ausnahme ein, so
werden alle nachfolgenden Anweisungen des Normalteils übergangen.
Statt dessen wird in den Ausnahmeteil verzweigt. Im Ausnahmeteil kann festgestellt werden, welche Ausnahme ausgelöst wurde:
ON e : ausnahme DO
anweisung
ausnahme ist der Bezeichner einer "Exception", d.h. eines Typ mit
dem Supertyp Exception.
IF ... THEN RAISE ausnahme.create(message);
...
ON e : ausnahme DO
Writeln(e.Message);
Wird keine Bezugnahme auf die Instanz e benötigt, so kann
kürzer
ON ausnahme DO ...geschrieben werden.
Im Ausnahmeteil kann auf beliebig viele Ausnahmen reagiert werden: Es werden
einfach verschiedene ON - DO Konstrukte aneinander
gereiht.
Dem letzten dieser Konstrukte darf ein ELSE-Zweig folgen:
TRY
...
EXCEPT
ON e : ausnahme_1 DO
...
ON e : ausnahme_n DO
...
ELSE
...
END;
Der ELSE-Zweig sollte mit Vorsicht eingesetzt werden: Es ist
problematisch, eine nicht genau bekannte Ausnahmesituation zu behandeln. Beispiel 1:
USES SysUtils; { enthält Definition der Exception-Typen }
TYPE ETrigError = CLASS(EMathError);
FUNCTION trigo(x: REAL): REAL;
BEGIN
TRY
trigo := 2 * Sin(x) / Cos(x);
EXCEPT
ON EMathError DO
RAISE ETrigError.Create('trigo ist nicht berechenbar');
END;
END;
Es wird eine neue Ausnahme ETrigError als Subtyp von
EMathError definiert. Beispiel 2:
USES SysUtils;
FUNCTION anteil(ist, soll: INTEGER) : REAL;
BEGIN
TRY
anteil := ist / soll;
EXCEPT
ON EZeroDivide DO
anteil := 0;
END;
END;
Bemerkung:
FUNCTION anteil(ist, soll: INTEGER) : REAL;
BEGIN
TRY
anteil := ist / soll;
EXCEPT
ON EZeroDivide DO
anteil := 0;
ON EInvalidOp DO
anteil := 0;
END;
END;
Es könnte die Frage gestellt werden, ob nicht die folgende Lösung
weniger Aufwand verursachen würde:
FUNCTION anteil(ist, soll: INTEGER) : REAL;
BEGIN
anteil := 0;
IF soll <> 0 THEN
anteil := ist / soll;
END;
Darauf läßt sich antworten:
Bei den obigen Beispielen werden anstelle der Fehlerbehandlungsroutinen des
Pascal-Laufzeitsystems eigene Maßnahmen wirksam.
Mitunter wird aber etwas anderes gewünscht: Die Behandlungsroutinen des
Laufzeitsystems sollen wirksam werden, aber erst nachdem eigene
Maßnahmen durchgeführt worden sind.
Dies kann durch eine erneute Auslösung der eingetretenen Ausnahme
(re-raising an exception) erreicht werden:
RAISE;Beispiel:
TRY
...
EXCEPT
ON ausnahme DO BEGIN
eigene Maßnahmen
RAISE;
END;
END;
Pascal++
Der Anweisungsblock, in dem Ausnahmen abgefangen werden sollen, wird wie folgt notiert:
BEGIN
anweisungsfolge { Normalteil }
HANDLER
ausnahmebehandlung { Ausnahmeteil }
END;
anweisungfolge sind die im Normalfall auszuführenden Anweisungen.
Tritt bei der Abarbeitung einer Anweisung des Normalteils eine Ausnahme ein, so
werden alle nachfolgenden Anweisungen des Normalteils übergangen.
Statt dessen wird in den Ausnahmeteil verzweigt.
Bemerkung:
Die verfügbare Version von Pascal++ erwartet, daß die Anweisung
unmittelbar vor dem END nicht mit einem Semikolon
abschließt.
Die Ausnahmebehandlung darf nicht in einen Zyklus eingebettet werden.
Im Ausnahmeteil kann festgestellt werden, welche Ausnahme ausgelöst wurde. Dazu wird Exception ausgewertet:
IF exception = ausnahme THEN
anweisung
ausnahme ist der Bezeichner einer Variable vom Typ Exception,
die auf die Art der Programmausnahme schließen läßt.
Im Ausnahmeteil kann auf beleibig viele Ausnahmen reagiert werden:
Mit Hilfe einer Mehrfachverzweigung werden die
als eintretbar erachteten Ausnahmesituationen abgetestet.
Beispiel:
PROGRAM trig(OUTPUT);
VAR et : ExceptionType := New(ExceptionType);
FUNCTION trigo(x: REAL): REAL;
VAR y : REAL;
BEGIN
y := Cos(x);
IF Abs(y) < EpsReal THEN CAUSE et;
trigo := 2 * Sin(x) / y;
HANDLER
IF Exception = et THEN BEGIN
Writeln('trigo ist nicht berechenbar');
trigo := 0;
END
END;
CONST pi = 3.14159265358979323846264338327950288;
BEGIN
Writeln(trigo(1.5));
Writeln(trigo(pi/2));
END.
Die Situation, die zu einer Division durch Null führen kann, muß
vom Programm selbst erkannt werden. Eine erfolgte Division durch Null kann
in Pascal++ nicht mehr abgefangen werden.
Bemerkung:
Es ist möglich, daß sich für eine bestimmte Rechnerarithmetik
kein x finden läßt, für das gilt
Cos(x) = 0.
Der Programmierer sollte sich jedoch nicht auf die Ungenauigkeit des Rechners
verlassen !
Außerdem muß bei sehr kleinem Cos(x) mit ungenauen
Ergebnissen gerechnet werden.