Standard Pascal FAQ

Welcome to the FAQ ! I will answer here various questions about ISO 7185
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.

This FAQ covers in main the ISO 7185 Pascal language. We don't cover the
ISO 10206 or extended standard, and we don't cover specific implementations
or alternate dialects of Pascal except to discuss the differences between some
popular dialects and the Pascal standard. We cover differences with several
dialects of Pascal, such as P-machine, UCSD and Apple, mainly for their historical
significance, since these dialects are no longer have supported installations.
We cover the differences between ISO 7185 Pascal and Borland Delphi because
this is a widely used dialect of Pascal.

If you are interested in the Borland Delphi language, please be
aware that this is a different language. You will be able to find several sites
specific to that language.

Finally, this site and the author of this FAQ is certainly biased. My bias
is towards the original implementation and idea of Pascal. I'll make it clear.
Implementations that implemented the language and then extended it, great!
Implementations that changed Pascal to some other language and then called it
"Pascal", not so great with me. That's my bias here.
I am a Pascal (original, standard, Jensen and Wirth) avocate.

A.

A.

Pascal is one of a series of languages put forth by one of the most prolific
computer language creators, Niklaus 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 68, 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. That was detailed by "The Pascal User
Manual and Report" [Jensen and Wirth].

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 addition, several
countries around the world issued their own national standard for Pascal.

A.

Pascal is in the Algol family of languages. Algol, whose first version was
called IAL or "International Algebraic 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 algorithms, 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
algorithms, 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 dimensions. 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 description of the language syntax, a first for
any computer language.

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 extensions 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 mathematician Leonhard Euler),
on which an ACM paper was based.

After Algol 60, the committee began work on a successor 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 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.

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 unsuccessful, 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:

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 Pascal 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.

A.

The original Pascal standard was an unofficial standard documented by the
author, Niklaus Wirth, in "The Report". The first official standard
was ISO 7185 issued in 1983. This was followed by the extended standard, ISO
10206, in 1990.
Another standard was the Object-Oriented Extension to Pascal. However, this
standard was never finished, and was basically abandoned for lack of interest.

A.

A.

There have been many implementations of Pascal, both those that follow and
those that don't follow the ISO 7185 standard. For the most part, ISO 7185 was
followed on large computer installations during the early days of Pascal (1973-1990),
and some installations on microcomputers. The other dialect that became popular
was the UCSD (University of California at San Diego) Pascal, followed by Borland's
Turbo Pascal. Although there are virtually no current implementations of UCSD
Pascal, Borland's products exist today for advanced IBM-PC compatibles under
Borland's Delphi name.

When the IBM-PC became 32 bit with the introduction of the Intel 80386, virtually
all of the 32 bit implementations of Pascal on the PC were ISO 7185 conforming.
However, there was a large shakeout of compiler vendors in the early 1990's
that removed many of these installations from the market.

Today, the basic choice is between Borland's Delphi dialect, which is also
covered by the popular FreePascal open source compiler, and the ISO 7185 Pascal
language, which is offered by several vendors and by the open source GPC (GNU
Pascal) compiler. It is not true that these dialects are mutually exclusive.
GPC offers both the ISO 7185 language and much of the Delphi language at the
same time.

For more on the exact differences between Delphi and ISO 7185 Pascal, please
see "Q. What are the differences between Delphi and ISO 7185 Pascal?".

A.

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
extensions 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.

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.

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 efficiency.

A.

Recently, I have had some folks email me that they are surprised I am supporting
advanced extentions for Pascal.

Pascal always had extentions. The original compiler created by Niklaus Wirth
had extentions specific to the CDC 6000 series computers. The idea of the standard
was never to forbid extentions, but rather that the basic implementation be
as standardized across processors and implementations as possible.

In the old days of the mainframe and line printers, there was actually a
chance that a program completely coded within the language standard would be
all that was needed. Now, with advanced graphics and sound, and advanced devices
like video editing, the general portable program is thought by many to be dead.
I would say that nothing is further from the truth. We need clean and portable
interfaces and programs more than ever. What has changed is that we rely more
on library construction and interfaces. Windows, OS X and Linux/X Windows can
be thought of as advanced intefaces with somewhat limited portability. Advanced
graphics libraries such OpenGL are paving the way to new levels of functionality
and portabilty.

Now, more than ever, the choice is clear. You can always be thinking about
portability, which is just another way of saying you are thinking about how
to address general problems with general solutions, and see your programs have
staying power. Alternately, you can design for this weeks vogue interface and
see your program sink with along with that interface.

I personally love well designed standards and interfaces. To me they are
the planks in a well designed and built whole. So yes, I believe in extentions.
I believe Pascal can be brought forward and has something to say for decades
to come.

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.

