home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-26 | 109.7 KB | 2,195 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- //////// // // //
- // // /// // //
- // // //// // //
- //////// // // // //
- // // //// //
- // // /// //
- // // // ///////
-
-
-
-
-
- Pascal NewsLetter
- Issue #3
- June, 1990
-
-
- Editor: Pete Davis
-
-
-
-
-
-
-
-
-
-
-
-
-
- The Programmer's Forum BBS is the home of
- PNL. It can be reached in Washington, DC at
- (202)966-3647. Information is available
- through the following locations:
-
- FidoNet: Pete Davis@1:109/138
- GEnie: P.DAVIS5
- BitNet: HJ647C@GWUVM & UE356C@GWUVM
- InterNet: HJ647C@GWUVM.GWU.EDU
- UE356C@GWUVM.GWU.EDU
- and Pete.Davis@f138.n109.z1.fidonet.org
-
-
- 2
-
-
- Table of Contents
-
-
-
-
- Introduction ..................................... Page 3 (P.D.)
-
- Letter from Charles Falconer ..................... Page 4 (C.F.)
-
- A Diatribe on Structured Programming and Pascal .. Page 8 (C.F.)
-
- Pascal I/O Semantics ............................. Page 18 (C.F.)
-
- All Sorts of Sorts ............................... Page 24 (P.D.)
-
- For Beginners .................................... Page 29 (B.G.)
-
- The Object of Objects ............................ Page 35 (J.R.)
-
- Doing More With Strings .......................... Page 39 (G.H.)
-
- Bits & Pieces .................................... Page 42 (****)
-
- Conclusion ....................................... Page 44 (P.D.)
-
-
-
-
- P.D. -> Pete Davis (Editor, Writer)
- C.F. -> Charles Falconer (Contributing Writer)
- J.R. -> Jim Reid (Contributing Writer)
- B.G. -> Bob Gowans (Staff Writer)
- G.H. -> Gerhard Hoogterp (Contributing Writer)
-
- Bits & Pieces is contibuted by various readers and contributing
- writers. Credit will be given in that Bits & Pieces area.
-
- Turbo Pascal is a registered trademark of Borland International
-
- 3
-
-
- Introduction
-
- Well, I'm starting on issue #3 of the PNL for an unexpected
- reason. I, just minutes ago, received what must have been the toughest
- criticisms I have received yet. Anyone who frequents the Pascal echo
- in FidoNet knows who Charles Falconer is. I received a nice-sized
- packet of files from Charles regarding the PNL. It was loaded with
- constructive criticism. Some of it is already noticable. Charles
- pointed out that most people will go through the PNL on the screen and
- would prefer single-spaced text. Since I print it out, I was making it
- look good for printouts. I think Charles is right, though, so I am
- taking that advice. If there are enough people who want the double-
- spaced version, I will either release them together, or I will provide
- the double-spaced version to those who request it.
-
- Anyway, on with what Charles sent to me. His article was full of
- advice and comments. I really found it helpful and as Charles wrote:
- 'If I agreed with everything I read there would be no point in reading
- it!' I agree with that, but not everything you said.I did agree with
- most of what you said, though. Hopefully the users will approve of the
- changes. Anyway, along with the helpful comments, Charles included two
- articles that he had written. How could I possibly refuse to include
- them? Charles, thanks a lot. I really appreciate you advice and
- encouragement. I also appreciate your articles. They'll help beef-up
- the third issue a bit.
-
- Because Charles included so many good tips and because some of
- them are regarding articles I wrote in the first issue, I have
- included a copy of his letter so others can see what he has to say
- about Generic Structures and Optimization, two articles that were
- written in the first issue.
-
- I meant to get to my sorting article in the last issue. Obviously
- that didn't happen, so I'm putting it in this issue. I have been
- blessed with 4 articles so far. I can't tell you how much these
- articles help out. I think it is going to be necessary to make some
- small rules for submissions, though. The rules are pretty simple:
-
- 1> Single-Spaced
- 2> No justification
- 3> No page numbers
- 4> carriage returns only at end of paragraphs and where necessary
- (i.e. creating diagrams)
-
- I'm not going to refuse an article if it doesn't follow these
- specifications, it just makes things easier for me when including it
- in the newsletter.
-
- Well, I hope you enjoy what follows.
-
- 4
-
- Letter from Charles Falconer
-
- I am attaching a couple of contributions - feel free to edit them
- within reason. These have been around in various forms for a while.
- Also feel free to grab anything I put on the Pascal Echo, if you wish,
- (unless I have done something foolish). It is all public domain. If
- you publish anything of mine include my Fidonet address please.
-
- On formatting of PNL: (all opinion)
-
- These are only suggestions, after all it is your project, and I am
- thankful for it. As an aside, the results are smaller and take less
- transmission time and disk space.
-
- I find the double spacing to be virtually unreadable on the CRT. This
- sort of thing is virtually never printed, and when it does the user
- doesn't want to use a lot of paper. Who knows, he may even have to
- feed individual sheets.
-
- I just found these on Hippocampus, and have not really read anything
- yet.
-
- I suggest a formatting of no more than 72, preferably 66, chars per
- line, with no indentation, single spaced, with a maximum of 60
- lines/page. If lines are not right justified (minor point) the user
- can easily reformat to taste. Pages should be separated with
- form-feeds, not white space, as the white space makes it very hard to
- follow anything on the CRT. For the same reason pagenumbers and the
- ilk should be at page top.
-
- I attach PNL001 reformatted to roughly these specifications, for your
- consideration. I passed it through two filters, changed all
- <eoln><eoln> into <eoln>, and did some minor hand editing afterwards.
- The original contained some naked <cr>s, which didn't even overprint,
- but were removed by my stripovr filter (the filters are available in
- DETAB12.LZH on 141/205)
-
- If you feel indentation for printing is critical, I will be happy to
- write a small filter to add it in. It can also expand <ff> to a
- constant 66 (or other) lines per page if needed. (Europeans have 12
- inch paper standard). Form-feeds also serve to trigger page printing
- on Laser Printers.
-
- I also have RNF, in Pascal, available with source, for generalized
- formatting. It can do quite a pleasant job. RNF13AT.LZH (110k), also
- on 141/205. RNF13SOR.LZH has ISO standard source, 13AT is for Turbo
- and includes the documentation and Turbo source. The docs are a
- deliberate mess, and get cleaned up by running RNF on them.
-
- With your permission only, I will mount the reformatted versions on
- Hippocampus to replace yours. No sweat either way. {Editors Note:
- Feel free to do it.}
-
- 5
-
-
-
-
- Net mail to 141/209.1 will reach me, addressed to Charles Falconer.
-
- 1990/5/18 Chuck.
-
- ------
-
- ps: I read over pnl001 and have a few minor comments:
-
- 1. Optimizing for size often DOES improve speed {ed. note: Yes, in
- most cases, but not all! }. The data structure and algorithm is
- usually more important than the code. Clarity is at the top of
- my wants 99% of the time. Do nothing without measuring the
- program first - otherwise the rewards are not going to be
- noticeable, but the (clarity) penalties are. Smaller code
- means more other resource available. I have a system where
- I can find sharp performance improvements for every 1k less code
- space used - sometimes only 128 bytes is important. In this
- case the difference is availability of swap space in memory, and
- the increment suddenly means something doesn't get swapped.
- 2. Generic procs - If the body of the system deals with the two
- pointer linkage item, rather than the data body, much more
- can be made generic. Only a few rare i/o procedures will
- need to know about the actual data item. Thus 'push' would
- push such a linkage record, pop would return one, and could
- be a function. Nothing need even know they are headers after
- the lowest level.
- 3. Fetish of mine - Pascal is ALWAYS capitalized. A proper name.
- 4. Optimizing - I virtually never turn off run time checks. The
- exception is in the heart of loops, once well debugged. Such
- loops should have loop invariants stated and checked. A whole
- program is never debugged.
- 5. I have a different view than most about formatting, some of
- which is in the attached files.
-
- 6. Generally excellent. If I agreed with everything I read there
- would be no point in reading it! You seem to have pretty sound
- teachers and a good mind.
-
- pps:
-
- Here is a useful tidbit for linked lists. This only assumes the list
- pointers contain a 'next' field. Takes a single pass. Just pass it
- the root pointer.
-
- PROCEDURE reverse(VAR dirlist : adirptr);
- (* Do a list walk and reverse the list order *)
-
- VAR
- prev, pprev : adirptr;
-
- 6
-
-
- BEGIN (* reverse *)
- prev := NIL;
- WHILE dirlist <> NIL DO BEGIN
- pprev := prev; prev := dirlist;
- dirlist := dirlist^.next; prev^.next := pprev; END;
- dirlist := prev;
- END; (* reverse *)
-
- This allows you to create a list with simple code, i.e.
-
- new(p); p^.next := root; root := p;
- (* then set any data fields *)
-
- and later access in the order of input. One example of use is in
- scanning parameter lists when compiling a procedure header. Then the
- final list is used to check procedure calls correctly as they come in
- from the source.
-
- and here is the performance of MRGSORT on my system, sorting 12 char.
- random alphabetic strings (packed into pksize = 4 integers, 3 per
- integer). The whole of this was published on Pascal Echo, and is
- available as MRGSORT.LZH on 1:141/205. The MRGSORT unit operates on
- singly linked lists, only requiring that 'next' be the first field.
-
- (* On my 8mhz V20 XT system, executes as follows: *)
- (* items creation time sorting time *)
- (* ----- ------------- ------------ *)
- (* 10 0.013 Sec. 0.010 Sec. *)
- (* 100 0.117 Sec. 0.164 Sec. *)
- (* 500 0.582 Sec. 1.050 Sec. *)
- (* 2500 2.903 Sec. 6.407 Sec. *)
- (* 12500 14.502 Sec. 38.028 Sec. *)
- (* (FULL) 33874 38.028 Sec. 113.692 Sec. *)
- (* which shows the n*log(n) behaviour of the algorithm. *)
-
- and using the following comparison procedure:
-
- {$f+} (* passed functions MUST be far *)
-
- FUNCTION greater(thing, than : pointer) : boolean;
- (* This is the time bind - make assy language. This *)
- (* will later be passed in as a param to mrgsort *)
-
- LABEL 9, 10;
-
- VAR
- k : pkindex;
- (* These gyrations bypass type checking, and describe *)
- (* the actual pointer type that mrgsort will call with *)
- {} a : alfaptr ABSOLUTE thing;
- {} b : alfaptr ABSOLUTE than;
-
- 7
-
- {$r-,s-}
- BEGIN (* greater *)
- greater := true;
- FOR k := pksize DOWNTO 1 DO (* Check most sig. first *)
- IF a^.s[k] > b^.s[k] THEN GOTO 10 (* decided *)
- ELSE IF a^.s[k] < b^.s[k] THEN GOTO 9; (* decided *)
- 9: greater := false;
- 10: END; (* greater *)
-
- {$r+,s+,f-} (* put the options back *)
-
- This being the major time bind, it is the only place that range checks
- are turned off. As an aside, I would have used your 'generic' linkage
-
- method, except that it would involve an extra dereference right here
- in the sensitive heart of the algorithm. Changing to such is easy.
- The {} in the lh margins mark non-standard usage.
-
- {Editors Note: 8 lines removed: Not of interest to readers.}
-
-
- 8
-
- A diatribe on Structured Programming and Pascal
- by C.B. Falconer, 680 Hartford Tpk, Hamden, Ct 06517. 281-1438
-
-
-
- Structured programming is NOT about GOTO less code, or languages,
- but about the design methodology. I use Pascal, (ISO standard
- version, not Turbo, but the remarks generally apply). You design
- a program from the top down, i.e.:
-
- Step 1. Write down what it is going to do, and specify the data
- used. Keep the data to an absolute minimum, because the less you
- have to remember the fewer mistakes there will be:
-
- (I will write a simple line copying program, assuming two extensions
- to standard Pascal, i.e. read(..) can read a string, and length(..)
- can return the length of that string. Most systems have these
- extensions, but if not the procedures are easily created in STANDARD
- Pascal)
-
- (For Turbo users, some additional changes have to be made. These are
- shown in a final addendum to this file. The problems are:
- 1. Turbo REQUIRES the assign operation
- 2. Turbo fails to automatically close files
- 3. Turbo fails to truncate string writes to the field value.
- 4. Turbo uses the predefined "string" type to enable the
- read(string).
- all are fairly easily handled, as can be seen in the modifications)
-
- -------
-
- PROGRAM something(infile, outfile, output);
- (* using output for error messages, processing infile to outfile *)
- (* Define all data types that will be used GLOBALLY or as parameters
- *)
-
- CONSTANT
- maxbuff = 80;
-
- TYPE
- buff = ARRAY [1..maxbuff] OF char;
-
- VAR
- infile,
- outfile : text;
- buffer : buff;
-
- BEGIN (* something *)
- initialize;
- WHILE NOT eof(infile) DO BEGIN
- getdata(infile, buffer);
- putdata(outfile, buffer); END;
-
- 9
-
- cleanup;
- END. (* something *)
-
- -------
-
- This models what you want to do, with no detail. Once you have
- written the other procedures (and whatever they require) you are
- done. ALL the data that is really needed is already specified.
- You can add dummy procedures and check the result by compiling at
- this point. Note that, as a matter of style, all data is passed
- via parameters. This makes future changes much easier, and avoids
- looking around for "what is this thing".
-
- Step 2: Put in dummy procedures to resolve the program. The result
- can be compiled.
-
- -------
-
- PROGRAM something(infile, outfile, output);
- (* using output for error messages, processing infile to outfile *)
- (* Define all data types that will be used GLOBALLY or as parameters
- *)
-
- CONSTANT
- maxbuff = 80;
-
- TYPE
- buff = ARRAY [1..maxbuff] OF char;
-
- VAR
- infile,
- outfile : text;
- buffer : buff;
-
- (* 1---------1 *)
-
- PROCEDURE initialize;
-
- BEGIN (* initialize *)
- END; (* initialize *)
-
- (* 1---------1 *)
-
- PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
-
- BEGIN (* getdata *)
- END; (* getdata *)
-
- (* 1---------1 *)
-
- PROCEDURE putdata(VAR outfile : text, buffer : buff);
-
- 10
-
- BEGIN (* putdata *)
- END; (* putdata *)
-
- (* 1---------1 *)
-
- PROCEDURE cleanup;
-
- BEGIN (* cleanup *)
- END; (* cleanup *)
-
- (* 1---------1 *)
-
- BEGIN (* something *)
- initialize;
- WHILE NOT eof(infile) DO BEGIN
- getdata(infile, buffer);
- putdata(outfile, buffer); END;
- cleanup;
- END. (* something *)
-
- -------
-
- Notice that each procedure is indented to show its control level,
- and the BEGIN/ENDS are commented. This will be useful when fully
- expanded, and if inserted at this stage as a habit will always be
- present to help.
-
- Notice also that each parameter is VAR only when the procedure must
- be able to alter it. In some cases this may cause a minor slowdown,
- but the advantage is the GUARANTEE that errors in one procedure do
- not propagate into the rest of the program. This also allows the
- parameter to be supplied by an expression (for integers, reals,
- booleans, etc.), which cannot be done for a VAR parameter. Think
- of non-VAR parameters as pre-initialized data areas for the procedure,
- dynamically assigned.
-
- Sometimes obscure bugs arise in Pascal because of failure to specify
- the VAR when the parameter is to be modified. This seems to be
- mentally easy to overlook. All file specification paramters must
- always be VAR.
-
- You can read this program (even though it does nothing yet) and
- trivially satisfy yourself that it is correct. I.E. it will perform
- the function, and will terminate.
-
- FROM HERE ON you will NEVER change the global part. EVERYTHING
- added will be in the 4 procedures that the global program calls. You
- may want to tweak the type definition of buffer (that is why the
- constant MAXBUFF exists).
-
- Keeping everything simple, we will leave the cleanup procedure empty
- (but another application may need it), and fill in the details for a
- 11
-
- complete program.
-
- Step 3: If complex, put in simple code to check that the outer
- system runs the way you want it (starts, stops, etc). Then repeat
- the design process on each individual procedure if needed. This
- example is so simple that no repeat will be needed.
-
- -------
- EXCEPT for the "readln" in GETDATA, and the "length" in PUTDATA,
- this will compile and run on ANY Pascal system meeting the ISO or
- ANSI standards. Correction will involve the definition of buff,
- and writing two custom procedures, at most.
-
- PROGRAM something(infile, outfile, output);
- (* using output for error messages, processing infile to outfile *)
- (* Define all data types that will be used GLOBALLY or as parameters
- *)
-
- CONSTANT
- maxbuff = 80;
-
- TYPE
- buff = ARRAY [1..maxbuff] OF char;
-
- VAR
- infile,
- outfile : text;
- buffer : buff;
-
- (* 1---------1 *)
-
- PROCEDURE initialize;
- (* all that is needed to open the input and output files in standard
- *)
- (* Pascal. Non-Standard systems (e.g. Turbo) may need more.
- *)
-
- BEGIN (* initialize *)
- reset(infile);
- rewrite(outfile);
- END; (* initialize *)
-
- (* 1---------1 *)
-
- PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
- (* We might want this to read one word, as an example of a different
- *)
- (* program using the same basic model, or to ignore non-numeric
- input *)
- (* For numeric input, we could send an error message if none found.
- *)
-
-
- 12
-
- BEGIN (* getdata *)
- readln(infile, buffer);
- END; (* getdata *)
-
- (* 1---------1 *)
-
- PROCEDURE putdata(VAR outfile : text, buffer : buff);
- (* And this might want to upshift everything, or insert tabs, etc.
- *)
-
- BEGIN (* putdata *)
- writeln(outfile, buffer : length(buffer));
- END; (* putdata *)
-
- (* 1---------1 *)
-
- PROCEDURE cleanup;
-
- BEGIN (* cleanup *)
- END; (* cleanup *)
-
- (* 1---------1 *)
-
- BEGIN (* something *)
- initialize;
- WHILE NOT eof(infile) DO BEGIN
- getdata(infile, buffer);
- putdata(outfile, buffer); END;
- cleanup;
- END. (* something *)
-
- -------
-
- And the program is written. Each component is so simple, and deals
- with so few items, that you can be sure it is correct. Almost all
- errors will be syntax errors (omitted semi-colons, mis-spellings,
- etc) which the compiler will catch for you.
-
- If you are writing in a non-structured language, such as assembly or
- Fortran, use an outline similar to the above, and translate it into
- the language you are using. GOTO's can then be used, BUT THE FLOW
- OF CONTROL is strictly structured, and thus clear. (But there is a
- place for GOTOs, even in Pascal - that is another diatribe). Similarly
- the use of data items is clear, even if you have to declare other
- globals to replace the local variables, because of the end language.
-
- Notice that, in Pascal, you are usually backing up to somewhere
- between the procedure (or program) heading, and the executable code
- for that block (marked by "BEGIN (* blockname *)" ) to insert the
- next level. In Pascal you never need to worry about names, because
- inserted procedures are local, and the only name conflicts that can
- occur are with those names shown in the header (and any local
- 13
-
- declarations). You can see all these immediately.
-
- This all builds on the well known fact that human brains can normally
- handle up to about 7 items simultaneously. Once you have to worry
- about more things you will miss something. Thus, KEEP IT SIMPLE.
- Build a complex system out of SIMPLE building blocks. At any level,
- you can understand what is going on.
-
- Pascal makes such coding very easy, but forces you to follow a
- standard format (basically declare everything before using it).
- The use of indentation to depict levels of control eases
- understanding, i.e. to see what controls whether a statement is
- executed, just follow up to the outer indentation level (this is a
- convention, not a language feature). Everything looks more or less
- like
-
- IF condition THEN BEGIN
- dothis;
- andthat;
- andsoforth; END
- ELSE BEGIN
- dosomethingelse
- andsoon; END;
-
- and you can tell at a glance what conditions will allow each group
- to be executed.
-
- If you really must use Basic, Fortran, Cobol, and other antiques,
- try writing pseudo code in a structured form, keep it as comments,
- and let it define the real code you write. When you make a change,
- revise the pseudo-code (for a real change, not just a coding error),
- and keep it current.
-
- It is not hard to write 500 or 1000 line programs that work first
- shot in this manner (excepting the typos, which the compiler usually
- will catch for you).
-
- Summary (and additions) -
- KEEP EACH module SIMPLE.
- Let the outer code define what each module must do.
- Keep each module on one CRT screen or less.
- Use parameters, even if not really needed. (You can change to
- globals for efficiency later if you have to for efficiency).
- AVOID proliferation of GLOBAL variables. Keep it SIMPLE.
-
- ------------------------------------------------------------------
-
- (For Turbo users, some additional changes have to be made. These are
- shown in a final addendum to this file. The problems are:
- 1. Turbo REQUIRES the assign operation
- 2. Turbo fails to automatically close files
- 3. Turbo fails to truncate string writes to the field value.
- 14
-
- 4. Turbo uses the predefined "string" type to enable the
- read(string).
- all are fairly easily handled, as can be seen in the modifications)
-
- HERE IS THE MODIFIED PROGRAM, with changes inserted commented.
- look for the "<<<" string.
-
- -------
-
- THIS Turbo VERSION will not run on an ANSI/ISO standard system.
-
- PROGRAM something(infile, outfile, output);
- (* using output for error messages, processing infile to outfile *)
- (* Define all data types that will be used GLOBALLY or as parameters
- *)
-
- CONSTANT
- maxbuff = 80;
-
- TYPE
- buff = string[maxbuff]; (* <<< CHANGED *)
- (* ^ *)
- (* ^-- one of the worst choices in Turbo is *)
- (* that "string" is a reserved word (rather than *)
- (* a predefined type. This causes all sorts of *)
- (* nuisances in porting standard Pascal to Turbo.*)
-
- VAR
- infile,
- outfile : text;
- buffer : buff;
-
- (* 1---------1 *)
-
- PROCEDURE initialize;
- (* all that is needed to open the input and output files in standard
- *)
- (* Pascal. Non-Standard systems (e.g. Turbo) may need more.
- *)
-
- (* 2---------2 *)
-
- PROCEDURE attachfile(VAR f : text; position : integer); (* <<
- ADD *)
- (* attach the Pascal file to the commandline parameter *)
- (* in position "position" of the run-time command *)
-
- (* A style note: An IF THEN .. ELSE .. clause should *)
- (* normally be written with the longer clause in the ELSE *)
- (* part. This makes it easy to see the flow of control. A *)
- (* short ELSE clause 28 pages down is easily missed, not to *)
- (* mention the nuisance of deciding which IF it goes with. *)
- 15
-
-
- BEGIN (* attachfile *)
- IF position <= paramcount THEN assign(f, paramstr(position))
- ELSE BEGIN
- writeln('Need file #', position : 1, ' specification');
- halt; END;
- END; (* attachfile *)
-
- (* 2---------2 *)
-
- BEGIN (* initialize *)
- attachfile(infile, 1); attachfile(outfile, 2); (* << ADDED *)
- reset(infile);
- rewrite(outfile);
- END; (* initialize *)
-
- (* 1---------1 *)
-
- PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
- (* We might want this to read one word, as an example of a different
- *)
- (* program using the same basic model, or to ignore non-numeric
- input *)
- (* For numeric input, we could send an error message if none found.
- *)
-
- (* Instead of using the Turbo string type, we could have *)(* <<
- NOTE *)
- (* made a different buff definition, such as: *)
- (* buff = RECORD *)
- (* lgh : integer; *)
- (* data : ARRAY[1..maxbuff] OF char; *)
- (* END; *)
- (* and altered this procedure to read into it, setting *)
- (* the lgh value. Then the putdata would have needed *)
- (* only minor modification, such as: *)
- (* writeln(buffer.data : buffer.lgh); *)
- (* except that Turbo fails to use the field correctly. *)
-
- BEGIN (* getdata *)
- readln(infile, buffer);
- END; (* getdata *)
-
- (* 1---------1 *)
-
- PROCEDURE putdata(VAR outfile : text, buffer : buff);
- (* And this might want to upshift everything, or insert tabs, etc.
- *)
-
- BEGIN (* putdata *)
- writeln(outfile, buffer : length(buffer)); (* << NOTE *)
- (* For Turbo strings we can omit the " : length(buffer)" *)
- 16
-
- (* clause above. If the buff type was still really an *)
- (* array of char we would need something like : *)
- (* FOR i := 1 TO length(buffer) DO *)
- (* write(f, buffer[i]; *)
- (* to compensate for the Turbo failure to truncate. *)
- END; (* putdata *)
-
- (* 1---------1 *)
-
- PROCEDURE cleanup;
-
- BEGIN (* cleanup *)
- close(outfile); (* << ADDED - Turbo doesnt automate
- *)
- END; (* cleanup *)
-
- (* 1---------1 *)
-
- BEGIN (* something *) (* << The outer block doesnt change
- *)
- initialize;
- WHILE NOT eof(infile) DO BEGIN
- getdata(infile, buffer);
- putdata(outfile, buffer); END;
- cleanup;
- END. (* something *)
-
- -------
-
- More style notes: BEGIN and END are used to delimit compound
- statements in Pascal, and not to show control flow. Modula uses
- END to show the end of controlled statements, and implies the BEGIN
- after IF, WHILE, etc. Thus I feel extra indentations for BEGINs
- are pure confusion (and lead to programs that run off the right of
- the page), and subordinate them. I also usually attach the END to
- the end of the controlled code, as shown, and use a separate line
- only when multiple ENDS must appear. This helps to keep code
- vertically compact, so that the whole control flow can be seen at
- a glance. In Pascal BEGIN END really delimit blocks only when
- used at the start and finish of PROCEDURE or FUNCTION code.
-
- Similarly, CASE labels are really LABELS, and belong at the left of
- the source listing. They are not controlled statements, but
- reference points to which control flows, eg:
-
- CASE ch : char OF
- 'A', 'a': dothingswitha;
- 'B', 'b': dothingswithb;
- 'C': BEGIN
- makeanoise;
- dothingswithbigC;
- END;
- 17
-
- 'c': dothingswithlittlec;
- END; (* case *)
-
- and, on reading, it is quite obvious that only one path will be
- followed, and how to find that path.
-
-
- 18
-
- PASCAL I/O semantics, File PASCALIO.DOC
- C.B. Falconer 85/9/11, 87/2/12, 88/11/20, 89/12/12
-
- This is an explanation of the action of Pascal I/O, as applied to
- text files. A system meeting the ISO and ANSI standards is
- assumed. This does not apply to Turbo Pascal exactly, because
- Turbo omits some of the standard abilities and functions,
- especially for console input (but Turbo 4 up is closer). UCSD
- Pascal fails in console i/o, but other operations are implemented.
- PascalP functions exactly as described below.
-
- REMEMBER - THIS IS ANSI/ISO STANDARD PASCAL. The standard has
- been published and in effect since 1983. The standard does NOT
- forbid extensions, but does insist on compliance. In addition a
- system meeting the standard MUST have a way of disabling any and
- all extensions, so that source can be checked for portability.
-
- Any Pascal file is conceptually a single stream, with a file
- buffer variable. If we always refer to the file variable itself
- as "f", the buffer variable is "f^". If f is declared as "f :
- FILE OF thing", then f^ is of type "thing", and may be used as
- such a variable at any time the file is open (i.e. after the file
- has been reset or rewritten).
-
- A Pascal text file is equivalent to "PACKED FILE OF char", and
- additionally specifies that the eoln, readln, writeln procedures
- may be used. THESE MAY NOT BE USED ON A NON-TEXT FILE.
-
- Reading
- -------
-
- For reading, a file at any time consists of two ordered arrays of
- items. The first is the portion that has already been input, and
- the second is the portion that has not been input yet. The
- buffer variable f^ always contains the last single item input
- (consisting of characters, an eof mark, and an eoln mark for text
- files). The eoln mark always appears as a space in f^, and may
- only be detected by the eoln procedure. The eof mark in any non-
- empty text file must immediately follow an eoln mark (specified
- by the standard). (Thus any good system will automatically
- append an eoln on closing a file, if and only if it is not
- already present.) The second portion of the file is unlimited,
- and unknown as yet to the Pascal program.
-
- When a file is "reset" the file is actually opened, and the first
- char is placed in f^ (this may be the eof or eoln mark, checked
- by eof/eoln functions). This first char is removed from the
- second portion.
-
- If reset is applied to an already open file, the effect is always
- to rewind it (if possible). Obviously some files cannot be reset,
- e.g. it is hard to make the console repeat its previous sequence,
- 19
-
- and thus "reset(input)" may be an error on some systems.
-
- From here on, the action of the "get(f)" procedure is to advance
- one further character in the source file, discarding the old f^
- value, and replacing it with the next char. It should always be
- an error to do this when eof is true.
-
- Note that nothing has yet affected any variable in the Pascal
- program, except the f^ buffer. These are the underlying
- functions of the input system. The program may use the file by
- such actions as "ch := f^" at any time.
-
- The syntax of "read(f, ch)" is STRICTLY defined as "ch := f^;
- get(f)", and the eoln and eof functions examine the non-visible
- characteristics of the last input character. If "f" is omitted,
- as in "read(ch)" the standard file "input" is assumed, and the
- buffer variable is "input^".
-
- For most CPM or MSDOS systems the file actually contains a <cr>
- to mark eoln, and a <^Z> to mark eof. The value of f^ when eof
- is true is not defined by the standards, but when eoln is true it
- should be a space. Thus the <cr> character can not appear (unless
- the system defines eoln as the <cr,lf> pair. Some systems always
- discard any <lf>, so that the file action remains the same when
- input from a keyboard as when input from a disk file.
-
- The syntax of "read(f, ch1, ch2, ..)" is defined as "read(f,ch1);
- read(f,ch2); .... ", and is simply a shorthand. If the object
- read-into is an integer, or a real, then automatic conversion is
- performed from a text string, and at completion f^ holds the
- terminating character (space, non-numeric, etc). Such a read
- causes a run-time error when no valid integer etc. is found
- before a terminator, but leading blanks (and eolns) are skipped
- over.
-
- Notice that nothing so far controls any flushing of input lines,
- to ensure that a read starts on the next physical line. This is
- performed by "readln(f)", which is defined as "WHILE NOT eoln(f)
- DO get(f); get(f)". NOTE the final get. This always leave f^
- holding the first character of the next line (which is a space if
- the next line is empty, i.e. consists of eoln alone), or possibly
- an eof mark. Again, an omitted "f" implies input.
-
- The syntax of "readln(f, item1, item2, .. itemn)" is defined as
- "read(f,item1); read(f,item2); ... read(f,itemn); readln(f)", and
- is again just a convenient shorthand.
-
- Interactive files
- -----------------
-
- This brings up the great bugaboo of Pascal text i/o: When a file
- is reset it MUST place the first character in f^. If that file is
- 20
-
- interactive (i.e. the keyboard) the first character must be typed
- at that time. Thus the natural sequence "reset(f); write('prompt
- message'); read(f, ch)" to get a reply to a prompt requires that
- the answer be typed before the prompt is made. The problem also
- reappears after any readln, because the first "get" from the next
- line is performed. (see below for why f^ is filled at all)
-
- This is normally cured by a special driver for text files.
- Whenever the "get" is executed it simply sets a flag somehere
- (totally invisible to the application program) which says "a get
- is pending". (If get finds the flag set it must perform the
- pending get, and then again set the flag). Note that the "get"
- may be implied by a reset, read, or readln operation. Now the
- system must again intercept any use of eoln, eof, or the f^
- variable and, before actually executing them, check the
- "get_pending" flag. If set the actual get must be performed, the
- flag reset, and then the eoln, eof, f^ references may be made.
- This prevents the early physical read, and allows natural
- programming. However the programmer should always remember that
- any reference to eof, eoln, or f^ will cause the physical read.
- Thus the sequence "reset(f); IF eof(f) THEN something;
- write('prompt'); read(f,ch)" will cause the physical read to be
- too early.
-
- Some systems (e.g. UCSD) do not follow the ANSI/ISO standard, and
- define a special interactive file type where read(f, ch) is
- defined as "get(f); ch := f^". This causes all sorts of problems,
- because the programmer must always know that this file is
- interactive, and programs cannot use the standard input and
- disk files interchangably.
-
- The "get" is normally executed on reset (or readln) so that the
- value of eoln and eof is available after using a character (by
- read), and so that the program can look ahead to the next
- character. This allows decisions to be made, i.e. is the
- following character numeric.. then read a number; or is it alpha
- .. then read a char; or is it a special .. then read a user
- command etc. Thus a file copy program such as:
-
- WHILE NOT eof DO BEGIN
- WHILE NOT eoln DO BEGIN
- read(ch); write(ch); END;
- readln; writeln; END;
-
- works naturally. The read/write line can be replaced by
-
- write(input^); get(input); END
-
- or by some sort of filter such as
-
- IF input^ <> ' ' THEN write(input^);
- get(input); END;
- 21
-
- to strip out all blanks ith the same action and no auxiliary variable.
- Such a fragment can copy the standard input to standard output,
- and works correctly with any i/o redirection applied.
-
- NOTE that "reset(input)" is always automatically performed when a
- program begins running, and similarly "rewrite(output)". Thus
- such statements should normally not appear in a program.
-
- Think of readln as a line-flushing procedure, but bear in mind
- that "readln(item)" is always equivalent to "read(item); readln".
-
- Writing
- -------
-
- Again, all files consist of 2 parts, that which has been written
- (and is in the external file), and that which has not. The next
- item to be written is ALWAYS in f^, and "put(f)" is defined to do
- the writing, and leave f^ contents undefined (in practice, most
- systems leave f^ unchanged).
-
- Similar to read, "write(f, item)" is STRICTLY defined to be the
- sequence "f^ := item; put(f)". For text files ONLY, writeln can
- put an eoln mark in the external file. Most systems, including
- PascalP, can in practice create an eoln mark by writing suitable
- characters, BUT THIS IS NOT portable.
-
- Write(f, item1, item2, .. itemn) is STRICTLY defined as being
- "write(f,item1); write(f, item2); ... write(f, itemn)", and
- "writeln(f, item)" is defined as "write(f, item); writeln(f)".
- Both of these are again shorthand. The writeln procedure alone
- (i.e. writeln(f) ) simply puts an eoln mark into the file being
- written. If the "f" specification is omitted the write is
- shipped to "output" file by default.
-
- Again, the fundamental writing procedure is "put(f)", which
- causes the content of f^ to be appended to the end of the file f.
- "write(f, item) is STRICTLY defined as "f^ := item; put(f)", and
- should be unable to create the eoln mark in a text file (reserved
- for writeln). The action of "rewrite(f)" is to empty any old
- version of f, and leave f^ undefined. f^ is also undefined after
- any write operation. Thus doing nothing except "rewrite(f)" in a
- program should leave f as an empty file, but existing.
-
- All Pascal files should be automatically closed when the defining
- program (or procedure for a local file) is exited. Some systems
- provide a "close" procedure to force an early close for one
- reason or another (e.g. to release a locked file to another user
- in a multi-process environment). If a file was open for write
- (via rewrite), and is later "reset", an automatic close is done.
- These closings of a written file append the eof mark, and force
- any system buffers to be flushed. Some systems are incomplete,
- and actually require that a specific call to "close" be made.
- 22
-
- This procedure is non-standard, and such programs will not be
- portable.
-
- Text file writes
- ----------------
-
- The standard specifies the formatting abilities for various types
- of objects. The use of fields for integers and reals is complied
- with in general, however
-
- write(f, astring : field)
-
- is defined to RIGHT justify astring in field positions, AND TO
- TRUNCATE astring (on the right) when it is longer than field. An
- item of type astring is compatible with PACKED ARRAY[1..] OF char.
- Failure to do this truncation is a major impediment to portablity
- in Turbo Pascal.
-
- To harp on the action of writeln, this marks the end of a text
- line and usually flushes any buffers. The actual implementation
- of the file system should not matter, provided it meets the
- abstract requirements of Pascal. Thus systems that never put an
- eoln marker on the disk, but simply retain pointers to the line
- endings, should function correctly.
-
-
- Fixes
- -----
-
- Again, this is how it should work according to international (and
- ANSI) standards. Some systems do not meet the standards - beware.
-
- The so-called string type in Turbo and UCSD Pascal is not really
- necessary, although it is often a convenience. It is possible to
- create systems that are fully Standard compatible, and still have
- string reads, concatenation, dynamic length, extraction, etc. All
- such operations are available in PascalP as extended system pro-
- cedures, and thus porting to another system only requires writing
- such procedures. When not provided as part of the system package
- efficiency may suffer, but no logical change in the program will
- be needed.
-
- For this reason I suggest that Turbo users should ALWAYS use the
- concat function for strings, rather than the "+" operator. When
- this is done the program can be converted fairly easily to an ISO
- standard system.
-
- For Turbo Pascal users, I have written a set of includable
- procedures or units (see TURBOFIX.LBR or TURBOFIX.ARC for TP3,
- TXTFInnn.LZH for TP4 up, with nnn 121 at present) which make
- Turbo meet these standards, although you will have to use
- non-standard procedure names. These are available without charge
- 23
-
- for non-commercial use.
-
- I hope this clears up some confusion.
-
-
- 24
-
- All Sorts of Sorts
- By Pete Davis
-
- Every programming student comes across sorting at one time or
- another. Occasionally, one comes across sorting in their own work.
- Picking the right sort for the job isn't always an easy process. Many
- things need to be taken into consideration. First of all, what will
- the typical size for the data be? Some sorts work better for a lot of
- data and others work better with small amounts. Other factors include
- knowing what kind of data-structure you're working with. If you're
- using a linked list, certain sorts might not be worth the trouble, but
- if you're using an array, it might be ok to use those sorts.
-
- I want to offer a range of sorts here. Each one will include a
- short algorithm and some code examples will be included with this
- issue of PNL. With each sort, I'll give a description of how it works,
- what it's good points are and what it's problems are. I'll explain
- what kind of applications it is best for and when to avoid it. There
- are many programming books that go into a lot of depth on sorting, so
- if you really want to get into the meat of sorting, I suggest you
- check out your public library or local bookstore.
-
- There are several ways to measure the quality of a sorts. Average
- number of comparisons and average number of exchanges are very common
- to get an idea of how much work the sort has to do for a particular
- amount of data. i.e. average number of comparisons for 100 items in a
- bubble sort is about 5000, depending on exactly how the algorithm is
- implemented. Other important factors are the actual time it took to
- execute the sort and memory requirments for the sort.
-
- A. Bubble Sort
- --------------
- Talk about basic, the bubble sort is about the most basic and
- easy to understand of the sorts. It's simplicity gives way to slow
- execution and many comparisons. For small amounts of data (i.e. 100 or
- fewer data items) the bubble sort will usually suffice. The exact
- amount of data really depends on the size of the data-items and the
- algorithm used. The only time where the bubble sort is the best sort,
- is if the data is already in order. Otherwise, chances are, most other
- sorts will beat the bubble sort, especially if the lowest value is
- near the end of the list or the highest value is near the beginning of
- the list.
-
- The bubble sort uses the simple concept of going through a list
- and checking each item against the item next to it. If they are out of
- order, then put them in order. It keeps repeating this process until
- it reaches the end of the list. Then it starts over at the beginning
- of the list again, and keeps repeating this whole process until no
- more items are switched. You can either check to see if no more items
- are switched or you can go through N-1 times where N is the number of
- items in the list. The prefered method is to check for whether or not
- anything is switched. This means that if the list is already in order,
- 25
-
- you won't have redundant passes through the list. The following will
- show a group of characters out of order. I will then show what would
- happen with each pass of the bubble sort.
-
- START -> F E R M T A P
- STEPS: { E&F SWITCH : F&R IN ORDER : R&M SWITCH
- R&T IN ORDER : T&A SWITCH : P&T SWITCH }
- END OF PASS 1 -> E F M R A P T { # exchanges: 4 }
- END OF PASS 2 -> E F M A P R T { # exchanges: 2 }
- END OF PASS 3 -> E F A M P R T { # exchanges: 1 }
- END OF PASS 4 -> E A F M P R T { # exchanges: 1 }
- END OF PASS 5 -> A E F M P R T { # exchanges: 1 }
-
- I only showed all of the steps for the first pass. I believe it
- is straight-foward enough that it was all that was necessary. You can
- examine the code for more examples. Notice how much work it took to
- sort only 7 items, though. there were 5 passes, and each pass
- consisted of 6 comparisons and at most, 4 exchanges and at best, 1
- exchange with a total of 9 exchanges and 30 comparisons. This isn't a
- worse case scenario, but it is what I will compare several of the
- sorts against. After that, we'll take some actual results from our
- test program.
-
-
- B. Selection Sort
- -----------------
- The selection sort is kind of like putting a hand of playing
- cards in order. First thing you do is look at your whole list. You
- take the lowest value and put it in the beginning. Then you take the
- next lowest value and put it right after the first. (Or you could take
- the highest and then the next highest and do it backwards, it really
- doesn't matter.)
-
- I don't think any sort of diagrams or algorithms need to be
- explained for this. I think everyone is familiar with this technique.
- Although the selection sort isn't incredibly fast, it is very simple
- and does give a marginal improvement over the bubble sort, in general.
-
- C. Insertion Sort
- -----------------
- The insertion sort can also use the idea of a hand of playing
- cards, but instead of working with all of your cards at once, you take
- a card one at a time and insert it where it belong as you get it. The
- insertion sort is fairly simple, but has some problems. The insertion
- sort is ideal for linked lists. If an insetion needs to be made, all
- you have to do is re-direct some pointers. The insertion sort is much
- less powerful when used with arrays, or contiguous lists. The problem
- is that when you insert a new value, chances are you'll average moving
- about half of the data in the list over one space. When your list gets
- long, that can cause major problems. Each time something is inserted,
- everything in the list would have to shift over.
- 26
-
- The insertion sort, like the selection sort is very straight-
- foward and simple, so I'll just let you examine the code if you have
- any more questions.
-
- D. Shell Sort
- -------------
- The shell sort uses the idea of sorting over an increment. Let's
- use a new list of data: F E R M T A P G N Y C
- and we'll take an increment of three. In our first step, we will
- compare item #1 with item #4 (1+increment of 3) then 2 and 5 and make
- exchanges over the increment. Let's see the results after 1 pass:
-
- F E A M G N P C R Y T
-
- We continue sorting with the increment of 3 until everything for
- that increment is in order. So, for the next pass we get:
-
- F E A M C N P G R Y T
-
- and the third step:
-
- F C A M E N P G R Y T
-
- now, everything is in order over the increment of 3, so we drop
- our increment to 2:
-
- A C E M F G P N R Y T
-
- and one more pass:
-
- A C E G F M P N R Y T
-
- now that that's in order, we drop to the final level with an
- increment of 1. At this point, a single pass will put everything in
- order:
-
- A C E F G M N P R T Y
-
- For larger amounts of data the results are a bit more dramatic.
- The choice of a starting increment of 3 and a decrement of 1 for each
- pass was completely ambiguous on my part. You can use any starting
- increment and any decrement per pass that you want. The final pass
- must be an increment of 1, however. With larger amounts of data, a
- starting increment of 5 or higher will be more useful, and keeping the
- space as an odd number for each pass is more efficient.
-
- The shell sort is a bit more complicated than the sorts shown
- previously but the average gain in speed is tens of times better than
- any of the previous sorts.
- 27
-
- E. Merge Sort
- -------------
- Although the concept behind the Merge Sort is fairly simple, the
- actual coding of the sort is a bit more complex than one would expect.
- In simple terms, the Merge Sort breaks your data in half and then
- sorts each half. After the halves are sorted it puts them back
- together. It's a bit more complex in that the routine calls itself
- again and breaks each of the half-piles into halves, and so on and so
- on until each pile has either 1 or no items.
-
- You might be wondering why this is so quick, but think of it this
- way, the Bubble Sort is called a quadratic sort. That means that if
- you double the data to be sorted, it takes more than double the amount
- of time to execute the sort. So, it would be quicker to break a big
- set of data into two sets of data and sort them. The only extra time
- you'd need is to put them back together in order. The results are a
- bit more dramatic than that, though, as the piles keep getting broken
- down more and more making each individual sort incredibly quick.
-
- The Merge Sort works well with either contiguous data (arrays) or
- linked lists. It's a great general purpose sort, but for small amounts
- (less than 100 items) of data, it probably isn't worth the effort. The
- only real drawbacks to the Merge Sort is that it requires double the
- amount of space for data to make copies of the data. Another is that,
- because it's recursive, it incurs a bit of overhead on speed and
- space. This, however, isn't incredibly significant, however, when
- comparing speeds with the previous sorts.
-
- F. Quick Sort
- -------------
- The Quick Sort is generally recognized as the best general-
- purpose sorting algorithm. It is much like Merge Sort in that the data
- is recursively broken into two pieces. The first step in the Quick
- Sort is to come up with a mid-value for your data. With numbers this
- is pretty easy but strings and characters might require a bit more
- effort. The way you come up with the mid-value can vary. The method
- I'm going to use in the sample provided is to take the mean of the
- first and last value in the list. It doesn't have to be the exact
- middle, but the more accurate it is, the faster the sort. If you have
- some sort of pre-knowledge of what your data will be like, you might
- be able to come up with a more accurate method to finding the mid-
- point.
-
- The next step is to move all values lower than the mid-point to
- the left (or lower end of your list) of the mid-point and all the
- higher values to the right. Then you keep recursively splitting the
- left and right in half, moving the values to the left and right side
- of the mid-point, appropriately. You keep doing this until you are
- down to 1 or 0 elements in the left and right. At this point, your
- data is in order.
- 28
-
- Summary
- -------
- The main point of this wasn't to go completely in-depth
- explaining the subtelties of each individual sort, but more to give an
- overview of each sort. I wanted the readers to be able to get a basic
- idea of how each sort works, find its advantages and dis-advantages,
- and be able to decide which sort will work best for your particular
- application.
-
- I'll leave most of the more technical explanations in the inline
- documentation of the sort unit I am providing. The test program gives
- you some stats on each sort that I have explained above.
-
- These routines that I am providing are not necessarily the
- fastest or most efficient algorithms. Everyone has their own minor
- variations on certain sorts and you may want to change them to suit
- your purposes.
-
- 29
-
- For Beginners
- By Bob Gowans
-
- In the last issue of PNL (no.2) the beginner's column discussed a
- simple but complete Pascal program in which the use of the Pascal
- standard procedures writeln and write were highlighted. The rules
- governing identifiers were also put to you. Continuing on this theme I
- would like to show how you can build on this basic layout, and produce
- a more substantial program.
-
- Who has not heard of data? In this day and age it seems that
- there is an overwhelming amount of data available on all sorts of
- subjects. Our computer systems manipulate data - they take data in,
- process it and churn it out and there you have it, your electricity
- bill! As programmers we are mainly concerned with the manipulation of
- data, we write programs that can do all sorts of things with data and
- that produce data as results. But what exactly is data and how can we,
- as prospective programmers, make use of such data that is suitable for
- computers. Data comes in many forms, the actual word data means
- 'things given', an item of data represents some fact, observation or
- idea. We humans can recognize all sorts of data easily - text,
- numbers, pictures and speech to mention but a few. However, the poor
- computer can only, in most cases, accept data in the form of symbols
- such as characters and numbers, they are picking up mind you and there
- are devices that enable the input of sound and pictures to computers.
- Even with this restricted set of characters and numbers a huge range
- of data is available as input to the computer. For example, two
- characters can represent true and false, digits allow the computer to
- use integer numbers, a decimal point with digits means the computer
- can use real numbers,characters will allow us humans to input
- languages ( such as Pascal ) into the computer. Once the data is in
- the computer it can be processed and this is done according to sets of
- instructions or algorithms. This is where we come in, we want to be
- able to write algorithms that can manipulate the data that is
- available.
-
- 'What data is available?', might be a question you would be
- justified in asking. Well, Pascal has several different inbuilt types
- of data and also there is a facility for creating your own data types
- so you have plenty to go by. In Pascal the values True and False make
- up the BOOLEAN data type, whole numbers constitute the type INTEGER,
- decimal numbers are represented by REAL data types and characters are
- represented by the CHAR type. If this seems a little fuzzy to you it
- will soon become clear once you learn to implement the various data
- types in a Pascal program. Lets do that, sticking to the
- implementation of the integer type for now.
-
- Briefly, the store manager wants you to write a program that will
- calculate the total number of customers that use his store each day
- and output to the screen the total number of customers and the sub
- totals of female and male customers. You are given the respective male
- and female customer subtotals at the end of each day. In the following
- 30
-
- program note how the lines are indented, if you copy this layout your
- programs will be more readable, but more about that later. Also note
- that we have introduced a new Pascal reserved word VAR, it is after
- this statement that variables are declared ie. the data types of the
- variables are declared. Do not worry about variables for the time
- being as we will again deal with these later. However, note that we
- can assign values to variables using the symbol := this is a very
- important and fundamental feature of Pascal.
-
- program add_up; { Program heading }
-
- var
-
- female : integer;
- male : integer;
- total : integer;
-
- begin
- female := 250;
- male := 101;
- writeln('The total number of customers today was ',total);
- writeln('The number of male customers was ',male);
- writeln('The number of female customers was ',female)
- end.
-
- In the program we have three variables which are declared to be
- of type integer, that is to say that the values we are going to give
- to these variables must be of an integer data type. Variables are
- declared following the Pascal reserved word VAR and are given a data
- type as follows
-
- variable : datatype;
-
- We could have written the variable declarations in our program as
- follows
-
- female,male,total : integer
-
- Each variable is separated by a comma then comes a colon before
- the data type. As the variables are of type integer, the computer now
- knows what type of data to store in them and will reserve space at a
- memory location for three integer data types, and this is crucial - it
- cannot store any other type of data in the locations it has reserved
- for our three variables. If, for example, we tried to give female a
- value of 1.5 then the computer would go haywire ( at least the
- computer knows there is no such a thing as half a female ). Seriously
- what would happen is that the computer would issue an error message
- and the program would probably abort, which would not be to good if
- you had just spent the last half hour entering data. At this point it
- would be as well to define the data type integer.
-
- INTEGER - the positive and negative whole numbers.
- 31
-
-
- Incidentally the range of integers that you will be able to use
- depends on your computer/compiler, the range for Turbo Pascal using a
- 640K RAM IBM Compatible is 32767 to -32768 for those who are
- interested.
-
- The situation with our program is that we have declared three
- variables of type integer and now we are going to write some
- statements in our program that can play around with these variables -
- make them do some work for us! We can think of a variable as a memory
- location, with an attached name or identifier which the computer uses
- to access the contents of the variable. The rules for naming variables
- are the same that apply to naming identifiers which were discussed in
- the last issue of PNL. Why are they called variables? because as the
- name variable infers they can be updated or given new values. If we
- look at the program add_up we can see that female has been given a
- value of 250, male a value of 101 and total a value of the sum of male
- and female but these values are not fixed values as the program is
- updated every day so the values of male, female and total will change.
- In the program we say we have assigned a value of 250 to female and
- assigned a value of 101 to male. Finally we have assigned the value of
- the sum of male and female to total and written out the results.
-
- With each program that you write it is a good idea to plan a data
- table. Choosing the right data structures for variables and deciding
- which is the right data type to use is sometimes the programmers most
- difficult task, a data table can assist you greatly in helping to make
- things more clear. Lets write a data table for our program - in later
- issues you will be made to realise that it is better to plan and
- design the program first before writing the actual code.
-
- Identifier ( variable) Brief description Data type
-
- male holds current total of
- male customers. integer
-
- female holds current total of
- female customers integer
-
- total holds the current total
- of male + female integer
-
- You will have no doubt noted from the program that the value of a
- variable can be output to the screen, or to a printer or a file for
- that matter, and that this is done by using the writeln statement
- typically as follows
-
- writeln(variablename);
-
- This will have the effect of outputting to the screen the current
- value stored in the variable. The screen output from our program would
- thus be:
- 32
-
-
- The total number of customers was 351
- The number of male customers was 101
- The number of female customers was 250
-
- At the same time as outputting our variables we also took the
- opportunity to output a relevant textual comment. The string that we
- want to output must be in quotes and separated from the variable name
- by a comma (,) and the whole writeln statement is enclosed in
- brackets. I wonder if you noticed that there is space inserted between
- the last character in the textline and the final quotation mark in the
- writeln statement, the space is placed there so that the output from
- the variable is not written directly at the end of the text line, such
- as : The number of female customers was205 - resulting in messy
- screen output. A small point but well formatted text output is a must
- for today's user friendly programs.
-
- The assignment statement can do more than just give a single
- value to a variable, the assignment statement in Pascal has the
- following form :
-
- variable := expression
-
- When the computer executes such a statement, the expression on
- the right-hand side of the assignment operator (:=) is evaluated and
- the value is given to the variable on the left-hand side. If it helps
- you try reading the assignment operator as 'becomes' ie variable
- becomes expression.
-
- In this article we have learnt how to develop our programming
- skills by realising that the declaration and correct use of data types
- is an essential an important part of program development and that if a
- data type is declared the it can only be used for the purpose ie. data
- for which it was intended. We also discovered how to make assignment
- statements and how to perform certain operations on variables
- including writing them out to the standard output ( screen ). In the
- next article we will further expand on these basic concepts and
- hopefully introduce to you how to read in values to variables, by user
- input.
-
- The answer to the exercise given in the last article of PNL is :
-
-
- writeln(''How many times have I told you, don''t do that;she said'');
-
-
- This shows you that if you want to output text in quotation marks
- then you must double up on quotation marks in the writeln statement.
-
- 33
-
- Self Test
- ---- ----
-
- (a) The following sequence of statements appears in a pascal program.
- All variables are declared to be of type integer.
-
- apples := 10;
- oranges := 12;
- bananas := 6;
- fruit := oranges + bananas - apples;
- apples := fruit - apples;
-
- Write out the final value of fruit, apples, oranges and bananas.
-
- (b) The variable number is declared to be of type integer. Which of
- the following Pascal statements are valid :
-
- (1) number := 10;
- (2) number := number + 1;
- (3) 100 := number;
- (4) number = 100;
- (5) number := 23.5;
- (6) number := 100 + 15 - 205;
-
- (C) You are asked to write a program that counts the number of
- automobiles that are sold from a showroom. What data type would you
- choose to represent the total number of cars sold? How would you
- implement this problem in Pascal?
-
-
- Solutions
- ---------
-
- (a) fruit = 28, apples = 18, oranges = 12, bananas = 6.
-
-
- (b) (1) valid.
- (2) valid.
- (3) invalid ( you can only assign a value to a variable if they
- are on the
- left of the assignment operator).
- (4) invalid ( the assignment operator is := ).
- (5) invalid ( number is of type integer and you cannot assign to
- it a real
- value ).
- (6) valid.
-
- (c) integer as automobiles are best represented by whole numbers.
-
- program car_add;
-
- var
- 34
-
- total,autos : integer;
- begin
- total := total + autos;
- writeln('The total automobiles sold are ',total)
- end.
-
- Obviously this program is incomplete as we require some method of
- inputting the automobile data into the variable autos. This would be
- done by writing prompts to the screen so that the salesman could enter
- information, the program would read in such information. We will cover
- this in the next article.
-
-
-
- For fun
- -------
- The following program is intended for user's of Turbo Pascal only
- and makes use of the Turbo Pascal crt unit to produce sound on your
- PC's internal speaker. The main program is incorporated in a loop.
- Sound is used to get the attention or make the user aware of errors or
- as a security measure to deter unwanted users operating the system. As
- we become more proficient we will be able to put these advanced
- features to better use in our programs.
-
-
- program alarm;
-
- uses crt;
-
- var
-
- i : integer;
-
-
- begin
- for i := 1 to 100 do { loop start }
- begin
- sound(1500);
- delay(10);
- sound(500);
- delay(500);
- nosound;
- delay(1500)
- end { loop finish }
-
- end.
-
-
-
- Bob Gowans
- 35
-
- The Object of Objects
- By Jim Reid
-
- With version 5.5 of Turbo Pascal, Borland added one of the newest
- features in modern programming languages--the concept of objects. The
- good news is that object-oriented Pascal programming is a major step
- forward for programmers. The bad news is that if you don't already
- know something about object- oriented programming (OOP for short),
- Borland's version 5.5 OOP Guide won't help you very much. The first
- page of Chapter 1, for example, drops on you such household concepts
- as "encapsulation", "inheritance", and "polymorphism." Ugh! I hope
- this short article can help a bit by talking about objects more
- plainly.
-
- So what is an object anyway? An object is a group of Pascal
- variables (of any type) and a group of functions and procedures that
- operate on them. In short, it is a programming technique that lets
- you create new conceptual data types (like CIRCLES) and new conceptual
- operators (like DRAW or SHRINK) for them.
-
- Here's a simple example. One way to define a window area on your
- display screen is by specifying two coordinates--the upper left (X,Y)
- position and the lower right (X,Y) position. So, you might think of a
- WINDOW_AREA as an object with four variables. Here's how you would
- start to define this as an object.
-
- Type
- Window_Area = Object
- Upper_X ,
- Upper_Y ,
- Lower_X ,
- Lower_Y : byte;
- {...more to follow here later...}
- End;
-
- As you can see, an object looks a little like a RECORD TYPE.
- But there's nothing strange or unfamiliar about how you define
- the variables of an object. You use the same type of definitions
- you would use in the VAR statement.
-
- If this were all that objects had to offer, you'd wonder what all
- the fuss was over them. But defining the data variables of an object
- is only the first part of the job. Next, you define the procedures
- and functions that can operate on these variables. Using our example,
- suppose you wanted to have one procedure that sets the window
- coordinates, another procedure that defines and clears the windowed
- area on the screen, and a third procedure to disable it. Let's expand
- the object definition a bit further to do this:
-
-
- 36
-
-
- Type
- Window_Area = Object
- Upper_X ,
- Upper_Y ,
- Lower_X ,
- Lower_Y : byte;
- Procedure Init (byte X1, Y1, X2, Y2);
- Procedure Enable;
- Procedure Done;
- End;
-
- Procedure Window_Area.Init (byte X1, Y1, X2, Y2);
- Begin
- Upper_X := X1;
- Upper_Y := Y1;
- Lower_X := X2;
- Lower_Y := Y2;
- End;
-
- Procedure Window_Area.Enable;
- Begin
- Window(Upper_X,Upper_Y,Lower_X,Lower_Y);
- ClrScr;
- End;
-
- Procedure Window_Area.Done;
- Begin
- Upper_X := 1;
- Upper_Y := 1;
- Lower_X := 80;
- Lower_Y := 25;
- Window(1,1,80,25);
- End;
-
- Notice several things about the object's definition now. First, the
- object TYPE defines not only the variables but also a set of
- procedures. The PROCEDURE definitions look just the way you would
- define them in the INTERFACE portion of a Turbo Pascal UNIT--that is,
- you define the name and parameters of the procedure, but not the
- statements in it.
-
- Later in your program, below the object definition, you include the
- body of each of these procedures. Notice that each of the procedure
- names is prefixed with the name of the object type ("Window_Area" in
- this case). The procedures (or functions) defined for an object
- automatically have access to the variables of that object. Thus,
- these procedures can refer to "Upper_X" without having to qualify
- where that variable was defined.
-
- Within the body of an object's procedures, things look the same as
- usual. These procedures can be passed variables, or not. They can do
- 37
-
- anything that any typical Pascal procedure can do. They are simply
- linked to their object's variables by reference.
-
- There's nothing magical about the names INIT and DONE, but Turbo
- Pascal's programming convention suggests that you name the procedure
- which initially defines an object's variables as INIT, and the
- procedure which finally terminates the object as DONE. If you don't
- like those names, you are free to use whatever names you prefer.
-
- Now that you've defined the object TYPE and its procedures, to
- actually define an instance of the object (like our Window_Area) you
- simply define it as a VAR. For example:
-
- Var
- My_Window : Window_Area;
-
- To use your defined object, you execute one of the object's defined
- procedures or functions. Here's a short example:
-
- My_Window.Init(20,5,60,20);
- My_Window.Enable;
- WriteLn('See. It worked!');
- Delay(1000);
- My_Window.Done;
-
- This example would define the window as the area between (20,5) and
- (60,20), enable the window and clear it, write a short message in the
- window display area, pause briefly, then reset the window as the
- entire screen.
-
- Notice that you invoke an object's procedures just like any other
- Pascal procedures, but you prefix the procedure name with the name of
- a specific object variable ("My_Window" in this case).
-
- This may seem a little odd at first, but the concept is fairly
- simple. Think of an object as a RECORD variable that is tightly
- linked to a set of procedures and functions. Think of invoking an
- object's procedure as if you had simply called the procedure normally,
- passing it all the defined parameters plus the object's record
- variable. If you think of it in that way, you can see that this much
- of Turbo Pascal's object oriented programming extension is simply a
- shorthand method for passing record variables to procedures.
-
- There is much, much more to objects than this, however. Objects can
- be constructed out of the variables and procedures of other objects.
- For example, if you were writing a graphics program, you might define
- a POINT as an object. The point has a single (X,Y) coordinate. You
- might define a CIRCLE object as a POINT plus a radius. And you might
- define a SPHERE object as a CIRCLE plus a 3-Dimension boolean flag.
- The advantage which OOP offers you is that each object can be built on
- the foundation laid by the predecessor objects. That is, higher level
- objects inherit the data variables and procedures of lower level
- 38
-
- objects on which they are defined. Objects also let you define to the
- procedure at execution time which objects they will act on. (This
- feature is called dynamic methods and polymorphism.) I'll try to
- write more on these concepts in a later article.
-
- The bottom line is that object-oriented programming can be used to
- make your programs more flexible and easier to test. By
- "encapsulating" the variables of an object and the procedures that
- operate on them, you simplify the debugging process. By building
- layers of objects, you simplify the coding process by reusing
- functions and procedures of predecessor objects. Eventually, after
- enough use of objects, this technique will change the way you
- structure and design your programs. You will learn to think first
- about the structure of your data, and second about the functions you
- perform on the data.
-
- If you'd like to see a longer example of using objects, I have
- included TP unit named TEXTLIST.ZIP. This unit can be used to build
- and manage a linked list of textual values. You might use this to
- build a simple editor, for example. Enjoy, and start becoming
- familiar with Turbo Pascal's object-oriented programming!
-
- 39
-
- Doing More With Strings
- By Gerhard Hoogterp
- Fidonet 2:283/1.2
- BitNet HOOGTERP@HENUT5
-
-
- One of the things most programmers who switch from Basic to
- Pascal notice first is the limited number of procedures and functions
- Turbo Pascal has available to work with strings. Standard Pascal, not
- having strings at all is even worse. Actually it's been a long time
- since I programmed in Basic, but the need for some more advanced
- string routines was there when I was working on a text adventure. My
- string toolbox grew and became more advanced over the years, and so it
- evolved into what I present here.
-
- For my purposes, I defined a string as a list of tokens separated
- by a delimiter. A sentence like:
-
- This is a sentence, with seven words.
-
- ^ ^ ^ ^^ ^ ^ ^^end of string
-
-
-
- Contains seven tokens and 4 delimiters. At some places the
- delimiters are double, like the ', ' combination. The fourth delimiter
- is the end of string Which, although not explicitly used by the
- routines, is there anyhow.
-
-
- As the toolbox was intended for use with a natural language
- parser I couldn't put restrictions on the delimiters, or the way they
- should be used. So the first routine to write was
-
-
- Procedure SimplifyDelimiters( Var TokenList : String;
- Delimiters : String);
-
-
-
- It takes a string and changes double delimiters into single
- delimiters. So the ', ' combination would be replaced with only
- space.
-
-
- To use this function with the above example would be:
-
-
- Sentence:='This is a sentence, with seven words.';
- SimplifyDelimiters(Sentence,' ,.');
- 40
-
- The second function needed was a way to separate the string into
- a head and a tail. To find the first token. This token was of course
- delimited by a delimiter again.
-
- Function FindToken(Var TokenList : String;
- Delimiters : String):String;
-
-
-
- When this function is used on the example sentence like
-
- Sentence:='This is a sentence, with seven words.'
-
- Token:=FindToken(Sentence,' ,.');
-
-
- it will return the string 'This'. The delimiter is removed and the
- sentence becomes 'is a sentence, with seven words.'
-
-
- These two routines provide the user with a lot of power when, for
- example, reading configuration files. SimplifyDelimiters accepts a
- string in a user readable way and turns it into something more
- suitable for a computer, the FindToken takes the first token (the
- keyword in a CFG file) which can be converted to a number or a
- subrange type to use in a CASE Statement.
-
- To make life a little easier there are some functions in the toolbox
- that alter the complete string too. Of course there are the
-
- UpStr(Var TokenList : String) and
- DownStr(Var TokenList : String)
-
-
- functions to turn a string in all uppercase/lowercase, a
-
- SkipLeadingSpaces(Var TokenList : String)
-
- Which deletes the leading spaces (Spaces are almost always used as
- delimiters, so leaving them there would, even after a
- SimplifyDelimiters, always let the string start with an empty token)
-
- DeleteTrailingSpaces(Var TokenList : String)
- Which deletes the trailing spaces of a string for the same reason
- as the SkipLeadingSpaces function. That leaves only two procedures in
- the toolbox, which are useful in the original set up of the unit.
-
- DeleteNoise(Var TokenList : String; Noise : String);
-
-
- Deletes all the characters in the NOISE string from the
- TokenList. When the user is free to type what he likes (as in an
- 41
-
- adventure game) there are always characters which shouldn't be there.
- DeleteNoise deletes those characters. It's even more useful when used
- together with the other left procedure
-
- ReplaceToken( Var TokenList : String;
- Tok1 : String;
- Tok2 : String);
-
-
-
- which is used to change a certain token to an other token or
- character.. For example, in a typical adventure sentence one could
- type:
-
- 'Take the blue sword and go to the north'
- In this sentence the token 'AND' is a delimiter. It separated two
- commands. So it would be useful to change the 'AND' in for example '&'
- which can be used by the FindToken to break the sentence in two
- pieces.
-
- Sentence:='TAKE THE BLUE SWORD AND GO TO THE NORTH';
- ReplaceToken(Sentence,
- 'AND',
- '&');
-
- would do the trick. There are also some words in the sentence that
- don't add any information to the command. Their only used because it's
- english. The words 'THE' and 'TO' can be removed from the sentence. So
- with
-
- Sentence:='Take the blue sword and go to the north';
- ReplaceToken(Sentence,'THE',' ');
- ReplaceToken(Sentence,'TO',' ');
- ReplaceToken(Sentence,'AND','&');
- SimplifyDelimiters(Sentence,' ');
-
-
- Results in: Sentence = 'Take blue sword & go north'
-
-
- which is more suitable for a computer than the original sentence. An
- other approach is to change all the "noise" words to a noise character
- and delete that character with the delete noise procedure.
-
- 42
-
- Bits & Pieces
-
- Bits & Pieces is going to be a sort of gathering ground for small
- routines and things that readers or maybe even me will contribute to.
- It's basically quick and dirty routines that can't really make up a
- whole article. Individual authors and programmers will be given credit
- with their routines. This issues Bits & Pieces is going to be a bit
- scarce, having only one item, but I think it will give readers an idea
- of the kinds of things I'm looking for in it and maybe get them to
- contribute to it.
-
-
- Bits & Pieces #1 : Nathan S. Phillips
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-
- Here is a procedure to display a number with commas (12345
- becomes 12,345). I wrote this procedure some time ago for my "DSIZ -
- Directory Size Utility" program. The program displays the size of a
- directory (among many other things), and a display like "C:\FOO -
- 13245336 bytes" would be a little confusing - is that 1, 13, or 132
- megs? But display the sizes with commas, such as "C:\FOO - 13,245,336
- bytes", and the user can easily see how big the directory is. But
- enough history - on to how the procedure does what it does. The
- procedure takes the number you want to display with commas in a value
- parameter of type real. It uses the real type so that large values
- may be passed - only the integer portion of the number is used.
- Basically, it takes a number and either:
-
- 1. Displays the number if it doesn't need
- any commas (0-999)
- 2. Calls itself, passing the number divided
- by 1000, if the number needs a comma
- (greater than 999)
-
- When the procedure calls itself, the remaining instructions are
- "stacked", and executed when the call is complete. Therefore, the
- procedure keeps calling itself (without displaying anything) until it
- gets to the leftmost digit(s) that are displayed before the first
- comma. It displays that portion, and returns. Then the stacked
- instructions start executing, printing the commas and zero-padded
- numbers. When all of the stacked instructions have been executed, the
- entire number will have been printed.
-
- Like many recursive procedures, it is an elegant, compact solution to
- the problem. And, like many recursive procedures, it is difficult to
- follow, especially if you don't use recursion often. (I should say
- difficult for Pascal programmers to follow; Lisp programmers *think*
- recursively.)
-
- 43
-
- procedure DisplayWithCommas(r : real); { displays 1024 as 1,024 }
- var t : real;
- begin { NON-RECURSIVE CASE if r is less than 1000 }
- if r < 1000 then { if this part is under a thousand, it doesn't }
- write(r:1:0) { need zero padding or commas, so just print it }
- { (This would be the 1 in 1,024) }
- else
- begin { RECURSIVE CASE - will need at least one comma }
- { call this procedure again }
- DisplayWithCommas(int(r/1000)); { with the same number, but }
- { without the last 3 digits }
- write(','); { display the comma }
- t := r - int(r/1000)*1000;{get the value of the last 3 digits}
-
- { (will be 24 for 1024) }
- if t < 100 then write('0');{pad with 0s so the routine will}
- if t < 10 then write('0'); { print 1,024 rather than 1,24 }
- write(t:1:0); {now just write the value of the last 3 digits}
- end;
- end; { procedure DisplayWithCommas }
-
- 44
-
- Conclusion
-
- I like to do things in order. I wrote the introduction first
- thing, and I'm finishing off with the Conclusion, after everything
- else has been put togather. At this point, I'm speechless. I would
- like to thank all of the wonderful people who contributed to this
- issue and previous issues. We had a lot of article submitted this
- month. If people can keep sending them in, the Pascal NewsLetter might
- really gain some momentum.
-
- I hope you've enjoyed this issue as much as I have. I've enjoyed
- reading all of the articles and I've enjoyed putting them together for
- you. I've been blown away by all the contibuted articles. It's really
- been exciting to see the response. I am constantly getting
- suggestions, comments, and good criticism for the newsletter. I'm glad
- there are so many people out there who enjoy it. It makes it worth my
- time.
-
- I'm not really sure what I'm going to do for the fourth issue. I
- do have some ideas written down here and there, but nothing firm yet.
- I'm sure users will keep sending in the articles which will keep us
- alive. If I had to rely on myself for each issue, I can assure you
- they would only come out once every two months, and wouldn't be nearly
- as good. I think I'm going to be able to put new issues out about once
- every 3 or 4 weeks, which to me seems reasonable. If you'd like to see
- it come out more often, then pitch in and send in some articles.
-
- I'm still open to contributed articles. Please send them in. I
- ask only one thing more: Please do not send the documents in
- formatted. It is almost impossible to work with the documents which
- are justified, double-spaced, etc... Please send them in single-
- spaced and hard returns only at paragraph breaks. I'll take care of
- the rest once it's integrated into the newsletter.
-
- Again, I would like to thank everyone, and please keep the
- comments and suggestions coming, but more importantly, keep the
- article submissions comming!!!
-
- _Pete Davis
- Editor
-
- 45
-
-
- The Pascal NewsLetter is Copyrighted by Pete Davis.
- Articles submitted by others are the property of those
- authors and are used with permission. They may not be
- treated seperately from this newsletter without the
- author's permission and thus maintain all distribution
- rules of the newsletter as a whole. It may be freely
- distributed in un-modified form, but no charge
- whatsoever may be incurred on the recipient. All code
- is provided 'as-is' with no guarantees whatsoever.
-
- The Pascal NewsLetter can be obtained from the
- following locations:
-
- GEnie : General Electric Network for Information
- Exchange. It is located in the IBMPC filelist.
-
- Simtel: Internet address: 26.2.0.74 or Simtel20.ARPA It
- is located in the <MSDOS.PASCAL> directory.
-
- Programmer's Forum : This is the home of the PNL. Each
- issue can be found in the MAG
- directory from the main area.
- The number is on the title page.
-
- If you would like to receive back issues of PNL
- directly from me, send a diskette and $2.00 for
- shipping. Don't forget to include your address.
- Send your order to:
- Peter Davis
- 4851 Brandywine St. NW
- Washington, DC 20016
-
- If you are a SysOp that will regularly carry PNL and
- would like to have your bulletin board listed as such,
- here, send me a message either by postal mail or at one
- of the electronic addresses given on the title page,
- with your bulletin board's name, phone number, and your
- name.
- 46
-
- Distribution List
-
- The following is the phone numbers to bulletin boards known
- to carry PNL. If you would like your bulletin board's name and
- number added to or deleted from this list, please send me a
- message at one of my many addresses. I can not guarantee whether
- a listed board will have any particular issue, however.
-
- The Programmer's Forum ................. Phone: (202) 966-3647
- The Programmer's Forum is the home of the PNL.
-
- The Bored .............................. Phone: (512) 303-0471
-
- Classic City ........................... Phone: (404) 548-0726
-
- Theive's World ......................... Phone: (713) 463-8053
-
- Hippocampus ............................ Phone: (203) 484-4621
-
- Rogers State College BBS ............... Phone: (918) 341-8982
-
- The Foxtrot BBS ........................ Re-Locating
-
- Turbo City BBS ......................... Phone: (209) 599-7435
-
- Austin IEMUG/MIDI BBS .................. Phone: (512) 528-0626
-
- Laser Publishers ....................... Phone: (918) 438-2749
-
- Fargo RBBS-PC .......................... Phone: (701) 293-5973
-
-