Trail: Pascal

Performance Testing : Pascal

KnowledgeBase :: Categories :: PageIndex :: RecentChanges :: RecentlyCommented :: Login/Register

PASCAL


ANSI-ISO PASCAL FAQ

Welcome to the FAQ ! I will answer here various questions about ANSI-ISO
Pascal, and compilers of that language. This FAQ is not limited to any
one machine, operating system or language level. Any language that is
based on the original Wirth language or the standards that came from it
may be covered here.
Requests to add information are welcome, submissions are encouraged.



Q. WHY IS THE NAME PASCAL ?

A. This should be a trivia question. Pascal was named after the French
mathematician Blaise Pascal, who created a calculating machine (not a true
computer).



Q. WHAT IS ANSI-ISO PASCAL ?

A. Pascal is one of a series of languages put forth by one of the most
prolific computer language creators, Nicklaus Wirth, a professor at
Institut fur informatik, ETH, Zurich, Switzerland. Professor Wirth
participated in various versions of Algol, a language put forth by
international cooperation that introduced the basic concepts of structured
programming to the world. Wirth terms Pascal as a descendant of Algol 60
(for Algol, 1960 standard). The "official" descendant of Algol 60 was
Algol W, famous for having assignment as an expression operator (a basic
feature of the later language C). Wirth felt that the design committee
for Algol, after Algol 60, was losing focus and creating an unnecessarily
complex language.
While Algol W has had it's fans, the language Pascal was considered
to be a new high of consistent language design.
The first draft of Pascal was created in 1968. The first compiler was
operational in 1970, and the language was generally published in 1971.
In 1973, after two years of testing and use, the language was revised
into it's final form.
The first compiler for Pascal was implemented on a CDC 6000 computer
at ETH, for "unrevised" Pascal. After the language was revised, a new,
high optimization compiler for the new language was created using the
old compiler, then the source for that compiler itself changed to
"revised" format, so that it could compile itself (known as "bootstrapping"
a compiler).
In 1974 there were 10 compilers running on various systems. By 1979
there were at least 80.
In 1977, various committees began the work to standardize the language.
In 1982, the ISO (International Standards Organization) issued ISO 7185,
the official Pascal standard. In the same year, the US ANSI committee
issued ANSI/IEEE770X3.97-1983, the US standard for Pascal. In addition,
several countries around the world issued their own national standard
for Pascal.



Q. WHAT IS THE HISTORY OF PASCAL ?

A. Pascal is in the Algol family of languages. Algol, whose first version
was called IAL or "International Algerbraic Language", was the first language
created by international committee. The resulting language was rather odd
for its time. The committee had the goal of designing a unified computer
language, but also saw Algol as a way to cleanly express computer
alrorithims, and so was not directly concerned with creating a practical
language for compilation. That is, the language would serve a purpose even
if it was only used for publishing algorithims, not running them.
This resulted in Algol not having many data types, or built in I/O. Also,
Algol was generally free of the limits common to programming languages of
that time, such as number of array dementions. One of the goals of Algol
was for it to be as close to mathematical notation as possible. In
particular, Algol used a special operator for assignment, ':=', because
'=' had a different meaning in mathematics.

Algol was introduced in 1958 as Algol 58. In 1959, the committee prepared
a new version that would become Algol 60. One of the hallmarks of that
version was not a language feature, but that a language syntax notation
called BNF (Backus-Normal Form), which gave a complete discription of the
language syntax, a first for any computer language.

The revised report for Algol 60 is available at:

http://www.masswerk.at/algol60/report.htm

While Algol 60 was a pivotal language, its (relatively) abstract nature
reduced the number of practical implementations. It was common to hand
translate Algol programs in to Fortran, and real world Algol compilers
that existed tended to provide a number of extentions necessary for
practical problem solving, for example, I/O statements.

In 1962, working at UC Berkley in California, Niklaus wirth worked on
an Algol 60 variant/implementation Euler (after Swiss mathmatician
Leonhard Euler), on which an ACM paper was based.

After Algol 60, the committee began work on a sucessor standard. In 1964,
Niklaus Wirth was invited to join the Algol working group, in response to
his work on the language Euler. The proceedings of the Algol group were
contentious, perhaps explaining why many years passed without producing the
next Algol standard. There were three proposed versions of Algol. The one
proposed by Wirth was Algol W, which was implemented on on an IBM 360
computer. The proposal that was accepted as the official standard for
Algol was Algol 68, the last widely implemented version of Algol.

You can find the revised report on Algol 68 at:

http://members.dokom.net/w.kloke/RR/

In 1968, after the working group for Algol, Wirth decided to design a new
language in the tradition of Algol 60 and Algol W that met his goals for
including advanced data types, structuring of data types, and I/O for the
language. It was called Pascal (after Blaise Pascal, 15th century scientist
and inventor of early mathematical calculating machine).

In 1969, a bootstrap compiler using Fortran as the implementation language
was completed. Although the compiler was written in Fortran, the idea was
to rewrite the compiler in Pascal itself, and so bootstrap the compiler.
Wirth called that project unsucessful, and instead, a Pascal compiler
was written in a subset of the full Pascal language and translated by hand
to a language called SCALLOP on the CDC 6000 computer, and thus bootstrapped.

In 1972, the language Pascal was revised based on working experience with
it, and a new compiler for the revised language was created and completed in
about 1974.

Meanwhile, in 1973 a Pascal language subset and implementation was created
called Pascal-P (for Portable). The implementation included a compiler to
an abstract machine called the P-machine, and an interpreter for that
machine. The idea was that Pascal could be bootstrapped to new machines by
several methods, including writing a fairly small interpreter for the
target machine, rewriting the backend of the compiler to target a new
machine, or hand translating the intermediate code.

You can find the source and details for the Pascal-P implementation at:

http://www.moorecad.com/standardpascal/p4.html

In 1978, Kenneth Bowles at the University of California at San Diego
created a microcomputer implementation of Pascal-P that kept the p-system
interpreter and did not produce final machine code. Bowles believed that
microprocessors weren't powerful enough to run such an advanced system,
and were better off running on the interpreter on such machines, using a
carefully coded interpreter written in assembly language. Under Bowles,
an entire programming system, including operating system, editor and
compiler and even graphics system were created that all ran on the
interpreter.

Implementations of UCSD Pascl existed on machines as diverse as a MITS
Altair and a PDP-11. In 1979, a version of the system appeared on
the Apple II.

Also in 1978, the IEEE computer society began the proceedings to standardize
the Pascal language. In 1983, the full IEEE/ANSI Pascal language standard
and the first ISO Pascal language standard were issued.

In 1984, Borland introduced a version of Pascal for both CP/M on the Z80 CPU
and the IBM PC with an 8088/8086 CPU, as a full compiler. Borland released
several versions throughout the years, with the latest being Delphi, which
incorporated Borland Pascal as the base language.