A.

This assertion has often been used to imply that Pascal is a toy language.
I can't state the answer any better than Niklaus Wirth himself did:

"Occasionally, it has been claimed that Pascal was designed as a language
for teaching. Although this is correct, its use in teaching was not the only
goal. In fact, I do not believe in using tools and formalisms in teaching that
are inadequate for any practical task." - Niklaus Wirth, from the 1984
ACM A.M. Turing award lecture.

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. 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.

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.

Change

Backward compatible?

1. Procedure and function parameters

No

2. Var parameters on procedure and function parameters

Yes

3. Standard procedures and functions as parameters

No

4. Exact definition of type compatibility

Yes

5. Removal of symbol length limit

Yes

6. Goto target restrictions

No

7. "for" control variables must be local

No

The "backward compatible" collumn means that this change would
not cause J&W compliant programs to break if they used the given feature.

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.

3. 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.

4. 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.

Note I have marked this as a backward compatible change because the original
J&W left the matter of type compatibility up to the installation, and the
ISO 7185 qualify as such a definition of type compatibility.

5. 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.

6. 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.

7. 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).

There are many more aspects to the ISO 7185 standard than we cover here.
However, these are all specific details of the ISO Pascal language that would
have qualified as "implementation specific" details under the rules
of original Pascal.

A.

The reason we discuss the P-machine variant of Pascal here is because it
was used to form several other implementations, such as UCSD and Apple Pascal.
In addition, UCSD Pascal was a major influence on the Borland dialects.

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:

A.

First, please be warned, the contents of this section comes from my reading
of the UCSD Pascal manuals, and not from running programs on the system. Note
that early versions of the system had more restrictions than the later ones.
What is documented here was the latest known version, which represents UCSD
Pascal in 1982. It comes from "The UCSD Pascal Handbook" [Randy Clark
and Stephen Koehler]. I'll be trying to get a running version of UCSD to test
with in the future.

UCSD Pascal was derived from the same code as the P-machine, so you will
notice similarities. The UCSD implementors added some of the standard features
back in, and also removed some.

A.

A.

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

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

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 Delphi.

4. No "sized" dynamic variable allocation. Given a variant record,
the size of a particular variant cannot be specified as per the standard. I.e.,
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 Delphi (Delphi uses the scheme of allowing
the different comment types to indicate nested comments).

7. 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 Delphi
gives the character code for carriage return (13), followed by line feed (10).

8. 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 Delphi, but:

: 5:

(spaces depend on compiler integer
width) in ISO 7185.

For booleans:

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

outputs:

:true:

in Delphi, but:

: true:

In ISO 7185.

9. Temporary files are not supported. Applying reset() or rewrite() to a
file results in an error under Delphi. Under standard Pascal it opens a temporary
file that exists only for the run of the program.

Note: The following shell command line was used to test for the above behavior.

> dcc32 -CC test.pas

The option "-CC" tells the Delphi compiler to assume that the application
is a shell application, and the resulting test.exe was run in a shell.

I have collected the above points into a program that demonstrates each:

Most of the points simply won't compile, but the other ones that will, but
do the incorrect thing will print out to that effect. The program run on an
ISO 7185 compilant system appears as:

This should print

The value of eoln is: 32

Should be same as space (32)

1

true

false

Should be similar to:

1

true

false

(ie., justified right in field)

I get the occasional email telling me that Delphi is capable of performing
all these operations. Please note once again, we are not comparing features
here, but compliance with the original language Pascal. Pascal didn't and does
not restrict what extensions or local methods exist on a particular implementation,
just what minimum set of standard features must exist to compile programs that
are in the Pascal language.

A.

No. The standard story which you can find on Wikipedia and several other
web sites goes like this. Borland introduced Turbo Pascal before the ISO 7185
standard was produced, and followed the UCSD dialect of Pascal that existed
before the standard.

The original Pascal language definition appeared in 1970, and Pascal was
revised by its author into its final form in 1972. In 1983, the ISO 7185 standard
appeared. Also in 1983-1984, Borlands first compiler for Turbo Pascal appeared.

The problem with this "theory" is Turbo Pascal implemented neither
the ISO 7185 1983 standard nor the 1972 version. Also, the draft standard that
became ISO 7185 was printed in public several times during its development,
in the Pascal Users Group newsletters in 1979 (#15, page 5, you can find it
on this site). UCSD also
followed neither the 1983 nor 1972 standards, but at least had the excuse that
it came well before the ISO 7185 standard. Further, the limitations of UCSD
were, for the most part, due to the limitations of the P-series compiler kit
it was based on. In any case, UCSD implemented more of full Pascal than Turbo
did, so it is hard to say that Turbo was simply following UCSD.

