next up previous
Next: About this document Up: No Title Previous: No Title

Chapter 8. Sequencers, Escapes and Exceptions

Sequencers

In this chapter we study several kinds of sequencer:

Jumps

Most programming language control structures (e.g., a sequential, conditional (if-then-else), or iterative command) have the flowcharts with a single-entry and a single-exit.

if E then C1 else C2 

        -------------------
        |                 |
        |     true        |
   ------> E --->  C1 ---------->              
        |  |           |  |
        |   -----> C2 -   |
        |     false       |
        |                 |
        -------------------

while E do C 

        ----------------------
        |                    |
        |        false       |
   ---------> E ------------------>
        | |   |              |
        | |    ------> C     |
        | |      true  |     |
        |  <-----------      |
        ----------------------

It is ``easy'' to follow the flow-of-control when these structures are ``plugged-together''. While all structured control constructs can be implemented with a disciplined use of gotos, undisciplined use of goto's make reasoning about programs more difficult because they allow multiple entry/exit from program blocks.

Jump appears in many programming languages, typically in the form "goto label" .

Consider the following program fagment:

 begin
  if E1 then C1
     else begin C2;
          goto L
          end;
  while E2 do
     begin
           C4;
  L:       C5:
     end
  end

Escape

while (not eof()) {
    
   if (ch == 'q') break;
}
The control flow diagram is the following. 

        ----------------------
        |                    |
        |        false       |
   ---------> E ------------------>
        | |   |              |  |
        | |    ------> C--------   
        | |      true  |     |
        |  <-----------      |
        ----------------------

The C break statement can only exit the containing block, so if we had two nested loop with the break in the inner loop, it couldn't exit from both loops.

In a function, a return can act as a general escape (leave the function now).

while (...) {
  while (...) {
    
   if (ch == 'q') return;  /* exit both loops */
  }
}

The most drastic of all is to ``halt'' the entire program. In C, we can do this with an exit() function call.

while (...) {
  while (...) {
    
   if (error) exit(return_code);  /* exit program */
  }
}

Exceptions

     arithmetic, e.g., division-by-zero 
     arrays, e.g., out-of-bounds 
     I/O, e.g., can't open file

When the condition happens, an exception is raised or signaled, there are machine code instructions that raise the exception. Some languages have no capabilities for handling exceptions. What happens when we try to divide by zero in Pascal? In C?

  x = 0;
  z = y / x;  /* error division by zero --> core dump */

Other languages provide exception handlers. PL/1 was the first major language to provide exception handlers.

Java provides exception handlers with the try-catch statement.

 try {
    x = 0;
    z = y / x;  
    x = z;  // control returns to this statement after the exception.
 } catch (dividebyzero) {
   System.out.println("Warning, tried to divide-by-zero,am continuing");
   z = 0;
 }

Exceptions are especially nice in I/O. Consider the standard act of opening a file and reading data into memory. There are lots of exceptions (or errors) to handle.

    readFile {
               try {
                   open the file;
                   determine its size;
                   allocate that much memory;
                   read the file into memory;
                   close the file;
               } catch (fileOpenFailed) {
                   doSomething;
               } catch (sizeDeterminationFailed) {
                   doSomething;
               } catch (memoryAllocationFailed) {
                   doSomething;
               } catch (readFailed) {
                   doSomething;
               } catch (fileCloseFailed) {
                   doSomething;
               }
           }

Note that the catch statements scans for particular kinds of errors. The alternative is to write code like this.

 errorCodeType readFile {
     initialize errorCode = 0;
     open the file;
       if(theFileIsOpen) {
         determine the length of the file;
           if (gotTheFileLength) {
              allocate that much memory;
              if (gotEnoughMemory) {
                read the file into memory;
                if (readFailed) {
                   errorCode = -1;
                }
              } else {
                      errorCode = -2;
                }
           } else {
                   errorCode = -3;
             }
       close the file;
         if(theFileDidntClose &&errorCode ==0)
         {
            errorCode = -4;
         } else {
             errorCode = errorCode and -4;
           }
       } else {
              errorCode = -5;
        }
        return errorCode;
  }

But this code is very bloated, and it is unclear as to what is actually going on.

What happens if we call a method inside of a try statement, but detect errors in that method? A method may propagate exceptions to callees (up the call stack).

 
 method1 {
     try {
         call method2;
     } catch (exception) {
          doErrorProcessing;
       }
  }
  method2 throws exception {
      call method3;
  }
  method3 throws exception {
      call readFile;
 }

Exception handling in Java

Java Exception classes hierarchy, whose root class is java.lang.Exception, is divided into two groups of classes which are treated differently by the Java language. Firstly there is the java.lang. Runtime Exception class and all the classes which are derived from it; and secondly all other classes descended from java.lang.Exception.

 
Object
  |--Throwable               
        |--Exception         
            |                     |--..
            |--RuntimeException --|--..
            |                     |--..
            |--io.IOException
                |--EOFException 
                |--FileNotFoundException 
                |--InterruptedIOException
                |--ObjectStreamException 
                |--java.rmi.RemoteException..

All exceptions are 'objects' generated from one of above classes, and thrown from an error or exception source. The exception handling program must 'catch' these exception objects to process them.

try-catch-finally statement

 
 try {
   statements; 
  //Normal program, possibly generate exception
 }
 catch(Throwable-subclass e){
   statements;  // exception handling codes
 }
 ....
  finally{
    statements; 
            //these will always be executed.
 }

It is possible to have several catch sub-statement. Sequentially look for the next to use, until exception type matches (consistent) The exception is 'thrown' out to the caller, if the called program cannot catch the error. If user does not catch the error, then Java exception handler catches it, and stops the program.

Example

 
class BadString {
 public static void main(String args[]){
    String name=null;
  try{
    if (name.equals("John"))
      System.out.println("Name is "+name);
    }
    catch(ArithmeticException e){
     System.out.println("ArithmeticException!");
    }
    catch(NullPointerException e){
     System.out.println("NullPointerException!");
   }
  }
}
The result: NullPointerException!
Can also replace the 2nd catch statement by:
      catch(Exception e) { System.out ...}

What's the problem here?

Consider program segment:

 
   try {
      do something;
   }
   catch(Exception e) {}
   catch(NullPointerException){}  
                    \\not reachable

Java compiler tells you this is wrong.

Another Example

 
class Example{
  public static void main(String args[]){
   try{
     int x=0;
     int y=20;
     int z=y/x;
    System.out.println("The value of y/x is: "+z);
    }
   catch(ArithmeticException e){
     System.out.println("Caught ArithmeticException");
    }
    finally
    {
     System.out.println("Executing finally clause.");
     try{
        String name=null;
        if(name.equals("Tom")){
          System.out.println("My name is Tom.");}
        }
        catch(Exception e){
          System.out.println("Caught another exception");
        }
        finally{
          System.out.println("Executing finally clause again.");
        }
       }
     }
 }      // will trace this in class

Use finally together with break/continue/return

 
class example{
  public static void main(String args[]){
    while(true){
     try{
       System.out.println("Want to leave the try block");
       break;
     }
     finally{
       System.out.println("Must do this before leaving");
     }
    }
  }
}
Output: Want to leave the try block
        Must do this before leaving
Similarly, for continue and return.



next up previous
Next: About this document Up: No Title Previous: No Title

Jinli Cao
Tue Sep 22 21:45:39 EST 1998