In 1986, Apple released a version of its Pascal that supported objects, which
was developed in consultation with Niklaus Wirth.

In 1989, Borland introduced a version of Turbo Pascal with objects.



Q. What are the different Pascal standards?

There are currently 3 different documents that can be classified as
Pascal standards: Unextended Pascal, Extended Pascal, and the
Object-Oriented Extensions to Pascal.



Q. WHAT IS THE CURRENT STATUS OF PASCAL STANDARDS ?

A. Originally, unextended Pascal was actually 2 standards. An ANSI/IEEE
standard (ANSI/IEEE770X3.97-1993) and an ISO standard (ISO 7185 : 1983).
There were 2 standards for mostly political differences that I won't
get into here. For the most part, the ISO standard was a superset of
the ANSI/IEEE standard and included the conformant array feature. See
the foreword of Extended Pascal for some additional history of the
development of unextended Pascal.

In 1989, ISO 7185 was revised to correct various errors and ambiguities
found in the original document. Also, the ANSI/IEEE770X3.97 standard was
replaced with a "pointer" to the ISO 7185 standard. So finally in 1989,
there was only 1 unextended Pascal standard in the world.

The unextended Pascal standard (ISO 7185 : 1990) is still in force as
a valid ISO language standard.



Q. WHY USE THE STANDARD VERSION OF THE LANGUAGE (WHEN OTHER DIALECTS ARE
MORE WIDELY USED) ?

A. Its a good question. First of all, the ISO 7185 standard is the original
language as created by N. Wirth, more precisely defined and more secure
than the original. The standard makers refrained from making large
improvements or extentions to the language. In fact, because Pascal is one
of the most carefully designed languages and also one of the most carefully
standardized, there is a high degree of ability to determine, unambiguously,
if a given program construct is legal according to ISO 7185 rules.

Unfortunately, Pascal, almost from the first of its use, was widely extended
and changed. One reason for this may be that the language was also very
popular in compiler classes, and tended to produce many experimental
versions.

However, the original language, Pascal/1972 or J&W Pascal, has been around
since 1972, standardized in 1982, and only minor changes were required to
programs to bring them into compliance with it (see below). The basis of
the language is still very strong, and the ISO 7185 standard is freely
available. Further, there are many books written with the standard in mind.

While it is certainly true that a standard does no good if you cannot find
anyone who makes product according to it, using a non-standard Pascal
puts you at the mercy of the compiler maker for that dialect. If they go
out of business, you may have to rewrite your program. Also, even if they
stay around, the more obscure rules of using a non-standard dialect may
be found only by trying out test examples. It can and has happened that
non-standard compilers have changed and broken even programs that worked
previously on earlier versions of that compiler.

Interest in standards complying Pascal has always been there, but in recent
years it has been growing again, especially with the advent of a freeware
ISO 7185 standard compiler with good efficientcy. What will make the
difference now is ISO 7185 compilers with more modern implementations
and extentions.



Q. WHAT ARE THE BASIC FEATURES OF PASCAL ?

A. Pascal is a structured language, using if-then-else, while, repeat-until,
and for-to/downto control structures. It differs primarily from proceeding
languages in that data structures were also included, with records (a feature
borrowed from COBOL), arrays, files, sets and pointers.
Pascal is also unusual for forging an effective compromise between language
simplicity, power, and matching of language structures to underlying machine
implementation.
Pascal also has many features for compiler writers. The language is
constructed to have a minimum of ambiguity. Pascal, with few exceptions,
can be processed "forward" with all of the smaller elements (like constants,
types, etc) being defined before they are used. Pascal requires the types
and exact sizes of operands to be known before they are operated on, again
leading to simplified language processing and efficient output code
(although this feature has often been called a problem).
For this reason, Pascal still remains a popular language to implement
compilers for as part of a compiler science class.



Q. WHAT IS J&W (OR THE "REPORT") ?

A. This refers to the "Pascal user manual and report", by Kathleen Jensen
and Niklaus Wirth. This is the original bible of Pascal. The second
edition contained the finalized language under Wirth. It is no longer
available. The current edition is the fourth, containing almost twice
as many pages, and contains the second edition extensively revised to
meet the ISO Pascal standard.



Q. WHAT ARE THE DIFFERENCES BETWEEN STANDARD PASCAL AND THE ORIGINAL
PASCAL ? WAS IT CHANGED EXTENSIVELY ?

A. No. The stated goal of the standards committees was to keep Pascal
unchanged, but simply address the insecurities and ambiguities that had been
discovered by users of the language.

The MAJOR changes are:

1. Procedure and function parameters (where the procedure or function
itself was passed as a reference) appeared without a parameter list
in the declared procedure or function. The standard requires that
the parameter list appears as well, so that it can be checked against
any call of that procedure or function. For example:

<old way>

procedure junk(function y: real);

begin

y(z);
...

end;

...

x := junk(sin, y);

<new way>

procedure junk(function y(x: real): real);

etc.

2. The original language only allowed procedure and function parameters
to have value parameters. The standard allows value or VAR parameters.

2. In conjunction with (2), standard procedures and functions (those
defined by the compiler itself) are no longer acceptable as
procedure or function parameters in the standard. The REPORT shows
several examples of passing such functions.

3. In the original language, it was left as implementation defined as
to the exact rules of whether type x was compatible with type y.
In fact, the first implementations at ETH (which were not documented
in the REPORT) were based on "best effort", such that:

var rx: record x, y: integer; c: char end;

and

var ry: record x: integer; y: 0..10; c: char end;

Were considered compatible because they had the same basic structure.
The standard tightened these rules up considerably. In the standard,
types are compatible with a few exceptions only if they are the same
type or "aliases" of the same type as:

type a = b;

The standard also exactly defines the rules for assignment and other
compatibility modes.

4. The REPORT defined symbol lengths to be implementation defined. The
standard defines them as "unlimited", which for practical purposes
means that if the program lines will fit through the compiler, and
a symbol fits on one of those lines, it should work.

5. The report leaves the rules for interprocedure goto's as
implementation defined. The standard says they must only target the
OUTER level of the block.

6. The control variable in a "for" statement must be a variable local
to the procedure, function or program block in which it appears.
This change was to allow a more efficient implementation with
better checking.

In fact, most of what the standard did was simply acknowledge what were
already good coding practices. The original REPORT method of assuring
portability could be stated as:

APPLICATION: Stay within the guidelines as possible. Don't rely on
implementation dependent features, such as the compiler's ability
to recognize the similarity between types, etc.

COMPILER: Implement the language as fully as possible, and always
try to do the most reasonable thing for implementation dependent
features, such as attempting to determine whether types are compatible
as best as possible.

The idea being that a program will not fail unless it is a poorly written
program run on a poorly written compiler.
The standard changed that to a much more exact set of rules that all
compilers and programs must follow.
As an example of the compatibility between the REPORT language and the
standard, I moved several thousand lines of my own Pascal source from the
"old" to a standard compiler without A SINGLE CHANGE because of the standard.
The only error I found was that the compiler would not accept:

var s: array [1..10] of char;

...

writeln(s);

Because such Pascal strings must be "packed". This was actually also required
in the REPORT, I just had not read it correctly (or well enough).



Q. WHAT ARE THE DIFFERENCES BETWEEN P-MACHINE PASCAL AND THE STANDARD ?

A. P-machine Pascal was designed to be a proper subset of pre-standard
Pascal. Therefore, P-machine Pascal will have all the differences that exist
between 1972 Pascal above and the 1982 standard, except concerning those
features that are missing from P-machine Pascal, and the following additional
changes/subsetting:

1. Procedures and functions may not appear as parameters.

2. Goto statements cannot reference targets outside procedure/function
bodies (so called "intraprocedural gotos").

3. All files not of type "text".

4. Features associated with "packing", including the keyword "packed", and
the pack and unpack system procedures.

5. Dispose is not implemented, it is replaced by "mark" and "release".

6. The brackets {} for comments.

Note that (4) above makes it impossible to create a program in P4 that
is acceptable to all of P4, Pascal/1972 and ISO 7185, the reason being that
the keyword "packed" is required for strings in the standard, but cannot
appear in a P4 program.

Source: Pascal-P Implementation Notes [Nori, Ammann, Nageli & Jacobi]



Q. WHAT ARE THE DIFFERENCES BETWEEN UCSD PASCAL AND THE STANDARD ?

A. Because UCSD Pascal is the P4 compiler with enhancements, the differences
are the same, with the following exceptions:

1. {} comment brackets ARE implemented, but in a nonstandard way. In ISO
7185, the following IS a valid comment:

{ hi there *)

But this is not valid in UCSD Pascal. In UCSD Pascal, comments using
different brackets can be nested:

{ this is a (* nested *) comment }

Which would not work in ISO 7185 Pascal.

2. Numbers are not printed out in their "default" field widths, but are
printed in the minimum amount of space. For example:

write(':', 5, ':');

Outputs:

:5:

in UCSD, but:

: 5: (spaces depend on compiler integer width)



Q. WHAT ARE THE DIFFERENCES BETWEEN APPLE PASCAL AND THE STANDARD ?

A. Early Apple Pascal was based entirely on the UCSD system, and the same
comments apply to it as to UCSD Pascal above.



Q. WHAT ARE THE DIFFERENCES BETWEEN BORLAND PASCAL/DELPHI/KLYIX AND THE
STANDARD ?

A. Because Borland Pascal/Delphi/Klyix is arguably the most prevalent version
of Pascal in existence, it is useful to compare the two languages. Note that
I compare here only the differences between Borland and the basic standard.
Undiscussed are any extensions provided by Borland. In other words, this
section answers the question "why doesn't my standard Pascal program run
under Borland/Delphi/Klyix ?", and perhaps "what can I write in
Borland/Delphi/Klyix that will also be compatible with the standard ?".

1. Procedures and functions may not appear as parameters (it is true
that it can be done, but a non-standard sytax must be used).

2. Goto statements cannot reference targets outside procedure/function
bodies (so called "intraprocedural gotos").

3. No file buffer variable handling. Standard Pascal has file "buffer
variables", and "get" and "put" procedures to operate on them. This
functionality is not present in Borland Pascal/Delphi/Klyix.

4. No "sized" dynamic variable allocation. Given a variant record, the
size of a particular variant cannot be specified as per the standard.
Ie, the following statement is invalid:

new(p, t)

Where t is a variant record tag type.

5. The functions "pack" and "unpack" are not implemented.

6. { and (*, } and *) are not synonyms of each other as required by the
standard. Ie.:

{ comment *)

is not valid in Borland Pascal/Delphi/Klyix.

7. (Delphi) It is not possible to construct a standard program without
compiler directives. At minimum:

{$APPTYPE CONSOLE}

is required.

8. Does not replace eoln with space as the standard requires. When reading
through the end of a line, the eoln character is supposed to be replaced with
a space in ISO 7185. Instead, reading through eoln in
Borland Pascal/Delphi/Klyix gives the character code for
carriage return (13), followed by line feed (10).

9. Numbers and booleans are not printed out in their "default" field widths,
but are printed in the minimum amount of space. For example:

write(':', 5, ':');

Outputs:

:5:

in UCSD, but:

: 5: (spaces depend on compiler integer width)

in ISO 7185.

For booleans:

write(':', true, ':');

outputs:

:true:

in Borland Pascal/Delphi/Klyix, but:

: true:

In ISO 7185.



Q. DID BORLAND PASCAL CONFORM TO THE ORIGINAL J&W PASCAL BEFORE THE
STANDARD ?

A. No, sorry. I have both seen this mentioned in several newsgroups, and
have also heard this repeated by Borlands own customer service. It simply
isn't so. In fact, the first Borland Pascal versions were farther from the
original language than the current ones, for example, Borland Pascal didn't
used to have variant records.



Q. I HAVE HEARD THERE IS A DELPHI UNIT THAT MAKES DELPHI PASCAL STANDARD,
DOES IT WORK ?

A. It is true that there has been such a package presented on the newsgroups.
It is a cruel joke. There is no such unit available or possible. Even if you
were to emulate "get" and "put" procedures, you cannot implement file
buffers such as f^ in Delphi. Neither is it possible to add procedure
or function parameters, since the problem is that Borland uses wildly
different syntax for that. Pack and unpack have to be compiler procedures.
In fact, virtually none of the incompatibilities can be corrected by just
adding a "unit".

I don't doubt the person who wrote that package really thinks that it brings
Delphi back to the ISO 7185 standard, but I also don't doubt that the same
person has not studied the ISO 7185 standard in any detail.



Q. MY PASCAL COMPILER MAKER SAYS THEIR COMPILER IS STANDARD. IS IT ?

A. If your compiler is ISO 7185 compilant, it is required to have a
"compliance statement", either printed by the compiler itself, or appearing
in the documentation, of the form:

(this processor) complies with the requirements of level (number) of
ISO/IEC 7185.

Note that some compilers may require a standard "switch" or option be turned
on to output this message. See your documentation.

If your compiler does NOT have this statement, think of it this way. If the
company is claiming to be compliant, how could they have missed this
required message, which is on page 5 of the standard ? They probally
missed a lot of other standard requirements as well.

It is possible for you to perform your own tests to determine how standard
your compiler is. Simply download and compile one of the standard-obeying
programs from my site:

http://www.moorecad.com/standardpascal/source.html

These have all been tested to at least compile under ISO 7185 Pascal.
They are all fairly famous programs that have been around since the 1970s.
They are large programs, and tend to use most of the language.