All of the facts above can be verified by the original documents appearing
on this web site. We invite you to look for yourself, and please remember that
there is no consequence for placing incorrect statements on web sites such as
Wikipedia.

When Turbo Pascal first came out, the users' manual had the following text
(taken from Turbo Pascal Version 2.0 Reference Manual):

Actually, there
are five other points on which TP differs from orginal Pascal that were not
mentioned in the manual, see the section
Q. What are the differences
between Borland Delphi and the ISO 7185 standard, points 3, 6, 7, 8, and
9. Further, at the time TP
was published in 1983, it also lacked variant records, not mentioned in the
above manual. In any case, TP differed from Pascal substantially (despite the
"minor differences" comment above), and Borland was well aware of
what the original standard was.

A.

No, it is not possible for several reasons. First, there are several differences
between the languages that are purely syntactic in nature, such as the way comments
work. Second, there is no way to write, for example, file handling functions
that accept all types of files. Third, there are features such as interprocedure
gotos that only the compiler can implement.

I have seen many claims in the past that it is "easy to bridge the differences
between ISO Pascal and the Delphi language", but it is usually apparent
that those making the claim haven't read the ISO 7185 standard in any detail.
It simply isn't that easy.

A.

Sure. 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 and Delphi.

2. Do not use intraprocedural gotos (gotos that leave the current procedure
or function). If you need a deep nested bailout to a higher level procedure,
try setting an error variable and checking that after each procedure/function
call that might have an error, then skipping either out of the routine, or to
the goto point.

3. Do not use file buffer handling (such as f^ accesses, where f is a file), nor the built in routines "get"
and "put". Basically, this just means you cannot use the lookahead
buffering that ISO 7185 Pascal provides.

4. Do not size your variant records with "new". Delphi knows about
variant records, but not how to size them (at least not the standard way). This
will have no functional effect on your program, it will just take more runtime
space.

5. Always use the keyword "packed" on a string that is intended
to be printed with "writeln". Delphi does not require this, but ISO
7185 does.

6. Always 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). Delphi simply ignores these
header parameters, so they don't hurt.

7. Always use format specifications to set the width that will be output
for integers. This will remove differences from varying default fields.

8. Don't use external files other than input and output, since Delphi
does nothing with header
files.

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 delphi does not. There are many other
such restrictions of ISO 7185 that are relaxed in Delphi, not to mention the
many Delphi extensions that you need to refrain from using (of course, all Pascal
compilers have extensions, so that would apply to them as well). Also remember:
Pascal originally had no "string" type. This might seem strange, but
C (for example) does not have one either. Instead, you use an array of characters
(which is not the same thing!). See other sections of this FAQ.

The old bit of cross compiler checking that applies here is to run a check
compile on all of the different compilers you plan to be compatible with frequently.
This will tell you about problems with different compilers before they get out
of hand.

For this author's point of view, I lived with mutiple Pascal compilers for
years, and made it work by isolating system specific code to modules that implemented
that on a particular platform. For example, I had a set of routines in
a module I called "basicio.pas" that contained things like opentext(f,
filename), closetext(f) and similar functions. Then, this module is simply recoded
or swapped out to move to a different compiler.

A.

Yes. GNU GPC is such a compiler. It will take switches that configure it
for either ISO 7185 use or Borland use. Note that several of the differences
between the languages are compatible between the languages without the need
for an option. Here is a list of ISO 7185 to Delphi differences, and whether
they require a configuration optiion, and why. See the section "Q. What are the differences between Borland Delphi and the ISO 7185 standard?",
for details on each difference.

1. Procedure and function parameters.

Requires a configuration option: No

Reason: In delphi mode, the keyword procedure or function in
a procedure or function header is an error. In ISO 7185 Pascal, it introduces
a procedure or function parameter. This makes it essentially an extention to
Delphi.

2. Interprocedural gotos.

Requires a configuration option: No

Reason: Such gotos cause an error in Delphi, so it behaves as simple extention.

3. File buffer access, "get" and "put" procedures.

Requires a configuration option: No

Reason: There are no get or put procedures in Delphi, and access to a file
variable is illegal, so both of these act as simple extentions.

4. Sized variant record allocation.

Requires a configuration option: No

Reason: Allocating a variant record with new with Delphi is illegal, so it
behaves as a simple extention.

5. "pack" and "unpack" functions.

Requires a configuration option: No

Reason: There are no pack or unpack procedures in Delphi, so it behaves as
a simple extention.

6. { and (*, } and *) are not synonyms.

Requires a configuration option: Yes

Reason: There is no way to have a single behavior that covers both the ISO
7185 and Delphi definition of how comments work.

7. End of line returns ASCII codes.

Requires a configuration option: Yes (or a different runtime library)

