Many popular operating systems, including UNIX and MS-DOS, have a feature that
allows the standard input and output files--normally the keyboard and screen,
respectively--to be "redirected" or temporarily reassigned to disk files. This
feature, which is independent of Ada or any other programming language, allows
you, for example, to tell a program that normally gets its input interactively
to get it instead from a given file. Similarly, a program that normally writes
its output to the screen can be told to put all that output in a file instead.
In UNIX or MS-DOS, if you have an Ada program called MyProg
, say,
which uses keyboard Get
calls, executing the operating
system-level command
MyProg < FileOne.datcauses
MyProg
to take all its standard input from
FileOne.dat
instead of the keyboard. (This assumes that
FileOne.dat
has been created and filled with data.) Executing the
command
MyProg < FileOne.dat > FileTwo.datcauses the program, without any change in its source code, to read its input from
FileOne.dat
and write its output to FileTwo.dat
. This
is a handy technique, used in writing many operating system commands. It
doesn't work well if the program is highly interactive, with a lot of
prompting, because the prompts go to the output file while the input comes from
the input file, untouched by human hands! The next case study will show a
program that does not prompt but uses keyboard Get
calls; its
input data can be entered either from the keyboard or by redirection.
Researchers in linguistics or cryptography (the study of secret codes) are often interested in the frequency of occurrence of the various letters in a section of text. A particularly useful way to summarize the number of occurrences is the histogram or bar graph, in which a bar is drawn for each letter, the length of the bar corresponding to the relative frequency of occurrence.
PROBLEM SPECIFICATION
Write a program which draws a histogram for the frequency of occurrence of the letters of the alphabet. Uppercase and lowercase letters are to be counted separately; nonletter characters can be ignored.
ANALYSIS
This program is a variation of the concordance program, Program 8.13, developed in Section 8.9. Instead of getting input as a single line from the terminal, this program will read a text file by using input redirection, compute the number of occurrences of each of the 52 (lower- and uppercase) letters, and draw an appropriately tall vertical bar on the screen for each of the 52 letters. A sample screen dump, produced by running the program with its own source file used as input, is shown in Figure 9.2.
Figure 9.2
Output from Histogram Program for Its Own Source File
Scale: 1 star = 10 occurrences * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * ** ** *** * * * * ** ** *** * * * * ** * ** **** * * * ** * *** ** * *** **** * * * * ** ** * *** ** ***** **** ** * * * ** * *** *** * ********* ***** ******** ****** ** ***** **** * **************************************************** abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
DESIGN
Algorithm
The initial algorithm for this program is
1. Initialize all letter counters to 0.
2. Read the input file character by character. For each character that is a letter, increment the appropriate letter counter.
3. Plot the results on the screen.
We leave it to the student to fill in the algorithm refinements and to develop a test plan.
IMPLEMENTATION
Program 9.4 gives the program for this case study.
Program 9.4
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Screen; PROCEDURE Histogram IS ------------------------------------------------------------------------ --| Plots a histogram on the screen consisting of vertical bars. --| Each bar represents the frequency of occurrence of a given --| alphabet letter in the input file. --| The input file is assumed to be Standard_Input; --| use input redirection if you wish to use a disk file instead. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: November 1995 --| ------------------------------------------------------------------------ SUBTYPE UpperCase IS Character RANGE 'A'..'Z'; SUBTYPE LowerCase IS Character RANGE 'a'..'z'; TYPE Occurrences IS ARRAY(Character RANGE <>) OF integer; Uppers : Occurrences(UpperCase); Lowers : Occurrences(LowerCase); NextCh : Character; Scale : Natural; MaxCount : Natural := 0; WhichCol : Screen.Width; PROCEDURE Plot(WhichCol : Screen.Width; BottomRow : Screen.Depth; HowMany : Screen.Depth; WhichChar : Character) IS -- draws one vertical bar on the screen -- Pre: WhichCol, BottomRow, HowMany, and WhichChar are defined -- Post: draws a bar in column WhichCol, using character WhichChar -- to do the plotting. The bottom of the bar is given by -- BottomRow; the bar contains HowMany characters. BEGIN -- Plot FOR Count IN 0 .. Howmany - 1 LOOP Screen.MoveCursor(Column => WhichCol, Row => BottomRow - Count); Ada.Text_IO.Put(Item => WhichChar); END LOOP; END Plot; BEGIN -- Histogram -- initialize letter-counter arrays Uppers := (OTHERS => 0); Lowers := (OTHERS => 0); -- read each character in the file; update letter counters WHILE NOT Ada.Text_IO.End_Of_File LOOP WHILE NOT Ada.Text_IO.End_Of_Line LOOP Ada.Text_IO.Get(NextCh); CASE NextCh IS WHEN UpperCase => Uppers(NextCh) := Uppers(NextCh) + 1; IF Uppers(NextCh) > MaxCount THEN MaxCount := Uppers(NextCh); END IF; WHEN LowerCase => Lowers(NextCh) := Lowers(NextCh) + 1; IF Lowers(NextCh) > MaxCount THEN MaxCount := Lowers(NextCh); END IF; WHEN OTHERS => NULL; END CASE; END LOOP; Ada.Text_IO.Skip_Line; END LOOP; Scale := MaxCount / 20 + 1; Screen.ClearScreen; Screen.MoveCursor(Row => 1, Column => 15); Ada.Text_IO.Put(Item => "Scale: 1 star = "); Ada.Integer_Text_IO.Put(Item => Scale, Width => 1); Ada.Text_IO.Put(Item => " occurrences"); Screen.MoveCursor(Row => 22, Column => 4); Ada.Text_IO.Put (Item => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); WhichCol := 4; FOR C IN LowerCase LOOP IF Lowers(C) /= 0 THEN Plot(WhichCol, 21, Lowers(C) / scale + 1, '*'); END IF; WhichCol := WhichCol + 1; END LOOP; FOR C IN UpperCase LOOP IF Uppers(C) /= 0 THEN Plot(WhichCol, 21, Uppers(C) / scale + 1, '*'); END IF; WhichCol := WhichCol + 1; END LOOP; Screen.MoveCursor(Row => 24, Column => 1); END Histogram;
Procedure
Plot
takes care of plotting the vertical bars on the screen, from
bottom to top. Its parameters are the column in which the bar is desired, the
bottom row of the column, the height of the column, and the character to be
used for plotting the bar. Screen.MoveCursor
is used to move the
cursor from the bottom of the column to the top, plotting a character at each
point.
The main program counts the occurrences of each letter as was done in the concordance program ( Program 8.13), with one essential difference: A record must be kept of the maximum number of occurrences. This is done because a column can be no more than 20 rows high, so the height of the columns must be scaled to the maximum. For example, if no letter occurs more than 60 times in the file, a 20-row column corresponds to approximately 60 occurrences. Each dot in the column then corresponds roughly to 3 occurrences of that letter; the number of occurrences of each letter, then, is divided by 3 to get the height of the column; 1 is added so that if there are any occurrences at all of a given letter, that column will be at least 1 row tall.
Copy_File
(
Program
9.3) so that redirection is used to get the names of the input and output
files.
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.