NOTE: several persons on the internet have been claiming to have compiled
and run these programs on non-standard compilers, and claim that as "proof"
of a compilers standard compliance. In reality, they have simply hacked the
source until it compiles on the non-standard processor. This proves nothing.
Do not believe in source you have obtained from elsewhere, get it from my
site where it is in ISO 7185 form.

Also, most of these programs were written before the ISO 7185 standard, and
needed some small modification to get them to compile under ISO 7185 rules.
Again, the answer is to only get the files from the above mentioned web
site.



Q. IS IT POSSIBLE TO WRITE IN A PASCAL SUBSET THAT WILL BE ACCEPTABLE TO ALL
DIALECTS OF PASCAL ?

A. For the most part, yes. You can use the ISO 7185 "level 0" Pascal with
the following omissions:

1. Do not use procedure or function parameters. These have different syntax
in ISO 7185, Pascal/1972, and Borland/Delphi/Klyix.

2. Do not use intraprocedural gotos (gotos that leave the current procedure
or function).

3. Do not use file buffer handling, nor the built in routines "get" and
"put".

4. Do not size your variant records with "new".

5. Use only "text" type files.

6. Use old style comments (* *) and not new style { }.

7. Do not use the "dispose" procedure (see for example the notes on "roll
your own storage recycling" below).

8. Allways use the keyword "packed" on a string that is intended to be
printed with "writeln".

9. Allways include the files "input" and/or "output" in the program header
if they are used in the program (and remember that write/read with no
file parameter is a defacto reference).

10. Don't use more than 8 characters to separate identifiers (ie., identifers
must differ over the first 8 characters, an original J&W requirement).

11. Don't use external files (since most dialects do nothing with header
files).

The exception would be the "packed" keyword exclusivity. As mentioned
elsewhere, some nonstandard compilers don't allow "packed" while the
standard pretty much requires it (otherwise, strings cannot appear in
"writeln"). For these cases, you must be prepared to add or remove "packed"
as required.

Finally, note that you MUST also comply with the ISO 7185 standard
requirements for this to work. For example, ISO 7185 forbids gotos into
program structures like "for" loops, etc, whereas many dialects do not.

I leave it to you to determine if these limits are too restrictive to allow
use of the language.



Q. WHAT IS THE DIFFERENCE BETWEEN PASCAL AND C OR SIMILAR LANGUAGES ?

A. Pascal is a strongly typed language and attempts to protect references and
types. In C, it is possible to use a cast to convert any type to any other,
and the address of any variable can be taken at any time.

Pascal does not have these features. It is still possible to generate invalid
references (see next question), but it is not as common. The inability of
Pascal to generate type convertions can require more work to accomplish
the same programming results. However, functionally there is little
difference between these languages, and there is usually a way to do the
same operation in both.

One significant difference that comes up is that Standard Pascal does not
allow variable length data structures (such as arrays), and C and similar
languages do. It is a common extention to Pascal compilers to allow this,
but of course those implementations may not be standard.



Q. WHAT WAS UCSD PASCAL ?

