home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
ada
/
bd3.arc
/
BD3.LST
< prev
next >
Wrap
File List
|
1989-03-12
|
22KB
|
541 lines
1 package BANK is
2 ------------------------------------------------------------------------
3 --| BEGIN PROLOGUE
4 --| DESCRIPTION : BANK defines a bank, the TELLER objects
5 --| : within it, and the procedure PRINT_REPORT
6 --| : (which reports on the status of the BANK).
7 --| :
8 --| : BANK is an abstract state machine, defining
9 --| : a BANK object which contains TELLER objects.
10 --| :
11 --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
12 --| : object-oriented design and tasking
13 --| : with Ada
14 --| :
15 --| LIMITATIONS : None
16 --| AUTHOR(S) : Richard Conn (RLC)
17 --| CHANGE LOG : 1/16/89 RLC Initial Design and Code
18 --| CHANGE LOG : 2/25/89 RLC Final Review Prior to Release
19 --| REMARKS : None
20 --| PORTABILITY ISSUES : None
21 --| END PROLOGUE
22 ------------------------------------------------------------------------
23
24 -- TRANSACTION requested of a TELLER
25 type TRANSACTION is (ADD_NEW_CUSTOMER,
26 GET_BALANCE,
27 MAKE_DEPOSIT,
28 MAKE_WITHDRAWAL);
29
30 -- Unit of currency
31 type DOLLAR is new FLOAT;
32
33 -- Identification of a CUSTOMER
34 type CUSTOMER_ID is new NATURAL range 1 .. NATURAL'LAST;
35
36 -- Index of and Number of TELLER objects within the bank
37 type TELLER_INDEX is new NATURAL range 1 .. 4;
38
39 -- A TELLER_PERSON is an object to which a CUSTOMER may make a REQUEST
40 -- The BANK tells the TELLER_PERSON to START_WORK, giving the
41 -- TELLER_PERSON its TELLER_NUMBER
42 task type TELLER_PERSON is
43 entry REQUEST(ID : in out CUSTOMER_ID;
44 KIND : in TRANSACTION;
45 AMOUNT : in out DOLLAR);
46 end TELLER_PERSON;
47 -- These are the TELLER objects available at the bank
48 TELLER : array(TELLER_INDEX) of TELLER_PERSON;
49
50 -- PRINT_REPORT gives the transaction log of all the bank
51 -- customers
52 procedure PRINT_REPORT;
53
54 -- STOP_WORK terminates all TELLER tasks
55 procedure STOP_WORK;
56 end BANK;
57 --
58 with CONSOLE;
59 package body BANK is
60 ------------------------------------------------------------------------
61 --| BEGIN PROLOGUE
62 --| DESCRIPTION : Package Body BANK implements the TELLER
63 --| : tasks and the PRINT_REPORT procedure.
64 --| : CUSTOMER data is maintained within the
65 --| : BANK as a linked list.
66 --| :
67 --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
68 --| : object-oriented design and tasking
69 --| : with Ada
70 --| :
71 --| LIMITATIONS : None
72 --| AUTHOR(S) : Richard Conn (RLC)
73 --| CHANGE LOG : 1/16/89 RLC Initial Design and Code
74 --| CHANGE LOG : 2/25/89 RLC Final Review Prior to Release
75 --| REMARKS : None
76 --| PORTABILITY ISSUES : Uses CONSOLE (TEXT_IO), so is very portable;
77 --| : no known portability problems.
78 --| END PROLOGUE
79 ------------------------------------------------------------------------
80
81 -- Identifier of next customer
82 NEXT_ID : CUSTOMER_ID := CUSTOMER_ID'FIRST;
83
84 -- Linked list of customer data
85 type CUSTOMER_DATA;
86 type CUSTOMER_DATA_POINTER is access CUSTOMER_DATA;
87 type CUSTOMER_DATA is record
88 ID : CUSTOMER_ID;
89 BALANCE : DOLLAR := 0.0;
90 TRANSACTION_COUNT : NATURAL := 0;
91 ATTEMPTED_OVERDRAWS : NATURAL := 0;
92 NEXT : CUSTOMER_DATA_POINTER := null;
93 end record;
94
95 -- Count of number of transactions for each TELLER object
96 TELLER_TRANSACTION_COUNT : array(TELLER_INDEX) of NATURAL
97 := (others => 0);
98
99 -- Pointers to first and last customer data entries
100 FIRST_CUSTOMER : CUSTOMER_DATA_POINTER := null;
101 LAST_CUSTOMER : CUSTOMER_DATA_POINTER := null;
102
103 --
104 -- package body BANK
105 -- Print a report of the status of the BANK
106 procedure PRINT_REPORT is
107 CURRENT_CUSTOMER : CUSTOMER_DATA_POINTER;
108 begin
109
110 -- Check for any customers and issue an error message if none
111 if NEXT_ID = CUSTOMER_ID'FIRST then
112 CONSOLE.WRITE("The bank doesn't have any customers");
113 CONSOLE.WRITE(CONSOLE.NEW_LINE);
114
115 -- Generate report
116 else
117
118 -- Customer balance, transaction count, attempted overdraw
119 -- count report
120 CONSOLE.WRITE("**** BANK STATUS REPORT ****");
121 CONSOLE.WRITE(CONSOLE.NEW_LINE);
122 CONSOLE.WRITE(
123 "Customer Balance Transactions Attempted_Overdraws");
124 CONSOLE.WRITE(CONSOLE.NEW_LINE);
125 CURRENT_CUSTOMER := FIRST_CUSTOMER;
126 while CURRENT_CUSTOMER /= null loop
127 CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.ID), 5);
128 CONSOLE.WRITE(" ");
129 CONSOLE.WRITE(FLOAT(CURRENT_CUSTOMER.BALANCE), 8, 2);
130 CONSOLE.WRITE(" ");
131 CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.TRANSACTION_COUNT), 8);
132 CONSOLE.WRITE(" ");
133 CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.ATTEMPTED_OVERDRAWS),
134 8);
135 CONSOLE.WRITE(CONSOLE.NEW_LINE);
136 CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
137 end loop;
138 CONSOLE.WRITE(CONSOLE.NEW_LINE);
139
140 -- Teller transaction count report
141 CONSOLE.WRITE("Teller : ");
142 for I in TELLER_INDEX loop
143 CONSOLE.WRITE(INTEGER(I), 8);
144 end loop;
145 CONSOLE.WRITE(CONSOLE.NEW_LINE);
146 CONSOLE.WRITE("Transaction_Count: ");
147 for I in TELLER_INDEX loop
148 CONSOLE.WRITE(INTEGER(TELLER_TRANSACTION_COUNT(I)), 8);
149 end loop;
150 CONSOLE.WRITE(CONSOLE.NEW_LINE);
151
152 end if;
153 end PRINT_REPORT;
154
155 -- Terminate all TELLER tasks
156 procedure STOP_WORK is
157 begin
158 for I in TELLER_INDEX loop
159 abort TELLER(I);
160 end loop;
161 end STOP_WORK;
162 --
163 -- package body BANK
164
165 -- FIND_CUSTOMER is used to find a CUSTOMER_DATA record
166 -- based on a CUSTOMER_ID number
167 function FIND_CUSTOMER(ID : in CUSTOMER_ID)
168 return CUSTOMER_DATA_POINTER is
169 CURRENT_CUSTOMER : CUSTOMER_DATA_POINTER;
170 begin
171 CURRENT_CUSTOMER := FIRST_CUSTOMER;
172 while CURRENT_CUSTOMER /= null loop
173 exit when CURRENT_CUSTOMER.ID = ID;
174 CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
175 end loop;
176 return CURRENT_CUSTOMER;
177 end FIND_CUSTOMER;
178
179
180 --
181 -- package body BANK
182
183 task TELLER_ASSIGNER is
184 -- This task assigns an ID number to a teller.
185 -- TELLER_ASSIGNER is called by the TELLER_PERSON task when the
186 -- TELLER_PERSON task first starts up.
187 entry GET_TELLER_ID(ID : out TELLER_INDEX);
188 end TELLER_ASSIGNER;
189
190 task body TELLER_ASSIGNER is
191 NEXT_TELLER_ID : TELLER_INDEX := TELLER_INDEX'FIRST;
192 begin
193 loop
194 accept GET_TELLER_ID(ID : out TELLER_INDEX) do
195 ID := NEXT_TELLER_ID;
196 if NEXT_TELLER_ID /= TELLER_INDEX'LAST then
197 NEXT_TELLER_ID := NEXT_TELLER_ID + 1;
198 end if;
199 end GET_TELLER_ID;
200 end loop;
201 end TELLER_ASSIGNER;
202
203 --
204 -- package body BANK
205
206 -- Implementation of a TELLER task
207 task body TELLER_PERSON is
208
209 THIS_CUSTOMER : CUSTOMER_DATA_POINTER;
210 MY_NUMBER : TELLER_INDEX;
211
212 begin
213
214 -- TELLER gets his ID number
215 TELLER_ASSIGNER.GET_TELLER_ID(MY_NUMBER);
216
217 -- TELLER loops on REQUESTs from CUSTOMERs
218 loop
219 accept REQUEST(ID : in out CUSTOMER_ID;
220 KIND : in TRANSACTION;
221 AMOUNT : in out DOLLAR) do
222
223 -- Increment teller's transaction count
224 TELLER_TRANSACTION_COUNT(MY_NUMBER)
225 := TELLER_TRANSACTION_COUNT(MY_NUMBER) + 1;
226
227 --
228 -- package body BANK
229
230 -- Process REQUEST
231 case KIND is
232
233 when ADD_NEW_CUSTOMER =>
234 if LAST_CUSTOMER = null then
235 LAST_CUSTOMER := new CUSTOMER_DATA;
236 FIRST_CUSTOMER := LAST_CUSTOMER;
237 else
238 LAST_CUSTOMER.NEXT := new CUSTOMER_DATA;
239 LAST_CUSTOMER := LAST_CUSTOMER.NEXT;
240 end if;
241 LAST_CUSTOMER.ID := NEXT_ID;
242 ID := NEXT_ID;
243 NEXT_ID := NEXT_ID + 1;
244 THIS_CUSTOMER := LAST_CUSTOMER;
245
246 when GET_BALANCE =>
247 THIS_CUSTOMER := FIND_CUSTOMER(ID);
248 AMOUNT := THIS_CUSTOMER.BALANCE;
249
250 when MAKE_DEPOSIT =>
251 THIS_CUSTOMER := FIND_CUSTOMER(ID);
252 THIS_CUSTOMER.BALANCE
253 := THIS_CUSTOMER.BALANCE + AMOUNT;
254 AMOUNT := THIS_CUSTOMER.BALANCE;
255
256 when MAKE_WITHDRAWAL =>
257 THIS_CUSTOMER := FIND_CUSTOMER(ID);
258 if THIS_CUSTOMER.BALANCE < AMOUNT then
259 AMOUNT := 0.0;
260 THIS_CUSTOMER.ATTEMPTED_OVERDRAWS :=
261 THIS_CUSTOMER.ATTEMPTED_OVERDRAWS + 1;
262 else
263 THIS_CUSTOMER.BALANCE
264 := THIS_CUSTOMER.BALANCE - AMOUNT;
265 end if;
266
267 end case;
268
269 -- Increment CUSTOMER's transaction count
270 THIS_CUSTOMER.TRANSACTION_COUNT
271 := THIS_CUSTOMER.TRANSACTION_COUNT + 1;
272
273 end REQUEST;
274
275 end loop;
276
277 end TELLER_PERSON;
278
279 end BANK;
280
281 --
282 package CUSTOMER_WORLD is
283 ------------------------------------------------------------------------
284 --| BEGIN PROLOGUE
285 --| DESCRIPTION : CUSTOMER_WORLD is an abstract state machine
286 --| : which defines the collection of all CUSTOMERs
287 --| : of the BANK. It allows the mainline procedure
288 --| : to ADD a new CUSTOMER and TERMINATE_ALL
289 --| : current CUSTOMERs. The CUSTOMER itself acts
290 --| : as an independent task and requires no
291 --| : direct interaction with the mainline once
292 --| : it starts.
293 --| :
294 --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
295 --| : object-oriented design and tasking
296 --| : with Ada
297 --| :
298 --| LIMITATIONS : None
299 --| AUTHOR(S) : Richard Conn (RLC)
300 --| CHANGE LOG : 1/16/89 RLC Initial Design and Code
301 --| CHANGE LOG : 2/25/89 RLC Final Review Prior to Release
302 --| REMARKS : None
303 --| PORTABILITY ISSUES : None
304 --| END PROLOGUE
305 ------------------------------------------------------------------------
306
307 -- Add another CUSTOMER task to the system
308 procedure ADD;
309
310 -- Terminate all CUSTOMERs in the system
311 procedure TERMINATE_ALL;
312
313 end CUSTOMER_WORLD;
314
315 --
316 with BANK;
317 with RANDOM;
318 package body CUSTOMER_WORLD is
319
320 -- Support infix operations, like DOLLAR < DOLLAR
321 use BANK;
322
323 -- This is the amount that a CUSTOMER initially deposits
324 -- into his account
325 INITIAL_DEPOSIT : constant BANK.DOLLAR := 100.0;
326
327 -- A CUSTOMER is a task, running concurrently with the TELLERs,
328 -- other CUSTOMERs, and the mainline task
329 task type CUSTOMER;
330
331 -- CUSTOMER_POINTER is a pointer to a CUSTOMER, used to
332 -- create new customers and track old customers in the linked
333 -- list of customers used for task termination when the
334 -- program is complete
335 type CUSTOMER_POINTER is access CUSTOMER;
336
337 -- These are the constructs used to create a linked list of
338 -- the customers
339 type CUSTOMER_LIST_ELEMENT;
340 type CUSTOMER_LIST_ELEMENT_POINTER is access CUSTOMER_LIST_ELEMENT;
341 type CUSTOMER_LIST_ELEMENT is record
342 THIS_CUSTOMER : CUSTOMER_POINTER;
343 NEXT : CUSTOMER_LIST_ELEMENT_POINTER := null;
344 end record;
345
346 -- Pointer to the first of the customers
347 FIRST_CUSTOMER : CUSTOMER_LIST_ELEMENT_POINTER := null;
348 LAST_CUSTOMER : CUSTOMER_LIST_ELEMENT_POINTER := null;
349
350 --
351 -- package body CUSTOMER_WORLD
352
353 -- Implementation of the CUSTOMER task
354 task body CUSTOMER is
355
356 ID : BANK.CUSTOMER_ID := BANK.CUSTOMER_ID'FIRST;
357 BALANCE : BANK.DOLLAR := 0.0;
358 AMOUNT : BANK.DOLLAR := 0.0;
359 MY_TRANSACTION : BANK.TRANSACTION;
360
361 -- SELECT_TELLER makes a random selection of one of the
362 -- BANK's tellers
363 function SELECT_TELLER return BANK.TELLER_INDEX is
364 begin
365 return BANK.TELLER_INDEX(
366 RANDOM.NUMBER * FLOAT(BANK.TELLER_INDEX'LAST) + 1.0);
367 exception
368 when others =>
369 return BANK.TELLER_INDEX'LAST;
370 end SELECT_TELLER;
371
372 begin -- CUSTOMER activity
373
374 -- As a new CUSTOMER, the first two transactions of the
375 -- CUSTOMER are to ask the TELLER to add him as a new
376 -- CUSTOMER and make an initial deposit
377 BANK.TELLER(SELECT_TELLER).REQUEST(ID, BANK.ADD_NEW_CUSTOMER,
378 BALANCE);
379 BALANCE := INITIAL_DEPOSIT;
380 BANK.TELLER(SELECT_TELLER).REQUEST(ID, BANK.MAKE_DEPOSIT, BALANCE);
381
382 -- The rest of the life of the CUSTOMER is spent in the
383 -- these steps within the following loop:
384 -- (1) delay a random amount of time from 0 to 5 seconds
385 -- (2) compute a random amount from -$50 to +$50
386 -- (3) if the random amount is negative, attempt to
387 -- withdraw that amount; if positive, deposit that
388 -- amount
389 loop
390 delay DURATION(5.0 * RANDOM.NUMBER);
391 AMOUNT := BANK.DOLLAR(100.0 * RANDOM.NUMBER - 50.0);
392 if AMOUNT < DOLLAR'(0.0) then
393 MY_TRANSACTION := BANK.MAKE_WITHDRAWAL;
394 AMOUNT := -AMOUNT;
395 else
396 MY_TRANSACTION := BANK.MAKE_DEPOSIT;
397 end if;
398 BANK.TELLER(SELECT_TELLER).REQUEST(ID, MY_TRANSACTION, AMOUNT);
399 end loop;
400
401 end CUSTOMER;
402
403 --
404 -- package body CUSTOMER_WORLD
405
406 -- Add a new CUSTOMER to the linked list
407 procedure ADD is
408 begin
409
410 -- If the list is empty, start a new list
411 if LAST_CUSTOMER = null then
412 FIRST_CUSTOMER := new CUSTOMER_LIST_ELEMENT;
413 LAST_CUSTOMER := FIRST_CUSTOMER;
414
415 -- If the list is not empty, add an element onto it
416 else
417 LAST_CUSTOMER.NEXT := new CUSTOMER_LIST_ELEMENT;
418 LAST_CUSTOMER := LAST_CUSTOMER.NEXT;
419 end if;
420
421 -- Start a new CUSTOMER task
422 LAST_CUSTOMER.THIS_CUSTOMER := new CUSTOMER;
423
424 end ADD;
425
426 -- Terminate all CUSTOMER tasks by moving thru the linked list
427 -- and explicitly terminating the tasks pointed to by the list
428 -- elements.
429 procedure TERMINATE_ALL is
430 CURRENT_CUSTOMER : CUSTOMER_LIST_ELEMENT_POINTER;
431 begin
432 CURRENT_CUSTOMER := FIRST_CUSTOMER;
433 while CURRENT_CUSTOMER /= null loop
434 abort CURRENT_CUSTOMER.THIS_CUSTOMER.all;
435 CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
436 end loop;
437 end TERMINATE_ALL;
438
439 end CUSTOMER_WORLD;
440
441 --
442 with BANK;
443 with CUSTOMER_WORLD;
444 with CONSOLE;
445 procedure BD3 is -- BANK_DEMO_3
446 ------------------------------------------------------------------------
447 --| BEGIN PROLOGUE
448 --| DESCRIPTION : Procedure BD3 (BANK DEMO 3) is a mainline
449 --| : which demonstrates the operation of the
450 --| : BANK. Upon invocation, the console becomes
451 --| : a command processor for the bank manager.
452 --| : The bank manager can obtain the status of
453 --| : the bank (balances, number of transactions,
454 --| : and attempted overdraws of all customers
455 --| : and number of transactions processed by all
456 --| : tellers) in a single or continuous (group
457 --| : of 11 over about one minute) display.
458 --| : The user at the console can also cause new
459 --| : Customer tasks to be created and shut down
460 --| : the system.
461 --| :
462 --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
463 --| : object-oriented design and tasking
464 --| : with Ada
465 --| :
466 --| LIMITATIONS : None
467 --| AUTHOR(S) : Richard Conn (RLC)
468 --| CHANGE LOG : 1/16/89 RLC Initial Design and Code
469 --| CHANGE LOG : 2/25/89 RLC Final Review Prior to Release
470 --| REMARKS : None
471 --| PORTABILITY ISSUES : Uses CONSOLE (TEXT_IO), so is very portable;
472 --| : no known portability problems.
473 --| END PROLOGUE
474 ------------------------------------------------------------------------
475
476 -- Line input from the console
477 INPUT : CONSOLE.OUTSTRING;
478
479 -- Number of continuous status reports displayed by the 'c'
480 -- command before control is returned to the console
481 NUMBER_OF_CONTINUOUS_STATUS_REPORTS : constant := 10;
482
483 --
484 -- procedure BD3
485
486 begin -- mainline
487
488 -- This is the beginning of the main loop. In this loop,
489 -- a list of commands is printed on the console, the user
490 -- at the console (as CUSTOMER 0) enters one of these commands
491 -- followed by striking the RETURN key, and the command is
492 -- processed.
493 loop
494
495 -- Command listing and prompt
496 CONSOLE.WRITE("Enter");
497 CONSOLE.WRITE(CONSOLE.NEW_LINE);
498 CONSOLE.WRITE(" b for bank status");
499 CONSOLE.WRITE(CONSOLE.NEW_LINE);
500 CONSOLE.WRITE(" c for continuous bank status");
501 CONSOLE.WRITE(CONSOLE.NEW_LINE);
502 CONSOLE.WRITE(" s for start next customer");
503 CONSOLE.WRITE(CONSOLE.NEW_LINE);
504 CONSOLE.WRITE(" x for exit: ");
505 CONSOLE.READ(INPUT);
506
507 -- Interpretation and execution of input command
508 case INPUT(1) is
509 when 'b' | 'c' => -- Short or continuous bank status
510 -- report
511 BANK.PRINT_REPORT;
512 if INPUT(1) = 'c' then
513 for I in 1 .. NUMBER_OF_CONTINUOUS_STATUS_REPORTS loop
514 delay 5.0;
515 BANK.PRINT_REPORT;
516 CONSOLE.WRITE(CONSOLE.NEW_LINE);
517 end loop;
518 end if;
519
520 when 's' => -- Start up a new CUSTOMER
521 CUSTOMER_WORLD.ADD;
522
523 when 'x' => -- Exit program
524 CUSTOMER_WORLD.TERMINATE_ALL; -- Kill CUSTOMER tasks
525 BANK.STOP_WORK; -- Kill TELLER tasks
526 exit; -- Exit loop
527
528 when ' ' => -- Non-error on a null input line
529 null;
530
531 when others => -- Other commands are invalid
532 CONSOLE.WRITE("Invalid Command: ");
533 CONSOLE.WRITE(CONSOLE.TRIM(INPUT));
534 CONSOLE.WRITE(CONSOLE.NEW_LINE);
535
536 end case;
537
538 end loop;
539
540 end BD3;