Reason: There is no way to satisfy both program standards. An eoln is either
a space or the underlying ASCII characters.

8. Default field widths.

Requires a configuration option: Yes (or a different runtime library)

Reason: The basic behavior of the compiler must be changed.

So of the 9 basic differences between the standards, 3 of them are mutually
incompatible between the two languages, and require options to change the basic
workings of the compiler. The 6 remaining differences that are simply additions
to the Delphi language can also be thought of as "freebies" that can
be added to any Delphi compatible compiler in order to enable it to be closer
to the ISO 7185 standard without compromising its Delphi processing in any way.

A.

If your compiler is ISO 7185 compliant, 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 probably 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:

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.

We have done a full evaluation of several ISO 7185 compilers for you, which
can be found at:

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 conversions 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 extension to Pascal compilers to allow this, but of course
those implementations may not be standard.

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. Professor Bowles, at the time, said he didn't
believe that the microprocessors of the time had enough power to directly run
compiled Pascal programs. What Professor Bowles did is to use the P2 compiler
as a front end, then write an interpreter for the intermediate code directly
in machine code on the target machine, then run the P2 compiler on that. This
was not a unique step, and in fact this was one course of action suggested by
the "Pascal P compiler implementation notes" published in December
of 1974.

What made the UCSD implementation unique is that Professor Bowles created
a complete operating system that remained interpreted, and used the fact that
the code was interpreted to increase the portability of the system, across multiple
machines and processors. This work served as the inspiration for the later Java
language.

UCSD was not strictly compatible with Wirths Pascal. Some of the incompatabilities
came from the Wirths P-machine implementation, which didn't, and was not designed
to implement the whole language. However, the UCSD implementation did put back
several standard Pascal features like typed file I/O (as indeed was the intent
of the P compiler bootstrap method).

UCSD Pascal is said to be a direct ancestor to Apple Pascal, and Borland
Pascal implements many of the original functions of UCSD Pascal, perhaps making it also
a defacto derivative of UCSD Pascal (note that Borland Pascal did not come from
the P-machine implementation, but was written in machine code).

There was a IBM-PC/DOS version of the UCSD p-system, and this can still be
run via the Windows operating system (I tried it with WIndows XP) for people
interested in running the system. In addition, the full source code for the
entire system has been released in both the UCSD USUS Software library:

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.

There has been a fair amount of confusion concerning the fact that the P-machine
implementation didn't implement the entire language Pascal. This sometimes leads
to the claim that, since this compiler was sanctioned by Wirth himself, that
it represents a valid alternate version of the Pascal language. The P-machine
was a bootstrap kit designed to make porting a Pascal compiler faster. It didn't
implement the entire Pascal language, because it didn't need it for its own
use. For example, it was restricted to text only input and output because the
Pascal source, and even the intermediate code in an assembly like format, was
all in text. The P-machine was designed to bootstrap itself as a compiler, that's
all. It was never designed to define a subset 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. Initialization. There is no guarantee that a variable in Pascal is initialized
to a known value:

procedure x;

var p: ^integer;

begin

p^ := 6;

...

Use of "p" before it is initialized could result in a random area
being written to, and perhaps a program crash. Note that many compilers provide
for initialization 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 piece
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.

A.

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 efficient 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.

A.

Many books have been published on ISO 7185 Pascal. I will be happy to collect reviews
here. I have also included some books that discuss Pascal in J&W "report"
form. See the "differences" section above. In practice there is virtually
no difference.

There are really countless books available on the standard language. However,
it is difficult to tell from the descriptions if a particular book does or does
not deal with general Pascal, or with a specific implementation of Pascal. You
cannot always tell by the title. All of the below titles are titles I own, and
verify that they are either standard Pascal or language neutral, meaning that
they cover different implementations, but are not directed at a specific implementation.

A great book, it discusses graphics implementation in a compiler independent
way. It does this by describing, in detail, the base graphics calls used to
costruct the routines in the book. Most books of this kind are pinned to a particular
implementation. The last time I checked, it could be had new for $0.26 (26 cents),
a very underappreciated book.

A very unusual book, it covers schemes to implement concurrent programming
algorithims using Pascal, and introduces a modified Pascal-S implementation
that simulates multiple CPUs and threads. There is a new, expanded second edition
of this book for a breathtaking price, but I suspect it is possible that Pascal
as an implementation language might have been purged from the book, and I don't
have the $70 to gamble with. In the meantime, the first edition is Pascal based,
interesting, and has a nifty cover drawing to boot.

It's the ANSI standard, reprinted with annotations, sidebars that explain
what each part of the standard means in english and not standardise (that strange
language that people learn when going to standards meanings). The bad news is
that ANSI basically took their standard out back and shot it in the head. The
good news is that it was 99% identical to the ISO 7185 standard, so this book
is still useful. In any case, it incorporates the entire original ANSI standard
and don't feel like shelling out the $0.32 (32 cents) used copies of the original
ANSI standard are going for on Amazon.

