Category : Pascal Source Code
Archive   : PNL001.ZIP
Filename : PNL001.TXT

 
Output of file : PNL001.TXT contained in archive : PNL001.ZIP

















//////// // // //
// // /// // //
// // //// // //
//////// // // // //
// // //// //
// // /// //
// // // ///////





Pascal NewsLetter
Issue #1
May, 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: PDAVIS5
BitNet: HJ647C@GWUVM & UE356C@GWUVM



















Table Of Contents



Introduction .......................... Page 3 (Pete Davis)
Generic Structures in Turbo Pascal .... Page 5 (Pete Davis)
Turbo Pascal Program Optimization ..... Page 10 (Pete Davis)
Conclusion ............................ Page 16 (Pete Davis)























Turbo Pascal is a Registered Tradmark of Borland
International.
































Introduction



Well, welcome to the premier issue of the Pascal News

Letter. Since this is the first issue, it's important that

the purpose of the newsletter be stated. I run a bulletin

board in Washington, and I often come across newsletters and

magazine. I have yet to find any geared towards Pascal,

though. (Save for a few which aren't really worthy of

mention.) Because I use Pascal quite often, I became

frustrated that there wasn't a free source of information.

Sure, I could go out and buy some magazines that are Pascal

oriented, but when there are newsletters like CNews, and

MicroCornucopia about, why should I have to bother with

that? There should be a Pascal oriented one. Well, now there

is.

My main purpose with the newsletter is to provide a

good place for the solutions to common problems. Many people

have questions regarding pascal and have a lot of problems

getting those questions answered. There are also a lot of

people with fantastic concepts and ideas waiting to be

passed around, but no means to pass it around. There will

now be a way. Because this is the first issue, all articles

are written by myself, this is also why it might be a bit

skimpy. Hopefully this will improve with further issues. It

is my hope that people with interesting ideas and concepts

will pass them along to me, preferably with an article


3














attached.

Most of the articles are geared towards Turbo Pascal.

This is not meant as a limitation, however. Turbo Pascal is

about as standard as the IBM compatible pascal compilers

get. Many of the ideas will be portable to other versions of

pascal, if possible.

Like many of you, I'm sure, I'm a busy person. Doing

this newsletter will take a significant amount of my time,

but from this, I would like to explain my articles a bit.

Complete pieces of code are not always provided. Instead,

partial pieces of code and algorithms will make up a large

part of my articles. (I am only speaking for myself and not

others, who in the future may provide full pieces of code

for the newsletter.) My purpose is to get the concepts and

ideas across and let you, the reader, implement them in a

way that suits you.

I am very fond of feedback, and would love to get a

message now and then about what you, the reader, thinks

about PNL, and what you would like to see in future issues.

Please feel free to send your feedback, suggestions, and

articles, especially, to any of the above addresses. As

editor, you may expect several topical changes to your

articles, but nothing major.

Pete Davis

Editor




4














Generic Structures in Turbo Pascal



I have to thank my current professor, Raymond Thomas

for the ideas and concepts covered in this article. Although

I had thought only a bit about the generic structures, his

class forced me too look at them more closely.

The structure provided in our class was a generic

linked list, but the idea can be carried out into several

other implementations. The idea is to have a unit of code

that can be re-used for different types of data. For

example, one could write a unit that performs stack

operations of POP and PUSH, but have it be able to work with

integers, strings, real numbers, or even records. This is

very useful if you want to write units and distribute them

in the public domain or as shareware, and have people be

able to use them for themselves. Such procedures as generic

linked lists, stacks, queues, B-Trees, sorting routines,

etc...

There are several features of Turbo Pascal that make

this possible. Among them is the untyped pointer, the SizeOf

function, the Move, GetMem, and FreeMem procedures, and the

untyped parameter.

The heart of any generic structure is going to be the

source of information about the structure and the

information holder. In our example, it is going to be the

head of the stack:


5

















type
StackPtr = ^StackItem;
StackItem = record
NextItem : StackPtr;
DataItem : pointer;
end;

HeadPtr = ^Header;
Header = record
Size : word;
Top : StackPtr;
end;


Now for a bit of an explanation of our stack. For the

most part, it follows the standard structure of a linked

list implementation of a stack. The main differences one

notices are the Size (in the Header record) and DataItem (in

the StackItem record). Size is the size of the data items

being placed in the stack. This is where Turbo Pascal's

SizeOf function comes in handy. To show how this works, I

will present the StackInit procedure.



