Turbo Tutor Version 1.0 Jan85
Turbo Tutor Version 1.0 Jan85
Turbo Tutor Version 1.0 Jan85
Pascal Tutor·
A Self-Study Guide to TURBO Pascal
Copyright @1984
Copyright @1985
BORLAND INTERNATIONAL, INC.
4585 Scotts Valley Drive
Scotts Valley, CA 95066
U.S.A.
Borland's No-Nonsense License Statement!
By saying, "just like a book", Borland means for example that this software may be
used by any number of people and may be freely moved from one computer location to
another so long as there is No Possibility of it being used at one location while it's
being used at another. Just like a book that can't be read by two different people in
two different places at the same time, neither can the software be used by two different
people in two different places at the same time. (Unless, of course, Borland's Copyright
has been violated.)
WARRANTY
With respect to the physical diskette and physical documentation enclosed
herein, BORLAND INTERNATIONAL, INC., ("BORLAND") warrants the same
to be free of defects in materials and workmanship for a period of 30 days from
the date of purchase. In the event of notification within the warranty period of
defects in material or workmanship, BORLAND will replace the defective
diskette or documentation. The remedy for breach of this warranty shall be
limited to replacement and· shall not encompass any other damages, including
but not limited to loss of profit, special, incidental, consequential, or other similar
claims.
GOVERNING LAW
This Statement shall be construed, interpreted and governed by the laws of the
state of California.
PREFACE
Congratulations! Since you have this book, you have undoubtedly
joined the ranks of the 200,000+ owners and users of TURBO
Pascal. And you've probably bought this book to help you better
learn how to use TURBO Pascal. That's what this book is for, and
we don't think that you'll be disappointed.
If you're a novice computer user, or novice programmer, then
you'll probably want to begin with Part I, TURBO Pascal for the
Absolute Novice. This will help you to get your feet wet, showing
you just how to get started with TURBO Pascal. If you're a more
experienced programmer, you may want to skim through these
chapters, especially Chapter 6, Getting Started with TURBO
Pascal.
If you know yourway around a computer pretty well, then you're
probably ready to dive into Part II, A Programmer's Guide to
TURBO Pascal. This starts right at rock bottom and builds swiftly,
taking you step by step through all the different aspects of Pascal
in general, and TURBO Pascal in particular. By the time you get to
the end, you should have a solid foundation in Pascal and be able
to glean any additional needed information from the TURBO
Pascal Reference Manual and other books.
Once you feel comfortable with TURBO Pascal, you might take a
look at Part III, Advanced Topics in TURBO Pascal. This section
contains listings of working programs, showing you how to do
things like read the directory off a disk or communicate through a
serial port. The listings also demonstrate different programming
techniques; they're worth studying for that, if for no other reason.
Of course, this book is more than just a book: it comes with a disk
as well. The disk is filled with running programs and tutorial
information, giving you a ready-made library of routines to copy
into your own programs. This is both time-saving and edu-
cational, especially as you adapt these routines to suit your
needs.
iii
This book, of course, can't replace the TURBO Pascal Reference
Manual. Rather, this book's goal is to help you grasp the basic
principles underlying Pascal and its various aspects; the Re-
ference Manual can then help pOint out the exact definitions of
the TURBO Pascal implementation.
Hope you enjoy your exploration. Good luck and have fun!
- Borland International Inc.
Acknowledgements
The following products mentioned in this manual are manufactured and/or sold by the following
companies:
The IBM Personal Computer (PC) is a product of IBM. IBM® is a registered trademark of International
Business Machines Corporation.
MicroPro® and WordStar® are registered trademarks of MicroPro International Corporation.
CP/M® is a registered trademark and CP/M-80™ and CP/M-86™ are trademarks of Digital Research. Inc.
Microsoft® is a registered trademark and MS™ is a trademark of Microsoft Corporation.
Tupperware® is a registered trademark of Dart Industries Inc.
TURBO™ Pascal and SideKick™ are trademarks of Borland International. Inc.
iv
ABOUT THE AUTHOR
Frank Borland is more mystique than mystic, as elusive as the
Trinity Alps big foot, as shy as the famous Loch Ness monster.
Even at Borland International, his namesake, few people have
ever seen him. The old-timers recognize him for his remarkable
algorithms, still the fastest in the west. Borland lives deep in the
Santa Cruz mountains with his transportable computer, his
burro, and his dogs. In the early days, he didn't have a permanent
homestead, but lived in a couple of camps deep in the redwood
groves. Now, Frank has settled down a little, bought a cabin, and
is raising a family, thanks to the success of his programming.
These days he is seen even less around town, but still can
occasionally be reached by modem.
If you are a Compuserve user, you are closer to Frank Borland
than you realize. He is writing either a gothic novel or an epic
poem-he hasn't decided which-entirely in bulletin board
messages left on different SIGS (Special Interest Groups). But he
never uses his real name, and he switches names often, so his
writing is hard to follow. Look for messages in cadence, or
rhymes. (You can find information on Borland products and a
Borland SIG by typing GO BOR from any Compuserve prompt.)
Frank is a warm-hearted person. He wrote Sidekick (one of his
latest programming efforts) for humanitarian reasons. Carrying
notepads, calculator, and calendar from camp to camp was
beginning to stunt the growth of his burro, Lotus, so he wrote
Sidekick to make all that unnecessary. He left a note in our
mailbox, saying he'd saved Lotus' development.
He rarely talks about his background, or why he chose to
abandon normal life and take to the mountains. Some say it had
do to with changing the whole motherboard on a PC, just to
replace a single chip. Others blame the high price of micro-
computer software. We don't really know. Do you?
v
TABLE OF CONTENTS
Preface 0 0 0 0 000 0 0 0 0 0 0 0 0 0 0 00000 0 0 00000000 0 0 0 0 0 0 000 iii
About the Author 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 v
vii
8.4 Advanced Program Structure............ 8-12
8.4.1 Typed Constants .................. 8-14
• 8.4.2 Subprograms...................... 8-15
8.4.3 Block Statements . . . . . . . . . . . . . . . . . . 8-17
9. Predefined Data Types.......................... 9-1
9.1 Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-1
9.2 Integer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-3
9.1.2 Integers as Unsigned Values. . . . . . . 9-7
9.3 Byte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-9
9.4 Real.................................. 9-10
9.5 Char................................ 9-15
9.6 Boolean.. . . . . . . . . . . . . . . . . . . . . . . . . . .. 9-17
10. Control Structures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-1
10.1 Statements. . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-1
10.2 Boolean Expressions. . . . . . . . . . . . . . . . . . . 10-3
10.3 Conditional Execution ................. 10-4
10.4 ·Iteration............................... 10-6
10.4.1 The FOR ... DO Loop............ 10-7
10.4.2 The WH I LE ... DO Loop ......... 10-9
10.4.3 The REPEAT ... UNTIL Loop..... 10-10
10.5 The Case Statement ................... 10-11
10.6 Sample Program....................... 10-14
10.7 Conclusion............................ 10-14
11. Procedures and Functions. . . . . . . . . . . . . . . . . . . . . . 11-1
11.1 Subprograms.......................... 11-1
11.2 Scope................................. 11-3
11.3 Parameters. . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-6
11.4 Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-8
11.5 Recursive Subprograms. . . . . . . . . . . . . . . . 11-11
11.6 Forward Declarations .................. 11-12
11.7 External Subprograms. . . .. . . . .. . .. .... 11-13
12. Declared Scalar Types. . . . . . . . . . . . . . . . . . . . . . . . . . 12-1
12.1 Subranges............................. 12-12
12.2 Direct Declarations .................... 12-13
13. Arrays......................................... 13-1
13.1 Packed Arrays . . . . . . . . . . . . . . . . . . . . . . . . . 13-5
13.2 Array Initialization. . . . .. .. . . . . .. . . .... . . 13-5
13.3 Order of Elements..................... 13-6
viii
14. Strings........................................ 14-1
14.1 String Comparisons .................. 14-5
14.2 String Functions and Procedures..... 14-7
14.3 Numeric Conversions................. 14-13
14.4 Strings as Parameters................. 14-14
14.5 Stri ngs, Characters, and Arrays. . . . . . . 14-16
15. Records. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-1
15.1 The "WITH" Statement ............... 15-4
15.2 Variant Records. . . . . . . . . . . . . . . . . . . . . . . 15-8
16. Sets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-1
16.1 Set Comparisons..................... 16-3
16.2 Set Operations. . . . . . . . . . . . . . . . . . . . . . . . 16-4
17. Pointers and Dynamic Allocation............. 17-1
17.1 Pointers ............................... 17-3
17.2 The Heap............................. 17-4
17.3 Linked Lists. . . ... . . . . .. .. . . .. . .. . .. . .. 17-6
17.4 Deallocation and
Memory Management. . . . . . . . . . . . . . . . . 17-9
18. Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-1
18.1 Random Access of Files. . . .. . . . .. . . .. 18-5
18.2 Text Files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-7
18.3 The EOLN Function .................. 18-9
18.4 Formatted Output..................... 18-10
18.5 Fi lenames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-13
18.6 Untyped Files......................... 18-14
18.7 Device I/O ............................ 18-16
18.8 IIReal-Time" Keyboard Input. . . . . . . . . . 18-19
18.9 I/O Error Handling. . . . . . . . . . . . . . . . . . . . 18-20
ix
20. MS-DOS Routines . ............................. 20-1
20.1 Randomize (RANDOM.PAS) .......... 20-2
20.2 Read Directory (DIRECTRY:PAS) ..... 20-4
20.3 Read Directory II (ODL.PAS) .......... 20-6
20.4 Disk Status (DISKSTUS.PAS) ......... 20-11
20.5 DOS Version Number
(VERSION.PAS) ...................... 20-13
20.6 Direct Video Output
(ISMINTIO.PAS) ...................... 20-13
20.7 Direct Memory Output
(MEMSCREN.PAS) ................... 20-15
20.8 Reading the Command Line
(CMDLlNE.PAS) ...................... 20-17
20.9 Seial Port Library
(COMLlS.PAS) ....................... 20-18
20.10 Microsoft Mouse Interface
(TSOMOUSE.PAS) ................... ·20-23
20.11 FiliChar Demo (FILLCHAR.PAS) ...... 20-25
21. CP/M Routines ................................. 21-1
21.1 Read Directory ....................... 21-1
21.2 System Status ........................ 21-2
22. Assembly Language Routines .................. 22-1
22.1 In-Line Code (INLlNE.PAS) ........... 22-2
22.2 Assembly Language Routines
(PASS FUNC.PAS, PASS.ASM) ....... 22-3·
22.3 Conclusion ........................... 22-6
23. Subject - Index
23.1 ......................................... 23-1
x
PART I
TURBO PASCAL FOR
THE ABSOLUTE NOVICE
Part 1 Chapter 1 Introduction
1. INTRODUCTION
I'd like to begin by thanking you for buying TURBO Pascal. Like
me, you must be fed up with the high price of computer software,
and are ready to get good value for (very little of) your money.
Don't be fooled-my software is as good as, if not better than, the
high-priced programs on the market, many of which cost 10
times more than mine. As you can imagine, I am quite proud of
my programs, especially TURBO Pascal.
But before I forget my manners, let me introduce myself. My
name is Frank Borland, and the company which puts out TURBO
Pascal was named after me.
I wrote this book so that you could learn to program in TURBO
Pascal. You and I will look at the Pascal language (that is to say,
standard Pascal), and then I will teach you how to write good
programs in TURBO Pascal.
I live up in the mountains with my family, my dogs, and my burro,
Lotus. It is peaceful here. Just the kind of place where a person
can sit around and think and put things into proper perspective.
Once in a while, when I really want to think through a problem, I
take Lotus and hike a few miles from home. There I will camp out
for a few days until the quiet and isolation have allowed me to
solve my problem. Then I return home to my computer and easily
bang out the code that was such a problem only a few days
before.
Some people think I am an elusive person, with an aura of
mistique surrounding me. Actually, I am just a simple man with
simple needs. I keep to myself for the most part, not because I am
a loner, but because I got tired of city life, and besides, this is the
only way I can write enough good programs to keep the folks at
my company happy.
It was while camping under the stars that I got the idea to write
TURBO Pascal. The thought occurred to me that people like you
wanted to write computer programs with a good programming
1-1
Chapter 1 Introduction Part 1
1-2
Part 1 Chapter 1 Introduction
Besides the Reference Manual, there are a few other things you
will need. First, is your computer-of course!
1-3
Chapter 1 Introduction Part 1
Another handy thing about printers and Pascal has to do with the
very structure of Pascal. You will find that big programs written in
Pascal are made up of little programs written in Pascal. We call
these little programs procedures, and we'll discuss them a little
later On in this book. The result is that these little Pascal programs
(procedures) can be stored on your floppy disk for later use, and
they can be printed out and stored as printed programs which
you could then enter when needed.
Then, when you are working on the solution to a problem that
your computer can help you with, you won't have to reinvent the
wheel. It very often is the case that you have already written
something for another program that will be of use in the program
you are working on now. A quick look through your printout file
will be more reliable than an anxious scram ble tryi ng to remem ber
where you last saw the code that you need. So that's about it for
introductions. Let's get on to something I have always found to be
important to my understanding of a new matter-a bit of history.
. 1-4
Part 1 Chapter 2 Short History
I can still remember back in the early days of computers (it wasn't
that long ago) when programs were hand-entered by flipping
switches to toggle the state of the computer's electronics. In fact,
before my time, the first computers were mechanical. To program
by flipping switches, you had to know your particular computer's
machine language and you had to convert everything to binary
(base 2 numbering system) or some other number representation.
And, if that wasn't bad enough, you had to check your completed
program by stepping through it and looking at a series of lights.
~
~
Bye
2-1
Chapter 2 Short History Part 1
You see, computers (that is, digital computers) are devices which
only understand different patters of two different states. One
state is the presence of voltage (often called a "1 "); the other state
is the absence of voltage (often called a "0"). Telling the
computer to do one simple thing like "add 2 + 2" involved
entering a series of patterns of ones and zerQs by flipping a whole
bunch of switches. If the answer came up "5," the poor
programmer would have to look at his mess and try to decide
where the mistake was. The situation tended to make some early
programmers crazy. Boy, those were the days. I am glad they're
behind us.
Later, paper tape came along to ease the frustration. The switches
remained on the computer, but paper tape readers were added as
input devices and paper tape punches were added as output
devices. Little holes were punched in the tape which represented
the ones and zeros (ons and ofts) previously entered by switches.
Punched cards, which were originally designed to automate the
weaving industry, and later used to compile the United States
census, also were used in a similar manner to paper tape.
Entering machine-oriented digits to represent computer instruc-
tions was tedious, time consuming, and error prone. As program-
mers become more frustrated, they began using a shorthand,
English-like method of representing these instructions. They
then converted them to machine "code" by associating computer
instruction values with their shorthand notation.
Finally, someone had the idea to write a program which would
make the computer do the "dirty work" of converting the
programmer's shorthand into machine codes. The result was the
first assembler. This was a huge improvement, and assemblers
are still in wide use today; however, the problem is that both the
assembler and its assembly-language programs must be specific
to a particular computer architecture. You could spend months
writing a program for a particular computer, but to use it on
another type of computer you would have to learn another
assembler language and then spend a lot oftime converting your
original program to a new one for the other machine. This
problem was the reason programming languages were invented.
2-2
Part 1 Chapter 2 Short History
2-3
Chapter 2 Short History Part 1
2-4
Part 1 Chapter 2 Short History
2-5
Part 1 Chapter 3 Simple Program
3-1
Chapter 3 Simple Program Part 1
DUMB
MACHINE
j
l
aYB
3-2
Part 1 Chapter 3 Simple Program
3-3
Chapter 3 Simple Program Part 1
program MyName;
const
TotalTimes = 20;
var
Name String[ 25 ] ;
NumberOfI'imes Integer;
begin
Write('What is your name, please: ');
Readln(N arne);
ClrScr;
for NumberOfI'imes := 1 to TotalTimes do
begin
Writeln('Your name is ',Name);
end;
end
5. When you have finished typing in the program, press your
CONTROL key and hold it down while you press K, then let
both keys up and press D.
6. Press S to save the program you just typed in. This way you
will have it later, if you want it.
7. Press R to compile the program (don't worry what that means
for now) and to run it. You will see a message at the bottom of
your screen which you can also ignore for now.
In a moment, the program will run itself.So, just what did this
program do?
If you typed it in correctly, and then typed your name correctly
when it asked you for it, the program told you your name 20 times.
If you did not type it in correctly, or if you did not type your name
correctly, all the program gave you was garbage (if anything at
all). Rememberwhat I said about "Garbage In/Garbage Out?" (If
you did get garbage, you may want to go back and compare what
you typed into your computer with the program here in the book,
and then try again. If you made a mistake and haven't yet learned
the editing commands, it might be easier to retype the entire
program at this time, using a new file name.)
3-4
Part 1 Chapter 3 Simple Program
Now let's look at the different parts of the program and talk for a
moment about each. We will go into more detail about each in a
few pages. For now, just try to get a sense of what is going on.
The program, called "MyName", has three main parts:
First: the place where you tell the compiler the name of the
program.
programMyName;
var
Name string[ 25];
NumberOfTimes Integer;
3-5
Chapter 3 Simple Program Part 1
3-6
Part 1 Chapter 4 Programming Discussion
4-1
Chapter 4 Programming Discussion Part 1
4.1 DATA
4-2
Part 1 Chapter 4 Programming Discussion
4-3
Chapter 4 Programming Discussion Part 1
4.2 VARIABLES
4-4
Part 1 Chapter 4 Programming Discussion
Let's say we have to store a list of names. The first actual name
(Joe Blow) would be stored in a variable-the pigeon hole-
called NAME[1 ].The second name (Dudley Doright) could go
into a variable named NAME[2], and so on. If we had no data to go
into a variable, it would remain empty.
Variable Contains Character Data
NAME[1] Joe Blow
NAME[2] Dudley Doright
NAME[3]
NAME[4]
You will notice that NAME[1] and NAME[2] aren't worth a thing,
by themselves. All they are good for is holding something else.
(NAME[1] is not Joe Blow, it only holds a string of characters
which means "Joe Blow"). To make things easierfor us, however,
in Pascal we call ourvariables by some name which will give us an
idea of what data they are likely to contain.
4.3 STATEMENTS
4-5
Part 1 Chapter 5 Developing a Program
5. DEVELOPING A PROGRAM
5-1
Chapter 5 Developing a Program Part 1
In order to solve a problem, you must first have a very good idea
about what the problem is. If your car has a flat tire, the problem is
obvious. So is the solution. But then, a computer isn't much help
in fixing a flat.
On the other hand, if you suddenly are asked to keep track of all
the names and addresses of the families attending your church, a
computer would be ideal. The problem is also reasonably
obvious.
You will have to store data regarding the church members. This
data will involve such things as each member's name, address,
phone number, and maybe birthday.
Part of your identification of the problem should include a
description of why you have to solve it. It should also include an
indication of what results you expect to achieve from your
solution.
You should also take your problem apart, breaking it into its
smallest parts. Then you can attack each part of the problem in its
turn. When each small part of the problem is solved, and you
5-2
Part 1 Chapter 5 Developing a Program
Sometimes people put deciding what data to put into their system
in front of the second step. When they do, they soon find
themselves "backing down the stairs" to get things right. This is
because getting the information out is basic to knowing what is to
be put in.
As you are deciding what data to put into your system, make sure
that each item is, in fact, available. Then look at it with an idea as
to what mistakes people could make as they enter this data.
For instance, a date entered by an American would normally have
the form: month, day, and then year (MM/OO/YYYY). A European
would more likely put the day before the month as in (OO/MMI
YYYY). Part of good programming is to identify possible errors
before they are made, and to somehow plan around them.
5-3
Chapter 5 Developing a Program Part 1
5.1 PSEUDOCODE
As you are writing your plan on paper, you should state each step
in complete sentences. Then, as you write the solution to each
step, each should also be a complete sentence.This collection of
sentences which describe the solution to a problem (in easy-to-
read steps) is called Pseudocode. The term is derived from jargon
for writing a program, which most programmers call coding a
. program, or writing code.
This brings up two more computer terms with which you should
be familiar:SOURCE CODE and OBJECT CODE. Source code
refers to the words you write in the Pascal programming
language using yourTURBO Pascal editor. This is the information
the compiler translates into object code. Object code, in turn, is
the information your computer uses to solve your problem. You
see, you can read source code, while your computer cannot. On
the other hand, your computer can read object code, while you
can't. It is your compiler (the "heart" of TURBO Pascal system)
which does the translation from source code to object code.
5-4
Part 1 Chapter 5 Oeveloping a Program
I will also want to start with a clean screen, but TURBO Pascal has
already taken care of that for me with a function (about which
we'll talk more later) called C/rScr.
Pseudocode:
5-5
Chapter 5 Developing a Program Part 1
program MyName;
const
TotalTimes = 20;
var
Name : string [ 25 J;
Numbe:r{)1Times : Integer;
begin
Write('What is your name, please: ');
Readln(Name);
ClrBcr;
for Numbe:r{)1Times:= 1 to TotalTimes do
begin
Writeln('Your name is ',Name);
end;
end
The only real difference between the two is that the program
source code is written in a way that the compiler will be able to
read it and then translate it. Other than for that accommodation to
the compiler's requirements, it is very close to English.
5-6
Part 1 Chapter 5 Deve/oping a Program
When you get more familiar with TURBO Pascal, and with good
programming habits, you will be thankful for Pascal's similarity to
English. You will be able to take almost any Pascal program,
written by almost anyone, and figure out what they are trying to
do.
Well, that's enough about getting ready to write a program. I
could have continued longer, but we have many more issues to
discuss. Let's get into the next chapter now and get down to the
n itty-g ritty ...
5-7
Part 1 Chapter 6 Getting Started
6. GETTING STARTED
WITH TURBO PASCAL
6-1
Chapter 6 Getting Started Part 1
TURBO <Enter>
3. When the computer asks whether you want the messages included
press:
y
This has to do with mistakes you make when you write your
program and then try to compile it.
By preSSing Y you are telling the computer to tell you what the mistake
was, in English. Pressing N, for"NO", tells the computerthatyou would
rather look up your mistake in the Reference Manual from the mistake's
number (we call this an error code). You can do this because the
computer will tell you the error code number to look up. All in all, it is
simpler, right now, to have the computer tell you.
If you have done the foregoing correctly, you will shortly see what we
call the Main Menu.
6-2
Part 1 Chapter 6 Getting Started
Logged drive:
Work file: Mamfile:
Edit Compile Run Save
eXecute Dir Quit compiler Options
Text: 0 bytes
Free:nnmm bytes
>
, Let's take each part of the menu and see what it does. We will do
so in a more or less logical order, but first... do you notice that
some letters are brighter than others? With computers, this
usually means that pressing a key with this letter will have some
effect different from pressing another key. (Notice that there are
no two bright letters the same). That is the case here. When I
mention any option from this menu, it will mean that you should
press a key which corresponds to a bright letter to indicate that
option.
Logged drive:
The logged drive is the disk drive (or hard disk directory) with
which you wish to work. For instance, if you have your TURBO
Pascal master disk in drive A:, and the programs you are writing
stored on a disk in drive B:, then the logged drive should be drive
B:. To make it so, do the following:
6-3
Chapter 6 Getting Started Part 1
1. Press
L
to choose the Logged drive option on the menu.
2. Press
B
to indicate your choice of drive B:.
3. Press
<Enter>
to tell the computer to accept your instruction.
But how about with a hard disk, or even a floppy disk with
subdirectories? Well, if you're using PC-DOS or MS-DOS,
version 2.0 (or later), you would see the following:
Logged drive:
Active direotory.
6-4
Part 1 Chapter 6 Getting Started
3. Press
<Enter>
to tell the computer to accept your instruction.
Work File:
Main file:
Since these two are so closely related, let's look at them together.
Work file: is the name of the file which is also the program you are
now writing. If you just enter the name of a file, TURBO Pascal
will add the file extension .PAS for you. If you have an extension
in mind which you would rather have than .PAS, just put it in
(TURBO Pascal won't mind).
Main file: has to do with a more advanced programming concept
of INCLUDED FILES. This is farther along in programming than
we will go in this tutorial. Suffice it to say, when you get better
(more knowledgeable) at computer programming, the INCLUDE
FILES facility will be available to you.
If you ever choose to edit, run, or compile a program without
having first indicated a work file, you will be prompted for a work
file name.
Edit
There has to be a way for you to actually write your program in a
form the computer can use. More importantly, there must be a
way for you fix the mistakes you make as you are writing the
program as well as after you have written it and tried it out. A
correct term for this process is "Editing". To accomplish this
process we use an Editor, which is called for our use by pressing
<E>.
6-5
Chapter 6 Getting Started Part 1
~\n/~·
"/ \f--:-
'BYE.
Note
TURBO Pascal is a compiler-type language in which you
write your programs using an editor, then compile them so
that the computer can understand them. In contrast, most
BASIC programming languages are interpreter-type lan-
guages in which you write your program using the interpreter
and the computer translates it as you go. If you have been
using BASIC, try to forget everything you know about it, it
really won't help you very much with TURBO Pascal.
Writing your program using the TURBO Pascal editor is a lot like
writing a note with a word processing computer program called
WordStar. If you use that program already, then you are familiar
with the various commands which help you accomplish what you
would like to do, and you are all set to go. On the other hand, if
you don't-you're not; but you are still not out of luck.
6-6
Part 1 Chapter 6 Getting Started
In the latter case, you have two choices: either you get familiar
with the commands as they are listed in the TURBO Pascal
Reference Manual, or you "customize" the commands to suit
yourself.
The latter is not a hard thing to do. Just follow the directions in the
Reference Manual Section 1.6.3 Installation of Editing Commands.
By the way, I would make my notes in the Reference Manual in
pencil. Believe me, you will want to keep track of what pressing a
particular key, or key combination, does. Sooner or later you will
change your mind about some command or other. A pencil will
make changing your mind a lot less messy.
When you start to edit a program (by pressing E), the screen will
go blank for a moment while TURBO Pascal is taking care of
some housekeeping. Like anything with TURBO Pascal, the
moment will be a short one because TURBO Pascal does things
so quickly.
If you have specified the name of a file which is not on your disk,
TURBO Pascal will take just a moment to check, and then will
send you into the editor so you can start your programming.
Once you are done editing, you can save your work to disk. (See
Save, below.)
To write a program, once you are "in the editor", is simply a
matter of typing away! Oh yes-to get out of the editor and back
to the Main Menu, press
<Control> KD
6-7
Chapter 6 Getting Started Part 1
This means, press and hold down the key marked "Control" or
"Ctrl", then press "K", then "0". That's all there is to it.
Compile
The whole object of programming in TURBO Pascal is this:to
write code and compile it. Compiling is the step where you find
out how well you did. This is where you find out if you wrote the
program correctly, and if your program's logic is correct.
B 5
6-8
Part 1 Chapter 6 Getting Started
I
I
I
i
I
I --'-~"'--'-
I, -
!--.. , \
-
COJ1PILD'I.
CArCHE.5
I /c~ :-:.~ £R.R.DP...!
SEND5 IT BliCK
70 EDITOR..-+
-Error Handling-
The thing to do now is to fix your mistake and try again. Believe
me-the first time you write a complete Pascal program, on your
own and then run it will be a high point in your life indeed.
Remember, however, that the compiler will only find a syntax
error. Logical errors should already have been eliminated in your
planning (it says here). Believe me, it is better that they be found
6-9
Chapter 6 Getting Started Part 1
6-10
Part 1 Chapter 6 Getting Started
6-11
Chapter 6 Getting Started Part 1
6-12
Part 1 Chapter 6 Getting Started
This is telling you that a Run-time error occurred, and that the
computer has stopped executing your program. A run-time error
is one which happens while a program is being executed-or
running. The number (01, or whatever) refers to what TURBO
Pascal thinks the mistake was. You can look up the error, by its
number, in the back of your Reference Manual (if it is of interestto
you).
6-13
Chapter 6 Getting Started Part 1
Anytime you start something, you will eventually want to quit. It's
the same with this menu. The only difference is: when you press
Q to leave this menu, you will only go back to TURBO Pascal's
Main Menu.
Save
SAVE early and often. The reason for this is that sometime,
somewhere, when you least expect it, the power to your
computer will be interrupted. When that happens, all the work
you have done since your last save will go into never-never land.
Like the Good Book says, "A word to the wise, ... "
Oir
Every now and then, you will want to be reminded of the name of
the file you were working on the last time. If it is on the current
logged drive, pressing 0 will allow you to find out. Or you may
simply want to have a list of the files you have stored on disk.
Pressing 0 will show you those files as well.
6-14
Part 1 Chapter 6 Getting Started
What happens when you press D is that you are prompted for a
mask. If you wanted to see only the files ending in .PAS, for
instance, type in an asterisk (*) and a "dot-pas" like this:
*.pas <Enter>
All the files on the currently logged drive ending in .PAS will be listed for
you. If you want all the files to be listed, simply press:
<Return>
Remember, only the files on the logged drive (and the active directory)
will be listed. You will have to change the logged drive (see preSSing L,
above) before pressing 0 to get a listing of the directory, if it is different
from the one you are currently working with.
eXecute
Quit
All good things have to come to an end, every now and then. To
leave TURBO Pascal to get back into your computer's disk
operating system (DOS), pressQ. If you haven't saved yourwork
file, you'll be asked:
6-15
Chapter 6 Getting Started Part 1
6.3 CONCLUSION
Well, that ends TURBO Pascal for the Absolute Novice. You're
now ready to start learning how to program in Pascal, which, of
course, is the point of the next part of the book, A Programmer's
Guide to TURBO Pascal. I'm happy to have been your guide; I
hope that you've enjoyed it as much asl have. You've done fine
up until now, and I'm sure you'll zip right through the rest of the
book. Me? Well, the dogs are chasing the burro (or is it the other
way around?), the chickens are out of their yard, and I've got a
few programming projects of my own that need to be finished, so
I'll see you around ...
6-16
PART II
A PROGRAMMER'S GUIDE
TO TURBO PASCAL
Part 2 Chapter 7 The Basics of Pascal
If you've gotten this far (and you obviously have, or else you
wouldn't be reading this), then you should know the fundamentals
of how to use TURBO Pascal. (That is, you should know how to
use the parts of the Main Menu; I don't yet expect that you can
write a program.) If my assumption is not correct, go back
through Part I again. Of course, you won't really need that for the
following example, since it's just a penciland-paper exercise
anyway, but you will need it before you go too much farther into
Part II.
Having gotten that out of the way, let's take a simple BASIC
program and convert it into a simple Pascal program. Suppose
our BASIC program looks like this:
100 REM SIMPLE BASIC PROGRAM
110 INPUTA
120 INPUTB
130 C=A+B
140 PRINTC
160 STOP
160 REM END OF SIMPLE BASIC PROGRAM
7-1
Chapter 7 The Basics of Pascal Part 2
This program allows you to enter two numbers, which are stored
in variables A and B. These two values are then added together
and stored in C. The contents of C are then printed out so that you
can see the sum of the two numbers that you entered. So far, so
good. Now comes the fun part: converting this innocuous little
piece of code into a real, live Pascal program. You're going to do
it a step at a time, so that you can understand what you're doing
and why. As usual, the explanation is more complicated than the
actual process.
The first step is to remove all the line numbers, since you don't
need them. Even if you wanted them, you would still remove
them, since Pascal uses other means of getting around than
jumping to a given line. Your program now looks like this:
REM SIMPLE BASIC PROGRAM
INPUT A
INPUTB
C=A+B
PRINTC
STOP
REM END OF SIMPLE BASIC PROGRAM
Next, three more changes. First, you will replace the equals sign
(=) in the fourth line with a colon followed by an equal sign (:=).
Pascal uses := for assigning values and reserves the plain = for
comparing values.
7-2
Part 2 Chapter 7 The Basics of Pascal
7-3
Chapter 7 The Basics of Pascal Part 2
that all (and I do mean ALL) variables be declared before they can
be used. So let's declare our variables:
program simple;
var
A,B,C : Integer;
begin
REM SIMPLE BABIC PROGRAM
ReadLn(A);
ReadLn(B);
C:=A+B;
WriteLn(C)
REM end OF SIMPLE BABIC PROGRAM
end.
7-4
Part 2 Chapter 7 The Basics of Pascal
7.2.1 Characters
7-6
Part 2 Chapter 7 The Basics of Pascal
Now on to the printing characters. As you can see from the table,
the ASCII character set contains all the letters of the alphabet, in
both upper and lower case. The upper case letters start at code 65
and go to 90, while the lower case ones start at 97 and go to 122. A
little math shows that the ASCII value of any lower case letter is
exactly 32 greater than 'its upper case equivalent. Remember
that-it can come in handy. The ASCII set also has all the decimal
digits (0 through 9), starting at code 48. Letters and digits
together are collectively known as alphanumeric characters.
Of course, there are plenty of visible characters besides just the
alphanumerics. Starting at 32 (which, as I said, is a space:" "), you
have several punctuation and other special characters in addition
to the letters and digits. These are usually called special
characters. The alphanumerics and the special characters togeth-
er are known as the printing characters, and they plus the control
characters form the entire ASCII character set.
Ta summarize: characters 0 through 31 are the control characters;
along with character 127 (did you find it?), they form the non-
printing characters. Characters 65 through 90 ('A' ... 'Z') and 97
through 122 ('a' ... 'z') are the letters, while characters 48 through
57 ('0' ... '9') are digits. Letters and digits together are known as
alphanumeric characters. All other characters not already men-
tioned make up the special characters.The alphanumeric and the
special characters together make up the pri nti ng characters. And
the printing and non-printing characters form the entire ASCII
character set.
Well, almost the entire set. Many computers recognize characters
128 through 255 as special printing or non-printing characters.
For example, the IBM PC uses those codes to represent foreign
characters, graphics characters, and special symbols. However,
since those are not standard for all makes of computers, they
really can't be listed here. Just be aware that you can have
characters with values greater that 127.
7-7
Chapter 7 The Basics of Pascal Part 2
7.2.2 Identifiers
7-8
Part 2 Chapter 7 The Basics of Pascal
And here are some reserved words that TURBO Pascal uses as
well:
7.2.4 Symbols
7.2.5 Constants
You often need to use a specific, fixed value of some sort when
writing a program. For example, if you were solving some
7-9
Chapter 7 The Basics of Pascal Part 2
TYPE EXAMPLES
Integer 3 0 -17382
Byte 3 0 255
Real 2.71828 0.00 -6.67E-22
Char 'A' '$' '0'
Boolean true false
set [0 .. 9] [] ['a' ,'r:, 'u']
string 'STARS.TXT' 'Amt in $'
Incidentally, the first five types shown are the standard predefined
data types of TURBO Pascal (more on those in Chapter 9). Sets
are a type of data structure; we'll cover these in Chapter 16.
Strings will be discussed in Chapter 13.
7.2.6 Variables
7-10
Part 2 Chapter 7 The Basics of Pascal
program SampleVariables; {
purpose shaw different types
of variables
var
Valuel,Value2,8um Integer;
Radius ,Circumference Real;
Selected,Done Boolean;
Answer,Initial Char;
begin
Valuel := 53; Value2 := 228;
Sum:= Valuel + Value2;
Radius:= 40.25;
Circumference:=2.0 * Radius * Pi; {Pi is predefined as 3.l4l5926536}
Selected:= True;Done := not Selected;
Answer: = 'Y' ;Initial : = 'd.'
end. { of program SampleVariables }
You can, of course, type in, compile, and run this program. Be
warned though: since there's no input or output (I/O, for short),
you won't see anything happen. A safe program, but dull.
7.2.7 Expressions
7-11
Chapter 7 The Basics of Pascal Part 2
See, it's not as bad as you thought. Really, you've probably seen
many expressions before; in your science and math classes, they
were called formulas (or, if you want to be classical, formulae).
Things like the circumference of a circle orthe velocity of a falling
object with respect to time are just expressions (of the type Real,
usually). In fact, FORTRAN (one of the earliest programming
languages) stands for FORmula TRANslator. So, if it helps you,
just think formula every time you use the term expression.
7.3 REVIEW
7-12
Part 2 Chapter 7 The Basics of Pascal
0 NUL 32 (space) 64 @ 96 \
1 SOH. 33 ! 65 A 97 a
2 STX 34 " 66 B 98 b
3 ETX 35 # 67 C 99 c
4 EDT 36 $ 68 D 100 d
5 ENQ 37 0/0 69 E 101 e
6 ACK 38 &
, 70 F 102 f
7 BEL 39 71 G 103 9
8 BS 40 ( 72 H 104 h
9 HT 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 I
.-
13 CR 45 77 M 109 m
14 SO 46 78 N 110 n
15 SI 47 / 79 0 111 0
16 DLE 48 0 80 P 112 P
17 DCl 49 1 81 Q 113 q
18 002 50 2 82 R ·114 r
19 DC3 51 3 83 S 115 s
20 DCA 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 ETB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 Y
26 SUB 58 90 Z 122 z
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 \ 124 I
29 GS 61 = 93 ] 125 }
30 BB 62 > 94 A 126 -
31 US 63 ? 95 - 127 DEL
7-13
Part 2 Chapter 8 Program Structure
8. PROGRAM STRUCTURE
8-1
Chapter 8 Program Structure Part 2
8-2
Part 2 Chapter 8 Program Structure
8-3
Chapter 8 Program Structure Part 2
var
Alive,Breathing,ConscioUB Boolean;
Age,Height,Weight Integer;
Score,Tries Byte;
Ratio),ercentage Real;
First,Middle,Last Char;
8-4
Part 2 Chapter 8 Program Structure
begin and proceeds to the last statement before end (or, at least,
tries to). Notice that there may be several such begin...end pairs,
and that only the final end is followed by a period (.). This is the
only place where a period should follow end.
Between the reserved words begin and end in our sample
program are five executable statements:
Wr1te('Entertwo numbers: ');
ReadLn(A)j
ReadLn(B)j
C:=A+Bj
Wr1teLn( 'The sum is ',C)
or this way:
program SIMPLE
var
A,B,C : Integer
,
begin
Wr1te('Enter two numbers: ')
,
ReadLn(A)
,
ReadLn(B)
,
C:=A+B
,
Wr1teLn('The sum is ',C)
end.
8-5
Chapter 8 Program Structure Part 2
As you can see, semicolons are only used when it's necessary to
show where one statement ends and the next begins. You can
also see that Pascal also doesn't care about line indentation,
upper and lower case, and (sometimes) spaces. You have the
freedom to format your programs in a variety of ways. The best
policy is to pick a consistent, readable, and easy-to-use format,
then stick with it. The two alternate styles shown are neither
readable nor desirable to use, so we'll stick with the regular
TURBO format.
Now let's look at the five executable statements, one at a time.
Write('Enter two numbers: ')j
8-6
Part 2 Chapter 8 Program Structure
ReadLn(B);
It's waiting for another number, followed by Enter. Since the
program is waiting for Enter, you can correct any mistakes you
might have made in typing the number when you do so before
pressing Enter. Your program won't accept (read) data until
Enter is pressed.
Your program executes the next two statements on its own. With
the statement
C:=A+B;
The sum is
The sum is 56
8-7
Chapter 8 Program Structure Part 2
Since you used WriteLn, the cursor will be moved down to the
start of the next line after the message has been written.
The procedures Write and WriteLn will print out any number or
combination of messages and values enclosed in the parentheses.
Expressions (formulas) can be included as well. You could
eliminate the assignment statement and get the same message
by changing the last statement to be
WriteLn('The sum is ',A + B);
All separate messages and values within the parentheses must be
separated by commas.
8.3 COMMENTS
program Simple;
{
purpose adds two user-entered values and
prints out the sum
last update 21 April 1985
8-8
Part 2 Chapter 8 Program Structure
WriteLn
end;
Your problem is solved, right? Wrong. The comment will start
o.k., but it will end when it finds the} after the words show
8-9
Chapter 8 Program Structure Part 2
This works fine, but you must be sure to change each and every
one back when the code is "un-commented." Why? Because if
you miss one, the comment will merrily continue throughout
your pt'c,rFn.m until it finds an }.
An en r'. . :·:!':is can cause real headaches. If you're lucky, it will
mess ur.~ ____ .. ; program enough so that it won't compile, and you'll
be forced to find the error immediately. If you're not, the program
will compile just fine, and you won't see any problem until you
execute it. If you're really unlucky, the program will appear to
work just fine, and you won't discover that there's a problem until
after the first 5000 copies have been shipped.
There is a cleaner way of handling this problem, however.
Remember, you can use two different sets of delimiters for
comments: {,} and (*,*). What's more, TURBO Pascal allows you
to nest one kind of comment within the other. Allow isn't quite the
8-10
Part 2 Chapter 8 Program Structure
WriteLn
end;
A few more words about comments. Not only can they extend
across many lines, they can be stuck in anywhere. As a
demonstration of this, we present your example program with
comments stuck in everywhere. I'm not sure why you would want
to do this to a program, but it's good to have the freedom if you
ever need it.
program Simple{ file parms: }(input,output);
var{ iables}
A{ input} ,O{ input} ,O{ output} : Integer;
begin { main body of program }
Write{ to screen }(,Enter two numbers: ');
ReadLn(A); ReadLn(B);
o {sum} := A {1st value} + B {2nd value};
WriteLn{to screen}('The sum 18 ',0)
end. { of pro( * bye! *) gram Simple }
Well, almost anywhere. Had you inserted comments in the strings
'Enter two numbers:' and 'The sum is " they wouldn't have been
comments. Instead, they would have been printed to the screen
along with the other text within the single quote marks.
8-11
Chapter 8 Program Structure Part 2
8-12
Part 2 Chapter 8 Program Structure
const
XMax = 8;
YMax = 10;
ShipMax = 15;
type
XRange = l..XMax;
YRange = 1..YMax;
var
Sector : array [XRange,YRange ] of O..ShipMax;
const
label
10,ProcExit,4213,Error;
const
XMax =8;
Yes = True;
Answer ='Y';
G = 6.673E-08;
8-13
Chapter 8 Program Structure Part 2
8-14
Part 2 Chapter 8 Program Structure
program Whatever;
var
Flagl,Flag2 : Boolean;
begin
Flagl := True;
Flag2 := False;
end
This is fine, but if you have many such variables, it can consume
space and time to do all of the initialization. With TURBO Pascal,
you could instead do this:
program Whatever;
const
Flagl : Boolean = True;
Flag2 : Boolean = False;
begin
end
Flag1 and Flag2 can still be used as variables; that is, you can still
assign values to them through the course of your program.
However, they will now start out with the desired values and will
not have to be explicitly initialized.
Forthoseofyou who know something about Pascal, yes, you can
have typed constants for data structures such as arrays, strings,
sets, and records. All the details can be found in the TURBO
Pascal Reference Manual, Chapter 13.
8.4.2 Subprograms
Between the definitions and the main body of the program you
place any subprograms (procedures and functions) that you
might define. I'll talk more about these in Chapter 11, but a brief
explanation isn't out of place. A subprogram has exactly the
same structure as a program, except that it starts with a
8-15
Chapter 8 Program Structure Part 2
program Sample;
{
purpose to demonstrate a subprogram
last update 28 August 1985
}
procedure CalculateSum;
{
purpose read in two values and print the sum
last update 28 August 1985
var
A,B,C : Integer;
begin { main body of procedure CalculateSum }
Write('Enter two numbers: ');
ReadLn(A); ReadLn(B);
C :=A+ B;
WriteLn('The sum is ',C)
end; { of proc CalculateSum }
8-16
Part 2 Chapter 8 Program Structure
8-17
Chapter 8 Program Structure Part 2
You can nest block statements; that is, have block statements
within block statements. For example, you could have a block
statement in the if ... then statement, yielding:
with StarmapA [Indx] do begin
Write('SYSTEM: ',Name);
Write(' Population; ',Pop);
if Indx = CurStat.Loc.System then begin
Write(' <current location> ');
LocationFound := True
end;
WriteLn
end;
8-18
Part 2 Chapter 8 Program Structure
8-19
Chapter 8 Program Structure Part 2
8-20
Part 2 Chapter 9 Predefined Data Types
9.1 VARIABLES
In much the same way, you can use variables in your programs.
You can declare lots and lots of variables, designed to hold
different kinds of information. Some are designed for numbers,
others for characters, yet others for logical values. Similar or
identical types of variables can hold similar or identical values.
One variable can receive the value of another.'
Actually, the Tupperware® analogy is weak in a few spots, but it
should convey the basic idea:variables hold stuff for later use.
And, instead of buying them at a home party, you get create
variables by declaring them. Remember our sample program?
program Sample;
var
A,B,C, : Integer;
begin
Write('Enter two numbers: ');
ReadLn(A); ReadLn(B);
C:=A+B;
Write('The sum is ',C)
en4.{ of program Sample}
9-1
Chapter 9 Predefined Data Types Part 2
For your program, you needed three variables: two to hold the
values you typed in, and one to hold the sum of the other two. So
you created them by declaring them. You declared them by (1)
listing their names (identifiers), and (2) saying what type of
variables they were (in this case, Integer). You did all this in the
variable declaration section, which started with the reserved
word var and ended when you reached the main body of the
program. Here you get back to the Great Underlying Rule of
Pascal (or, GURP): All identifiers must be declared before they
are used. In your case, it means that A, B, and C must all be
declared before you can use them in your program. Suppose you
added a variable to your program:
program Sample;
var
A,B,O : Integer;
begin
Write('Enter two numbers: ');
ReadLn(A);
ReadLn(B);
O:=A+B;
D:=A-B;
WriteLn('The sum is ',0);
WriteLn( 'The difference is ',D)
end.. { of program Sample}
9-2
Part 2 Chapter 9 Predefined Data Types
9.2 INTEGER
9-3
Chapter 9 Predefined Data Types Part 2
Two other things to keep in mind about div and mod. First, if A is
less than B, then A div B will equal O.ln other words, while 200 div
200 equals 1, 199 div 200 equals O. Second, if B equals 0, then
both A div B and A mod B will result in some sort of error when
they are executed. Make sure that you keep both situations in
mind when working with these integer operations.
O.K., you've got integer constants, integer variables, and integer
operators, and you can combine these into integer expressions.
You're all done, right? Well, consider the following program:
program Sample;
var
A,B,O : Integer;
begin
A:= 10;
B:=5;
0:= 5 * A + 2 * B;
Write('O = ',0)
end.. { of program Sample}
Question: what value will this program print out? Well, that
depends upon how you evaluate the integer expression 5 *A x 2 *
B. Here are four different ways you could evaluate it (remember,
A=10andB=5):
9-4
Part 2 Chapter 9 Predefined Data Types
As you can see, the order of evaluation can make a big difference.
Which brings you back to your question:What will Pascal do with
this expression? Answer: it will use operator precedence. Pascal
will carry out all multiply, divide, and remainder operations before
any addition or subtraction. A complete list of operator prec-
edence is given in the first of two tables at the end of this chapter.
So the correct (according to Pascal) evaluation is:
(5 * 10) + (2 * 5) = 50 + 10 = 60
Having solved that problem, let's tackle the next one. How would
you evaluate the expression A div 2 * B? You have two choices
(again, A = 10 and B = 5):
(10 div 2) * 5 = 25
10 div (2 * 5) =1
You would probably choose the first one, and you'd be right.
When operators of equal precedence show up, you take them in
the order they come: left to right.
9-5
Chapter 9 Predefined Data Types Part 2
C := (5 *A + 2) * B;
What started out as a short discussion of integer expressions has
gotten rather long. And you're not done yet. Let's modify your
program a little more:
program Sample;
var
A,B,C : Integer;
begin
A:= 100;
B :=200;
C : = ((5 * A) + 2) * B;
Write('C = ' ,C)
end. { of program Sample}
What value will you get when this program runs? Well, let's look at
it:
9-6
part 2 Chapter 9 Predefined Data Types
worst kind of program bugs are those that allow your program to
keep running with values that no longer have any relation to your
original data. A few simple steps can check the result to see if it is
within the realm of realism.
I n addition to the operators described above, Pascal offers a few
predefined functions that work on integers. They're listed below,
with the data type of the result given in parentheses:
Abs(l) returns absolute value of I (integer)
Odd(l) returns true if I is odd (boolean)
Pred(l) returns 1-1 (integer)
Random(l) returns random integer from 0 to 1-1
Sqr(l) returns 1*1 (integer)
Sqrt(l) returns square root of I (real)
Succ(l) returns 1+1 (integer)
9-7
Chapter 9 Predefined Data Types Part 2
9-8
Part 2 Chapter 9 Predefined Data Types
The Boolean variable BitSet will be set to True if any of the bits in
Val match any of the bits in Mask. By the same token, the
statement:
Val:= Val or Mask;
As you can see, shl and shr shift in a's and throwaway whatever
gets shifted out.
As mentioned, TURBO Pascal also provides two functions and a
procedure for byte manipulation:
Lo(I) Returns lower byte of I
Hi(I) Returns upper byte of I
Swap(I) Swaps upper and lower bytes of I
These do just what you think they would do. For example,
assuming that Val = $0810, then
Lo(Val) returns $0010
Hi(Val) returns $0008
Swap(Val) returns $1008
9.3 BYTE
9-9
Chapter 9 Predefined Data Types Part 2
9.4 REAL
9-10
Part 2 Chapter 9 Predefined Data Types
<mantissa> * 10 <exponent>
such as 100.4 * 1000, or 100400.0. Of course, you don't always
have to use the exponent format-just if you're working with very
large or very small numbers. (A negative exponent gives you a
very small number, moving the decimal point to the left according
to the value of the exponent.)
If you choose to not use exponents, you can just write real
numbers as you normally would:
3.1415926
-3546.3
0.0034
56793834.21
The same rules of operator precedence mentioned above apply
to real numbers. In addition, TURBO Pascal offers some pre-
defined functions for use with reals. Note that the trigonometric
functions (arctan, cos, sin) assume that the angle involved is in
radians (360 degrees = 2*pi radians):
9-11
Chapter 9 Predefined Data Types Part 2
9-12
Part 2 Chapter 9 Predefined Data Types
Round(3.1415926) = 3
Round(-32.3) = -32
Round(421.7) = 422
Round(O.5) = 1
Round(542832.32) = **error**(too large for integer)
Note that if you use Round or Trunc on a real value that's too
large, you will get a run-time error.
program FindRadius;
{
note: Pi is a predefined Real constant = 3.1415926536
var
Radius,Area : Integer;
begin
Write('Enter radius: '); ReadLn(Radius);
Area:= Rmmd(Pi*Radius*Radius);
WriteLn('The area is ',Area)
end; { of program FindRadius }
Two issues come up with reals or, rather, two aspects of the same
issue. The issue is this:how many bytes are used to represent a
real? With TURBO Pascal, the answer is:6 bytes. The first aspect
deals with the allowable range for the exponent. Unless you're
dealing with really large numbers, you won't have worry too
much abou~ this-TURBO has a range of -38 to +38, and 10
raised to the power of 38 is a very large number. This, of course,
doesn't mean that the issue will never come up. It's just very
unlikely.
9-13
Chapter 9 Predefined Data Types Part 2
values should you push too close to the limit or should you have
to do a long series of calculations. This is due to cumulative
round-off error, or CROE. CROE is a fancy way of saying that bad
values tend to propagate themselves. Too many bad values can
work together to produce results that have no relation to your
initial values.
What causes these mysterious errors? Here are four major
factors behind CROE. First, decimal numbers are represented in
binary form. Did you know that the number 0.1 is impossible to
express exactly in binary form? It's an infinite fraction, much like
1/3 in decimal form (0.333333 ... ). Several of these errors can
cause values to shift slightly.
Second, values with different exponents are normalized before
addition. (This means that their exponents are made equal and
their mantissas adjusted accordingly. If you add 1.0E+04 (10,000)
and 1.5E+OO (1.5), then the latter is normalized to 0.00015E+04
before the two are added together. With limited precision, you
might lose some digits off during' normalization.
Third, when nearly identical values are subtracted, the least
significant (and least accurate) digits become the most significant
digits. If you subtract 1.4356876523E+05 from 1.4356876527E+05,
you should end up with 4.0E-05. But if you have 11 significant
digits, then the last digit in each number (3 or 7) is the one most
likely to be wrong due to the other errors mentioned here. The
result: your answer may be totally wrong. Furthermore, that
answer is then used to "fill" 11 digits. Combine that with the
binary/decimal problem, and you get an actual answer of
3.981590271 OE-05 ... not quite what you'd expect.
9-14
Part 2 Chapter 9 Predefined Data Types
9.5 CHAR
The data type Char is simply the set of ASCII characters. More
accu rately, a variable of type Char can have 256 val ues, incl ud i ng
the 128 characters in the standard ASCII set. You may remember
from Chapter 7 the discussion on printing and non-printing
characters. Printing characters can be represented as the char-
acter itself within two single quote marks:
'a' '$'
, , 'J'
Remember the control characters? Those are the characters with
ASCII values 0 through 31, and they are usually expressed in
terms of the printing characters ranging from 64 to 95. For
example, the character with the ASCII value of 7 is commonly
called "control-G"; 'G' has an ASCII value of 71 (=7+64). But
since these characters have no printable equivalent, there's no
way to represent them within quotes. However, TURBO Pascal
lets you represent them with the notation:
Aohar,
9-15
Chapter 9 Predefined Data Types Part 2
That takes care of codes 0 through 31, but what about characters
with ASCII codes 127 (DEL) through 255? TURBO again comes
to the rescue, with the notation #val, where val is a byte constant
(0 ... 255). For example, you could represent DEL as #127 or #$7F
(yes, you can use hex constants). Here, then, are some different
ways of representing the same characters:
NUL #0 #$00 A@
ctrl-G (BEL) #7 #$07 AG
ESC #27 #$1B A[
blank (space) #32 #$20 ' ,
the digit 0 #48 #$30 '0'
the letter A #65 #$41 'A'
DEL #127 #$7F
ASCII 237 #237 #$ED
Suppose, now, you wanted to put a control-G (which causes a
beep on printing) within a string. If you wrote:
9-16
Part 2 Chapter 9 Predefined Data Types
9.6 BOOLEAN
9-17
Chapter 9 Predefined Data Types Part 2
= <>
<
>
<=
>=
IN
For example
3>5
will return Fa/se, while
7 <= 10
will return True. Again, more about this will be discussed in
following chapters.
OPERATOR PRECEDENCE
9-18
Part 2 Chapter 10 Control Structures
10.1 STATEMENTS·
10-1
Chapter 10 Control Structures Part 2
Score:= 10;
Maximum := 32*Score div 17;
Score := Score + 10;
Maximum := Succ(Maximum);
<statement n>
end;
10-2
Part 2 Chapter 10 Control Structures
10-3
Chapter 10 Control Structures Part 2
10-4
Part 2 Chapter 10 Control Structures
if <condition>
then <statementl>;
:If not <condition>
then <statement2>;
Pascal, however, provides a simpler way:
:If <condition>
then <statementl>
else <statement2>j
By using the if...then ... else construct, you can amplify your
example as follows:
10-5
Chapter 10 Control Structures Part 2
10.4 ITERATION
-Looping-
10-6
Part 2 Chapter 10 Control Structures
for Indx:= 1 to 10 do
WriteLnC'n = ' ,Indx,' n*n = ' ,Indx*Indx);
This will display the integers from 1 to 10, along with their
squares. If you want to decrement (decrease) var instead of
incrementing it, you can use the format:
10-7
Chapter 10 Control Structures Part 2
type: Char, Byte, Boolean, or any declared scalar type (DST) you
care to define. Given appropriate definitions, the following loops
are all valid:
for Indx := 30 downto 20 do
<statement>;
for Ch := 'A! to 'Z' do
<statement>;
for Flag := True downto False do
<statement>;
for D~:= Mon to Fri do
<statement>j
Now you can see why there is no step capability. Mixing numeric
and non-numeric values could be very confusing, especially for
those programmers who write compilers. Besides, there is
something clumsy about a statement like
for Month:= January to December step 2 do
<statement>j
while the statement
for Month := January to December step February do
<statement>j
doesn't make any sense at all. So there is no step capability in for
loops.
As with if ... then ... else, you can use a compound statement in
place of statement, to wit:
for Indx := 20 to 30 do begin
<statement 1>j
<statement n>
end;
10-8
Part 2 Chapter 10 Control Structures
Since the for... do loop can't easily meet all your iterative needs,
Pascal give you two others, both controlled by boolean expres-
sions. The first is the while... do loop:
while <boolean expression> do
<statement>;
This loop will cause statement to be executed as long as boolean
expression resolves to a value of True. It will never be executed at
all if boolean expression is initially False.
If you wish, you can replace for... do loops as follows:
<var> := <exp1>;
while <var> <= <exp2> do begin
<statement 1>;
<var> := suce(<var> )
end;
If you want to use a step value, then you need to change the last
statement to reflect that. For example, to have a step value of 3,
you could change the last statement in the loop to read
<var> := <var> + 3
Of course, you can do other things than imitate for loops. For
example, here's a binary search program. It searches a sorted list
for a given value until it either finds it or determines that it is not in
the list. The advantage of a binary search is that it only takes a
maximum of (n log 2) tries to search a list of n objects. This means
that a list of 1024 elements will take at most 10 tries through the
loop. .
10-9
Chapter 10 Control Structures Part 2
var
Upper,Lower : Integer;
begin
Upper := IMa.x;Lower :=. IMin; Found := False;
while DOt Found and (Lower <= Upper) do begin
Index:= (Upper +;Lower) DIV 2;
if DKey < LiBt[Index]
then Upper :=Pred(Index)
elle ifDKey> LiBt[Index]
.thaD. Lower := Succ(Index)
elle Found:= True
8Dd.
end; { of proc Bina.rySearch }
repeat'
<statement 1>;
<statement 2>;
<statement n> .
until <boolean. condition>;
This differs from while..• doin three important ways. First, the
statemef)ts within the loop are always executed at least once. In
other words, ,all the statements in the loop are executed before
boolean condition is resolved. Second, the statements continue
to execute as long as boolean condition is false; the while loop
executes while boolean expression is true. Third, the repeat loop
can directly execute more than one statement and, therefore,
doesn't n(3ed a compound statement (begin...end) to handle
multiple statements ..
,One common use of 'repeat loops is to condition input, that is, to
prompt the u~er for some value and to continue to prompt until
the value entered is one of those that you decide to allow. For
example, the following routine prompts the user to enter an
10-10
Part 2 Chapter 10 Control Structures
integer within the range [Iow ... high]. It repeats the prompt if (1)
there is an I/O error (due to bad numeric format), or (2) the value
is not within the proper range:
program TestGetInteger;
type
Prompt = striDg[80];
10-11
Chapter 10 Control Structures Part 2
repeat
Write(,Enter direction: U)p,D)own,L)eft,R)1ght:');
ReadLnCOh) {Oh is of type Ohar}
untU COh IN ['U' ,'U: ,'D' ,'d.' ,'L' ,'1' ,'R' ,'r' J);
if COh = 'U') or COh = 'U:)
thenY:=Y-l
else if COh = 'D') or COh = 'd')
thenY:=Y+ 1
else if COh = 'L') or COh = '1')
then X :=X-l
else ifCOh = 'R') or COh = 'r')
then X := X + 1;
GotoXYCX,Y)
However, the if... then ... else chain can get a little tiresome (and
difficu It to follow) if there are a lot of different conditions to check.
So Pascal includes an additional flow-of-control structure called
the case statement.
The case statement requires a scalar variable which has been set
to some value. Scalar variables include those of type Integer,
Byte, Char, Boolean, and any declared scalar type (DST).
(Variables of type Real are not considered scalar.)The case
statement has this format:
case <variable> of
<constant list 1> : <statement 1>;
<constant list 2> : <statement 2>;
10-12
Part 2 Chapter 10 Control Structures
repeat
Write('Enter clirection; U)p,D)own,L)eft,R)ight:');
ReadLn(Ch) {Ch is of type Char}
untU ( Ch IN ['0' ,'U: ,'D' " d' ,'L' ,'1' ,'R' ,'r' j);
caseChof
'U','U: : Y:=Y-l;
'D','d': Y:=Y+ 1;
'L','I' : X:=X-l;
'R','r' : X:=X+ 1
end;
The above example ensures that Ch would only have one of the
specified values in the case statement. This is done by checking
Ch against a set of allowable values (you'll learn about sets in a
later chapter). What if you removed that restriction? What if Ch
had a value other than those listed in the case statement? Under
the original Pascal definition (by Wirth and Jensen), the result
was undefined; that is, the outcome was uncertain.
TURBO Pascal, however, takes the commonsense approach
that, in such a case, all of the statements are skipped and
execution resumes right after the end of the entire case statement.
In fact, TURBO Pascal goes one step farther and allow an else
section at the end of the list of choices. This section is executed
only if the variable does not match any of the constant lists. With
such an extension, you might rewrite your example as follows:
Write('Ent.er clirection; U)p,D)own,L)eft,R)ight: ');
ReadLn( Ch);
caseChof
'U','U: : Y:=Y+l;
'D','d' : Y:=Y-l;
'L','l' : X:=X-l;
'R','r' : X:=X+ 1;
elae
WriteLn('Illegal entry ');
WriteLn('PIease use U ,D,L or R')
end;
10-13
Chapter 10-Control Structures~ Part 2
", . ~\' r . ' : '.
. ,
10.7 CONCLUSION
10-14
Part 2 Chapter 10 Control Structures
Even with these aids, you still are limited to writing one big
program and having to duplicate code if you need it in more than
one place. In the next chapter, you will learn about the solution:
procedures and functions. You've already seen some standard
Pascal procedures and functions, such as WriteLn and ReadLn;
in the next chapter, you'll learn. how to write your own.
Before we go on to the next chapter, here are the table and the
sample program I promised you a while ago:
BOOLEAN TRUTH TABLES
Exp1 Exp2 (Exp1 and Exp2) (Exp1 xor Exp2) (Exp1 or Exp2)
False False False False False
True False False True True
False True False True True
True True True False True
program. Example;
{
Example Sample Pascal program
demonstrates control structures
note the use of typed constants
}
canst
Bell =AGj
FireMax = 6;
Dot =" . ,.
Done : Boolean = False;
X : Integer = 0;
y : Integer = 0;
CmdSet : set of Char = ['L' ,'R' ,'U' ,'D' ,'F' ,'Q' ] j
var
Ch : Charj
Count : Integer;
10-15
Chapter 10 Control Structures Part 2
begin
while DOt Done do begin
WriteLn('X,Y = (' ;X,',' ,Y,'),);
repeat
Write('CMD: L)eft, R)ight, U)p, D)own, F)ire, Q)uit: ');
Read(Kbd,Ch); WriteLn;
if Ch >= 'a' { convert to upper case }
thenCh:= Chr(Ord(Ch)-32);
if DOt (Ch IN CmdSet)
then WriteLn('Illegal entry-try again')
else WriteLn('Command accepted')
untU Ch in CmdSet;
caseChof
'U' Y:=Y+ 1;
'D' Y:=Y-1;
'R' X:=X+ 1;
'L' X:=X-1;
'F' begin
Write( 'Firing');
for Count := 1 to FireMax do
Write(Dot,Bell);
WriteLn
end
'Q' : Done:= True
end { of CaBe }
end { ofwhlle }
end. { of program Example}
10-16
Part 2 Chapter 11 Procedures and Functions
11.1 SUBPROGRAMS
As mentioned above, you can get by with just this for small
programs, but you'll find this structure very limiting with big
programs, especially if you have sections of code that are
repeated throughout the program. The solution? Pascal allows
you to create subprograms. A subprogram is indeed like a
11-1
Chapter 11 Procedures and Functions Part 2
11-2
Part 2 Chapter 11 Procedures and Functions
procedure Whichever;
cODBt
Star = '*",
type
DIW8 = (Mon,Tues,Wed,Thur,Fri,Sat,8un);
var
Daor : DlW8i
begin { main boqy of proc Whichever}
for Daor:= Mon to Fri do
Write(Star)
end; { of proc Whichever}
11.2 SCOPE
11-3
Chapter 11 Procedures and Functions Part 2
procedure SetB;
var
B Integer;
begin { proc SetB}
B:=2*A
end; { ofproc SetB}
11-4
Part 2 Chapter 11 Procedures and Functions
Here, your simple rule has been met-both A and B have been
defined as being variables of type Integer before being used-
and yet this program will not compile. Why? Because B, having
been declared in the procedure SetB, is only recognized within
that procedure. In other words, the variable B is local to the
procedure SetB. By contrast, the variable A is recognized both
within SetB and in the main program itself.
So you now must modify your simple rule to this:each identifier
must have been previously declared in an enclosing program or
subprogram before being used. By enclosing, I mean that .the
definition of the identifier must come after its declaration and
before the begin statement of the program or subprogram in
which is was defined. In the example above, you can see that the
statement WriteLn(A+B) comes after the begin statement of the
procedure SetB.
Here's another case to consider:
:program Scope2;
var
A Integer;
:procedure SetA;
var
A Integer;
begin
A:=4
end { of proc SetA }
Two questions: (1) will this program compile, and (2) if it does,
what value will it print out? Two answers: (1) yes, and (2) 3. This
brings up a corollary to our rule:the most recent declaration of a
given identifier will always be used. The procedure SetA assigned
its own local variable A to 4 and left the global variable A
untouched.
11-5
Chapter 11 Procedures and Functions Part 2
11.3 PARAMETERS
11-6
Part 2 Chapter 11 Procedures and Functions
Now, a little thought will show just what a lousy approach this is.
You are executing more statements before and after each call to
Swap then you would if you just did each swap directly. Luckily,
you don't really have to do this. Instead, you can define Swap as
having a list of parameters. For example:
program TestBwap;
var
Alpha,Bravo,Charlie,Delta,Eagle,Foxtrot
: Integer;
11-7
Chapter 11 Procedures and Functions Part 2
Swap. Each time Swap is called, the actual variables in the call
(say, Alpha and Eagle) are used in place of S1 and S2. Because of
this, S1 and S2 are called formal or dummy parameters, while
Alpha and Eagle are known as actual parameters.
There is one other twist in parameter lists. The prefix var before
any formal parameter means that the corresponding actual
parameter is directly substituted for the formal parameter. In
other words, if the formal parameter has its value changed, the
actual parameter is also changed. If there is no var prefix, then the
actual parameter cannot be affected by anything that happens to
the formal parameter. For example, here's a procedure that
forces a variable to be within two values:
procedure Condition(Min : Integer; var Valu : Integer;
Max: Integer);
begin
it Min > Max
then SwapcMin,Max);
itValu<Min
then Valu:= Min
else itValu > Max
then Valu := Max
end; { of proc Condition}
11.4 FUNCTIONS
As you've seen, a procedure can change the values of parameters
passed to it. The calling program (or subprogram) can then use
those modified parameters for whatever purpose it has. Suppose,
forexample, that you wrote a procedure to find the integersquare
root of a given value:
11-8
Part 2 Chapter 11 Procedures and Functions
This procedure would take Valu, find its square root, and set Root
to that value. The calling program might use it as follows:
re:peat
Write('Enter value: '); ReadLn(Able);
ISqrt{Able,Baker);
WriteLn( 'The square root is ',Baker)
untUAble = 0;
There are many other cases where you might want to do
something similar, that is, return a value based on certain
variables or conditions. After a while, it can get a little clumsy
and/or tiring to always set aside one parameter for the returned
value. So, instead, you can use a function. A function acts just like
a procedure, but with one difference: it returns a Real or a scalar
value. (Brief review:scalar data types include I nteger, Byte, Char,
Boolean, and any defined scalar type-OST.) For example, you
might rewrite ISqrt as follows:
function ISqrt{Valu: Integer): Integer;
var
oddSeq,Square,Root : Integer;
beg:in
ISqrt := Root
end; { of func ISqrt }
11-9
Chapter 11 Procedures and Functions Part 2
repeat
Write(/Enter value: '); ReadLnCAble);
WriteLn(/The square root is I,ISqrt(Able))
until Able = 0;
A function can be used anywhere that a constant or an
expression of the same data type could be used. Suppose you
wanted to find both the integer square- and fourth-roots of a
given value. You could rewrite the program this way:
repeat
Write(/Enter value: '); ReadLnCAble);
WriteLn('The square root is ',ISqrt(Able));
WriteLnC/The fourth root is I,ISqrt(ISqrt(Able)))
until Able = 0;
When using a function, care must be taken to ensure that you
have set it to some value before exiting. As shown above, you do
this by assigni ng some value to the function name. You must also
be careful about using the function name in any other way within
the function itself. For example, you couldn't rewrite ISqrtto look
like this:
procedure ISqrt(Valu: Integer; var Root: Integer);
var
oddS eq,S quare : Integer;
begin
OddSeq:= -1;
Square :=0;
repeat
OddSeq:= OddSeq + 2;
Square := Square + OddSeq
until Valu < Square;
ISqrt:= Succ(OddSeq div 2);
ifValu <= Square - ISqrt
tli.en ISqrt := Pred(ISqrt)
end; { of proc ISqrt }
11-10
Part 2 Chapter 11 Procedures and Functions
Can you see how this works? Each time Fill is called, it checks to
see if the location (X,V) has been plotted. If it has, then Fill doesn't
do anything. Otherwise, Fill plots a point at (X ,V) and then tries to
fill in each of the four adjacent points to (X,V).
One cautionary note about recursive subprograms: they can
quickly use up a lot of memory, causing your program to behave
erratic'ally or to blow up. You could easily come up with a
example where Fill would continue to call itself until you had over
100 levels of nested subroutine calls ... and a lot of systems just
can't handle that many levels,of nesting. So be careful.
11-11
Chapter 11 Procedures and Functions Part 2
Are there any more situations where the Great Underlying Rule of
Pascal gets in the way? Well, occasionally, you may wish to call a
subprogram before it has been declared, out of convenience or
necessity. For example, you might have the following program:
program Example;
var
Alpha : Integer;
procedure Testl(var A: Integer);
begin
A:=A-l;
itA>O
then Test.2(A)
end; { of proc Testl }
As you can see, Test1 calls Test2, and Test2 calls Test1. As it
stands, this program won't compile; you'll get an "Unknown
identifier" error when it finds the reference to Test2 within Test1.
If you swapped Test1 and Test2, then you'd get a similar error
within Test2. So vyhich do you declare first? The answer:both.
How? By declaring Test2 with a forward declarations:
program Example;
var
Alpha : Integer;
procedure Test.2( var A : Integer); forward;
11-12
Part 2 Chapter 11 Procedures and Functions
»rocedure Test2;
beg:ln
11-13
Part 2 Chapter 12 Defined Scalar Types
12-1
Chapter 12 Defined Scalar Types Part 2
Now the code is completely clear as to the date and day of the
week. All uncertainty and ambiguity is gone. Instead of having to
second-guess the programmer, you can easily see what each
statement means.
In defining Months and Weekdays, you have created two
declared scalar types (DSTs). To make a DST, you simply (1)
come up with a name for it, and (2) enter its list of values. The
name and the values both follow the rules for creating identifiers:
starts with a letter or underscore, followed by 0 or more letters,
digits, and underscores; up to 127 characters long; case (upper-
and lower-) doesn't matter; all characters (including under-
scores) are significant. The DST is defined in a type section; it has
the format
12-2
Part 2 Chapter 12 Defined Scalar Types
end.
12-3
Chapter 12 Defined Scalar Types Part 2
case ShipClass of
NoShip
Constitution,Enterpr1se
Reliant
Loknar,Chandley
Larson,Baker
Excelsior
end;
In other words, DSTs can be treated almost like numeric values.
As a matter of fact, each element in a DST has an implied numeric
or ordinal value. The very first element has an ordinal value of 0;
each following element then has a value one greater than the
element before it. For example, here are all the elements of your
DST ShipType, along with their ordinal values:
12-4
Part 2 Chapter 12 Defined Scalar Types
Pred(ShipClass) Enterprise
Succ(ShipClass) Loknar
Pred(Pred(ShipClass)) Constitution
Succ(Succ(ShipClass) ) Larson
Pred(Succ(ShipClass) ) Reliant
Succ(Pred(ShipClass) ) Reliant
Ord(Pred(ShipClass)) 2
Ord(ShipClass) 3
Ord(Succ(ShipClass) ) 4
Note that for all scalar types except Integer, Ord returns a value
greater than or equal to 0, since all scalar types except integer
start with an ordinal value of O. For values of type Integer, Ord
returns the actual integer value, which can fall anywhere in the
range -32768 through 32767. Of course, using the Ord function
on any Integer (or Byte) expression is a waste oftime anyway, so
the issue is not a critical one.
12-5
Chapter 12 Defined Scalar Types Part 2
Here's another example. You've seen that you can use DSTs in
for statements, but, if you wanted to, you could build your own
loops:
ShipClass := NoShip;
repeat
ShipClass:= Succ(ShipClass);
ShipClass:= Pred(ShipClass)
end;
end;
12-6
Part 2 Chapter 12 Defined Scalar Types
var
Ship : array [1 ..10] ofShipType;
(If you're not familiar with what an array is, don't worry-you'll
run into them later. Once you know what they are, come back and
look at this again, and it'll all make a lot more sense.)Suppose that
Ship[5] := Reliant, but that during the course of the game, that
ship gets destroyed. How do you keep track of that information
within the program? You have to come up with some means of
remembering that Ship[5] is gone. If you've included NoShip in
your definition of Ship Type, then you can just set Ship[5] :=
NoShip, and presto! it disappears. This leads to the following
loop, which will ignore all destroyed ships (assume Indx is oftype
Integer):
for Indx:= 1 to 10 do
ifShip[Indx] <> NoShipthen begin
end;
The code in the center of the loop will be executed for each
existing ship; all others will be ignored.
The second subtle reason of a "none of the above" element was
demonstrated earlier, when you created your own loops with
while and repeat statements. I n both cases, you either started or
ended with ShipC/ass equal to NoShip; in other words, NoShip
acted as a "doorstop" of sorts. Without it, you would have had a
much harder time setting up the loops without going out of range,
either with Succ(ShipC/ass), where ShipC/ass = Baker, or Pred
(ShipC/ass), where ShipC/ass = Constitution. The result is either
a range error (if range checking is turned on) or an undefined
value for ShipC/ass (if range checking is turned off). Either case
can cause problems.
There are times when you don't need (or want) a "none of the
above" element. Take, for example, your DST Months. If you
confine your loops to for statements, then you don't need to
define a NoMonth element. On the other hand, it could still be
12-7
Chapter 12 Defined Scalar Types Part 2
useful for two reasons. First, it would allow you to have a true
"undefined" date, rather than just some default date (1/Jan/OO)
that was understood to be undefi ned. Second, it would force the
ordinal values of the elements to match the conventional values
used; Ord(Apri/) would equal 4 instead of 3. The lesson, then, is
think carefully about how you define your DSTs.
TURBO Pascal gives you an additional feature for working with
declared scalar types, one not found in Standard Pascal. You can
convert any scalar type to any other scalar type with the same
numeric (ordinal) value. Forexample, you know that Ord(Re/iant)
give you the Integer value 3; by the same token, ShipType(3)
returns the ShipType value Reliant. Likewise, Boo/ean(NoShip)
returns Fa/se, and ShipType(Fa/se) returns NoShip, since
Ord(NoShip) = Ord(False).
There are two things that you would probably like to do with
DSTs, but which you can't: directly read and write them. For
example, the statement
WriteLn('Ship Class: ' ,8hipClass);
will produce an error when you compile it. The same is true for a
statement such as
ReadLn(ShipClass);
There are, however, some ways around this limitation. If you are
interested in writing out elements of a DST, you will need to
create an array (list) of strings (yes, we'll talk more about both
strings and arrays later). You could do the following:
program example3;
type
ShipType = eNoShip,Constitution,Enterprtse,Reliant,
Loknar,Larson,Chandley,Excelsior,Baker);
var
ShipClass : ShipType;
ShipName : array [ShipType] ofstriDg[12];
12-8
Part 2 Chapter 12 Defined Scalar Types
begin
ShipName[NoShip] .= 'No ship'j
ShipName[ Constitution] := 'Constitution' j
ShipName[ Enterprise] .= 'Enterprise' j
{etc.}
ShipName[Baker] .= 'Baker'j
end.
Now you can write out the "value" of Shipe/ass by printing the
appropriate string in ShipName. Similar arrays can be set up for
each DST that you want to be able to write out. If you have several
lists like this, you may want to store the strings out in a text file
(and you'll read about those later on, as well) and then read them
in at the start of the program. In that case, your code might look
like this:
var
ShipClass :ShipType;
ShipName:array [ShipType] ofstriDg[12];
InFile :Text;
begin
Ass1gn(InFile,'SHIPNAME.DAT');
Reset(InFile);
for ShipClass := NoShip to Baker do
ReadLnClnFile,shipName[ShipClass]);
Close(InFile);
end.
This assumes that you have a text file SHI PNAME.DAT out on the
disk with the contents:
No ship
Constitution
Enterprise
(and so on. .. )
12-9
Chapter 12 Defined Scalar Types Part 2
Using a separate data file has two advantages. First, it reduces the
size of the source and executable files, often by quite a bit if you
have long arrays to ilitialize. Second, it allows you to change the
string associated with each element without having to recompile
the program.
You have several options for reading in DST values. The first is to
make use of the array you've set up for writing the DST value out
(if, indeed, you have set up such an array). You prompt the user
for a string and search though the array until you've found it:
var
TempStr: str1Dg[ 12];
Found : Boolean;
{ and the rest of the declarations }
begin
end.
Here, you start at the end of the array and work backward to (but
not including) NoShip. When you find the matching string,
Found gets set to True, and you fall out of the loop with ShipC/ass
set to the correct value. If ShipC/ass gets to NoShip, then you fall
out of the loop with Found = False and must take appropriate
action. You could, for example, put this code with the loop
repeat
until Found;
which would force the user to keep entering the string until one
matched.
12-10
Part 2 Chapter 12 Defined Scalar Types
WrlteLn('Sh1p Classes:');
for Sh1pClass:= NoSh1pto Baker do
WrlteLn(Sh1pName[Sh1pClass],': ',Ord(ShipClass));
repeat
Wrlte('Enter value: '); ReadLn(Indx)
untU(Ord(NoSh1p) <= Indx) and(Indx <= Ord(Baker));
Sh1pClass := Sh1PJ?ype(Indx);
end.
This example assumes that you did set up ShipName but decided
to use numeric (rather than string) input. It first writes out the
names of the different ship classes, along with their ordinal
values. It then goes into a repeat loop which won't let the user out
until a correct value is entered. Finally, it converts that value tothe
appropriate ShipType element and assigns it to ShipClass.
12-11
Chapter 12 Defined Scalar Types Part 2
12.1 SUBRANGES
where FirstVal and LastVal are values of a scalar type such that
FirstVal is less than Lastval. The data type SubRange can now
legally have any value from First Val through LastVal. Subranges
can also be directly declared, that is, a given variable can be
directly declared as having a subrange value, as opposed to
having to first declare the subrange. Here are some examples of
subranges (with some accompanying declarations):
CODBt
XMax = 8j
YMax 10j
Sh1pMax 40j
ty:pe
Daors (Mon,Tues,Wed,Thurs,Fri,8at,8un)j
Sh1pType (NoS h1p,Constitution,Enterpr1se,Reliant,
Loknar,Larson,Chandley,Excelsior,Baker)j
Cruiser Constitution.,.Reliantj
Nibble 0 ..16j
UpperCase '.A! ..'Z'j
Lowercase 'a' ..'z'j
WeekDaors Mon..Fri;
WeekEnd Sat..8un;
XRange 1.,XMaxj
YRange 1..YMaxj
12-12
Part 2 Chapter 12 Defined Scalar Types
var
SX XRange;
BY YRange;
ShipCount O..ShipMa.x;
Alphas .. ,
"'-'.
Subranges are often used as index ranges for arrays, as data
types for both arrays and records, and as part of the declaration
of a constant set. In all these functions, they serve to limit the
amount of RAM used and to set boundaries as to what values can
be used.
rather than
type
ShipRange =O ..ShipMa.x;
var
ShipCount :ShipRange;
Being able to directly declare subranges like that saves you from
having to come up with names for every subrange that you want
to use. What you may not realize is that you can do the same for
declared scalar types, and, indeed, for any data type (array,
string, record, set, pointer, file). However, there are a few
restrictions on doing this. First, all of the variables of that data
type have to be declared at the same time and in the same place.
You can't write
: (Mon,Tue,Wed,Thu,Fr1,Sat,8un);
: (Mon,Tue,Wed,Thu,Fri,Sat,8un);
12-13
Chapter 12 Defined Scalar Types Part 2
You'll get an error when the compiler hits the second declaration,
since the second set of days uses the same identifiers as the first
set. Instead, you would have to write
var
D8iY'l,DBJT2 : (Mon,Tue,Wed,Thu,Fri,Sat,8un);
12-14
Part 2 Chapter 13 Arrays
·13. ARRAYS
Val'
Index : Integer;
then Index has only one specific value at any moment. However,
there are situations where you'd like to have a list of values, such
as a list of numbers or characters. That's where arrays come in.
We've talked some about the "Trek" game, so that will be the
examp!e here. Let's suppose that the game area is an 8 by 10 grid.
Each square in the grid is called a sector. Each sector contains (1)
oor more stars, (2) 0 or more enemy ships, and (3) possibly one
starbase. Now, with what you've learned in previous chapters,
how would you represent the grid?
Tough, huh? Now you see why we need arrays. Simply put, an
array is a collection of variables of identical type, each one of
which may be referenced by a unique index value. For example:
var
List : array[ 1 ..10] of Integer;
The array List is a collection of 10 integer variables, namely,
List[1], List[2], List[3], List[4], List[5], List[6], List[7], List[B],
List[9] , and List[10]. You can use any of those 10 variables
anywhere you could use any integer variable. Furthermore, the
index value doesn't have to be a literal value ('1' through '10'); it
can be any expression that resolves to an integer in the range
1.. 10. For exam pie, the statement
for Index := 1 to 10 do
List[Index] := 0;
would set each of those ten variables to O.
13-1
Chapter 13 Arrays Part 2
The array Regular has an explicit index range (Mon .. Fri), while
the arrays Overtime and Present have an implicit index range
(Sun ... Sat).
The data type of any array can be almost any data type- Integer,
Boolean, Char, Real, DST, arrays, records, sets, pointers, strings,
oreven files. In fact, arrays with multiple index ranges (known as
multi-dimensional arrays) are just arrays of arrays (of arrays ... ).
For example, you might define your game information as follows:
var
Stars,8hips,Base: array[1..8] of array[l..lO] of Integer;
To reference the elements of such an array, you can write
statements like these:
Stars[3][2] := 0;
if Base[X] [Y] =0
then WriteLnC'N0 starbase present')
else Refu.elShip;
Stars[3,2] := OJ
if Base[X,Y] = 0
then WriteLn('No starbase present')
else RefuelShipj
Danger:= 5 * Ships[X,Y]j
This makes for Simpler code, but it can hide the fact that you are
working with arrays of arrays. Consider another solution for your
game using a 3-dimensional array:
type
SectItem = (Stars,8hips,Bases);
SectArrBiY = array[l..8,1..10] of Integer;
var
Sector: array[SectItem] ofSectArrBiY;
Temp SectAl'rBiYj
Now, YOUCould refer to the number of stars in Sector 3-2 as
Sector[ Stars, 3,2] , Sector[ Stars] [3,2], or Sector[ Stars] [3] [2]. What
you might not realize is that you could also do the following:
Temp:= Sector[Stars];
This single statement copies all of the values Sector[Stars,1,1]
through Sector[Stars,8, 10] into the locations Temp[1,1] through
Temp [8, 10]. Why? Because both Sector[Stars] and Temp are
defined as being of type SectArray, and TURBO Pascal will allow
direct assignment of identical array types. In fact, any operation
you could do on Temp, you could also do on Sector[Stars] ,
Sector[Ships], and Sector[Bases]. The key to making this work is
to define an array type-such as SectArray-and then using that
in all the appropriate declarations.
13-3
Chapter 13 Arrays Part 2
13-4
Part 2 Chapter 13 Arrays
13-5
Chapter 13 Arrays Part 2
what you want to fill it with-O, which is Drd(False), that is, the
numeric equivalent of False. Now you just need the length in
bytes ... which brings you to the next procedure: SizeD'. SizeD'
can take as its argument any variable or the name of any data
type.lt returns the size of that variable (or of a variable of that
type) in bytes. So, to initialize Base, you could write:
FillChar(Base,8izeOf(Base) ,0);
This statement will set all bits and bytes in Base = to o. The
combination of FiIIChar and SizeD' is a hard one to beat,
especially for array initialization.
13-6
Part 2 Chapter 13 Arrays
Stars[8,9]
Stars[8,10]
All you need to do is remember that the index furthest to the
right-the last index-changes the fastest. If you have the array
var
BigOne : array[0 ..3,0 ..4,0 ..6,0 ..2] of Byte;
then you can quickly work out that the elements are stored as
BigOne[O,O,O,O]
BigOne[ 0,0,0,1]
BigOne[O,O,O,2]
BigOne[ 0,0,1,0]
BigOne[3,4,5,1 ]
BigOne[ 3,4,5,2]
13-7
Chapter 13 Arrays Part 2
13-8
Part 2 Chapter 14 Strings
14. STRINGS
-String-
When Niklaus Wirth designed Pascal, he did so in a punched-
card/mag tape/mainframe environment, where fixed-length data
were the rule. At least, that's probably the reason he was satisfied
to store a character string as a array[1 .. n] of Char. At any rate,
Standard Pascal does not (currently) have a predefined data type
for strings. String constants such as
ccmst
FlleName = 'B:STABB.DAT';
LifeName = 'WHATEVER YOU WANT';
14-1
Chapter 14 Strings Part 2
Note that you must specify a length for each variable. This
defines the maximum number of characters that each string can
hold. The variable MyName could hold up to 80 characters.
Token could only hold up to 15 characters, so that the statement
Token := 'this is too long a string for token';
would only store the first 15 characters ('this is too Ion') into
Token. The last variable, BigString, represents the maximum
length possible for a string-255 characters.
14-2
Part 2 Chapter 14 Strings
then Token[O] contains the value 11, since there are 11 characters
in'this string'. However, you could not do something like this:
program Example;
var
Token : striDg[15];
Len : Integer;
begin
Token: ='this string';
Len := Token[O];
WrlteLn('The length of token is ',Len)
end.
Why not? Because Token[O] is of type Char, and you can't assign
a character to an integer. You could, however, substitute the
statement
Len:= Ord(Token[O]);
14-3
Chapter 14 Strings Part 2
var
Indx,Len : Integer;
begin
Len:= Length(Str); { more on this later}
for Indx := 1 to Len do
Str[Indx] := UpCase(Str[Indx]) {bunt-in TURBO func}
end.; { of proc LowToUp }
14-4
Part 2 Chapter 14 Strings
14-5
Chapter 14 Strings Part 2
var
Len,Indx : Integer;
Flag : Boolean;
begin
StrEqual := False;
Len:= Length(Strl);
if Len = Length(Str2) then begin
Indx:= 1;
Flag := True;
while FlagAND (Indx <= Len) do
ifStrl[Indx] = Str2[Indx]
then Indx := Indx + 1
else Flag := False;
StrEqual := Flag
end
end; { of func StrEqual }
14-6
Part 2 Chapter 14 Strings
14-7
Chapter 14 Strings Part 2
program LengthTest;
type
SmallStr = strmg[16];
var
Test : SmallStr;
procedure ShowLength(St: SmallStr);
begin
WriteLn('length of<' ,Bt,'> is' ,Length(St))
end; { of proc ShowLength }
begin
Test: = 'hello, there';
ShowLength(Test);
Test := 'hi';
ShowLength(Test);
Test: = ";{ null string }
ShowLength(Test)
end. { of program LengthTest }
14-8
Part 2 Chapter 14 Strings
14-9
Chapter 14 Strings Part 2
14-10
Part 2 Chapter 14 Strings
Note that you use the Pos function to figure out where to insert
'Ann' and also where to insert a blank (to separate 'Ann' and
'Webster') .
Token expansion is one good use for Insert. Suppose you were
writing a program to take a form letter and put in the appropriate
14-11
Chapter 14 Strings Part 2
names, dates, and so on. Within the form letter, these fileds might
be represented by tokens; for example, the salutation might look
like this:
The statements
Line := 'And so, <title> <last>, the entire <last> family'j
Replace(Line,'<title>' ,'Dr.');
Replace(Line,'<last>' ,'Lewis');
WriteLn(Line);
would produce
And so, Dr. Lewis, the entire Lewis fa.m1ly
This should give you a clue on hawaII that "personalized" junk
mail that you receive is generated.
14-12
Part 2 Chapter 14 Strings
Notice that Str does, indeed, behave like numeric output. The
string length is set equal to the field width; if the width is too small
(such as X:1 0:7, X:5:4, or 1:3), it is increased to fit the number. If the
field is wider than is necessary, then the number is right-justified,
that is, blanks are put in front of the number to fill out the
remaining space. In the case of real numbers, rounding off is
done when needed.
The second procedure, Val, converts from a string to a number
(again, either Real or Integer). The string itself must contain
exactly a number and nothing else; no characters other than
digits, except for '+','-','.', and 'E' in the appropriate places. And,
of course, the number in the string must be of the same type as
the variable to which Val is converting it. Since there are so many
chances for error, Val has a third parameter-a result value-
14-13
Chapter 14 Strings Part 2
which tells you whether or not there were any problems. If the
result is 0, then there were no problem during the conversion. If
the result is greater than 0, then it indicates the character
(S[Result]) at which it ran into problems. Here are a few
examples:
!fS holds
the string: then VALCS) = result code
"14916" 14916 0
" 32" <undef> 1 {space}
"4281.963" 4281.963 0
"-332.3" -332.3 0
"-332.3 " <undef> 7 {space}
"4,281" <undef> 2 {comma}
instead of
procedure ParseC var Line,Word: striDg[266 ]);
If you tried to compile the program with this addition, you would
get a type mismatch error when it got to the line Parse(TLine,
Tword);. Why? Because TLine and TWord are declared to be of
length 80, while Parse is expecting two strings of length 255. This,
of course, can cause real problems if you're trying to write some
general-purpose routines (such as LowToUp) to handle all
different strings. The reason for the error is to prevent you from
returning too long a string or indexing into "random" memory
(that is, beyond the end of the string). You can, however, disable
this error checking by putting a compiler option at the start of
14-15
Chapter 14 Strings Part 2
your program (more about these later in the book). All you have
to do is to place the following comment somewhere before the
call to Parse; you could, in fact, put it at the top of your file, like
this:
{$V-}
program ParseText;
That way, you will be turning it off for only those places where
you actually do not need it.
UpToLow(Ch);
14-16
Part 2 Chapter 14 Strings
14-17
Chapter 14 Strings Part 2
14-18
Part 2 Chapter 15 Records
15. RECORDS
BY8
record
<Identl> : <DataTypel>;
<Ident2> : <DataType2>;
end.;
Note well that Ships, Stars, and Base are not elements of a
declared scalar type, nor are they separate arrays; they are field
identifiers for the record type ASector. Accordingly, you would
refer to the number of stars in sector 3-2 as Sector[3,2].Stars.
Note also that in setting up this record, you've restricted the
possible values of the fields Stars and Ships to a very small
15-2
Part 2 Chapter 15 Records
15-3
Chapter 15 Records Part 2
var
Sector : array[XRange,YRange] of ASector;
You've defined an array of records which you can now use in
your program. If you wished to clear the entire sector of starbases
and enemy ships, you might do this:
for X := 1 to XMax do
for Y := 1 to YMax do begin
Sector[X,Y] .Starbase := Falsej
Sector[X,Y] .SbX := 0;
Sector[X,Y] .SbY := 0;
Sector[X,Y].Ships:= 0;
Sector[X,Y] .Stars := 0
end;
As you can see, this could get very tedious, especially for more
complicated records and/or actions. Luckily, Pascal gives you a
shorthand means of referring to all those fields: the with
statement. This takes the form
with <record id> do <statement>;
15-4
Part 2 Chapter 15 Records
Within the statement, you can refer to all of the fields of the record
id without having to specify it each time. Instead, the base
address of record id is calculated when the with statement is
found, and that address is used to offset all of the fields. This
makes it very handy for use in loops. For example, you could
rewrite your initialization code as:
for X := 1 to XMax do
forY:= 1 toYMax do
with Sector[X,Y] do begin
Starbase := False;
SbX:=O;
SbY:=Oj
Ships:= OJ
Stars:= 0
end;
Note that the with statement is inside of the two for statements.
This is critical, for it ensures that Sector[X, Y] refers the desired
element of the array. If you had written
with Sector[X,Y] do
for X := 1 to XMax do
for Y := 1 to YMax do begin
end;
then the base address would be calculated just once: before you
entered the two loops, and using whatever the values of X and Y
were before the loops started.
You can nestwith statements, and you can also list morethan one
record identifier in a single with statement. For example, you
could write the following:
15-5
Chapter 15 Records Part 2
type
RecTypel =
record
Fieldl Integer;
Field2 Real
end;
RecType2 =
record
Field3 string [ 20];
Field.4 Boolean
end;
var
Reel RecTypel;
Rec2 RecType2;
begin
with Reel do begin
Fieldl := 32;
Field2 := 17.76;
with Rec2 do begin
Str(Fieldl ,Fiel(3);
Field.4 .= (Field2 > 3.14169)
end;
Fieldl .= Length(Rec2.Field3)
end
end.
15-6
Part 2 Chapter 15 Records
RecType2 =
record
Field.! striDg[20]j
Field2 Boolean
end;
Now Rec1 and Rec2 have fields with the same names. If you then
write something like
with Reel ,Rec2 do begin
WriteLn(Field.! )j
WrlteLn(Field2)
end;
which record's fields will be written out? The answer: Rec2, since
it was the last defined in the list. Likewise, if you have nested with
statements, the record last appearing has precedence over any
others. In this example, problems are unlikely to occur sincethe
data types ofthe identically-named fields are different; an attempt
to assign a value will either go to the correct field or will result in a
compiler error. But what if both records had Field1 defined as
type Integer? In that case, you might unknowingly assign a value
to the wrong field. The moral:avoid identically-named fields
unless you're very sure of what you're doing.
A similar problem can occur when you create a field that has the
same name as a variable:
program BadExamplej
type
RecType=
record
Name striDg[26]
Age Integer
end;
15-7
Chapter 15 Records Part 2
var
Rec : RecType;
Name : striDg[25];
begin
Name := 'J. Michael Browning';
with Rec do begin
Name := 'Bob Trammel';
WriteLnCName)
end;
WriteLnCName)
end.
Can you guess what the output of this program is? If you guessed
Bob Trammel
J. Michael Browning
you're absolutely correct. Again, much like the rules of scope you
learned about in Chapter 11, the last declaration takes prece-
dence. In this case, the with statement acts as a declaration.
Again: be careful with identical identifiers.
15-8
Part 2 Chapter 15 Records
type
Government = (Federation,Kl1n.gon,Romulan,Trader);
AShip =
record
SX XRange;
BY YRange;
QX,QY Byte;
Energy 0 .. 1023;
Source Government;
Phaser,D1Bruptor,Beam1 ,Beam2
Byte;
Photon 0 .. 15;
Torpedo 0 ..7;
Plasma 0 ..9;
Cloaked boolean
end.;
15-9
Chapter 15 Records Part 2
type
Government = (Federation,Kl1ngon,Romulan,Trader);
ABh1p =
record
SX XRange;
BY YRange;
QX,QY Byte;
Energy 0 ..1023;
case Source Government of
Federation (Phaser Byte;
Photon 0 .. 15);
Kl1ngon (D1sruptor Byte;
Torpedo 0 ..7);
Romulan : (Beam1,Beam2 Byte;
Plasma 0 ..9;
Cloaked Boolean);
Trader : ()
end;
For each value of Source, you define the fields that exist for that
case, enclosed within parentheses. Note that even if there are no
fields at all, you still need to put in the parentheses.
You may wonder what good this all is. First, it cuts down on the
size of the record. Why? Because the fields for each variant
occupy the same space. In other words, the fields Phaser,
Disruptor, and Beam1 all reside at the same location in memory,
rather than each having their own separate slot. The result is less
memory required for each record of that type. The original
definition required 15 bytes per record; this variant record takes
up only 11 bytes. That may not seem like a whole lot, but consider
this example:
15-10
Part 2 Chapter 15 Records
type
15-11
Chapter 15 Records Part 2
which would write out "72". What good is this capability? Well, it
allows for certain advanced programming tricks. For example,
assuming an a-bit system, you could define something like this:
type
B1g8tr = striDg[ 255];
StringPo1nter=
record
case Flag: Boolean of
True (Addr : Integer);
False (Ptr: A B1g8tr)
end;
var
VStr StringPo1nter;
begin
VStrAddr := $BOOO;
VStr.Ptr A := 'This string is beingwrltten at $BOOO'
end
Now, you can write a string at any given location in memory. Of
course, since you don't always know what is sitting at a given
memory location, this can be dangerous. That's why it's for
advanced programming efforts.
Here's one more variation on variant records. Sometimes you
want the variations, but you don't really care about the tag field.
The StringPointer above is a good example. You're interested in
Addr and Ptr, but you don't need or want Flag. In those cases,
Pascal allows you to dispense with the tag field altogether. For
example, you could rewrite StringPointer as:
type
B1g8tr = striDg[ 255];
StringPo1nter =
record
case Boolean of
True : (Addr : Integer);
False : (Ptr : A BigStr)
end;
Note that you no longer have the tag field, Flag; you just have the
tag field type, Boolean. This is known as a free union (as opposed
to a discriminated union, one with a tag field).
So much for records. ~ '40W, let's move on to sets ...
15-12
Part 2 Chapter 16 Sets
16. SETS
There are times when you want to test a scalar variable (Integer,
Byte, Char, Boolean, DST) to see if its current value belongs to a
set or collection of values. For example, suppose you want to
write a subroutine that will write out a prompt for the user and
then accept and return only a character belonging to an
allowable set of characters. Using what you know now, how
would you do that?
If you're really clever, you might come up with something like
this:
type
CharSet array [ Char] of Boolean;
var
OKSet CharSet;
16-1
Chapter 16 Sets Part 2
16-2
Part 2 Chapter 16 Sets
16-3
Chapter 16 Sets Part 2
type
ShipType = (Constltutlon,Enterpr1se,ReUant,Loknar,
Larson,Chandley,ExcelsIor,Baker)j
ShipSet = set of ShipTypej
var
AllShips,Frigates,Destroyers,Cruisers,Battleship,Temp
: ShipS etj
begin
AllShips ·= [Constltutlon..Baker] j
Frigates .= [Loknar,ChandleY]j
Destroyers .= [Larson,Baker]j
Cruisers ·= [Constltutlon..ReUant,Excelslor] j
Battleship ·= [ExcelsIor] j
Temp ·= [Constltutlon..Baker] j
end
Given this, the following expressions have the values shown:
AllShips = Temp True
AllShips = Cruisers False
Frigates < > Destroyers True
BattleShip <= Cruisers True
Temp >= AllSh1ps True
Destroyers < = AllShips True
Cruisers < = Battleship False
[] <= <any set> True
16-4
Part 2 Chapter 16 Sets
begin
.AllSets .= [Constitution..Baker];
Setl := [Constitution..Reliant,Excelsior];
Set2 := [Loknar,Larson,Chandley,Baker];
Set3 .= [Enterprise,Loknar,Baker];
Empty := [];
8D4.
*
Setl Set2 []
*
Set2 Set3 [Loknar,Baker]
*
Set3 .AllShips [Enterprise,Loknar,Baker]
*
.AllShips Empty []
In each case, the result is a set containing the elements that
appear in both sets. In two cases (the first and the last), there were
no elements in common, so the result was the empty set.
The second operation is set union, which uses the plus sign (+).
The union oftwo sets is the set containing all the elements in both
sets. Here are some examples:
Setl + Set2 [Enterprise..Baker] ( = .AllShips)
Set2 + Set3 [Enterprise,Loknar,Larson,Chandley,Baker]
Set3 + Setl [Constitution..Loknar,Excelsior,Baker]
.AllShips + Empty [Enterprise..Baker]
The third and last operation is set difference, which uses the
minus sign (-). The difference of two sets is the set containing all
of the elements in the first set that are not in the second set. Note
well that, unlike set intersection and set union, the set difference
operation is not commutative; that is, Set1 -Set2 is not the same
as Set2 -Set1. Here are some examples:
16-5
Chapter 16 Sets Part 2
16-6
Part 2 Chapter 17 Pointers
-Polnters-
From time to time, you will find yourself wanting to be able to
create and destroy data structures while a program is actually
executing. Let's recall the Ship data type from the chapter on
records:
ccmst
XMax 8',
YMax 10;
type
XRange l..x:Max;
YRange l ..Y.Max;
Government (Federatlon,Kl1ngon,Romulan,Trader)i
Sides (Forward,FPort,FStarboardA}'ort,
AStarboa.rd,A.:tt);
Weapons array[Sld.es] of Byte;
17-1
Chapter 17 Pointers Part 2
AShip=
record
SX XRange;
BY YRange;
QX,QY Byte;
Energy 0 ..1023;
case Source Government of
Federation (Phaser Weapons;
Photon array[Sides] of 0 .. 16);
(D1Bruptor Weapons;
Torpedo array[Sides] of 0 ..7);
(Beaml,Beam2 Weapons;
Plasma array[Sides] of 0 ..9;
Cloaked Boolean);
Trader ( )
end;
17-2
Part 2 Chapter 17 Pointers
This method is fine, but has two drawbacks. First, you (the
programmer) must decide ahead of time the maximum number
of ships possible (MaxShips). The program will never be able to
handle any more ships than that. Second, space (memory) will
always be allocated for the maximum number of ships, regardless
of how many are actually in use. If you defi ne MaxShips to be 100,
then you can never have more than 100 ships, and space for 100
ships will always be set aside even if you only have one or
two. These are common limitations in most languages, but
Pascal does offer a way around them: pointers.
17.1 POINTERS
17-3
Chapter 17 Pointers Part 2
17-4
Part 2 Chapter 17 Pointers
17-5
Chapter 17 Pointers Part 2
the number of bytes left on the heap; for 16-bit systems, the
number of paragraphs (16-byte chunks). MemAvaii returns an
I nteger value, which means that it will be negative ifthere are over
32K bytes/paragraphs free. You can convert it to a positive
number with the following code:
var
TrueFree : Real.;
begin
TrueFree := MemAvail; { convert to real. value}
if TrueFree < 0.0
then TrueFree := TrueFree + 65536.0;
WriteLn('Space available: ',TrueFree:7:0)
end.
17-6
Part 2 Chapter 17 Pointers
AShipptr = AAShip;
AShip=
record
SX XRange;
BY YRange;
QX,QY Byte;
Energy 0 ..1023;
ShieldB,Beams Byte;
Next AShipptr
end;
You may realize that you just have violated the Great Underlying
Rule of Pascal, namely that no identifier can be referenced until it
has been declared. As you can see, you defined AShipPtr to be a
pointer to type AShip before you defined AShip. This ability is a
necessary exception, since without it linked lists would be
impossible (or, at least, very messy).
Having modified your data structure, you now define your
variables as follows:
var
F1rst,Last : AShipptr
ShipCount : Integer;
At the start of the game, you would initialize your variables as
follows:
First := nil;
Last: = nil;
ShipCount := 0;
(The predefined identifier nil represents the value a pointer has
when it's not pointing at anything.)When you wish to create a
new ship, you call your procedure AddShip:
17-7
Chapter 17 Pointers Part 2
procedure AdclShip;
begin
if First = Dil then begin
New(First);
Last := First
end.
el8ebegin
New(L8Bt" .Next);
Last := Last" .Next
end;
Last" .Next := Dil;
ShipCount:= ShipCount + 1;
Creata<3hip(L8B1i' )
end; { of proo AddShip }
(Note that you have a special test for creating a ship when none
exist.) The pointer First always points to the first ship in the list.
Each ship then points to the next one in the list via the field Next.
, The pOinter Last always points to the last ship in the list. If there is
only one ship in the list, then First and Last both point to it. If there
are no ships at all in the list (the list is empty), then both First and
Last equal nil.
Now that you can create the list, how do you reference a
particular ship in it? With the array it was easy: all you had to do
was index into the array and hey, presto! there it was. With the
linked list, you have to look for it. Here's a procedure to do just
that. It takes the index value and returns a pointer to the
appropriate ship (if it exists):
procedure FetohShip(Index : Integer;
var Ptr : .ABhipPtr);
begin
Ptr := First; { point at first ship in list }
while (Index: > 0) 8D4 (Ptr < > Dil) do begin
Index: := Index: - 1;
Ptr :=Ptl"".Next
end.
end; { of proo FetohShip }
If Index is less than or equal to 0, then Ptr points to the first ship in
the list. If Index is greater than the number of ships in the list, then
Ptr gets set to nil. Otherwise, Ptr points to the appropriate ship.
17-8
Part 2 Chapter 17 Pointers
At this point, you need to know about how to reclaim the memory
used by a pointer when you no longer need the data structure it
points at. TURBO Pascal provides two approaches to memory
management. One method is to use the predefined procedure
Dispose to reclaim the memory pointed to by a given pointer.
Going back to your array of pointers (Ships), you could delete a
particular ship this way:
ifShips[Indx] < > nil
then Dispose(Ships[Indx]);
This would set Ships [Indx] equal to nil and makethe memory that
it had used available for other pointers. If you just wrote
Ships[Indx] := nil;
17-9
Chapter 17 Pointers Part 2
18. FILES
18-1
Chapter 18 Files Part 2
cOD.St
ShipMax 40;
XMax 8;
YMax 10;
tine
XRange 1 ..XMax;
YRange l ..YMax;
AShip
record
SX XRange;
BY YRange;
QX,QY Byte;
Energy 0 .. 1023;
ShieldB,Beams 0 ..266
end;
var
ShipFtle file of AShip;
Ship array[ l ..ShipMax] of AShip;
ShipCnt O..ShipMax;
18-2
Part 2 Chapter 18 Files
18-3
Chapter 18 Files Part 2
into Ship [ShipCnt] and then points at the next record. If there is
no next record, then the function EOF starts returning True, and
you drop out of the end of the loop. Since you didn't know ahead
of time how many records there were, you had to count them (by
incrementing ShipCnt) until you reached the end of the file.
Actually, with TURBO Pascal, you could have found out ahead of
time just how many records there were (though it really wouldn't
matter). The function FileSize will return the number of records in
a file, so you could have written:
ABs1gn(ShipFlle,'SHIPS.DAT');
Reset( ShipFlle)j
ShipCnt:= FllaSize(ShipFlle)j
for Indx := 1 to ShipCnt 40
Read(ShipFile,8hip[Indx] );
Close(ShipFile) j
Both approaches work equally well; the second one has the
advantage of letting you know ahead of time just how many
records you have to read in (in case that's important).
In this example, ShipFile was a file of records of type AShip. You
can define a file of anything (except files), so you could have
done this instead:
type
AShip =
record
SX XRangej
BY YRangej
QX,QY Byte;
Energy 0 .. 1023j
Beams,8hieldB 0 ..266
end;
ShipArraor = array[l ..ShipMax] of AS hip;
var
Ship ShipArraor;
ShipFile file of ShipArraorj
ShipCnt O..8hipMaxj
18-4
Part 2 Chapter 18 Files
Simple, isn't it? With a single Write statement, you have sent all
the ship records out to the disk. To read it back in, you just write:
Assign(ShipFlle,'SHIPS.DAT');
ResetCShipFile);
Read(Ship:B'ile,Ship);
Close(ShipFile);
18-5
Chapter 18 Files Part 2
Now let's suppose that you want to sort that file in some way.
Your sorting program would have to do a lot of reading from and
writing to the file, using the clumsy procedure above. If the file is
small enough, you can read the entire thing into memory, sort it
there, then write it back out. If it isn't, you're in for a long, tedious
program.
Your task would be easier if you could read and write any given
record in the file without having to go back to the start and read all
the preceding records. Such a capability is known as random
access of files, as opposed to the sequential access described
above. Since this is such a desirable trait, TURBO Pascal offers it
to you via the Seek statement, taking the form
Seek(FlleVar,RecNum);
will pOint to the first record in the file. By the same token, the
statement
Seek(FlleVar,Flla91ze(FlleVar)-1);
will point at the last record in the file. Seek can, in fact, be used to
expand a file, that is, to add records onto the end of it. The
statements
Seek(FlleVa.r,Fila91ze(FlleVar));
Write(FlleVar,Rec);
will append Ree onto the end of the disk file that FileVar is
assigned to. You can continue to do this until you run out of disk
space. Note, though, that you cannot seek beyond FileSize{File
Var); that, too, will result in an I/O error.
18-6
Part 2 Chapter 18 Files
You can now read in text from InFile, and write it out to OutFile,
using the following procedures:
18-7
Chapter 18 Files Part 2
18-8
Part 2 Chapter 18 Files
Having saved your game information as text, you can (and must)
read it back in the same way. The following code would suffice:
ABs1gn(InFtle,'SHIPS.TXT');
Reset(InFtle);
Rea.dln(InFtle,8hipCnt);
far Indx := 1 to ShipCnt do
with Ship[Indx] do
ReadLn(InFtle,8X,8Y,QX,QY,Energy,Beams,8hields);
Close(InFtle);
You don't know ahead oftime how many numbers there are on a
line, but you still need to read them in. The following chunk of
code will read them into an array:
program eolntest;
CODSt
nummax: = 60;
var
1nfile text;
numlist array[ 1 ..nummax] of integer;
numcnt integer;
18-9
Chapter 18 Files Part 2
begin
reset(1nflle); { agam, this will vary }
numcnt := 0; { noth1ng in arrB8 yet}
while DOt eott 1nflle) aDd. (numcnt < numm.a.x) do begin
whue DOt eoln( 1nflle) aDd. (numcnt < nummax) do begin
numcnt := numcnt + 1;
read( 1nfile,num11st[ numcnt])
end.;
readln(1nfile); { read in end of line}
end.;
for inch( := 1 to numcnt do
wrlteln('num11st[',indx:2,'] = ',num11st[indx]:6); close(1nfile)
end. { of program eolntest }
In the innermost loop, you read numbers off of a line, one by one,
until you hit the end of the line (eoln). You then advance to the
next line (using readln) and continue the process until you either
hit the end of the file (eof) or have filled up the array (numcnt =
nummax). At the end, for a check, you write all of the values out to
the screen.
18-10
Part 2 Chapter 18 Files
Indx:= 16421;
WrlteLn('This field is too narrow:' ,Indx:3);
WrlteLn( 'This field is just right:' ,Indx:6)j
WrlteLn('This field is too wide :' ,Indx:16);
would produce
This field is too narrow: 16421
This field isjust right: 16421
This field is too wide : 16421
Note that if you specify a field that is too narrow, the field
automatically expands by the minimum amount necessary to
write the value out. Specifying no field at all is equivalent to giving
one that is too short: just enough space is allocated to write the
value out, and no more. This can cause problems if you're writing
more than one value per line. For example, if you had written
Wrlte(OutFUe,SX,SY,QX,QY);
WrlteLn( OutFUe,Energy,Beams,8hieldB);
in the code to save the ship information out to a text file, the file
SHIPS.TXT would look like this instead:
3
7260176102300
31019912102300
66047102300
Reading the information back in would be impossible, since you
would be unable to separate the fields into their different values.
So it pays to use a width specifier whenever appropriate.
As mentioned above, you can write out Boolean values, with or
without a width parameter. The values translate into the strings
'TRUE' and 'FALSE', so that the statements:
Flag1 := Truej Flag2 := Falsej
Wrlteln('Flag1: ' ,Flag1:6,' Flag2: ' ,Flag2:6);
would produce the output
Flag1: TRUE Flag2: FAIBE
18-11
Chapter 18 Files Part 2
18-12
Part 2 Chapter 18 Files
program FormatDemo;
const
P1 = 3.1416926636;
begin
Wr1teLn(P1);
Wr1teLn(P1:8);
Wr1teLn( -P1:8);
Wr1teLn(P1:12);
WrlteLn(P1: 16);
Wr1teLn(P1:20);
Wr1teLn(P1:8:0);
Wr1teLn(P1:8:4);
WrlteLn(P1:12:10)
end. { of program FormatDemo }
18.5 FILENAMES
TURBO Pascal runs under CP/M, CP/M-86 and MS/OOS (a
version is available for each), so it follows the file conventions of
each system, which are essentially the same: a file name of up to
eight (8) letters and/or digits, with an optional 3-character
extension. If the extension exists, it is separated from the file
name by a period. For example, the following file names are
acceptable:
th1sflle
thx1138
Simple.pas
Simple. axe
stars.dat
18-13
Chapter 18 Files Part 2
If you use these file names "as-is", then your program will
assume that they are on the currently logged drive (as defined
either by TURBO Pascal, if it's loaded, or by the operating system
prompt "X>", where "X" is the logged drive). You can, of course,
explicitly state which drive the file is on by appending the drive
name in front of the file name:
a.:th1sflle
b:thxl138
c:stars.dat
It's opened and closed just like any other file. Reading from and
writing to it are different, though, from other files. Untyped files
can only be read or written a block ("128 bytes) at a time. You do
this using two procedures, BlockRead and BlockWrite. Here's
their format:
BlockRead(FlleVar,Buf,NumBlocks);
BlockWrlte(FlleVar,Buf,NumBlocks);
18-14
Part 2 Chapter 18 Files
18-15
Chapter 18 Files Part 2
begin
Indx := Abs(Indx) mod 16; { force to allowable range}
IBlk := Indx div4 + 10; { calculate block #}
IRec := Indx mod 4; { calculate rec w lin block}
Seek(BtgFlle,IBlk)
BlockRead(BtgFlle,Data,IBlk) { get the data }
if ReadFlag
thenRec:= Data[IRec] { get appropriate record}
e1sebegin
Data[IRec] := Rec; { else save it in 'data'}
Seek(BtgFlle,IBlk)
BlockWrite(BtgFlle,Data,IBlk) {&write it}
end
end; { of proc BaseRecIO }
.~ JlnputlOutput-
18-16
Part 2 Chapter 18 Files
This program prompts the user for the name of an input file,
which it expects to be a text file with three real numbers on each
line. It reads those three numbers into Star, then writes Star out to
the data file STARS. OAT. In short, it's converting the star
information from a text file to a data file.
18-17
Chapter 18 Files Part 2
18-18
Part 2 Chapter 18 Files
{handle commands}
else
Write(Chr(7)); {beep at illegal. cmd}
end
end
end; { of proc CheckCommand }
18-19
Chapter 18 Files Part 2
Suppose that you ran Convert (the program listed above), and
that you gave it the name of a file that didn't exist. What would
happen? As soon as the program tried to open that file for input
(via the Reset call), you would get an I/O error, and the program
would abort. This, of course, is something of a pain, more so if
you were in the middle of a large, complex program rather than
just at the start of a small, simple one. Fortunately, TURBO Pascal
offers a solution to this problem. Using a compiler directive, you
can disable the "abort on I/O error" feature for sections of code
(or, if you wish, for the entire program). To turn off I/O error
trapping, you insert the comment statement { $I-} into your
program. When you want to turn it back on, you insert { $I+}. For
example, you could rewrite part of Convert to read
{ $I-}
Write(/Enter input me: '); ReadLn(InFileName);
ABsign(InFile,InFileName);
Reset(InFile);
{ $I+}
18-20
Part 2 Chapter 18 Files
{ $l-}
repeat
Wrlte('Enter input file: '); ReadLnClnFlleName);
Assign(lnFlle,lnFlleName);
Reset(lnFlle)
untU lOresult = 0;
{ $l+}
If you entered the name of a non-existent file, you would get the
message 'File not found; try again'. However, the call to IOresult
that caused that message would clear the error condition.
IOresult would then always return 0 at the until statement, and the
program would never go back and ask you to re-enter the file
name. What you need, instead, is something like this:
{ $l-}
re»eat .
Wrlte('Enter input file: ')j ReadLnClnFlleName)j
As sign(lnFlle,lnFlleName)j
Reset( lnFlle)j
lOerr := (lOresult < > O)j
if lOerr
then WrlteLnC'Flle not found; try again')
untU not lOerr;
{ $l+}
18-21
Chapter 18 Files Part 2
cODBt
Bell : Char = Chr(7);
10 err : Boolean = False;
{ These are both typed constants }
type
Prompt : BtriDg[ 80];
procedureError(Msg: Prompt);
{
write error Msg out on line 24 of the screen
}
begin
GoToXY(l,24); ClrEol;
Write(Bell,Msg)
end; { of proc Error}
18-22
Part 2 Chapter 18 Files
l)rOC8Clure IOcheclq
{
check for I/O error; print message if needed
}
var
10 code :Intege~
Ch : Char;
begin
IOcode:= IOresult;
IOerr := (IOcode < > 0);
if IOerr then begin
case IOcode of
$01 : Error('File does not ex1st');
$02 : Error('File not open for input');
$03 : Error('File not open for output');
$04 : Error('File not open');
$10 : Error('Error in numeric format');
$20 : Error('Operat1on not allowed on logical dev1ce');
$21 : Error('Not allowed in direct mode');
$22 : Error('Assign to sta.nda.rdfUes not allowed.');
$90 : Error('Record length m1smatch');
$91 : Error('Seek beyond end-of-fUe');
$99 : Error('Unexpected end-of-fUe');
$FO : Error( 'Disk write error');
$Fl : Error('D1rectory is full');
$F2 : Error('File size over:tlow');
$FF : Error('File disappeared')
else
Error('Unlmown I/O error: ');
Wr1te(IOcode:3)
end; { of case }
Read(Kbd,Ch)
end.
end; { of proc IOcheck }
18-23
Chapter 18 Files Part 2
18-24
Part 2 Chapter 18 Files
!?5jP *
I~
~'
t
sy-p
18-25
PART III
ADVANCED TOPICS
IN TURBO PASCAL
Part 3 Chapter 19 Useful Pascal Routines
Welcome to Part III! I am glad you made it this far. Since you are
here, I assume that you are interested in some advanced
programming techniques. Well, there's no shortage of those
here. Happy programming!
Here are some program examples designed for advanced func-
tions under TURBO Pascal. They aren't specific to an operating
system (such as MS-DOS or CP/M); instead, they can be used
anywhere. They're designed as utilities to help you put your
programs together.
All of these programs can befound on yourTurbo Tutor diskette.
The file name of each program is given in the title for each
section. These programs can all be compiled and executed
immediately; no special hardware or software is assumed.
19-1
Chapter 19 Useful Pascal Routines PartS
begin
far Count:= 1 to 20 do begin
Rea.d(Kbd,Ch); {Reada character, 1fESC (chr(27) then}
if (Ch = chr(27)) aDd. keypressed thaD. begin
{ keystrokB must be either ESC key or one }
Previous := True; { that generates a two-digit code}
Rea.d(Kbd,Ch);
8D4
elM Prev10us := Fa.lse;
ifPrev10us
thaD. Write(/previous ')
elM Write( /s1ngle char ');
Writ&,n(/Ord(Ch)= I ,Ord(Ch))
8D4 end. { of program GetFunct1onKeyDa.ta. }
var
Ch : C~
Indx,Jndx : Integer;
beg:in
reped
far Indx := 1 to 10000 do { delaor loop to show type-ahead }
Jndx := Indx + Indx;
Rea.d(Kbd,Ch); { get next character from buffer}
Write(Ch) { and echo it back out to the screen }
until Ch = I#, { continue until "#,' is entered}
8114. { of program Buffered }
19-2
Part 3 Chapter 19 Useful Pascal Routines
procedure IOCheck;
{
This routine sets IOErr equal to IOresult, then sets
IOFlag accord1.n.gJy. It also prints out a message on
the 24th line of the screen, then waits for the user
to hit any character before proced1ng.
var
Ch : Char;
19-3
Chapter 19 Useful Pascal Routines Part 3
begin
IOVal := IOresult;
IOErr:= (IOVal < > 0);
GotaXY(1,24); ClrEol; { Clear error line in any case}
if IOErr then begin
Write( Chr( 7));
case IOVal of
$01 Write('File does not exist');
$02 Write('File not open for input');
$03 Write('File not open for output');
$04 Write( 'File not open');
$06 Write('Can"t read from this file');
$06 Write('Can"t write to this file');
$10 Write('Error in numeric format');
$20 Write('Operation not allowed on a logical device');
$21 Write('Not allowed in direct mode');
$22 Write('Asslgn to standard files not allowed.');
$90 Write( 'Record length mismatch');
$91 Write('Seek beyond end of file');
$99 Write('Unexpected end of file');
$FO Write('Disk write arror');
$F1 Write('Directory is full');
$F2 Write('File Size oveI'flow');
$FF Write('File disappeared.')
else Write('Unknown I/O error: ',IOVal:3)
end;
Read(Kbd,Ch)
Gli.d
end; { of proc IOCheck }
begin
PutLineNum( 1); Assign(InFile,' d:ununY); IOCheck;
PutLineNum(2); Rewrite(InFile); IOCheck;
PutLineNum(3); Read(Infile,Line); IOCheck;
PutLineNum( 4); Close(Infile); IOCheck
end.. { of program TestIOCheck }
19-4
Part 3 Chapter 30 MS-DOS Routines
Over half of the copies of Turbo Pascal out there are running
under MS-DOS, so this advanced section will start with some
code designed to aid in interfacing with MS-DOS. These routines
are meant to serve as examples for advanced programmers; by
their very nature, they can get you into trouble if you're not sure of
what you're dOing.
All of these programs can be found on your TURBO Tutor disk
(assuming that you have the MS-DOS version). The file name of
each program is given in the title for each section. These
programs can all be compiled and executed immediately; how-
ever, you should look at each program before running it, since it
20-1
Chapter 20 MS-DOS Routines Part 3
var
81,82,Indx,Jndx,Count : Integer;
8um,T,NP : Real;
Tally : array[ 0 ..9] of Integer;
procedure Randomize(I,J: Integer);
20-2
Part 3 Chapter 20 MS-DOS Routines
var
BBet : record.
AX,BX,CX,DX,BP,8I,DI,DS,ES,Flags: Integer;
end;
Ch : Char;
begin
if (1=0) aDd (J=O) then begin { Generate a random random number
seed}
RBet.AX:=$2COO; { DOS time of d.aor :function}
MSDos(BBet);
I:=BBet.CXj { Set I and J to the system time }
J:=BBet.DX;
DelacY(l00); {This dalBO' IruW have to be 1ncreasedfor faster systems}
MSDosCBBet);
if (I=BBet.CX) aDd (J=BBet.DX) then begin { Clock isn't ticking}
I :=0;
J:=O;
while KeyPressed do
Read(Kbd,Ch)j { Clear keyboard buffer}
Write( 'Hit any key to set the random number generator: ');
repeat
I := 1+13;
J:=J+17
until Keypressed;
Rea.d(Kbd,Ch)j {Absorb the character}
WriteLn
end
end;
MemW[DSeg:$0129]:=I; {This is the core of the routine: store a 32 bit}
MemW[DSeg:Ol2B]:=J; {seed at locations DSeg:$0129 ...DSeg:$012B}
end; { of procedure Rando:m:ize }
20-3
Chapter 20 MS-DOS Routines Part 3
TURBO Pascal gives you a lot of control over disk files, including
the ability to erase files as well as to rename them. But nothing
quite beats being able to read the directory off the disk.
Here's a simple program that will read the names of all the files off
a given drive. You can also specify a mask, so that you only get
files matching a given pattern.
program DirListj
{
This is a simple program to list out the directory of the
current (logged) drive.
}
type
Char12arr = array [ 1..12 ] ofCharj
Str:lng20 = str1ng[ 20 ] j
-RegRec =
record
AX, BX, OX, DX, BP, SI, DI, DS, ES, Flags : Integer;
end.;
var
Regs : RegRecj
DTA : array [ 1..43 ] of Bytej
Mask : Char12arrj
NamR : striDg20j
Error, I : Integerj
20-4
Part 3 Chapter 20 MS-DOS Routines
20-5
Chapter 20 MS-DOS Routines Part 3
{ $I-,U-,C-}
20-6
Part 3 Chapter 20 MS-DOS Routines
{-------------------------------------------------
SetDTA resets the current DTA to the new address spec1.fied in the
parameters 'SEGMENT' and 'OFFSET'.
{--------------------------------------------------
GetCurrentDTA is used to get the current Disk Transfer Area ( DTA )
address. A function code of$2F is stored in the high Byte of the AX register
and a call to the predefined procedure MSDos is made. This can also be
accomplished byustngthe "Intr" procedurewtth the same register record
and a $21 spec1.fication for the interrupt.
20-7
Chapter 20 MS-OOS Routines Part 3
{--------------------------------------------------
GetFirst gets the first directory entry of a particular file Mask The Mask is
passed as a parameter 'Mask' and,the Option was previously specified in
the SpectiYQption procedure.
20-8
Part 3 Chapter 20 MS-DOS Routines
{-----------------------------------------------------
GetNextEntry uses the first bytes of the DTA for the file Mask, and returns
the next file entry on cliBk corresponding to the file Mask
20-9
Chapter 20 MS-DOS Routines Part 3
begin
for I := 1 to 21 do DTA[ I ] := 0; { Initialize the DTA Buffer}
for I := 1 to 80 do begin { Initialize the Mask and }
Mask[ I ]:= ChI'( 0 ); { file name buffers}
NamR[ I ]:= ChI'( 0 );
end;
NamR[ 0 ]:= ChI'( 0 ); { Set the file name length to 0 }
WriteLn( 'QDL version 2.00A' );
WriteLn;
GetCurrentDT.A( DTAseg, DTAofs,
Error ); { Get the current DTA address}
if ( Error < > 0 ) then begin { Check for errors}
WriteLn( 'Unable to get current DTA' );
WriteLn( 'Program aborting.' ); { and abort. }
Halt; { end program now}
end;
SetDTAseg:= Seg( DTA );
SetDTAofs := Ofs( DTA );
SetDT.A( SetDTAseg, SetDTAofs,
Error ); { Reset DTA addresses}
if ( Error < > 0 ) then begin { Check for errors}
WriteLn( 'Cannot reset DTA' ); { Error message}
WriteLn( 'Program aborting.' );
Halt; { end program }
end;
Error:= 0;
Buffer[ 0 ] := Chr( 0 ); { Set Buffer length to 0 }
GetDption( Option); { Get file Option}
if ( Option < > 8 ) then begin
Write( 'File Mask:' ); { prompt}
ReadLn( Buffer );
WriteLn;
end;
if ( length( Buffer) = 0 ) then { if nothing was entered}
Buffer:= '???????????'; { then use global search}
for I := 1 to length( Buffer) do { Assign Buffer to Mask}
Mask[ I ]:= Buffer[ I ];
GetFirst{ Mask, NamR, SetDTAseg, SetDTAofs, Option, Error );
if ( Error = 0 ) then begin { Get the first directory entry }
if ( Option < > 8 ) then begin { if not volume label }
WriteLn( 'Directory of: " Buffer );{ Write directory message}
WriteLn;
end;
WriteLn( NamR )
end
else if ( Option = 8 ) then
WriteLn( 'Volume label not found' )
20-10
Part 3 Chapter 20 MS-DOS Routines
var
Tracks, { number of available Tracks }
TotalTracks, { number of total Tracks }
Drive, { Drive number}
Bytes, { number of Bytes in one sector}
Sectors : Integer; { number of total Sectors}
Used.,TotalBytes : Real;
Regs : RegRec;
procedure D1skStatus( Drive: Integer;var Tracks, TotalTracks,
Bytes, Sectors: integer);
20-11
Chapter 20 MS-DOS Routines Part 3
b~in
Regs.AX := $3600; { Get Disk free space}
Regs.DX:= Drive; { Store Drive number}
MSDos( Regs); { Call MSDos to get disk info }
Tracks := Regs.BX; { Get number of Tracks Used}
TotalTracks:= Regs.DX; {" " "of total Tracks }
Bytes := Regs.OX; {" " "of Bytes per sector}
Sectors: = Regs.AX { " " of Sectors per cluster}
end; { of proc DiskStatus }
vnr
Regs: RegRec;
bogin
Regs.AX := $1900; { Get current Drive number}
MSDos( Regs ); { Call MSDos }
DefaultDrive := (Regs.AX and $FF) + 1 { Return value via function}
end; { offunc DefaultDrive}
20-12
Part 3 Chapter 20 MS-DOS Routines
begin
Regs.AX := $3000;
MSDos( Regs);
AL:= Regs.AX and$FF;
AH := ( Regs.AX and $FFOO ) ohr 8;
DosVer := AL + AH/l00;
end; { offunc DosVer}
20-13
Chapter 20 MS-DOS Routines Part 3
COD8t
Video =$ 10; { Set Video I/O Interrupt}
SetVideo 0; { Set Video mode}
SetCurPosition =$200; { Set cursor position}
ReadCursor = $300; { Read cursor position}
WriteChar =$EOO; { Write character to sceen }
VideoBW80x25A 2; { Mode 80x25 B/W, Alpha }
VideoColorBOx25A 3; { Mode 80x25 Color, Alpha }
type
Result = { Regtster pack}
record
AX,BX,CX,DX,BP,8I,DI,DS,ES,Flags: Integer;
end;
var
Rec :Resul~
Row,Col : Integer;
begin
Rec..AX := SetVideo + VideoBW80x25A; {assumes BW 80x25 displSlY}
Rec.BX := 15;
Intr(Video,Rec); { Set Video Mode}
Rec.AX:= WriteChar + Ord{'A');
Intr(Video,Rec); {Output 'A'}
Rec.AX := ReadCursor;
Intr(Video,Rec); { Read the cursor position}
Row := Rec.DX and. $FFQO ahr 8;
Col := Rec.DX and. $FFj
Write('Row = ';Row,' Column = ',Col); { Show the Row and column}
RecAX := SetCurPosition;
Rec.DX := $DAOA;
Intr(Video,Rec)j { Set the cursor to Row 10 and column 10 }
Rec.AX:= WriteChar + Ord{'#')j
Intr(Video,Rec)j {Output '#'}
Rec.AX := ReadCursor;
Intr(Video,Rec); { Read the cursor position}
Row := Rec.DX and. $FFQO shr 8;
Col := Rec.DX and. $FF;
Write( 'Row = ';Row,' Column = ',Col); { Show the Rowand column }
Rec.AX:= SetCurPosition;
Rec.DX := $1414;
Intr(Video,Rec); {Setthe cursor to Row 20 and column 20 }
end. { of program IBMpcScreen }
20-14
Part 3 Chapter 20 MS-DOS Routines
-Interrupts-
20-15
Chapter 20 MS-DOS Routines Part 3
program ScreenMap;
{program to Write to the screen map}
cODBt
ColoIBeg = $BOOO;
ColorOfs = $8000;
var
I,J : Integer;
C : Char;
RowNumber,ColNumber,Length,Dir
: Integer;
Direction : Char;
begin
CIIBcr;
GotoXY(20,10);
Write( 'Do you want to plBiY <YIN> ? ');
Rea,d(kbd,C);
if (C = 'y') or (C = 'Y') then begin
repeat
CIIBcr;
GotoXY(20,10);
Write('Wouldyou like to draw a line <YIN>? ');
Read(kbd,C);
until (C = 'y') or (C = 'Y') or (C = 'n') or (C = 'N');
if (C = 'y') or (C = 'Y') then begin
repeat
CIIBcr;
Y(1,1,80,31,1);
20-16
Part 3 Chapter 20 MS-DOS Routines
Y(2,1,24,16,0);
Y(2,80,24,17,0);
Y(26,2,78,30,1 );
GotoXY(20,10);
Write(/The line starts at what row? ');
Read(rownumber);
GotoXY(20,12);
Write(' what colunm? ');
Read( colnumber);
GotoXY(20,14);
Write(' Line length in number? ');
Read(length);
GotoXY(20,16);
Write(' Whatcharactertouse? ');
Read(Kbd,C); Write(C);
repeat
Got£lXY( 10,18); Write(' wh1chd1rect1on<d>ownor<a>cross? ');
Read(Direction)
until (Direction=/a/) or (Direction=/d');
if Direction=, a'
then Dir:=l
elae Dir: =0;
CI:rt3cr;
Y(rownumber,colnumber,length,ord( C),dir);
GotoXY(40,24);
Write('Your line. Try again? ');
Read(Trm,C);
untU(C< > 'Y/) 8D4(C< > 'y);
CI:rt3cr
end
end
elae beg:lD.
GotoXY(23,13);
WriteLn('******** Bye ********/)
end
end. { of program ScreenMap }
20-17
Chapter 20 MS-DOS Routines Part 3
20-18
Chapter 20 MS-DOS Routines Part 3
type
_ -Registenget=Record case Integer of
1: (AX,BX,CX,DX,BP,DI,8E,DS,ES,Flags: Integer)j
2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte)j
end;
- .YaritfiYpe=(None,Even,Odd)j
20-19
Chapter 20 MS-DOS Routines Part 3
var
_ ...Regs: _ ...RegisterSet;
lnError,OutError: array [1 ..2] of Byte;
procedure _ Jnt14(PortNumber,Command,Parameter: Integer);
{ do a BIOS COM driver interrupt}
begin
with _ ...Regs 40
begin
DX:=PortNumber-1 ;
AH:=Command;
AL:=Parameter;
Flags: =0;
Intr($141-...Regs);
end;
end;
var
Parameter: Integer;
begin
case BaudRate of
110 : BaudRate:=O;
160 : BaudRate:=l;
300 : BaudRate:=2;
600 : BaudRate:=3;
1200: BaudRate:=4;
2400: BaudRate:=6;
4800: BaudRate:=6;
else BaudRate:=7; { Default to 9600 baud}
end;
if StopBits=2 then StopBits:= 1
else StopBits:=O; { Default to 1 stop bit}
if DataBits=7 then DataBits:=2
else DataBits:=3; {Default to 8 data bits}
Parameter:=(BaudRate sh16)+(StopBits sh12) + DataBits;
case Parity of
Odd: Parameter:=Parameter+8;
Even: Parameter:=Parameter+24;
else; { Default to no parity }
end;
_ Jnt14(PortNumber,O,Parameter);
end;
20-20
Part 3 Chapter 20 MS-DOS Routines
begin
_....Intl4 (PortNumber,3,O);
SerialStatus := _ -.Regs.AX;
end;
procedurL _OutPortl( C: Byte);
{ Called by Write to Aux or Usr when assigned to COMl }
begin
while (SerialStatus( l) and $30)=0 do ;
_....Intl4(l,l,C);
OutError[l]:=OutError[l] Or (_-.Regs.AH and $BE);
end;
begin
while (SerialStatuS(2) and $30)=0 do ;
__Intl4(2,l,C);
OutError[2]:=OutError[2] or (_ -.Regs.AH and $BE);
end;
begin
__ Intl4( 1 ,2,0);
__InPortl: =Chr( _ -.Regs.AL);
InError[l]:=InError[l] Or (_-.Regs.AH and$8E);
end;
J'aD.ction _ -InPort2: Chari
{ Called by Read fromAux or Usr when assigned to COM2 }
begin
__Intl4(2,2,0);
__InPort2:=Chr(_ -.Regs.AL);
InError[2]:=InError[2] or (_ -.Regs.AH and $BE)i
end;
20-21
Chapter 20 MS-DOS Routines Part 3
var
I: Integer; B: array [0 ..3] ofB'triDg[4];
20-22
Part 3 Chapter 20 MS-DOS Routines
begin
for 1:=0 to 16 do
if (V and.(18h1(16-1)))<>O thenB[1 div4][(I mod4)+I]:='I'
else B[1 div4][(1 mod4)+I] := '0';
for 1:= 0 to 3 doB[1][O]:= Chr(4);
B1na.ry:=B[O]+' '+B[I]+' '+B[2]+' '+B[3];
end;
begin
Write( 'Enter port number: ');
ReadLn(Port);
AsslgnUsr(Port);
Write('Enter baud rate: ');
ReadLn(Baud);
Write('Enter stop bitB: ');
ReadLn(StopBitB);
Write( 'Enter data bItB: ');
ReadLn(DataBitB );
Write('Enter parity (O=none, 1 =even, 2=odd): ');
ReadLn(Par);
Write('Enter message to print: ');
ReadLn(Message);
SetSer1a.l( l,Baud,StopBItB,DataBitB,ParltyType(Par));
WrlteLn(Usr,Message);
WrlteLn('OutError[' ,Port,']: ' ,B1nary(OutError[Port]));
WriteLn( 'Ser1aJBtatus(' 'port,'): ' ,B1nary(Ser1aJBtatus(Port)));
end. { of program ComLibTest }
20-23
Chapter 20 MS-DOS Routines Part 3
type
Regpack=
record
AX,BX,CX,DX,BP,8I,DI,DS,ES,Flags : Integer;
end;
var
OldX,OldY;X,Y : Integer;
M1,M2,M3,M4 : Integer;
Regpak : Regpack;
20-24
Part 3 Chapter 20 MS-DOS Routines
var
Segl: Integer;
Ofsl: Integer;
Count: Integer;
OutWord: Integer;
Num: Integer;
Varl: Integer;
Value: Char;
20-25
Chapter 20 MS-DOS Routines PartS
begin
ClIf3crj
GotoXY(20,5 );
Write('enterValue for starting address')j
ReadLn(Varl )j
Segl := Seg(Varl);
Ofsl := Ofs(Varl)j
WriteLn;
WriteLn( 'This variable is at segment: ' ,segl " with an offset of ',Ofsl);
WriteLn;
WriU('NowputinaValue(si.nglechar)thatyouw1Bhmemoryloadedwith: ');
ReadLn(Value);
Write('Put in how manywordByou want filled: ');
ReadLn(Num);
FillChar(Varl,Num,Value);
ClIf3cr;
WriteLn('Now we print our memory starting with ' ,segl ,':' ,Ofsl);
for Count := 1 to Num do begin
OutWord:= Mem[Segl:Ofsl];
WriteLn(Segl,':',Ofsl,' has value ',OutWord);
Ofsl := Ofsl + 1;
end
end. { of program DemoFillChar }
20-26
Part 3 Chapter 21 CP/M Routines
21-1
Chapter 21 CP/M Routines Part 3
begin
Error := BDos(Set..DMA.,Addr(DMA))j
FCB[O]:= OJ
for Loop := 1 to 11 do
FCB[Loop] := ord('?')j
Error:= BDos(Search..First~ddr(FCB))j
if Error < > 255 then begin
Start : = Error * 32j
for Loop:= Start to start+8 do
Write(Cha.r(Mem[Addr(DMA)+Loop]) )j
Write(' ')j
for Loop:= Start+9 to Start+11 do
Write(Cha.r(Mem[Addr(DMA)+Loop]))j
WriteLn
end;
repeat
Error:= BDos(searclLNext);
Start := Error * 32;
if Error < > 255 then bagin
for Loop:= Start to start+8 do
Write(Cha.r(Mem[Addr(DMA)+Loop]));
Write(' ');
for Loop:= Start+9 to Start+11 do
Write(Cha.r(Mem[Addr(DMA)+Loop]));
WriteLn
end
until Error=255
end. { of program CPM80Dir }
program. CPMstatus;
{
Reads and d1sp1aors CP1M status information
}
cODBt
CPMversion 12;
CurDiBk 25;
AllocVector 27;
DiBkParam 31;
GetUser 32;
21-2
Part 3 Chapter 21 CP/M Routines
type
Word = Intege~
HexStr = string[ 4];
DPBREC=
record
SPr : Integer; {SEareRS PER TRACK}
BSH : Byte; {DATAALLOCATIONBIDCKSHIFrFAaroR}
BLM : Byte;
EXM : Byte;
(* DSM : Integer; {TOTAL STORAGE CAPACITY} *)
DSMlo : Byte;
DSMhi : Byte;
DRM : Integer; {NO ofDIREarORY ENTRIES}
.AJ.JJ,AL1 : Byte;
OKS : Intege~
OFF : Integer
end; { DPBREC }
var
DPB : A DPBREC;
RecsPrBlock : Integer;
RecsPrDrive : Real;
TrksPrDrive : Real;
TPA : Real;
Version : Intege~
Result : Integer;
21-3
Chapter 21 CP/M Routines PartS
21-4
PartS Chapter 22 Assembly Language Programming
-Assembler-
There are usually three reasons for calling assembly language
from a high-level language. The first is to execute some system
operation; the second, to perform some sort of data manipulation;
the third, to carry out some set of instructions more quickly. In al!
22-1
Chapter 22 Assembly Language Programming Part 3
The above statement is often true, but not always ... so, yes, there
may be time when you want to write assembly language routines.
In that case, you have two routes to go. The first (and simplest) is
to use in-line machine code. Turbo Pascal allows you to insert
(anywhere!) machine code, which will then be executed everytime
the inline statement is encountered.
The inline statement takes the form:
:ln11ne( vall/vall/.. ./valn);
22-2
Part 3 Chapter 22 Assembly Language Programming
program InLinEBample;
{
The following program example divides even integers by two.
For odd integers this program returns -32768 + the value
divided by two (integer division)
var
Value : Integer;
procedure VInLine(var Value:Integer);
{
a simple use of inline code. Note that some constants
have been defined and used, while other values are left
as literal hexadecimal constants. This is done just for
illustration.
}
ccmst
CLC = $F8;
IN_CDI = $47;
begin
iDline
($C4/$BE/VALUE/ {LEB DI;VALUE[BP] }
CLC/ { CLC }
$26/$DO/$lD/ {RCR EB:BYTE PrR [DI] }
IN_CDI! { INC DI }
$26/$DO/$lD); {RCR EB:BYTE PrR [DI] }
end; { of proc VInLine }
22-3
Chapter 22 Assembly Language Programming Part 3
If instead you are using MS-DOS, then you must write a true
assembly language routine which is assembled separat,ely and
then linked in at compile time. The advantage is that you can write
directly in assembly language (rather than "hand-assembling"
your routines into machine code for the inline statement). The
disadvantages are that you have to own an assembler (and one
that's compatible with TURBO Pascal), and that you have to
make sure that your assembly routines and your Pascal code can
correctly communicate with each other. Again, the particulars
are specific to each operating system, so you are again referred
to the appropriate appendices in the TURBO Pascal Reference
Manual.
22-4
Part 3 Chapter 22 Assembly Language Programming
code segment
assume cs:code
pass proc near
push bp j SAVE ENVIRONMENT
mov bp,sp
inov ax,[bp+4] j GET PARAMETER 1
add ax,[bp+6] ; GET PARAMETER 2
j GIVES THE RESULT
mov sp,bp j RESTORE ENVIRONMENT
pop bp
ret 4
pass endp
code ends
end
j Now exit to PC-ooS and t:Q7pe:
>ASMPASS
>LINKPASS
>EXE2BIN PASS.EXE PABS.COM
,
; Ignore minor errors from ABM and LINK.
Having carried out the steps above, you can now compile the
following TURBO Pascal program (making surethat PASS.COM
is on the default (logged) drive):
»rogram PassFunc;
{
ThiS routine expects the assemb1y language routine 'Pass'
to reside in the file 'PASS.COM'
var
Varl, Var2, Var3: Integer;
22-5
Chapter 22 Assembly Language Programming Part 3
When this program compiles, TURBO Pascal will look forthe file
PASS.COM and link the machine code into the executable code
being produced.
22.3 CONCLUSION
Well, this is the end of my little book. I have enjoyed telling you
what I know about TURBO Pascal. I hope you've enjoyed
learning about it. All of the tools are now in your hands. It is up to
you to use those tools like any skilled craftsman would. Practice
what you have learned until you master it, then move on to
something else.
Since you have read the entire manual, I would like to reward you
with a few bits of wit I thought you might enjoy:
1. If it were not for the last minute, nothing would ever get done.
2. The efficency of a programming team is inversely propor-
tional to the number of members in that team, whenever that
number is greater than three!
3. Even the simplest things are more complicated than you
thought.
4. The first 90 percent of a job takes 90 percent of the available
time; the last 10 percent takes the other 90 percent.
5. Always plan for the project to take twice as long as you
expected, after first doubling your original estimates.
22-6
Part 3 Chapter 22 Assembly Language Programming
22-7
NOTES
INDEX
23-1
device 1/0, 18-16 forward declarations, '11-12
direct memory output routine, free union, 15-12
20-15 FUNCKEYS.PAS routine, 19-1
direct video output routine, 20-13 function key detection routine, 19-1
directory display, 6-14 functions, 9-8, 11-1, 11-8
DIRECTRY.PAS routine, 20-3
discriminated union, 15-12 G
disk status routine, 20-11 getting started, 6-1
DISKSTUS.PAS routine, 20-11
div, 9-3 H
DOS version number routine, 20-13
DST heap, 17-4
ordinal value, 12-4 size of, 17-4
reading values, 12-10 use of, 17-5
DSTs, 12-1 hex constants, 9-7
dynamic allocation, 17-1 History of Pascal, 2-1
E
editor, 6-6 1/0 error checking routine, 19-3
EOLN function, 18-9 1/0 error handling, 18-20
equations 1/0 special filenames, 18-18
using parentheses, 9-5 1/0 {$I-} compiler option, 18-15
error handling, 6-9 IBMINT10.PAS routine, 20-13
1/0,18-20 identifiers, 7-8, 9-2
error if...then ... else, 10-11
run-time, 6-12 in-line code routine, 22-2
type mismatch, 9-12 information, 4-2
value range error, 9-6 INLlNE.PAS routine, 22-2
executing a program, 6-16 input/output, 7-2
expression integer expressions, 9-4
boolean, 10-3 integers, 9-3
integer, 9-4 real,9-10
expressions, 7-11 unsigned,9-7
predefined functions, 9-7
F 10ERROR.PAS routine, 19-3
iteration, 10-6
file, 18-1
appending records to, 18-6 K
chaining, 6-12
definition, 18-1 keyboard
directory of, 6-15 real-time input, 18-19
random access, 18-5
saving, 6-14 L
text, 18-7 languages
untyped, 18-14 structured, 2-5
filenames, 18-13 linked list, 17-6
fillchar demo routine, 20-25 use of, 17-8
FILLCHAR.PAS routine, 20-25 local variable, 11-5
for... do loop, 10-7 logical operators, 9-3
formatted output, 18-10 looping, 10-6
23-2
M precedence of operations, 9-5
predefined data types, 8-3, 9-1
main body of a program, 7-3 predefined functions
main menu, 6-3 for integers, 9-7
memory management, 17-9 table of, 8-19
memory space, 6-16 predefined procedure, 8-6
MEMSCREN.PAS routine, 20-115
table of, 8-18
Microsoft Mouse interface routine,
procedure
20-23 definition, 1-4
mixing strings, characters, predefined, 8-6
and arrays, 14-16 procedures, 9-8, 11-1
mod,9-3 program statement, 8-2
program structure
N advanced, 8-11
Niklaus Wirth, 2-5 program
nil,7-10 body, 8-4
nonsequential program execution, commenting, 7-4, 8-8
10-1 conditional execution, 10-4
normalization, 9-14 declaration section, 8-1
not operator, 9-8 header, 3-5
numeric conversions, 14-13 main body, 7-3
numeric data, 4-2 parts of, 3-5
running, 6-10
o simple, 3-3
object code, 5-4 statements, 3-6
operator precedence, 9-5, 9-11 structure, 8-1
operator programming
unary, 9-8 basic concepts, 4-1
operators, 9-8 considering data to use, 5-3
order of elements in an array, 13-6 habits, 3-2 .
order of evaluation, 9-5 identifying the problem, 5-2
ordinal values, 12-4 pseudocode, 5-4
other books to read, 22-7
Q
p QDL.PAS routine, 20-6
packed array, 13-5
parameter lists, 11-8 R
parameters, 11-6 random accesss of files
parentheses definition, 18-6
use in equations, 9-5 RANDOM.PAS routine, 20-2
Pascal randomize rOL!tine, 20-2
converting BASIC to, 7-1 read command line routine, 20-17
history, 2-1 read directory routine, 20-4, 21-1
TURBO vs. Standard, 8-12 reading DST values, 12-10
PASS.ASM routine, 22-3 real integers, 9-10
PASSFUNC.PAS routine, 22-2 real number
pointer, 17-2, 17-3 exponent, 9-13
pointing, 17-4 precision, 9-13
use of, 17-3 round-off error, 9-13
portable languages, 2-3 real-time keyboard input, 18-19
23-3
record, 15-1 subranges, 12-12
field,15-2 swapping values, 11-7
space considerations, 15-10 symbols, 7-9
variant, 15-8 system status routine, 21-2
recursive subprogram, 11-11
T
remainder, 9-3
repeaL.untilloop, 10-10 TBOMOUSE.PAS routine, 20-23
reserved words, 3-3, 7-8 terminal installation program, 6-1
as symbols, 7-9 text files, 18-7
run-time errors, 6-12, 9-13 tinst, 6-1
running a program, 6-10 truth table, 10-15
type mismatch error message, 9-12
S TVPEAHED.PAS routine, 19-2
typed constants, 8-14
saving files, 6-14
scope of identifiers, 11-3 U
semicolon, 3-6 unary operator, 9-8
exceptions, 3-6 union
use of, 7-3, 8-6 discriminated, 15-12
serial port library routine, 20-18 free, 15-12
set, 16-1 Unknown Identifier error message,
comparison, 16-3 9-2
constant, 16-1 unsigned values, 9-7
defining, 16-1 untyped files, 18-14
difference, 16-5 using parentheses in equations, 9-5
intersection, 16-5
operations, 16-4 V
size, 16-2 value range error message, 9-6
union, 16-5 variable, 3-5, 4-4, 7-10, 9-2,13-1
use of, 16-2 Boolean, 9-17
simple word processor, 14-5 byte, 9-9
source code, 5-4 char, 9-15
space creating, 9-1
in memory, 6-16 declaring, 9-1
statement, 3-6, 4-5, 10-1 defining, 7-3
compound, 10-2 entering control characters, 9-16
string, 14-1 forward declaration, 11-12
and {$V-} option, 14-16 integer type, 9-3
,as parameter, 14-14 local, 11-5
comparisons, 14-5 of type string, 14-2
definition, 14-2 previously declared, 11-4
function, 14-7 variant records, 15-8
numeric conversion, 14-13 VERSION.PAS routine, 20-13
procedure, 14-7
W
procedure & function table, 14-18
structured language, 2-5 while ... do loop, 10-9
subprogram, 8-15, 11-1 Who is Frank Borland?, 4
location, 11-2 Wirth; Niklaus, 2-5
recursive, 11-11 WITH statement, 15-4
subrange nesting, 15-5
declaration, 12-13 writing a simple program, 3-3
writing to disk, 18-5
23-4
CATALOG
or ALL
BORLAND
PRODUCTS
.>.> BORlAnD
INTERNATIONAL
NOTES
SUPERKEY TURNS 1,000 KEYSTROKES INTO 1
Bllllrll'
AND KEEPS YOUR 'CONFIDENTIAL FILES' ... CONFIDENTIAL.
Borland International, the folks who brought you SIDEKICKn•., now offer you a keyboard enhancer that
can truly make your life easier and your files safer.
When you've got a lot to do, SUPERKEy™ lets you dramatically cut the number of times you touch
the keyboard. Even your most sophisticated programs becomes one-stroke easy.
SUPERKEY also performs as a high-level security encryptor/decryptor to protect your sensitive files.
Mode 1: DIRECT-OVERWRITE ENCRYPTION: Just give SUPERKEY your password and the files of
your choice will be encrypted or decrypted - without changing file size or creating backup
files for even greater document security. You can even encrypt public bulletin board messages.
No more curious reading of your files unless you provide the secret password.
Mode 2: EXE OR COM FILE ENCRYPTION: Using your personal code, SUPERKEY can encrypt your
files for transmission (over a phone line, for instance). On the other end, only your secret
code can reconstruct the file.
• PRIVACY MODE: SUPERKEY lets you turn off your screen and lock your keyboard against intruders.
• SCREEN BURN-IN PROTECTION: SUPERKEY will switch your monitor off if there's no input or screen
110. As soon as a key is touched, the screen image returns.
• RAM RESIDENCE AT ALL TIMES: Create, edit, save and even recall new or existing macro files
anytime, even while running another program.
• PULL-DOWN MACRO EDITING: A single keystroke opens a full-screen WordStarTr"-command edit
window. You can perform most word processing functions including file naming. SUPERKEY even
has our 'clip & tape' function for moving blocks of data from the screen for later retrieval.
• COMMAND KEY REDEFINITION: With a few easy strokes, you can redefine key commands 'on the fly'.
• ENTRY AND FORMAT CONTROL IN DATA FIELDS: SUPERKEY tests for digits or letters, converts
lower case to upper case and visa-versa, and justifies files right, left, or center.
• TOTAL PROKEY COMPATIBILITY: SUPERKEY uses every ProKey ™ macro file without any con
version! No time is wasted and you're that far ahead.
• DISPLAY-ONLY MACRO WINDOW: Create your own customized on-line help system for other users.
An ideal feature to set-up interactive tutorials on your computer.
• CONTEXT-SENSITIVE ON-LINE HELP SYSTEM: You can request just the help you want-no more
wading through the whole operating manual.
.»
• » BORLAnD
INTERNATIONAL
Available at Better Dealers Nationwide.
4585 Scotts Valley Drive
Scotts Valley, CA 95066
SideKick and SuperKey are trademarks of Borland Internallonal. Inc
IBM and PC· DOS are trademarks of International BUSiness Machines Corp
ProKey IS a trademark of RoseSoft
Telephone: (408) 438-8401
Telex: 172373
Telecopier: (408) 438-8691
For Credit Card Order Ca
(800) 255-8008,
(800) 742-1133 (in CA.)
WordStar IS a trademark of Mlcropro International Corp
NOTES
l1J'i7ln'\lij]'il~11( ilJ127
'~""l,~uili1'L"':\ '''~'::1)\'
.
,~ ./!-JL...::. i.-.JL-.4!-.4,-" '_ t __
''SIDEKICK™ stands in the shadows behind whatever program you are using, ready to
jump forward when you need it. The program's various functions use windows that overlay
the display you are working with and restore the screen when you are through. The pro-
gram contains a respectable word processor for note taking, a dialer that your smart modem
can use with your phone list, a calculator for hexidecimal/binary/decimal arithmetic, an ap-
pointment calendar and a ASCII table for programmers ... SIDEKICK IS A TIME-SAVING,
WORK-SAVING, FRUSTRATION-SAVING BARGAIN·"_Dan Robinson of INFOWORLD
Here's SIDEKICK running over Lotus 1,2,3TM. In the SIDEKICK All the SIDEKICK windows stacked up over lotus 1,2.3. From bot-
Notepad you'lI notice data that's been imported directly from the tom to top: SIDEKICK's "Menu Window': ASCII table, Notepad,
Lotus screen. In the upper right you can see the Calculator. Calculator, Appointment Scheduler and Calendar, and Phone
Dialer. Whether you're running WordStarTM, Lotusn.t, dBasen.t, or
any other program, SIDEKICK puts all these desktop accessories
instantly at your fingertips.
THE CRITIC'S CHOICE
- Charles Petzold, PC MAGAZINE: "In a simple, beautiful implementation of Word-
Star'sTM block copy commands, SIDEKICK can transport all or any part of the display
screen (even an area overlaid by the notepad display) to the notepad."
- Garry Ray, PC WEEK: "SIDEKICK deserves a place in every PC."
- Jerry Pournelle, BYTE: "If you use a PC, get SIDEKICK. You'll soon become depen-
dent on it."
SIDEKICK is an unparalleled bargain at only $54.95 (copy-protected)*
$84.95 (not copy-protected)*
"Minimum System Configuration: SIDEKICK is available now for your IBM pc, >IT. AT. jr. and 100% compatible microcomputers. The
IBM PCjr. will only accept the SIDEKICK not copy-protected version. Your computer must have at least 128K RAM, one disk drive and
PC-DOS 1.0 or greater.
SIdeKick IS a trademark of Borland International. Inc aBase IS a trademark of ~shloo·Tale. IBM and PC·DOS are lfaoemarkS of Internal,onai BUSiness
Machones Corp. InfOMlrld IS a trademark 01 Popular ComputIng. Inc.. a substo.ary 01 CW Cor,municatlOlls. Inc loCus and 1.2.3. are trademarks of lotus
Dew!lopment Co~ WordStar IS a trademark of M.cropro fnletnalional Corp
(.) Benchmark run on an IBM PC using MS Pascal version 3.2 and the DOS linker version 2.6. The 179 line program used is the "Gauss·
Seidel" program out of Alan R. Miller's book, Pascal Programs for Scientists and Engineers (Sybex, page 128) with a 3-dimensiona
non-singular matrix and a relaxation coefficient of 1.0.
TURBO PASCAL 2,0 had a lot of great features and they're stili there in TURBO PASCAL 3,0:
• BUILT-IN INTERACTIVE EDITOR: WordStar™-easy editing lets you debug quickly.
• ONE-STEP COMPILE: No more 'hunting & fishing' expeditions. TURBO PASCAL does it all in one simple step.
• MICROCALC: A full-blown spreadsheet on your disk ready-to-run with complete annotated source code.
The best Just gets better with a host of additional features:
• We rewrote the I/O system and we now support I/O redirection.
• For iBM PC versions we've added TURTLE GRAPHICS and full tree directory support.
• For all 16-bit versions, we now offer two options: 8087 math coprocessor sLipport for intensive calculations and Binary Coded
Decimals (BCD) for business applications.
Debugging is So Easyl When you run your program, TURBO 3,0 locates any error, takes you to It, and tells you what it
is, Your program Is up in record time,
Specifications:
Compile Speed Approximately 150 lines per Code size: Object code plus 9K for run time
second (IBM PC) library(complete)
Number of Max code size: 64K
passes: 1 Max data size: 64K
Complied to: Native machine code (.COM files Max stack size: 64K
I.CMD for CP/M-86)) Max heap: Unlimited
The Critics Unite:
Jeff Duntemann, PC MAGAZINE: "Language deal of the century ... TURBO PASCAL. It introduces a new programming environmenl
and runs like magic."
Dave Gariand, POPULAR COMPUTING: "Most Pascal compilers barely fit on a disk, but TURBO PASCAL packs an editor, compiler
linker, and run-time library into just 29K bytes of RAM."
Jerry Pournelle, BYTE: "What I think the computer industry is headed for: well-documented, standard, plenty of good features, anc
a reasonable price."
The unbelievable TURBO PASCAL 3.0 is available right away for $69.95 (not copy-protected)·,
• Options: TURBO PASCAL with 8087 or BCD at a low $109.90. TURBO PASCAL with both options (8087 and BCD) priced at $124.95.
Minimum System Configuration: TURBO PASCAL 3.0 is available today for your Z-80, 8088/86, 80186 or 80286 microprocessor com·
puter running either CP/M-80 2.2 or greater, CP/M-86 1.1 or greater, MS-DOS 1.0 or greater or PC-DOS 1.0 or greater. Your computel
must have at least 64K RAM and one disk drive. A XENIX version of TURBO PASCAL will soon be announced, and before the enc
of 1985, TURBO PASCAL will be running on most 68000-based microcomputers.
Integrated full screen editor with WordStar·like functions. Supports BIOs/BDOS calls for CP/M·80 and 86. Supports Interrupt and MS·DOS function calls for MS
DOS. PC· DOS. Inline machine code. External subroutines (in relocatabie binary format). Direct access to CPU and data ports.
ID BORlAnD
INTERNATIONAL
4585 Scotts Valley Drive
Scotts Valley, CA 95066
Telex: 172373
Telecopier: (408) 438-8696
For Credit Card Order Call:
(800) 255-8008,
(800) 742-1133 (in CA,)
TurboPascal. SideKick and SuperKey are trademarks of Borland International. Inc. CP/M is a trademark of Digital ResearCh, Inc. IBM and PC· DOS are trademark!
of International Business Machines Corp. MS·DOS and XENIX are trademarks of Microsoft Corp. WordStar is a trademark of Micropro International Corp. Z·8e
is a trademark of Zilog. Inc.
NOTES
TURBO TUTOR
Learn Pascal from the folks who invented TURBO PASCAL™ and TURBO TOOLBOX™.
Borland International proudly introduces TURBO TUTOR™. The perfect complement to
your TURBO PASCAL compiler.
If you're already proficient, TURBO TUTOR can sharpen up the fine points.
The 300 page manual and program disk divides your study of Pascal into three learning
modules:
For the Novice: Gives you a concise history of Pascal, tells you how to write a simple pro-
gram, and defines the basic programming terms you need to know.
Programmer's Guide: The heart of TURBO PASCAL. This section covers the fine points
of every aspect of TURBO PASCAL programming: program structure, data types, control
structures, procedures and functions, scalar types, arrays, strings, pointers, sets, files and
records.
Advanced Concepts: If you're an expert, you'll love the sections detailing subjects such
as "how to use assembly language routines with your TURBO PASCAL programs."
A MUST. You'll find the source code for all the examples in the book on the accompanying
disk ready to compile.
TURBO TUTOR may be the only reference on Pascal and programming you'll ever need!
"Minimum System Configuration: TURBO TUTOR is available today for your computer running TURBO PASCAL for PC-DOS, MS-DOS,
CP/M-8a. and CP/M-86. Your computer must have at least 128K RAM, one disk drive and PC-DOS 1.0 or greater, MS-DOS 1.0 or greater,
CP/M-80 2.2 or greater, or CP/M-86 1.1 or greater.
• » BORLAnD
. ) INTERNATIONAL
Available at BeHer Dealers Nationwide.
4585 Scotts Valley Drive
Telephone: (408) 438-8400
Telex: 172373
Telecopier: (408) 438-8696
Scotts Valley, CA 95066 For Credit Card Order Call:
(800) 255-8008,
(800) 742-1133 (in CA.)
Turbo Pascal. Turbo Tutor and Turbo Toolbox are trademarks 01 Borland International. Inc. CP/M is a trademark of D,gital Research. Inc. MS·DOS is a trademarl
of Microsoft Corp. PC-DOS is a trademark of International Business Machines Corp.
NOTES
TURBO TOOLBOX
"A PASCAL PROGRAMMER'S BEST FRIEND"
Borland International now offers TURBO TOOLBOXTv , a three-module TURBO package that gives
even a novice programmer the expert's edge. The perfect complement to TURBO PASCALrM , the in-
dustry standard in Pascal compilers. Fully commented source code to the first two modules is includ-
ed on diskette.
Take a Close Look:
TURBO-ISAM Files Using B+ Trees
A powerful implementation of the state-of-the-art B+ tree ISAM technique. The TURBO-ISAM
system makes it possible to access records in a file using keys (e.g., "Smith" or "Rear Bumper")
instead of just a number. Even though you have direct access to individual records in the file,
you also have easy access to the records in a sorted sequence. A must if you plan to work with
direct access files. Source code is included in the manual.
QUICKSORT On Disk
The fastest way to sort your data. A super efficient implementation of the quickest data sorting
algorithm preferred by knowledgeable professionals. Available for you now with commented source
code.
GINST (General Installation Program)
Now, your programs are easily installed on other terminals. Saves hours of work and research,
and adds tremendous value to everything you write.
Free Sample Database:
Your TURBO TOOLBOX now comes with source code for a working database... right on the disk.
Just compile it, and it's ready to go to work for you. It's a great example of how to use TURBO
ISAM, and at the same time, it's a working piece of software you can use right away. The database
searches by name or code, updates records as needed. Since you're supplied with commented
source code, you can tailor it to your own specific needs.
Specifications:
Random Record Access with ISAM files using B+ trees. Turbo Access Speed: 1.5 seconds (Average seek time with 1.000 records-86
bytes/rec). Quicksort speed: 43 seconds (1.000 records. 86 bytes/rec.. 256K RAM).
Jeff Duntemann, PC Tech Journal: .. Turbo Pascal is the most nearly bug-free compiler I have eVI
used, and the Turbo Toolbox comes close in quality. "
Jerry Pournelle, BYTE: "The tools include a B+ tree search and a sorting system; I've seen stuft
like this, but not as well thought out, sell for hundreds of dollars."
'Mlnimum System Configuration: TURBO TOOLBOX is available today for your computer running TURBO PASCAL 2.0 or greater fo
PC· DOS. MS·DOS. and CP/M·SO or Turbo Pascal 2.1 or greater for CP/M·86. Your computer must have at least 12SK RAM. one disl
drive and PC·DOS 1.0 or greater. MS·DOS 1.0 or greater. CP/M·SO 2.2 or greater. or CP/M·86 1.1 or greater.
• Tools that allow you to draw and hatch pie charts, bar charts, circles, rectangles and a
full range of geometric shapes.
• Procedures that save and restore graphic images to and from disk.
• Tools that allow you to create animation or solve those difficult curve fitting problems.
No sweat and no royalties. You can incorporate part, or all of these tools in your programs,
and yet, we won't charge you any royalties. Best of all, these functions and procedures come
complete with commented source code on disk ready to compile!
John Markoff & Paul Freiberger, syndicated columnists: "While most people only talk
about low-cost personal computer software, Borland has been doing something about it.
And Borland provides good technical support as part of the price."
The versatile TURBO GRAPH IX TOOLBOX is priced at only $54.95 (not copy-protected).·
"Minimum System Configuration: Turbo Graphix Toolbox is available today for your computer running Turbo Pascal 1.0 for PC-DOS.
Ms-DOS. and CP/M-86. Your computer must have at least 128K RAM. one disk drive and PC-OOS 1.0 or greater. MS-DOS 1.0 or greater.
or CP~ 1.1 or greater.
INTERNATIONAL
4)8~ Scoos Valley Drive
Scoos Valley, California 9)OS6
(4a!) 438-8400
Look for Borland software at the computer dealer near you or for VISA and MasterCard orders
call toll free , I (800) 255·8008: In California 1 (800) 742·11H. Lines are open 24 hours a day. 7 days a week.