A good textbook on programming in general, with examples in Pascal, written
by the author of Pascal 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.

A.

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.

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 lexographically 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 embedded 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.

Here is a series of routines, and a test for them, that perform common string
operations.

program test(output);

label 99; { terminate program }

const strmax = 20;

type string = packed array [1..strmax] of char;

var a, b, c: string;

function len(var s: string): integer;

var i: integer;

begin

i := strmax; { index the end of the string }

{ back up over any spaces }

while (s[i] = ' ') and (i > 1) do i := i-1;

{ adjust for zero }

if s[i] = ' ' then i := 0;

len := i { return length }

end;

procedure clear(var s: string);

var i: integer;

begin

for i := 1 to strmax do s[i] := ' '

end;

procedure insert(var a, b: string; p: integer);

var la, lb, i: integer;

begin

la := len(a); { find lengths }

lb := len(b);

if la+lb > strmax then begin

writeln('*** String too long');

goto 99

end;

for i := la+lb downto p+lb do a[i] := a[i-lb]; { copy remainder up }

for i := 1 to lb do a[i+p-1] := b[i] { copy new section in }

end;

procedure extract(var a, b: string; p, l: integer);

var i: integer;

begin

clear(a);

for i := 1 to l do a[i] := b[p+i-1]

end;

procedure cat(var a, b: string);

begin

insert(a, b, len(a)+1)

end;

procedure right(var a, b: string; l: integer);

begin

if l > len(b) then begin

writeln('*** Not enough characters');

goto 99

end;

extract(a, b, len(b)-l, l) { find net right characters }

end;

procedure left(var a, b: string; l: integer);

begin

if l > len(b) then begin

writeln('*** Not enough characters');

goto 99

end;

extract(a, b, 1, l) { find net left characters }

end;

function int(var s: string): integer;

var v, i, sgn: integer;

function next: char;

begin

if i <= strmax then next := s[i] else next := ' '

end;

begin

v := 0; { set default value }

sgn := 1; { set sign positive }

i := 1; { set 1st character }

while (next = ' ') and (i <= strmax) do i := i+1;

if next = '+' then i := i+1

else if next = '-' then begin i := i+1; sgn := -1 end;

if not (next in ['0'..'9']) then begin

writeln('*** Number not found');

goto 99

end;

while next in ['0'..'9'] do begin

v := v*10+ord(next)-ord('0');

i := i+1

end;

int := v*sgn

end;

begin

a := 'hi there ';

b := ' george ';

clear(c);

writeln('length a: ', len(a));

writeln('length b: ', len(b));

writeln('length c: ', len(c));

c := a;

cat(c, b);

writeln('cat: ', c);

b := ' boy ';

insert(c, b, 9);

writeln('insert: ', c);

extract(a, c, 4, 9);

writeln('extract: ', a);

left(a, c, 2);

writeln('left: ', a);

right(a, c, 3);

writeln('right: ', a);

a := ' -50 ';

writeln('int: ', int(a));

99: { terminate }

end.

Which resulted in the run:

length a: 8

length b: 7

length c: 0

cat: hi there george

insert: hi there boy george

extract: there boy

left: hi

right: org

int: -50

Of course, you can set strmax to any convient value. If you have used the
Basic function mid$(), you will find this equivalent to extract().

If you needed several different lengths of strings, you would have to create
a set of the above routines for each length, say "cat40()" for 40
character strings. A better way is if your Pascal installation allows variable
length string parameters, such as ISO 7185 level 1 conformant parameters. This
allows you to define the above set of routines so they can operate on any length
of padded strings.

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.

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.

A.

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:

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.

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:

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.

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.

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.

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.

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:

program test(output);

function bor(a, b: integer): integer;

var i, r, p: integer;

begin

r := 0; { clear result }

p := 1; { set 1st power }

i := maxint; { set maximium positive number }

while i <> 0 do begin

if odd(a) or odd(b) then r := r+p; { add in power }

a := a div 2; { set next bits of operands }

b := b div 2;

i := i div 2; { count bits }

if i > 0 then p := p*2; { find next power }

end;

bor := r { return result }

end;

function band(a, b: integer): integer;

var i, r, p: integer;

begin

r := 0; { clear result }

p := 1; { set 1st power }

i := maxint; { set maximium positive number }

while i <> 0 do begin

if odd(a) and odd(b) then r := r+p; { add in power }

a := a div 2; { set next bits of operands }

b := b div 2;

i := i div 2; { count bits }

if i > 0 then p := p*2; { find next power }