procedure InitStack(var H_Ptr : Header; ItemSize : word);

begin
New(H_Ptr);
H_Ptr^.Size := ItemSize;
H_Ptr^.Top := nil;
end;


A typical call to the InitStack procedure would be like

this:

InitStack(H, SizeOf(MyData));




6














Now, let's examine the StackItem record. The DataItem

field provides only a generic pointer. Here is where the big

difference between the Generic Data Structure and the Pre-

Defined Data Structure shows itself. Because DataItem is a

Generic pointer, it has no size associated with it. One is

unable to use the New and Dispose procedures for the

individual data items in the stack. Instead, the New and

Dispose procedures are used to handle the StackItem records,

while the GetMem and FreeMem procedures are used to handle

the data in those StackItem records. Here is a sample of a

Push procedure:


procedure Push(H_Ptr : Header; var Data);

{ Notice that Data is an un-typed variable }

var
ANode : StackPtr; { Our temporary node }

begin
{ Allocate memory for the node itself. }
New(ANode);

{ Allocate space for the user's data and set a
pointer to it in ANode. }
GetMem(ANode^.DataItem, H_Ptr^.Size);

{ Since it's a stack, and it's the newest item,
have it point to the previous top of the stack }
ANode^.NextItem := H_Ptr^.Top;

{ and have the new top point to our new node }
H_Ptr^.Top := ANode;

{ Now physically move the data from it's current
unprotected space, and into the space acquired for it.}
Move(Data, ANode^.NextItem^, H_Ptr^.Size);
end;




7














Ok, so now we have our Push procedure. The comments are

a little thick, but they can be removed to make it look

nicer. I don't really think I need to go into too much

discussion of the operations in the Push procedure, for the

most part they are pretty straight forward. I would like to

caution about the use of the Move procedure, however. You

need to know exactly where you are moving your data to and

from. It might take a little work to get exactly what you

want.

Now, what good is a stack that you can only put

information into, and not get any back? Not much, so here is

the Pop procedure:



procedure Pop(H_Ptr : Header; var Data);

{ It would be nice to have the Pop procedure be a function
returning the value, but we can't return an untyped
value }

var
ANode : StackPtr; { Our temporary node }

begin
{ First, make sure we're working with a
non-empty stack! }
if not StackEmpty(H_Ptr) then
begin

{ Set ANode to the top of the list }
ANode := H_Ptr^.Top;

{ Have the Top now point to the second item
in the list }
H_Ptr^.Top := ANode^.NextItem;

{ Move the contents of the data to the user's
variable. }
Move(ANode^.DataItem^, Data, H_Ptr^.Size);


8














{ Return our data's memory and our node
itself to the heap. }
FreeMem(ANode^.DataItem, H_Ptr^.Size);
Dispose(ANode);
end
else
... Error routine goes here ...
end;


Well, that just about covers the basics of our generic

data structure. I left out some of the routines, but they

should be pretty easy to add. For example, the EmptyStack

function would return a boolean value of true if H_Ptr^.Top

was nil. So, I'll leave the rest of it to you. There are a

multitude of possibilities and uses for generic data

structures. It's just one more way to make your routines

'user friendly'.





























9














Turbo Pascal Program Optimization



This article will cover a portion of program

optimization in Turbo Pascal. I say it covers a portion of

optimization only because optimization is such a vast

subject that it would be impossible to cover completely in a

single article. I also gear it towards Turbo Pascal, but

most of the tips here will apply to almost all pascal

compilers.



WHERE TO OPTIMIZE:



The most important step in optimizing a program is

deciding where to optimize. A good programmer is compelled

to optimize as he/she writes the code. This is a good

programming practice, which once you know most of the

important optimizations secrets, is easy to implement as you

code. A big problem occurs when you try to optimize after

writing the code. The reason this is a problem is one tends

to try to optimize every bit of code. This is incredibly

time consuming and usually results in only mild

improvements. Knowing where to optimize, however, can save a

lot of time in coding and a lot of time in execution.

There are a lot of places where optimization will make

huge improvements in code speed. Learning to recognize where

your program is spending it's time is easy once you know


10














what to look for. First of all, loops! Loops should stick

out like a sore thumb when optimizing a program. A user

recently came into work with a program that he thought

wasn't working. He complained that he had let it run for

fifteen minutes and still didn't get his results. Although

his program was only about 20 lines of code, it would take

at least 2 hours to run. Why? He had 4 loops. Each loop was

