Programmiersprache Pascal

Behandlung einer Ausnahme

Standard Pascal, Extended Pascal

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.
e bezeichnet eine Instanz dieses Types.
anweisung ist eine einzelne Anweisung oder eine Verbundanweisung, die ausgeführt wird, wenn im Normalteil die Ausnahme ausnahme ausgelöst wurde. Es kann dabei Bezug auf e genommen werden. Beispiel:
  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.
(Es gibt oft mehr Ausnahmemöglichkeiten als der Programmierer vermutet ...)

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.
Tritt bei der Berechnung des Funktionswertes ein Fehler auf, z.B. eine Division durch Null bei Cos(x) = 0, so wird eine geeignetere Fehlermeldung abgesetzt.

Beispiel 2:

  USES SysUtils;

  FUNCTION anteil(ist, soll: INTEGER) : REAL;
  BEGIN
    TRY
      anteil := ist / soll;
    EXCEPT
      ON EZeroDivide DO 
        anteil := 0;
    END;
  END;
Bemerkung:
Die obige Funktion berücksichtigt nicht alle Eventualitäten: Werden sowohl soll als auch ist mit Null belegt, so tritt eine andere Ausnahme ein: EInvalidOp.
Eine bessere Lösung ist deshalb
  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: Erneute Auslösung einer Ausnahme

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.
anweisung ist eine einzelne Anweisung, die ausgeführt wird, wenn im Normalteil die Ausnahme ausnahme ausgelöst wurde.

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.



P. Böhme, 28.08.1996