end;

band := r { return result }

end;

function bxor(a, b: integer): integer;

var i, r, p: integer;

begin

r := 0; { clear result }

p := 1; { set 1st power }

i := maxint; { set maximium positive number }

while i <> 0 do begin

if odd(a) <> odd(b) then r := r+p; { add in power }

a := a div 2; { set next bits of operands }

b := b div 2;

i := i div 2; { count bits }

if i > 0 then p := p*2; { find next power }

end;

bxor := r { return result }

end;

begin

writeln('or: ', bor(67, 43));

writeln('and: ', band(42, 83));

writeln('xor: ', bxor(62, 12))

end.

With the result:

or: 107

and: 2

xor: 50

The routines only work on positive integers, but and, or, and xor on negative
integers is kinda questionable in any case (what does it mean?).

A.

Often you must deal with files that randomly mix different types of data
that are not amenable 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 in any case.

A.

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 initialized 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 algorithm).
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 algorithm. 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".

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 probably not portable.

So Pascal HAS a defacto type conversion method, but it is far more painful
to use than, say, C. In this authors' humble opinion, its a good thing that
it is painful. Its bad coding practice, and should be avoided.

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 probably 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;

U: char

end;

r2 = record

O: real;

S: integer

end;

out = (rtr1, rtr2);

r3 = record

case out of

rtr1: (r1d: r1);

rtr2: (r2d: r2)

{ end }

end;

soufflé = file of r3;

Now "soufflé" 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 conversion (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 conversion 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).

A.

Standard Pascal has a series of structured statements, if-then-else, while-do,
repeat-until, for-do. A common feature of other languages are statements like
"break" and "continue" (which come from C). Unfortunately
they are also common extentions to Pascal compilers. I say unfortunately, because
break and continue are really nothing but a disguised "goto". The
whole idea of structured programming is that the flow of control in programs
can be stated with very few constructs. In fact, the classical structured program
statements are while-do and if-then-else. repeat-until and for-do are really
just special cases of the while-do loop.

The problem with break and continue is that they break the logical structure
of the loop, in an arbitrary way similar to a goto. A break or continue can
be executed at any statement depth and "bail out" to the outside loop.
So what are the equivalents to common uses of break an continue in ISO 7185
Pascal?

Continue equivalents

while x do begin
if y then continue;
...
if z then continue;
...
end;
while x do begin
if not y then begin
...
if not z then begin
...
end
end
end;

Break equivalents

while x do begin
if y then break;
...
if z then break;
...
end;
while x and not q do begin
if y then q := true
else begin
...
if z then q := true
else begin
...
end
end
end;

Of course, this dosen't account for deep nested breaks or continues, but
these kinds of statements look more and more like a defacto "goto".

Structured programming is a tequinque you have to live with for a while to
get right. I converted to structured programming from "spagetti" assembly
language programming some time ago, and it took a while of using flags before
I saw that the majority of code just needs to be arranged and thought out properly
to be structured. Now, it's second nature. I do a lot of C coding as well, and
I never feel the temptation to use break or continue even in that language.
It's just a crutch.

A.

I see a lot of folks frustrated with the read/readln statements and numbers.
If you perform a read/readln and there is nothing but spaces in the input, Pascal
will cross multiple lines until it sees a number, leading to users hitting return
again and again wondering why the program seems to be "hung". If there
is a number, great. If not, it's an error, and your program gets terminated.

This confusion comes from the fact that buffered input I/O, a standard feature
of Pascal, has been largely ignored, and has even been removed from the language
in the UCSD/Apple/Delphi dialects of the language. Buffered input is a cool
and natural way to solve these issues, and yes, it even works on interactive
files like the console, thanks to "lazy I/O".

Buffered input means that you can always "look ahead" to see the
next character coming in a file:

var f: text

...

if f^ in ['0'..'9'] then writeln('Number present');

You can skip blanks in the input to find a number:

while (f^ = ' ') and not eof(f) do get(f);

Now, let find a number, and reject multiple lines, then read the number if
present: For extra credit, we will even ensure that no other garbage exists
on the input line after the number.

produre getnum(var f: text; var n: integer);

begin

n := 0;

while (f^ = ' ') and not eoln(f) do get(f);

if not (f^ in ['0'..'9', '-', '+']) writeln('*** No number was found')

else begin

read(f, n);

while (f^ = ' ') and not eoln(f) do get(f);

if not eoln(f) then writeln('*** Invalid input')

end

end;

The skip space we have used in getnum only skips within a single line. It
takes advantage of the fact that ISO 7185 is defined such that all lines are
properly formed, and we won't see an eof without an eoln before it. The read
of n will work even if there is garbage after the number, because read/readln
stops when it runs out of valid digits. So the line:

+567bark

Will leave the next input position at the "b" following the number,
and we will then generate an error.

The last issue left is that the line:

-

Will generate an error, because what apparently looks like a number, the
"-", isn't followed by valid digits. Lets reformulate getnum to account
for this:

produre getnum(var f: text; var n: integer);

var sgn: integer;

begin

n := 0;

sgn := 1;

while (f^ = ' ') and not eoln(f) do get(f);

if not (f^ in ['0'..'9', '-', '+']) writeln('*** No number was found')

else begin

if f^ = '+' then get(f)

else if f^ = '-' then begin get(f); sgn := -1 end;

if not (f^ in ['0'..'9', '-', '+']) writeln('*** No number was found')

A.

Just following the standard is not enough to create a useable compiler. Obviously
freedom from limits (except the limit of available memory) is a good attribute
of a compiler, as well as producing the best code possible. Other points to
look for:

1. Should be able to represent "set of char" without problem. This
is really a must. For a while, it was under consideration to add this requirement
to the standard. It wasn't, but most character handling programs I have seen
rely on being able to use character sets, so you might as well consider it part
of the standard.

2. Represents 8 bit characters. I have found it best if the compiler leaves
it entirely up to you what is done with the 8th bit (of ASCII or ISO character
sets). This allows you do either deal with parity, or manipulate 256 valued
extended character sets (like IBM ASCII).

3. "file of char" is not the same as "text". This is
a somewhat obscure point. Normal "text" files are "filtered"
by Pascal I/O. Line endings are made regular, and eolns are converted to spaces.
But there may be times that you want to talk in terms of the exact characters
themselves, read and write carriage returns and line feeds directly, etc. For
example, when reading direct from the computer console, you may want to see
directly if the user hits the "return key".

There is no requirement in the standard that "file of char" do
the same filtering that "text" does, and better compilers consider
"file of char" a clue to completely get out of the way and pass raw
characters to and from the file. Also, it is common for Pascal systems to buffer
up whole lines when reading from the console (see below). File of char will
allow this buffering to be bypassed.

4. Input from the computer console is buffered. If you have a program like:

program readit(input, output);

var i: integer;

begin

writeln('Input the number: ');

readln(i);

writeln('The number was: ', i:1)

end;

If the console is read directly, and the user makes a mistake on entry, it
will not be possible to back up and correct typing. If the line is buffered,
the user can back up, correct the error, and continue without the simple program
above needing to do anything about it. Without this capability, you would
have to write such "line editing" features in yourself.

A REALLY GOOD Pascal system would implement a complete set of line editing
features, such as back up, insert characters, etc.

5. Ability to represent a file of bytes. One thing that really amazes me
about some compilers I have seen is an inability to read or write files
of byte value:

type byte = 0..255; { a predefined type on many compilers }

bytfil = packed file of byte;

If your compiler decides that bytes are integers, at whatever the size of
integers are on your machine (16, 32 or 64 bits), it may just read or write
integer size values to the file ! This forces you to break apart the bytes from
an integer yourself, which is not only tedious, but creates a nonportable program.

6. Does something with the program parameters. Somewhere, at some time, it
became standard to just ignore the program parameters. This is a real shame,
because when implemented, they are really useful for creating quick, short programs:

program copy(source, destination);

var c: char;

begin

while not eof(source) do begin

if eoln(source) then begin

readln(source);

writeln(destination)

end else begin

read(source, c);

write(destination, c)

end

end

end.

Now if the compiler ignores the program header parameters, this program does
nothing, and will probably terminate with an error. But the compiler can also
automatically attach program parameters other than the standard "input"
or "output" to command line parameters, like:

> copy myfile.txt thatfile.txt

So the compiler opens source to "myfile.txt", and destination to
"thatfile.txt". The result is a program that is completely standard,
and yet performs named file manipulation. Further, this method is much simpler
than using the "open by name" extensions present in most Pascals,
and allows you to create simple example programs faster.

7. Ability to tolerate control characters in source. If the compiler ignores
control characters in the source, such as tabs and form feeds (treats them as
spaces), you will have the freedom to format your source so that it can be directly
printed.

8. Don't have "extended" modes that break the standard rules. The
Pascal standards basically require that the compiler have a "switch"
(command line option) that causes the compiler to accept only standard Pascal,
and rejects any nonstandard constructs. Because some compilers were originally
nonstandard, and were brought into compliance with the standard after the fact,
it is quite possible that they may not accept standard programs with this switch
off ! This is truly unfortunate, since it forces you to write nonstandard Pascal
just to take advantage of Extensions to the language provided by your compiler.