inside another loop. That adds up pretty quickly. Each one

looped 100 times. Now, let's figure out how many loops that

is: 100 * 100 * 100 * 100 = 100,000,000 loops total. To make

things worse, he had some pretty heavy calculations inside

the inner loop. Ok, so loops are definitely one place to

look for optimization.

Don't just look at loops, though, look at what's inside

a loop. Sometimes redundant data is placed inside loops that

can be taken out of the loop. Declaring a variable inside a

loop that is always the same:

example ->

for x:=1 to 80 do
begin
y:=1
gotoxy(x,y);
write('x');
end;


Here we have the variable y being declared 80 times,

while it never changes. This can be fixed by declaring y

before entering into the loop. This is a very obvious

example, but sometimes it isn't quite so obvious.


11














SPEED vs. SIZE



Optimization really covers two areas: Speed and Size.

Unfortunately, optimizing for one usually ends up making the

other worse. There are some exceptions, however, like

passing variable parameters as opposed to value parameters

as we'll cover later. Speed is almost always of primary

importance and I will usually emphasize it.



VALUE vs. VARIABLE PARAMETERS



When writing procedures or functions, there is usually

a little thought about whether to use variable or value

parameters. The normal train of thought is that you pass a

variable parameter only if that value will change in the

procedure or function. Now lets look at what actually goes

on behind the scenes. When a parameter is a value parameter,

there are no changes made to the actual variable itself.

This means that an exact copy of the variable needs to be

made in memory. With a character or byte value, this isn't

real significant, but what if you're passing an array of

1000 integers. That means an exact copy of 2000 bytes needs

to be copied in memory. This not only takes time but it also

takes up quite a bit of memory. If your routine is recursive

or occurs inside a loop, you are looking at a serious

decrease in speed and a huge increase in memory use. One way


12














to repair this is to pass variable parameters whenever

possible. There are some times when it is impossible to pass

a variable parameter. In these cases you'll be forced to

pass a value parameters.

For those unfamiliar with variable and value

parameters, here are two examples:



procedure ShowIt1(S : string);

begin
write(S);
end;

procedure ShowIt2(var S : string);

begin
write(S);
end;

The first procedure, ShowIt1, uses a value parameter.

This means that an exact copy of the string S has to be made

in memory. Since a string can be up to 255 characters, this

can add up.

The second procedure uses a variable parameter. Instead

of passing a complete copy of the variable, a pointer to the

string S itself is passed. Since this pointer is only 4

bytes long, you can make a very significant improvement.



COMPILER DIRECTIVES



When testing a new program, it is very important to

have compiler options, such as range checking and stack


13














checking active. Truth is, though, that these options add

quite a bit of time-consuming code to your programs. Of

course, it is good to have them in when writing the first

copy of your program, but when compiling a final version, it

is a good idea to disable these options. The results are a

significant increase in speed, and a nice cut in the size of

the final program.



IF/THEN vs. IF/THEN/ELSE vs. CASE



The last point of optimization that I will cover in

this issue is the decision structures. Here is a short piece

of code. The variable C is type char:



1> ---- IF/THEN ----
if C = 'A' then writeln('You Win!');
if C = 'B' then writeln('You Lose!');
if C = 'C' then writeln('Tie Game!');

2> ---- IF/THEN/ELSE ----
if C = 'A' then writeln('You Win!') else
if C = 'B' then writeln('You Lose!') else
if C = 'C' then writeln('Tie Game!');

3> ---- CASE ----
case C of
'A' : writeln('You Win!');
'B' : writeln('You Lose!');
'C' : writeln('Tie Game);
end;


The first example is the slowest of the three. It is also

the least clear of the code. It is rarely a required

structure, and can usually be replace by the more efficient


14














IF/THEN/ELSE structure. When possible, though, one should

use the CASE structure. It is the best method for something

like the above coding. It is faster and requires less

memory.














































15














Conclusion



Well, like I said in the beginning, this is a little

skimpy, but it is the first issue. I hope to have a more

full second issue. If you have some good ideas, please

submit them. Since this is the end of the spring semester, I

will be looking at quite a bit more time as summer

approaches. So, with my extra time and, hopefully, your

submissions, the second and later issues will be larger. I

am also planning on including complete pieces of code with

the newsletter itself.

Please send your submissions to the addresses provided.

I hope you enjoy this and I look forward to your comments!




























16









  3 Responses to “Category : Pascal Source Code
Archive   : PNL001.ZIP
Filename : PNL001.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/