A. UCSD Stands for University of California at San Diego. Professor Kenneth
Bowles was teaching Pascal there, and used the P-machine implementation of
Pascal to create a Pascal that ran on Microcomputers (as PCs were called
back in the 1970's). It was an interpreted only version of Pascal, and
included a complete operating system written in Pascal.

UCSD was not strictly compatible with Wirths Pascal. Some features were left
out because of perceived complexity, such as variant records, and some were
left out deliberately, such as interprocedural gotos.

UCSD Pascal is said to be a direct ancestor to Apple Pascal, and Borland
Pascal implements most of the original functions of UCSD Pascal, making
it also a defacto derivative of UCSD Pascal.

See also:

http://www.threedee.com/jcm/psystem



Q. WHAT WAS THE "P-MACHINE" ?

A. The "P-Machine" was actually a "kit" of software issued by N. Wirth
and people working with him that was aimed at getting more Pascal compilers
running on different machines. The kit consisted of a compiler that output
to a "virtual machine" or a machine that was never designed to be implemented
on real hardware, as well as the actual binary file that was created by
having the compiler self-compile itself. The idea was that if you wrote a
program to interpret the "virtual machine" code on another CPU, you could
quickly get an interpreted version of Pascal running. Then, you would create
a "back end" program to create actual machine code for your system,
recompile the new compiler with that, and effectively "bootstrap" the
compiler to your brand of machine.

The P-machines most famous use was in UCSD Pascal. In that case, a full
compiler was not made and the interpreter was the final product.

See also:

http://www.cwi.nl/~steven/pascal/book/pascalimplementation.html



Q. WHAT ARE THE INSECURITIES OF PASCAL ?

A. Like most languages, it is possible to write Pascal programs that crash
or otherwise compromise the computer they are running on.

1. Infinite loop. There is nothing to keep a program from locking up in a
loop forever:

while true do;

Will do that. On many modern systems it is possible to terminate such
programs manually.

2. Insecure variants. The following procedures will effectively change a
pointer to an integer and back:

type intptr = ^integer;
convert = record

case boolean of

false: (i: integer);
true: (p: intptr)

{ end }

end;

function int2ptr(i: integer): intptr;

var cr: convert;

begin

cr.i := i; { place integer }
int2ptr := cr.p { return pointer }

end;

function ptr2int(p: intptr): integer;

var cr: convert;

begin

cr.p := p; { place pointer }
ptr2int := cr.i { return integer }

end;

So that you can usually crash your program by:

p := int2ptr(500);
p^ := 6;

(ie, poke an arbitrary location). Note that it assumes that pointers and
integers have the same length. Note that it IS possible for the compiler
to prevent this, see your local documentation.

3. Initalization. There is no garantee that a variable in Pascal is
initalized to a known value:

procedure x;

var p: ^integer;

begin

p^ := 6;

Use of "p" before it is initalized could result in a random area being
written to, and perhaps a program crash.
Note that many compilers provide for initalization of global, local or
dynamic variables, so this insecurity may not exist. Check your local
documentation.

4. Reuse of disposed data. The following code illustrates this:

var p: ^integer;

...

new(p);

...

dispose(p);

p^ := 1;

The variable "p" points to was returned to general storage by dispose.
The assignment statement below that writes the (now invalid) space that
it used to occupy. The system is free to give that space to a completely
different peice of data or even another application running concurrently.
This is a setup for a serious data corruption error.
Some compilers make sure that the pointer "p" would be set to NIL afterwards,
and the value NIL can be checked for as an invalid reference. But even
that can be circumvented. If there is another pointer of the same type
that "p" is copied to, that pointer is not cleared by dispose.
Curing the dispose problem is very difficult. It can be done, but usually
dramatically increases the amount of overhead in the system as the compiler
is forced to track all possible pointers in the program.



Q. IS C MORE EFFICIENT THAN PASCAL ?

There is nothing about the C language that is inherently more efficient
than Pascal, there are simply good compilers and bad compilers. Most
programmers who believe that C is fundamentally more efficent aren't
understanding the foundations of how compilers work. For example, the C
statement:

a;

Would correspond to the Pascal statement:

a := a+1;

While it may look more efficient, because compilers commonly turn "a
"
into a single "increment" instruction on the target machine, Pascal
compilers can recognize that "a:= a+1" is an increment as well, and
give the same single instruction.



Q. WHAT GOOD BOOKS ARE AVAILABLE ON THE STANDARD LANGUAGE ?

A. Many books have been published on Pascal. I will be
happy to collect reviews here.

TITLE:

Pascal user manual and report, third edition. Kathleen Jensen and
Niklaus Wirth, Revised by Andrew Mickel and James Miner.
Published by Springer-Verlag.

COMMENTS:

A definitive reference on standard pascal and a must have book.

TITLE:

Standard Pascal: User reference manual. Doug Cooper.
Published by W. W. Norton and Company.

COMMENTS:

Doug Cooper is a Professor at UC Berkley. If you buy just ONE book
on standard Pascal, this would be it. Contains ALL of the points in the
standard, in the most readable format anywhere.

TTTLE:

Oh! Pascal. Doug Cooper.
Published by W. W. Norton and Company.

COMMENTS:

Another Doug Cooper blockbuster, this is probably the most used classroom
book on Pascal. Recommended if you are learning standard Pascal.

TITLE:

Condensed Pascal. Doug Cooper.
Published by W. W. Norton and Company.

COMMENTS:

This is a combined version of Doug's Oh! Pascal and Standard Pascal books,
with some revisions.



Q. WHERE CAN I FIND BOOKS ON STANDARD PASCAL ?

A. The most common source for new books is:

http://www.amazon.com



Q. I AM WRITING (OR INTERESTED IN) A PASCAL COMPILER, WRITTEN IN PASCAL.
WHERE CAN I FIND GOOD MATERIAL ON THAT ?

A. Probally the best all around book is:

0130830984

Prentice-Hall

ISBN 0-13-083098-4

It is both a good book on compiler construction, and contains a complete
Pascal compiler for the IBM-PC.

A Small, toy language compiler for a Pascal-like compiler is contained in:

0130224189

Prentice-Hall

ISBN 0-13-022418-9

Which has a last chapter on compiler construction. This book is also perhaps
Wirth's best all around "how to" book on programming in general, and all
the examples are in Pascal.

Niklaus Wirth created a complete compiler-interpreter system known as
PASCAL-S, which processes a subset of the full Pascal language. You can
find the source on the ANSI/ISO Pascal web site:

http://www.moorecad/standardpascal

It was originally designed for the CDC computer, but I have changed a few
lines to use file handling on a typical PC based compiler.

You can also find the related P4 compiler project, which is a seperate
compiler/assembler/interpreter for the P4 stack computer language.

Q. Where can I get more information and help with writing Pascal compilers ?

A. The newsgroup comp.compilers discusses this quite frequently. Pascal is
still a very popular language to implement as a class project.

Also, I have 20 years of experience with Pascal compilers, and allways
appreciate the interest.



Q. HOW DO I PERFORM STRING OPERATIONS IN STANDARD PASCAL ?

A. Pascal and C have one feature in common, they include no basic support for
handling of strings of characters. Strings, as implemented in Basic and
other languages, are a "high cost" data element, mainly because a lot
of character copying must occur within the string functions. Most
"professional" (ie., used for paid programming) languages choose to leave
creation of string handling up to the programmer. The reason is that in many
or even most cases, applying primitives to simple arrays of characters can
achieve the same result at less expense.
However, one big difference between C and Pascal is that C allows variable
length string passage, which greatly facilitates creation of general purpose
string handling routines, and manipulation of string constants.
In Pascal, by contrast, you must declare a string as a fixed length array:

var string: packed array [1..50] of char;

Which means that all of your strings must have the same length as the handler
routines expect. Further, for any reasonable size of string, assigning
string constants to strings is prohibitive:

string = 'hello, world ';

And this is a short example ! More commonly, strings must be 100-200
characters in length, so the assignment of string constants is just
impractical.



Q. WHAT ARE "SPACE PADDED" STRINGS ?

A. No matter what the length of string, the first and best trick is to make
extensive use of space padded strings:

var s: packed array [1..10] of char;

...

s := 'hello ';

For example to read a word from the input:

var i: integer;

s := ' ';
i := 1; { set 1st character in string }
while not input^ = ' ' do { read characters }
if i <= 10 then begin { not overflow }

read(s[i]); { get next character }
i := i+1 { next character }

end;

If the user inputs "one more", s would be "one ", or the first word
with blank padding. Note the trick used to find the end of the word. Eoln
is returned as a space, which also happens to be the word delimiter, and
in standard Pascal every line must be terminated by a eoln.
Once all your strings are in space padded form, operations on them are
easy:

var s1, s2: packed array [1..10] of char;

...

s1 = s2; { find if strings are equal }

s1 < s2; { find if s1 is lexograpically smaller than s2 }

s1 := s2; { assign strings }

Note that comparing strings for order depends on the value of the space
character. If space has a smaller ordinal value than all other characters,
then "ab " is going to be less than "abc ". If space has a
larger values than others, the opposite would be true. In ASCII, the space
is the lowest value character, and this indeed gives the lexographical
sort that is most popular (ie., that shorter character sequences go first).
Space padded strings even work for strings with ebedded spaces ! A string
like:

s := 'this is a very long string ';

Would be equal to "this is a very long string" without the trailing blanks.
This works because, reading left to right as we do, any spaces after the
text are unimportant (and typically will not make any difference to
printout). Putting text through processing using blank padded strings
will have the effect of trimming all the trailing blanks off the text,
often a desirable side effect.
To find the length of a blank padded string:

var e: integer;
s: packed array [1..100] of char;

...

e := 100; { set maximum }
{ find end of string }
while (s[e] > 1) and (s[e] = ' ') do e := e-1;

Will set e to be the last character of the string, or to 1 if the string
is empty. A check for a blank string need not be:

s = ' ';

or similar, but simply:

s[1] = ' ';

Because if the first character is empty, the entire string is usually empty
as well.



Q. HOW CAN STANDARD STRINGS TAKE LESS SPACE ?

A. The best way to achieve "tight" code in standard pascal is to use custom
strings for given tasks. For instance, if you are going to input a command
from the user, and use that to look up a string in a table, you can create
a string type based on the maximum length of command string that you are
going to need. Then you can create a few custom handling procedures for
that string type. This works best if you use constant declarations to
declare the length of the string:

const strlen = 100;

type mystring = packed array [1..strlen] of char;

This way, if you must change the string size later, there is less difficulty.
Although these kinds of solutions may create a larger program listing, the
result is usually faster than using a general purpose string library, and
the cost saved by not including the general string library may pay for
any duplication of effort.



Q. WHAT IS THE BEST WAY TO CLEAR A STRING ?

A. Clearing long strings is best done as:

const strlen = 100;

var i: integer;
s: packed array [1..strlen] of char;

...

for i := 1 to strlen do s[i] := ' ';

This code will usually take less space than spelling out a long string of
blanks, take the same amount of CPU time (after all, a string assign uses
a copy loop as well), and most importantly, won't have to be changed if
we change the string lengths in the program.



Q. WHAT IS THE MOST EFFICIENT WAY TO INITALIZE LARGE NUMBERS OF STRINGS ?

If you have to have both long strings and also occasionally set these
strings to a known constant, it helps to create a procedure to initialize
them. You simply find what the longest constant string you are going
to assign to the variable strings, then create a special string type
for that. Finally, you create a custom procedure to do the copy:

const strlen = 250; { our "big" string }
cstlen = 12; { our constant strings }

type string = packed array [1..strlen] of char;
cstring = packed array [1..cstlen] of char;

var s: string;

procedure inistr(var s: string; c: cstring);

begin

for i := 1 to strlen do s[i] := ' '; { clear result }
for i := 1 to cstlen do s[i] := c[i] { place string }

end;

...

inistr(s, 'hello, world';



Q. CAN VARIABLE LENGTH STRINGS BE USED IN STANDARD PASCAL ?

A. Because Pascal does not have built in strings does not prevent you from
implementing them yourself:

type string = record

len: integer;
str: packed array [1..100] of char;

end;

Then you can go ahead and define a full set of procedures to concatenate,
find substrings, etc., within a string.
The principal drawback here is again, initializing strings. But using the
"initialize procedure" method, in combination with the "find end of blank
string" method, it is easy to create a procedure that will do the job:

var s: string;

...

inistr(s, 'mystring ');

Here intstr would find the exact length of the string by blank termination,
then assign that to the string length, and place the string body.



Q. HOW CAN YOU FIND AN ENUMERATED VALUE FROM AN INTEGER ?

A. One of the more irritating things in Pascal is converting an integer to an
enumerated type. Even though there is a one to one correspondence between
integers and enumerateds, and you can find the integer value of any
enumerated value with ord, you cannot go the other way easily. You might
use a case statement or similar kludge.
But there is a trick you can use that takes a bit of space, but incurs very
little speed penalty and is as easy to use sourcewise as the hypothetical
"unord" function would be:

type enum = (one, two, three, four, five, six, seven, eight, nine, ten);

var ei: enum;
etran: array [10] of enum;

begin

{ initalize translation array }
for ei := one to ten do etran[ord(ei)] := ei;

...

ei := etran[5];

Now translating an integer back to the enumerated type is simply a fast array
lookup. The price for this is the size of the translation array, and the fact
that you must declare the translation array with a number that depends on the
size of enum.



Q. WHAT IS THE BEST WAY TO CREATE TABLES OF CONSTANTS ?

A. Standard Pascal has no capability to create tables of fixed data at compile
time. But your compiler may be able to turn assigns into preinitalized data
if it can determine that the assign will ABSOLUTELY happen before anything
else. The best way to do this is to perform all such assigns first:

var table: record

a: integer;
b: integer;
c: char

end;

begin

table.a := 1;
table.b := 45;
table.c := 'x';

...

Typically this should only be done at the program block level. Doing this
gives the compiler the maximum chance to perform this optimization.



Q. HOW CAN DYNAMIC STORAGE "FRAGMENTATION" BE STOPPED OR REDUCED ?

A. You may be able to do a better job of dynamic variable recycling than the
standard "dispose" routine. getting and putting a lot of variable length
blocks tends to create "fragmentation" difficulties. You can illustrate
this problem fairly simply. If you are using two different data types
in dynamic storage, one of 100 bytes length, and the other 200 bytes in
length, and these are created and disposed at random, the standard new
and dispose procedures may be taking back the 200 byte blocks and breaking
them down into 100 byte blocks to satisfy the calls for that size of
variable. The result is that eventually, the call to new for a 200 byte
block may fail, even though plenty of storage still exists, because it is
all broken into 100 byte blocks.
I have found that in many cases, it is better to hold on to unused blocks,
and recycle them yourself:

program mine(input, output);

type blkptr = ^block;
block = record

next: blkptr;
array [1..100] of byte

end;

var freblk; { the free block list }

{ get a new block }

procedure getblk(var p: blkptr); { returns the block }

begin

if freblk <> nil then begin { recycle existing block }

p := freblk; { index the top block }
freblk := freblk^.next { remove from list }

else new(p) { otherwise create a new one }

end;

{ put an unused block }

procedure putblk(p: blkptr); { block to dispose of }

begin

p := freblk; { insert to free list }
freblk := p

end;

begin

freblk := nil; { clear free block list }

...

This system reduces fragmentation, because blocks are reserved for a
particular use, and not broken down into smaller parts. It tends to be
storage efficient, because programs typically do the same sort of work
over and over again. That is, if you needed to get N blocks of X type, this
means that X type blocks will be used a lot in the run of the program
(although obviously there are programs that break that rule).
I add "meters" to count the number of blocks going in and out of the free
list to tell me how the system is performing in real life.



Q. HOW CAN YOU MAKE VARIABLE LENGTH ARRAYS IN STANDARD PASCAL ?

A. If you require variable length arrays in standard Pascal, what do you do ?
For example, if you are going to create a text editor, and want to store
variable length lines, but you don't want to place a limit on the length of
a line. You need a variable length string type to contain each line. The
answer is that you can create variable length arrays yourself ! The secret
is to chain dynamically allocated arrays together to make a larger array:

type

blkptr = ^block;
block = record

next: blkptr;
data: packed array [1..10] of char

end;

var p: blkptr;

{ allocate string in terms of blocks }

procedure alcblk(var p: blkptr; { returns string allocated }
l: integer); { length of string }

var t: blkptr;

begin

p := nil; { clear result list }
while l > 0 do begin { allocate blocks }

new(t); { get new block }
t^.next := p; { link into list }
p := t;
l := l-10 { count that block }

end

end;

{ get character from string }

function getblk(p: blkptr; { string to fetch character from }
i: integer); { index to get character from }
: char; { returns character from index }

begin

while i > 10 do
begin p := p^.next; i := i-10 end; { index proper block }
getblk := p^.data[i] { return resulting character }

end;

{ place string character }

procedure putblk(p: blkptr; { string to put character to }
i: integer; { index to put character to }
c: char); { character to place }

begin

while i > 10 do
begin p := p^.next; i := i-10 end; { index proper block }
p^.data[i] := c { place character }

end;

This technique could be used on any array type. Although it looks pretty
horrible, the system can keep any number of any length of string, such as
an advanced editor would do, and the fact that all strings are broken down
into fixed length "quanta" keeps storage fragmentation to a minimum, or even
eliminates it entirely (and important attribute for an editor). The
processing cost of the system can be lessened by pulling the variable length
data to/from a large buffer, and working on it there. But of course, this
would limit the length of data you can work on.



Q. HOW CAN YOU PERFORM BOOLEAN OPERATIONS ON INTEGERS ?

A. If you have to perform booleans on a standard compiler that does not have
boolean bitwise operators on integers, you can create them.
First, if you know that the same bits are not set in two words, then you can
just add them to get "or" functionality:

i := i+64; { set bit 7 }

You can also mask off bits in an integer using "div" and "mod":

i := i mod 256; { is equivalent to i and $ff }
i := i div 256*256; { is equivalent to i and not $ff }

For generalized boolean operations you can use:

function bor(a, b: integer);

var i, r, p: integer;

begin

r := 0; { clear result }
p := 1; { set 1st power }
for i := 1 to maxbit do

r := r*2; { move bits up }
if ord(odd(a) or odd(b) then r := r+p; { add in power }
p := p*2 { find next power }

end;
bor := r { return result }

end;

function band(a, b: integer);

var i, r, p: integer;

begin

r := 0; { clear result }
p := 1; { set 1st power }
for i := 1 to maxbit do

r := r*2; { move bits up }
if ord(odd(a) and odd(b) then r := r+p; { add in power }
p := p*2 { find next power }

end;
bor := r { return result }

end;

function bxor(a, b: integer);

var i, r, p: integer;

begin

r := 0; { clear result }
p := 1; { set 1st power }
for i := 1 to maxbit do

r := r*2; { move bits up }
if ord(odd(a) <> odd(b) then r := r+p; { add in power }
p := p*2 { find next power }

end;
bor := r { return result }

end;

These assume a 32 bit integer, but can be set to any integer length. Note
that the sign bit is specifically left out of the operation.
You can find the value of maxbit (the number of bits in an integer) as:

var i, x: integer;

...

x := maxint;
i := 0;
while x <> 0 do begin x := x div 2; i := i+1 end;

This won't count the sign bit, which is correct for the above routines. This
should be done only once, when the program starts up.



Q. HOW TO READ AND WRITE INTEGERS TO A BYTE FILE ?

A. Often you must deal with files that randomly mix different types of data
that are not ameniable to declaration as a file of records.
If you read and write large integers using only standard constructs (and not
"type changing" using variant records), you may find it easier to use a
format known as "signed magnitude" than to try to write the number using
the 2's complement format used by the CPU. In signed magnitude, the sign
bit is determined and written out separately from the value of the integer:

{ write integer to byte file }

procedure wrtint(var f: bytfil; { file to write to }
i: integer); { integer to write }

var s: byte; { sign holder }

begin

{ remove sign and save }
if i < 0 then s := 128 else s := 0;
i := abs(i); { remove sign }
write(f, i div 16777216+s); { output high byte with sign }
write(f, i div 65536 mod 256); { output high middle }
write(f, i div 256 mod 256); { output low middle }
write(f, i mod 256) { output low byte }

end;

{ read integer from byte file }

procedure rdint(var f: bytfil; { file to read from }
var i: integer); { integer to read }

var s: boolean; { sign holder }
b: byte;

begin

s := false; { set no sign }
read(f, b); { get high byte }
if b >= 128 then begin s := true; b := b-128 end;
i := b*16777216;
read(f, b); { get high middle }
i := i+b*65536;
read(f, b); { get low middle }
i := i+b*256;
read(f, b); { get low byte }
i := i+b;
if s then i := -i { add back sign }

end;

For 32 bit integers written in "big endian" format (high order bytes first).
Note that the sign is written and read as bit 32, the same place as the
normal sign. Note that the only value you lose this way is $80000000, which
is an invalid value under standard Pascal anyways.



Q. HOW TO GET RANDOM NUMBERS ?

Since random numbers where not in the Pascal standard, a routine to generate
them is a common request. This is the classical routine:

var rndseq: integer; { global variable }

function rand: real;

const a = 16807;
m = 2147483647;

var gamma: integer;

begin

gamma := a*(rndseq mod (m div a))-(m mod a)*(rndseq div (m div a));
if gamma > 0 then rndseq := gamma else rndseq := gamma+m;
rand := rndseq*(1.0/m)

end;

In the main program, rndseq gets initalized to 314159. The result of each
call to rand is a random number in the range 0 < N <= 1 (random number
generators cannot give 0 as a number, since that terminates the algorithim).
This program is a recoding of the routine by N. Wirth (Sans authorization)
from the book "programming in Oberon", and uses the multiplicative linear
congruential algorithim. The big trick with this method, which as you can
see is pretty simple, is choosing the right magic numbers, and Wirth says:
"there will be over 2 billion random numbers that passed stringent
statistical tests".



Q. HOW CAN YOU PERFORM GRAPHICS OPERATIONS ?

A. If you have a command line Pascal compiler only, with NO graphical
operations whatever, can you perform graphical operations ?

Yes ! The following short program reads, processes and writes a Windows .bmp
file (black and white only):

{

BMP file processor, reduces the number of colors

}

program reduce(source, dest, output, command);

type byte = 0..255;

type bmphead = record { bitmap header }

fsize: integer; { size of file }
off: integer; { offset of header }
size: integer; { size of header }
width: integer; { image width in pixels }
height: integer; { image height in pixels }
planes: integer; { image planes }
bitcnt: integer; { bit per pixel }
comprs: integer; { compression type }
sizimg: integer; { size in bytes of image }
xpelsm: integer; { horizontal resolution }
ypelsm: integer; { vertical resolution }
clrusd: integer; { number of colors used }
clrimp: integer; { number of colors important }

end;

var source: file of byte;
dest: file of byte;
bh: bmphead;
store: array [1..2000, 1..2000] of byte; { picture storage }
reduce: integer;
x, y: integer;


procedure getint(var i: integer);

var b: byte;

begin

read(source, b);
i := b;
read(source, b);
i := i+b*256;
read(source, b);
i := i+b*65536;
read(source, b);
i := i+b*16777216

end;

procedure getwrd(var i: integer);

var b: byte;

begin

read(source, b);
i := b;
read(source, b);
i := i+b*256

end;

procedure wrtint(i: integer);

begin

write(dest, i and $ff);
write(dest, i div 256 and $ff);
write(dest, i div 65536 and $ff);
write(dest, i div 16777216)

end;

procedure wrtwrd(i: integer);

begin

write(dest, i and $ff);
write(dest, i div 256 and $ff)

end;

{ load picture }

procedure loadpic;

var r: integer;
b: byte;
x, y, i: integer;
red: byte; { colors }
green: byte;
blue: byte;
reserved: byte;

begin

read(source, b);
if b <> ord('B') then begin writeln('* bad signature'); halt end;
read(source, b);
if b <> ord('M') then begin writeln('
* bad signature'); halt end;
writeln;
getint(bh.fsize);
getwrd(r);
getwrd(r);
getint(bh.off);
getint(bh.size);
getint(bh.width);
getint(bh.height);
getwrd(bh.planes);
getwrd(bh.bitcnt);
getint(bh.comprs);
getint(bh.sizimg);
getint(bh.xpelsm);
getint(bh.ypelsm);
getint(bh.clrusd);
getint(bh.clrimp);
if bh.comprs <> 0 then begin writeln('* Cannot process compressed'); halt end;
if bh.clrusd <> 256 then begin writeln('
* Must be 256 colors'); halt end;
if bh.width > 640 then begin writeln('* Picture too wide'); halt end;
if bh.height > 480 then begin writeln('
* Picture too high'); halt end;
if bh.planes <> 1 then begin writeln('* Must be 1 plane'); halt end;
if bh.bitcnt <> 8 then begin writeln('
* Must be 8 bits per pixel'); halt end;
for i := 0 to bh.clrusd-1 do begin { list color map }

read(source, blue);
read(source, green);
read(source, red);
read(source, reserved);
if (blue <> i) or (red <> i) or (green <> i) then
begin writeln('* Bad color map'); halt end

end;
writeln('Loading ', bh.width:1, ' by ', bh.height:1);
{ read in picture }
for y := 1 to bh.height do begin { read rows }

for x := 1 to bh.width do { read pixels }
read(source, store[y, x]); { read that in }
{ read and discard row padding }
for i := 1 to 4-bh.width mod 4 do read(source, b)

end;
writeln('Picture loaded')

end;

{ write picture }

procedure strpic;

var x, y, i: integer;

begin

writeln('Writing picture');
write(dest, ord('B'));
write(dest, ord('M'));
wrtint(bh.fsize);
wrtwrd(0);
wrtwrd(0);
wrtint(bh.off);
wrtint(bh.size);
wrtint(bh.width);
wrtint(bh.height);
wrtwrd(bh.planes);
wrtwrd(bh.bitcnt);
wrtint(bh.comprs);
wrtint(bh.sizimg);
wrtint(bh.xpelsm);
wrtint(bh.ypelsm);
wrtint(bh.clrusd);
wrtint(bh.clrimp);
{ write color map }
for i := 0 to 255 do begin

write(dest, i);
write(dest, i);
write(dest, i);
write(dest, 0)

end;
{ write bitmap }
for y := 1 to bh.height do begin

for x := 1 to bh.width do { write pixels }
write(dest, store[y, x]);
{ write row padding }
for i := 1 to 4-bh.width mod 4 do write(dest, 0)

end;
writeln('Picture written')

end;

begin

reset(source);
rewrite(dest);
read(command, reduce);
loadpic;
for y := 1 to bh.height do
for x := 1 to bh.width do { read pixels }
store[y, x] := store[y, x] div reduce*reduce;
strpic;
writeln('Function complete')

end.

The program processes a picture as an input and an output file.
Using any simple graphics display program, including Windows "paint",
you can then look at the result of the operation.



Q. DOES STANDARD PASCAL HAVE A "TYPE CONVERTER" ?

A. No, but it is possible on most compilers anyway:

type intptr = ^integer;
convert = record

case boolean of

false: (i: integer);
true: (p: intptr)

{ end }

end;

function int2ptr(i: integer): intptr;

var cr: convert;

begin

cr.i := i; { place integer }
int2ptr := cr.p { return pointer }

end;

function ptr2int(p: intptr): integer;

var cr: convert;

begin

cr.p := p; { place pointer }
ptr2int := cr.i { return integer }

end;

Converts integers to pointers and vice versa. The effect of placing a value
in an untagged variant are not defined in the standard, which means you
must know what you are doing, and the resulting code is probally not
portable.
So Pascal HAS a defacto type convertion method, but it is far more painfull
to use than, say, C. In this authors' humble opinion, its a good thing that
it is painfull. Its bad coding practice, and should be avoided.



Q. HOW DO I READ/WRITE ARBITRARY DATA TYPES FROM/TO A BYTE FILE ?

A. Step back for a second. If you need to put a lot of different data types
in a file and want to do that to a byte file, you are probally applying
thinking used in other languages to Pascal. There is nothing to prevent
you from doing that entirely within standard Pascal:

type r1 = record

x: integer;
y: char

end;

r2 = record

q: real;
z: integer

end;

outtype = (rtr1, rtr2);

r3 = record

case outtype of

rtr1: (r1d: r1);
rtr2: (r2d: r2)

{ end }

end;

outfile = file of r3;

Now "outfile" can be used to output any of these record types. You are
letting Pascal format the data for you, but the result is the same.
If you REALLY want to write all data a byte at a time, use type convertion
(above), and output the bytes. For example, to output a real value (floating
point:

type bytefile = file of 0..255;

procedure writereal(var f: bytefile; r: real);

var rc: record

case boolean of

false: (r: real);
true: (ra: array [1..8] of 0..255)

{ end }

end;
i: 1..8;

begin

rc.r := r; { place real in converter }
for i := 1 to 8 do write(f, rc.ra[i])

end;

Note that this relies on reals being 8 bytes long, and that the machine is
byte addressable. The exact format written will be system dependent.

To read and write data files, and keep maximum portability for your programs,
you should look to do these types of I/O, in order of desirability:

1. Use standard Pascal record structured I/O.

2. Use standard methods of convertion to get byte values, then read or write
those values (see "how to read and write integers to a byte file",
"how to find an enumerated value from an integer" above).

3. Use type convertion.



Q. HOW TO AVOID THE "FULL EVALUATION" PROBLEM ?

A. The full evaluation problem goes like this:

if (p <> nil) and (p^.stuff = 1) then ....

This is technically wrong, because all parts of an expression may be
evaluated, so if pointer p is nil, the access p^.stuff will fail even though
we apparently check for that.
Although the evaluation problem is often quoted as a major failing of Pascal,
it is really a non-issue in practical use. A simple rewrite of the condition
cures it:

if p <> nil then if p^.stuff = 1 then ...

A more interesting problem is "skip blanks" in an array:

while (i <= maxlen) and (a[i] = ' ') then i := i+1;

Will fail because if i > maxlen (the length of the array), the access a[i]
may still take place, and a fault results.
Here is the reformulation:

t := a[i]; { get next character }
while (i <= maxlen) and (t = ' ') then begin

i := i+1;
if i < maxlen then t := a[i] else t := '*'

end;

A less complex formulation is to simply not use the last location of the
array for data, ie., use the last location as a "sentinel":

while (i < maxlen) and (a[i] = ' ') then i := i+1;

Will be fine as long as no data is placed in the last element.

Read further on http://www.moorecad.com/standardpascal/ansiiso.faq

There are no comments on this page. [Add comment]

Page History :: 2004-06-03 16:27:16 XML :: Owner: Roland Stens :: Search:
Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by Wikka Wakka Wiki 1.1.6.0
Page was generated in 0.0676 seconds