9. Accept Pascal strings for extended file naming procedures. A common extension
to Pascal is a Basic string construct (as opposed to a Pascal string, which
is just an array of characters). Unfortunately, it has become common to REQUIRE
that such strings be used with extended file "open by name" procedures.
A good compiler should accept standard Pascal strings as arguments to such procedures,
which allows you to use the string types you choose. These procedures should
also ignore trailing spaces in such strings, which allows use of the typical
Pascal "space padded string".

10. Implements "lazy I/O". Pascal as originally specified assumes
that all files are batch files (ie., not "interactive", or connected
to a console). This creates problems, say, reading from the console keyboard,
because Pascal assumes that the first character in a text file is always available.
Lazy I/O will only request the first character from a file when it is actually
used, and is completely compatible with the standard.

11. Can provide "strict packing". Strict packing means that if
a record is marked as "packed":

var r: packed record

a: boolean;

b: integer;

c: char

end;

Then, for example, "a" will only occupy a single bit, and all fields
will be packed into as few bits as possible. This has implications beyond simple
storage savings, because you can use strict packing to emulate ANY data structure
from any language. for example, if you receive the date as packed into a single
word:

-------------------------------------------

| year (0-99) | month (1-12) | day (1-31) |

-------------------------------------------

7 bits 4 bits 5 bits

This exactly fits in a single 16 bit word ! Then, this can be declared as
a packed record:

var date: packed record

year: 0..99;

month: 1..12;

day: 1..31

end;

And no "format conversion" is required. Note that if the alignment
of packed records to the data structure desired is not perfect, you can insert
"shims" in the form of single bits (boolean values).

A.

Most compilers include extensions to the basic language, the most popular
(and necessary) extensions being manipulation of external files by name, and
ability to separate program parts into modular form. In fact, a standard of
sorts was created by the popular UCSD Pascal system for these two items. This
is a list of popular extensions, and the form they usually take. Note that extensions
that are part of the extended Pascal standard are discussed in the extended
standard section.

1. Specification of hex constants. Allows you to directly specify hex numbers
in the source:

var a: integer;

...

a := $56;

"$" as the leading character seems to be the most common. Some
compilers also allow binary radix (base 2) and octal radix (base 8).

2. Integer bit boolean operations. Many or even most compilers allow you
to use the "and" and "or" operators on integers:

var a, b: integer;

...

a := a and b;

The result is a bitwise "and" of the two integers. Note that the
results when one or more of the operands is signed varies from compiler to compiler,
and use of these operators with signed integers should be avoided. Many compilers
also include an "xor" operator.

3. File open and close by name. This allows you to open an external file
by name. Many compilers use the Borland plan:

var f: text;

...

assign(f, 'myfile.txt');

reset(f);

...

In this method, an ASCII name can be "bonded" to the file by the
procedure "assign". If no assign is performed on a file, it is opened
as a "temporary" file (ie., the system just coins a name for the file,
and deletes it when complete) upon "reset" or "rewrite".
This allows the system to be completely backward compatible with standard Pascal.
If your system also has a "close" function:

close(f)

You should use it. Closing open files releases system space (used to keep
track of files), and allows a series of files to be opened under one file variable.

4. Modular compilation. Again the most common, UCSD adds an extra declaration
section before "label":

program junk(input, output);

uses trash, mylib;

label 1, 2;

...

This tells the compiler to include all the (public) constants, types and
blocks in the files specified within uses list to the present program. The exact
details of the format needed to compile the module (called a "unit"
in UCSD) vary quite a bit from compiler to compiler.

5. Include statements. Most compilers allow the appearance of an "include"
statement or marker in the source, that specifies that another file is to be
included in line. Most common is UCSDs "control comment":

{$I file.pas}

Which would include the file "file.pas" inline, replacing the entire
comment.

5. Flexible declaration order. Many or most compilers allow the declarations
to occur in any order, and for declaration sections to occur multiple times:

program test;

var this, that: integer;

const x = 10;

var mystring: packed array [1..x] of char;

...

The reason for this is that when using modular compilation or include statements,
each program section must have its own set of declarations. Note that the rule
that objects must be declared before use is still in effect even though the
declarations can appear in any order.

6. Strings. A full Basic string type is included in Pascal, which allows
constructs as:

Are common. Since Pascal must live in systems where these names are common,
this is allowed in most implementations.

8. "goto" labels as normal identifiers. The appearance of goto
labels as integers might be considered a sort of arcane plot to punish people
for using "goto"s. Many or most implementations allow goto labels
to appear in the same form as identifiers:

A.

A.

The PUG or Pascal Users Group was formed shortly after Pascal was introduced
by N. Wirth as a collection of letters that were printed and circulated to a
mailing list. It started publishing in January 1974, and ended in November,
1983.

The PUG newsletters were important because they cronicle, in an indisputable
way, the early history of Pascal.