One of the first things you will discover in writing programs is that a program often does not run correctly the first time that it is submitted. Murphy`s law, "If something can go wrong, it will," seems to have been written with computer programming in mind. In fact, errors are so common that they have their own special name--bugs--and the process of correcting them is called debugging a program. To alert you to potential problems, a section on common errors appears near the end of many chapters of this book.
There are three basic categories of errors:
When a compilation error is detected, an error message is displayed indicating that you have made a mistake and what the cause of the error might be. Unfortunately, error messages are often difficult to interpret and are sometimes misleading. However, as you gain some experience, you will become more proficient at understanding them.
Positive
variable). When an exception is
raised--that is, when an error occurs--the computer stops executing your
program and a diagnostic message is displayed that sometimes indicates the line
of your program where the exception was raised.
One of the interesting features of Ada is that it provides a way for programmers to predict the occurrence of exceptions and to handle them when they arise. In this manner a programmer can prevent the computer from halting the program. We will return later to the matter of handling exceptions in programs.
Program 2.10 is a modified version of the
distance program,
Program
2.5. The modified program contains errors, which we have purposely put in
for illustrative purposes. First, we ended the first PROCEDURE
line with a semicolon instead of IS
, and second, we garbled the
assignment statement that computes the distance, pretending that we didn't know
an assignment symbol is :=
and that the result variable must be on
the left side of the assignment.
We inserted several other errors as well. We declared How_Fast
as
Float
and also used Ada.Float_Text_IO
calls instead
of Ada.Integer_Text_IO
calls. These are all errors commonly made
by beginners.
Program 2.10
WITH Ada.Text_IO; WITH Ada.Float_Text_IO; PROCEDURE Distance_with_Errors; ------------------------------------------------------------------------ --| Finds distance traveled, given travel time and average speed --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ How_Long : Natural; How_Fast : Float; How_Far : Natural; BEGIN -- Distance_with_Errors -- prompt user for hours and average speed Ada.Text_IO.Put (Item => "How many hours will you be driving (integer) ? "); Ada.Float_Text_IO.Get (Item => How_Long); Ada.Text_IO.Put (Item => "At what average speed (miles per hour, integer) ? "); Ada.Float_Text_IO.Get (Item => How_Fast); -- compute distance driven How_Fast * How_long = How_Far -- display results Ada.Text_IO.Put (Item => "You will travel about "); Ada.Float_Text_IO.Put (Item => How_Far); Ada.Text_IO.Put (Item => " miles"); Ada.Text_IO.New_Line; END Distance_with_Errors;Figure 2.7 shows a compilation listing of the driving-distance program ( Program 2.10) produced by the GNAT compiler on a Sun SPARC system. You can ask the compiler to create a listing during translation. The listing shows each line of the source program (preceded by its line number) and also displays any errors detected by the compiler. You can tell from reading the listing just where the compiler found errors.
Figure 2.7
Compilation Listing with Error Messages
NYU GNAT Compiler Version 2.07 (C) Copyright NYU, 1992,1993,1994,1995 Compiling: distance_with_errors.adb last modified at 95-12-11 13:53.51 GMT. 1. WITH Ada.Text_IO; 2. WITH Ada.Float_Text_IO; 3. PROCEDURE Distance_with_Errors ; | >>> ";" should be "IS" 4. ---------------------------------------------------------------- 5. --| Finds distance traveled, given travel time and average speed 6. --| Author: Michael B. Feldman, The George Washington University 7. --| Last Modified: July 1995 8. ---------------------------------------------------------------- 9. How_Long : Natural; 10. How_Fast : Float; 11. How_Far : Natural; 12. 13. BEGIN -- Distance_with_Errors 14. 15. -- prompt user for hours and average speed 16. Ada.Text_IO.Put 17. (Item => "How many hours will you be driving (integer) ? "); 18. Ada.Float_Text_IO.Get (Item => How_Long); 19. Ada.Text_IO.Put 20. (Item => "At what average speed (miles per hour, integer) ? "); 21. Ada.Float_Text_IO.Get (Item => How_Fast); 22. 23. -- compute distance driven 24. How_Fast * How_long = How_Far | >>> missing ":=" 25. 26. -- display results 27. Ada.Text_IO.Put (Item => "You will travel about "); 28. Ada.Float_Text_IO.Put (Item => How_Far); 29. Ada.Text_IO.Put (Item => " miles"); 30. Ada.Text_IO.New_Line; 31. 32. END Distance_with_Errors; 32 lines:
The
actual format of the listing and error messages produced by your compiler may
differ from
Fig.
2.7. In this listing whenever an error is detected, the compiler prints a
line starting with >>>.
A vertical line (|
)
points to the position in the preceding line where the error was detected. This
is usually, but not always, where the error occurred. The error is explained on
the next line.
To see how a compiler listing works, look at the first error reported. The compiler caught the misplaced semicolon and also the garbled assignment statement but did not notice the use of the wrong input/output package, or the improperly declared variable.
This is because this particular compiler first finds all errors in use of the syntax or grammar, that is, the punctuation and spelling rules. Often if there are grammatical errors, the compiler goes no further.
Figure 2.8
NYU GNAT Compiler Version 2.07 (C) Copyright NYU, 1992,1993,1994,1995 Compiling: distance_with_errors.adb last modified at 95-12-11 14:01.02 GMT. 1. WITH Ada.Text_IO; 2. WITH Ada.Float_Text_IO; 3. PROCEDURE Distance_with_Errors IS 4. ------------------------------------------------------------------ 5. --| Finds distance traveled, given travel time and average speed 6. --| Author: Michael B. Feldman, The George Washington University 7. --| Last Modified: July 1995 8. ------------------------------------------------------------------ 9. How_Long : Natural; 10. How_Fast : Float; 11. How_Far : Natural; 12. 13. BEGIN -- Distance_with_Errors 14. 15. -- prompt user for hours and average speed 16. Ada.Text_IO.Put 17. (Item => "How many hours will you be driving (integer) ? "); 18. Ada.Float_Text_IO.Get (Item => How_Long); | >>> invalid parameter list in call 19. Ada.Text_IO.Put 20. (Item => "At what average speed (miles per hour, integer) ? "); 21. Ada.Float_Text_IO.Get (Item => How_Fast); 22. 23. -- compute distance driven 24. How_Far := How_Fast * How_long; | >>> invalid operand types for operator "*" 25. 26. -- display results 27. Ada.Text_IO.Put (Item => "You will travel about "); 28. Ada.Float_Text_IO.Put (Item => How_Far); | >>> invalid parameter list in call >>> possible missing instantiation of Text_IO.Integer_IO 29. Ada.Text_IO.Put (Item => " miles"); 30. Ada.Text_IO.New_Line; 31. 32. END Distance_with_Errors; 32 lines:
The
error messages in lines 3 and 24 did not re-appear because we corrected those
errors. This time, the compiler caught the remaining errors, which are not
grammatical but semantic or usage errors. The first message, at
line 18, informs us that the Item
parameter to Get
is
invalid, in this case because we tried to use the floating-point
Get
to read into an Integer
variable. The same
message appears at line 24, for the same reason. Finally, the message at line
28 indicates that the multiplication is invalid, because we are trying to
multiply a Float
variable (the incorrectly declared
How_Fast
) by a Natural
one (How_Long
).
As we learned in Section 2.10, such mixing of integer and floating-point values
is not allowed.
It is often hard to interpret error messages, but it gets easier as your experience increases. Also, sometimes you have made a certain error but the compiler interprets it as something entirely different. Remember, the compiler is only a computer program and is not as good a detective as you are!
One compilation error often leads to the generation of a number of error messages. (These "extra" errors are often called propagation errors.) For this reason, it is often a good idea to concentrate first on correcting the errors in the declaration part of a program and then to recompile, rather than to attempt to fix all the errors at once.
Many later errors will disappear once the declarations are correct. An
undefined variable
error occurs if the compiler cannot find the
declaration for an identifier referenced in the program body. This can happen
because you omitted the declaration or misspelled the identifier. It can also
happen if you forget to supply a WITH
for a package needed by the
program.
Programmers who are just learning to write Ada programs often forget to write
IS
and to insert semicolons in the required places. These are two
of the most common compilation errors made by beginners, and unfortunately they
are also errors which sometimes confuse the compiler hopelessly. Leaving out an
IS
or a semicolon, or using one where the other is expected, can
often lead to an entire sequence of messages (propagation errors), which will
all disappear when the original error is corrected. A word to the wise is
sufficient!
Another common Ada compilation error is the confusion of single and double quotation marks. You must remember that a string literal in Ada is surrounded by double quotation marks, but a single character literal must be surrounded by single quotation marks.
As we have seen, compilation errors are generally of two kinds: syntax errors and semantic errors. Some Ada compilers distinguish between these in their error messages; others do not. Some compilers try to find both syntactic and semantic errors at the same time; others do it in two stages, as we saw here.
In languages like Ada with data types, semantic errors occur quite frequently.
One of the things you will need to be careful about is making sure that the
types of your variables match the expectation of the expression or procedure in
which the variables are used. If a procedure expects an Integer
variable, supplying a Float
variable won't do; also, you cannot
mix Integer
and Float
variables in the same
expression!
Finally, there is no need to panic at getting a long list of messages; it happens to all new programmmers and occasionally to experienced ones as well. There are probably only a few actual errors and many extra messages because of propagation, or because you repeated the error in several places, so it's best just to try to correct the first one or two errors, then recompile. You'll be amazed at how quickly the number of messages decreases.
As discussed above, run-time errors are called exceptions in Ada.
The most common exceptions encountered by beginners are those relating to the
ranges of variables in their programs. A range error occurs when a program
tries to save an inappropriate value in a variable. This can happen in one of
two ways: Either the program itself computes a result that is out of range for
the variable in which it will be saved, or the program user enters an
out-of-range value from the keyboard. Ada gives the name
Constraint_Error
to such a range error; Ada uses the term
raising an exception for reporting the occurrence of such a runtime
error.
As an example of the second case, consider case 5 of the test plan for the coin
collection program (
Program
2.9,
Table
2.5).
Figure
2.9 shows a sample run in which we enter a negative value for the number of
pennies. Recall that the variable Pennies
was declared to be of
type Natural
, that is, nonnegative.
Figure 2.9
Sample Run of Coin_Collection
, Negative Input Entered
How many nickels do you have? 13 How many pennies do you have? -5 raised Constraint_Error Trace Back Information Program Name File Name Line ------------ --------- ---- coin_collection coin_collection.adb 17The form of the exception report and "trace back" to your source program varies from compiler to compiler, but the content is the same: You are told which exception was raised and where.
Figure 2.10 shows the results of test case 6, in which "bad" input is entered, namely, a sequence of characters that cannot be an integer token.
Figure 2.10
Sample Run of Coin_Collection
, Noninteger Input Entered
How many nickels do you have? xyz raised unhandled exception ***Exception ada.io_exceptions.data_error Raised Trace Back Information Program Name File Name Line ------------ --------- ---- coin_collection coin_collection.adb 15In this case, the exception raised is an input/output exception called
Data_Error
. This exception is raised when a Get
operation gets a token of the wrong form, in this case a string of letters
instead of an integer. The difference between Constraint_Error
and Data_Error
is that in the former case the value is formed
correctly but is too large or too small, while in the latter case the token is
not formed properly.To summarize, Ada's data types and exception system are designed to help you write programs whose results will make sense. In this book we will pay very careful attention to this matter, because it is important and can be very useful to you.
Debugging a program can be time-consuming. The best approach is to plan your programs carefully and desk check them beforehand to eliminate bugs before they occur. If you are not sure of the syntax for a particular statement, look it up in the syntax displays in the text or in Appendix B. Also, take care that your program variables have types that are appropriate and sensible. If you follow this approach, you will save yourself much time and trouble.
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.