THE LANGUAGE PASCALINE

REPORT VERSION 0.3

Contents

1       Introduction. 10

2       Summary of Pascaline extensions to Pascal 13

3       EBNF and syntax used in this document 19

4       Relationship to ISO 7185. 21

4.1        Pascaline as a series of extensions. 21

4.2        Additional reserved word-symbols. 21

4.3        Character escapes. 21

4.4        Compliance with ISO 7185. 21

4.5        ISO 7185 level 0 only. 22

4.6        Extensions to Pascaline. 22

4.7        Compliance statement 22

4.8        Compliance switch. 22

4.9        Similarities with the ISO 7185 standard document 23

5       Relationship to the Pascal-P6 series compiler 24

6       Language extensions for Pascaline. 25

6.1        Word-symbols. 25

6.2        Special symbols. 25

6.3        Comments. 25

6.4        Identifiers. 25

6.5        Labels. 26

6.6        Numeric constants. 27

6.7        Constant expressions. 28

6.8        Boolean integer operations. 28

6.9        View and out parameters. 30

6.10     Extended case statements. 32

6.11     Variant record case ranges. 34

6.12     Array type shorthand. 36

6.13     Container arrays. 36

6.14     Parameterized Variables. 40

6.15     Extended write/writeln statements. 42

6.16     Extended read/readln statements. 46

6.17     Type converters/restrictors. 58

6.18     Fixed types. 60

6.19     Extended file procedures and functions. 61

6.20     Added program header standard bindings. 72

6.21     Redeclaration of forwarded procedures and functions. 73

6.22     Anonymous function result 73

6.23     Extended Function results. 75

6.24     Halt procedure. 76

6.25     Overloading of procedures and functions. 77

6.26     Operator overloads. 79

6.27     Static procedures and functions. 82

6.28     Relaxation of declaration order 83

6.29     Exception handling. 83

6.30     Assert Procedure. 87

6.31     Extended range types. 88

6.32     Extended real types. 90

6.33     Real Limit Determination. 91

6.34     Character limit determination. 91

6.35     Matrix mathematics. 91

6.36     Properties. 96

6.37     Modularity. 98

6.37.1    Definition vs. implementation modules. 102

6.37.2    Overrides. 103

6.37.3    Parallel modules. 105

6.37.4    Monitor signaling. 108

6.38     Channels. 115

6.39     Classes. 117

6.39.1    Static objects. 119

6.39.2    Dynamic objects. 119

6.39.3    Classes as parameters. 121

6.39.4    Class parameters. 121

6.39.5    Inheritance. 125

6.39.6    Overrides for objects. 127

6.39.7    Self referencing. 128

6.39.8    Constructors and destructors. 132

6.39.9    Operator overloads in classes. 133

6.39.10    Derivation vs. composition. 135

6.39.11    Parallel classes. 136

A      Annex A: Collected syntax. 145

B      Annex B: Standard exceptions. 155

C      Annex C: Undefined program parameter binding. 159

D      Annex D: Character sets. 161

D.1       ISO 8859-1 Character Set Encodings. 161

D.2       ISO 10646 Character Set Encodings. 161

D.3       Unicode text file I/O.. 161

D.4       Use of different character sets. 162

E       Annex E: Character escapes. 163

F       Annex F: Overview of standard libraries and modularity. 169

F.1        Basic Language Support 169

F.1.1    services. 169

F.1.2    strings. 169

F.2        Advanced User I/O and Presentation Management 169

F.2.1    Naming. 171

F.3        Advanced device libraries. 172

F.3.1    sound. 172

F.3.2    network. 172

F.4        Classes. 172

F.5        Library procedure and function notation. 172

G      Annex G: System Services Library. 173

G.1       Filenames and Paths. 173

G.2       Predefined paths. 174

G.3       Time and Date. 174

G.4       Directory Structures. 176

G.5       File Attributes and Permissions. 177

G.6       Environment Strings. 177

G.7       Executing Other Programs. 178

G.8       Error Return Code. 179

G.9       Creating or Removing Paths. 179

G.10         Option Character 179

G.11         Path Character 179

G.12         Location. 179

G.13         Internationalization. 183

G.14         Exceptions. 185

G.15         Functions and procedures in services. 187

H      Annex H: String Library. 195

H.1       Conventions. 195

H.2       Words. 195

H.3       Format Strings. 195

H.4       Recycling. 197

H.5       String container classes. 197

H.6       Exceptions. 199

H.7       Procedures and functions in strings. 200

I        Annex I: Extended mathematics library. 213

I.1         Functions. 213

I.2         Further trancendentals. 214

I.3         Hyperbolics. 214

I.4         Special floating point values. 215

I.5         NaN functions. 215

I.6         Utility functions. 215

I.7         Exceptions in the math library. 215

I.8         Functions, procedures and constants in the math library. 216

J        Annex J: Terminal Interface Library. 221

J.1         ISO 7185 Pascal Compatible Mode. 221

J.2         Basic Cursor Positioning. 221

J.3         Automatic Mode. 222

J.4         Tabbing. 222

J.5         Scrolling. 222

J.6         Colors. 222

J.7         Attributes. 223

J.8         Multiple Surface Buffering. 223

J.9         Advanced Input 224

J.10      Event callbacks. 227

J.11      Timers. 229

J.12      The Frame Timer 230

J.13      Mouse. 230

J.14      Joysticks. 231

J.15      Function Keys. 231

J.16      Automatic “hold” Mode. 231

J.17      Direct Writes. 232

J.18      Printers. 232

J.19      Metafiles. 232

J.20      Remote display. 233

J.21      Terminal objects. 233

J.22      Exceptions. 237

J.23      Procedures, functions and methods in terminal 238

J.24      Events and Callbacks In terminal 246

K      Annex K: Graphical Interface Library. 253

K.1       Terminal model 253

K.2       Graphics Coordinates. 253

K.3       Character Drawing. 253

K.4       String Sizes and Kerning. 255

K.5       Justification. 255

K.6       Effects. 255

K.7       Tabs. 255

K.8       Colors. 255

K.9       Drawing Modes. 256

K.10         Drawing Graphics. 256

K.11         Figures. 257

K.12         Predefined Pictures. 257

K.13         Scrolling. 258

K.14         Clipping. 258

K.15         Mouse Graphical Position. 258

K.16         Animation. 258

K.17         Copy between buffers. 259

K.18         Printers. 259

K.19         Metafiles. 259

K.20         Remote display. 259

K.21         Declarations. 259

K.22         Event callbacks. 262

K.23         Graphical Terminal Objects. 262

K.24         Exceptions. 267

K.25         Procedures and functions in graphics. 269

K.26         Events and Callbacks In graphics. 280

L       Annex L: Windows Management Library. 281

L.1        Screen Appearance. 281

L.2        Window Modes. 281

L.3        Buffered Mode. 281

L.4        Unbuffered Mode. 282

L.5        Defacto transparency. 283

L.6        Delayed Window Display. 283

L.7        Window Frames. 283

L.8        Scroll Bars. 283

L.9        Multiple Windows. 284

L.10     Parent/Child Windows. 284

L.11     Moving and Sizing Windows. 285

L.12     Z Ordering. 285

L.13     Class Window Handling. 286

L.14     Parallel Windows. 286

L.15     Menus. 287

L.16     Setting Menu Active. 288

L.17     Setting Menu States. 288

L.18     Standard Menus. 288

L.19     Menu Sublisting. 289

L.20     Advanced Windowing. 290

L.21     Events. 290

L.22     Event callbacks. 293

L.23     Window Objects. 293

L.24     Exceptions. 301

L.25     Procedures and Functions in windows. 303

L.26     Events and Callbacks In windows. 310

M     Annex M: Widget Library. 313

M.1      Tiles, Layers and Looks. 313

M.2      Background colors and placement 313

M.3      Sizes. 314

M.4      Logical Widget Identifiers. 314

M.5      Killing, Selecting, Enabling and Getting Text to and from Widgets. 314

M.6      Resizing and repositioning a widget 315

M.7      Types of widgets. 315

M.8      Z ordering. 315

M.9      Controls. 315

M.10        Components. 319

M.11        Dialogs. 320

M.12        Events. 322

M.13        Event callbacks. 325

M.14        Widget Classes. 326

M.15        exceptions. 335

M.16        Procedures and functions in widgets. 336

M.17        Events and Callbacks In widgets. 356

N      Annex N: Sound Library. 359

N.1       Ports. 359

N.2       Channels and Instruments. 361

N.3       Volume. 367

N.4       Time and the Sequencer 367

N.5       Effects. 368

N.6       Pitch Changes. 369

N.7       Prerecorded MIDI 369

N.8       Waveform Files. 369

N.9       Synthesizer objects. 370

N.10         Waveform objects. 371

N.11         Exceptions. 372

N.12         Functions and Procedures in sound. 372

O      Annex O: Networking Library. 379

O.1       Exceptions. 379

O.2       Functions and Procedures in network. 380

 


 

1       Introduction

"Standards are great. Everyone should have one of their own" - Anon.

Pascaline is a formal statement of a language that was created over the period 1993 to 2008 in a series of extensions to ISO 7185 Pascal. The name "Pascaline" was chosen both to show that the language is designed to be %100 compatible with the original language, and to continue the language Pascal’s tribute to Blaise Pascal. The Pascaline being Pascal’s calculator, Pascaline the language is "The machine Pascal built", or the "Machine that runs Pascal".

In 2008, there are several defacto standards for an extended Pascal, and one official one, the ISO 10206 standard. I have been dissatisfied with these existing extensions for the simple reason that instead of extending Pascal, they are more akin to redesigns of the language. A good definition of what I mean by redesign would be the introduction of a feature that is designed to replace or duplicate a construct of original Pascal. In particular, the addition of the ability to coin pointer addresses to any variable and perform "type escapes" at will remove at a stroke all of the type security Niklaus Wirth designed into Pascal.

At the same time, I wanted Pascaline to achieve a level of completeness that the language never achieved in its original form. My goal was not to create an instructional language, but a complete and practical implementation that could address current problems in computing without further extensions or special support packages.

To design Pascaline I have enumerated a set of goals for the language design:

·         To be completely upward and downward compatible with ISO 7185 Pascal.

·         To be a "logical extension" of original Pascal. That is, to extend Pascal using the same working theories and means as the original language, and poses no element that does not interoperate completely with the original language.

·         To provide a reasonable upgrade to the language capability, that can be implemented using an existing standard compiler with minor effort compared to the original implementation of the compiler.

·         To implement only features that could be implemented efficiently using existing computing hardware.

Pascaline was designed in a series of steps starting in 1993. For each feature, one or more proposals were made. Then, the proposals were evaluated, a winner chosen, and a test implementation in the compiler was made. Then, any adjustments required by the experience of actual use were performed. Every element in Pascaline is backed by a real implementation that is efficient and tested.

As for most modern languages, the major theme of Pascaline is for extending the language via libraries, objects and code reuse. Pascaline will, and should, "obsolete itself" by allowing user written extensions to such a point that the major thrust of development with the language would become that of developing libraries of functions to cover new areas in computer applications.

This very ability to extend the language also forms the basis of a new problem in standard implementation that, although it has existed from the time Pascal was originally designed in the 1970s, has become ever more pressing. That is the definition of standard libraries and platforms. Towards this end, the Pascaline standard, as in the standard for most of today’s languages, is divided into the base standard and a "platform", consisting of a series of libraries that handle common I/O and support problems in a machine and system independent way.

These libraries appear here as annexes. There is also a series of annexes covering issues such as character handling, string escapes and other "recommended practices" for Pascaline. The result should greatly aid the ability to write non-trivial Pascaline programs that are truly portable across machines, systems and implementations.

The second, but no less important theme in Pascaline, is parallel language execution. Pascaline is a thoroughly parallel language, and completes the idea that strong type security is a fundamental building block to parallel language implementation. Indeed, Pascaline now exists as one of the only languages that offers parallel execution security in a language, instead of being added in as a library with security left to the user.

As I have offered in the past for Pascal, I extend the offer now, that I will evaluate Pascaline implementations for conformance to the Pascaline standard, no matter what the purpose of that implementation, public or private, profit or nonprofit. I only make the conditions that my access to the implementation be reasonable, that the authors provide me with a list of annexes that are complied with, and that an option exists in the implementation to enforce strict compliance with Pascaline regardless of any other extensions that might be present over and above Pascaline. This last is the same requirement that the ISO 7185 Pascal standard states.

This author further respectfully requests that the name "Pascaline" be applied only to an implementation that has been found to comply with the language specification here, and by the tests I provide free of charge or restriction. Further, unlike the ISO 7185 standard, I ask that no exceptions be allowed for the language (ISO 7185 5.1). A language may well comply with part of this specification, and be called a Pascal, or some other name. I only ask that it not be called "Pascaline" unless it can process the full language, aside from the annexes, without exception.

Scott A. Moore

July, 2008


2       Summary of Pascaline extensions to Pascal

Pascal defined a program as a series of nested blocks, one inside the other. The most basic block was the program block, which could contain any nested series of procedure and function blocks. Each block can contain a series of declarations containing labels, constants, types, variables, procedures and functions. Each block contains the code that executes the algorithms contained in the block.

The blocks of Pascal define a closed collection of these declarations with an interface that consists of a parameter list. In Pascaline terminology, this is a "top" interface, as the block communicates with the outside of the block via an interface at the "top" of the block:

Block

(procedure or function)

Parameter

List

In Pascaline, each block can also interface, informally, with declarations in the surrounding block. This is referred to in Pascaline terminology as the "side" interface:

Block

(Module or Class)

Constants

Variable declarations

Procedures

Surrounding Block

Each block can import declarations from the surrounding block.

Pascal envisioned a program as a tower of blocks resting one atop the other. This paradigm is a good one, but views the program as a monolithic whole. The provision of fixed types without the ability to extend them with change also contributes to the model of a program created as a static structure of code.

Pascaline's main thrust is to add extensibility to Pascal, and this is done by greatly augmenting the methods to create side blocks. Pascaline views programs as a series of adjoining tiles:

Block

Constants

Variable declarations

Procedures

Block

 

In Pascaline, the program block is such an adjoining block, and adds several other block types that have this ability to export their declarations directly to other blocks. The primary of these is the module, which has all the powers of a program block, but adds the ability to specify both code that executes when the program starts, and code that executes when the program ends. In this way, modules appear as "service blocks" whose point is to provide constants, types, variables, procedures and functions to the program, along with a method both to set up such items as well as shut them down.

The program and module blocks form a group executing the same thread of execution for a program. Another module is the process, which defines a new thread of execution aside from the main program. Process modules cannot directly access program or module blocks, but the two can communicate via a monitor or channel block, which automatically implements the multitasking primitives needed to coordinate such an exchange. A share block gives a way to define constants, types, procedures and functions that are usable by any task without the overhead of multitask coordination.

Pascaline also defines a new level of block that is an intermediate between a so-called "global" block such as a program, module, monitor, channel, etc. Those blocks are static, with variables that are allocated for the duration of the program. This is a natural outermost block, since any program ultimately is rooted in such program constructs. The class block fits between the level of global blocks and procedure and function blocks. A class block has the ability to share its declarations via the "side", but also can have its variables created dynamically, or as part of the local variables in a block. Further, classes have the ability to be extended to any level. Any new class has the ability to be based on a previously defined class, and to have that class accepted as compatible with the base class.

Because classes define both declarations such as constants and types that have no allocation, as well as variables that do, the class must be instantiated either as part of the variable data, or via a reference. Any number of instances of a class may exist associated with such references. The instance of a class is called an object, and it is the set of the data associated with a class. The class contains the declaration of the format of the object it creates, and thus it is a "class" or "kind" for all of the objects created using it.

Because a class defines both a series of constants, types, variables, and also procedures and functions that can operate on those declarations, which are known as "methods", An object forms an instance of a module. Classes complete the idea of "object orientation" which dictates that data exists as paired with the procedures or functions that form its methods, needed to manipulate that data. Because classes that inherit from each other also have references that are compatible, classes can extend each other to any number of levels to implement program concepts.

As a dynamic corollary to a module, classes also can have a separate thread of execution as a thread class, and perform as a tasking communications block as an atom or liaison class.

To allow the static idea of parameter lists in Pascal to be extended, Pascaline implements the "overload" concept. Procedures, functions and methods can form "groups" under the same name that are differentiated by kind, type and number such that calls to such procedures and functions are sent to the instance that has the correct interface to operate on them. Built in expression operators can be overloaded, thus completing a full circle of data abstraction.

The concept of extendibility is further enhanced by the ability to override existing procedures, functions and methods. New modules and classes can override the previous meaning of them, and also extend them by performing new operations and calling the original definitions.

Pascaline has "container" types for arrays that do not specify an exact size. These types can be used to form a template to create such arrays of a runtime determined size at runtime. This allows procedures and functions to accept arbitrarily sized arrays to any dimension, and allows such arrays to be dynamically created as variables and pointer types as well.

The common case of an integer indexed array can be specified by a short form, which also underscores the idea of container types.

A line comment uses a single character, “!”, that allows the rest of the line to appear as a comment.

Pascaline introduces the break character, "_", for both identifiers and numbers. This aids readability for long identifiers and numbers.

Goto labels are freed from the restriction that they must appear as numbers, and can assume the same form as an identifier. Goto labels both retain their status as an interprocedure deep nested branching, but also allow for intermodular branching via a procedure or function call.

Pascaline implements the method of structured exception handling to handle deep nested returns. This allows code to be written that delivers exceptions to higher level code without needing knowledge of the surrounding code. This further enhances extendibility, and allows for complete replacement of “goto”s.

Constant expressions can be used wherever constants were used in Pascal. This makes it possible to use formulas for these constants instead of precalculated numbers.

Extended radixes allow direct specification of hexadecimal, octal or binary constants.

Boolean operations on integers are permitted, and a new operator, "xor", is implemented for both boolean and integer operands.

For procedures, functions and methods, two new parameter "modes" are implemented, the view and out modes. The view mode is identical to value parameter semantics, except that the parameter is protected from all modification. This makes certain compiler optimizations possible. The out mode is identical to var mode, but flags to the compiler that the parameter will be used only to pass out results.

Case statements now have an else clause, and ranges of case constants are possible.

Case variant declarations can also use ranges of case constants.

Write/writeln can specify left justified fields, and a special mode allows the output of right padded strings in their natural length.

Read/readln can specify fields on read variables, and can specify literal strings to be matched to the input. A special mode allows the input of right padded strings in their natural length.

A new declaration exists, fixed, which can be used anywhere a variable can, but cannot be modified. This allows the compile time specification of fixed tables, and ameliorates the need to create blocks of assignments at the start of a program.

Pascaline introduces a limited type conversion/restriction operation to convert between scalar types. This relieves the need to produce special handling to convert enumerated types to integer. It also introduces the ability to directly specify the precision needed within integer expressions, instead of always promoting such operations to the full size of integer. This allows more efficient numeric processing on small word size processors and arbitrary word length processors.

Pascaline standardizes a series of procedures and functions for files, such as binding to external file names, opening and closing a series of files, indexing within files, finding the length of a file, updating existing files, and appending to the end of such files, checking the existence of a file, and deleting and changing the name of a file.

A few new standard header parameters are introduced, including an error output, a list (or print) output, and a command line or file input.

The strict order of declarations from Pascal is relaxed in Pascaline. label, const, type, var and fixed declarations can occur in any order. This aids in the modular structure of Pascaline.

When a forwarded procedure, function or method appears as the actual declaration, the parameter list can be repeated. It is checked for congruence with the original. This allows such declarations to be created by cut and paste, and is more readable than the original method of having the actual declarations far from their forwarded declarations.

Procedures and functions can be declared as static, or non-recursive. This allows the creation of more efficient code on some processors.

Asserts are implemented, allowing the incorporation of runtime checks for code being debugged that can be removed without modifying the source.

Pascaline allows "subrange" types to be created that are larger than the natural Pascal range of an integer (-maxint..maxint). This allows an implementation to implement types that utilize double more precision while taking longer to perform them, so called "extended range" types. It also implements a set of predefined types that give an implementation defined set of unsigned and signed extended range types.

Besides standard reals, there is a type that is smaller than the standard real, and a type that is larger than the standard real. There are new constants that give the maximum values in each real type.

There is a predefined constant for the maximum character value in an implementation.

Matrix mathematics is supported with one dimensional and two dimensional arrays.

A way to specify a function result that obeys the rule of single entry/single exit with the result formed at the end. This is also required for operator overloads.

Function results are extended to allow most types, including structured, to be returned as a result.

Properties specify a program object that appears as a variable, but has its read and write actions completely program defined. Properties are also a building block to advanced multitasking structures.

Besides the extensions to the base Pascal language, Pascaline defines a set of optional extension modules that define the Pascaline "platform". This is a nod to the fact that the set of support calls for an implementation make as much difference to portability for a program as the base language does.


3       EBNF and syntax used in this document

For the purpose of describing syntax elements of Pascaline, the EBNF or Extended Backus-Naur Format as used in the ISO 7185 standard is used. The syntax that appears here consists of the syntax elements from the ISO 7185 standard as modified for Pascaline use.

name = syntax-description .

Describes the syntax expansion of the syntax element by name of "name", which is terminated by '.'.

 a | b

Either construct a or constructor b may appear, but not both.

{ a }

Construct a is repeated 0 or more times.

[ a ]

Construct a is repeated 0 or 1 times (it is optional).

'abc'

The characters "abc" appear literally.

( a b )

The elements a and b are grouped together.

The syntax expansions that appear in this document mirror the same by name in the ISO 7185 document. If a syntax element by name matches a name used in the document, and is different from the one contained there, then it represents a Pascaline extension to ISO 7185 Pascal, and replaces the original syntax definition.

Note the ISO 7185 use of ">" or "alternate" is not used here, because Pascaline does not use the "level 1" extensions of ISO 7185. The syntax for the level 1 extensions was removed.

Annex A contains a full syntax for Pascaline.


4       Relationship to ISO 7185

4.1      Pascaline as a series of extensions

The Pascaline standard accepts the entire language defined in the standard defined in ISO 7185 such that the set of features defined by Pascaline qualify as extensions under ISO 7185 3.2 “Extension”.

4.2      Additional reserved word-symbols

As allowed in ISO  7185 3.2 “extension”, the following additional spellings of identifiers are prohibited because of their use as word-symbols in the Pascaline standard:

forward          module           uses                private            external

view                fixed                process          monitor          share

class               is                     xor                  overload         override

reference        joins                static               inherited         self

virtual             try                   except             extends          on

result              operator         start                thread             atom

property         channel          liaison             out

 

These word-symbols are all new word-symbols defined by Pascaline. The fact that certain identifiers are prohibited in Pascal may cause ISO 7185 compliant programs to fail to compile for this reason. To use a Pascaline implementation for such programs, one of two methods are used:

1.      The ISO 7185 compliance switch is enabled (see ISO 7185 5.1 “Processors” note 2).

2.      The identifiers in the program that overlap the above list are changed.

4.3      Character escapes

Annex E “Character Escapes”, if implemented by the target system, can affect the behavior of character strings in an ISO 7185 implementation. Although ISO 7185 does not specify the character set or contents of strings in a complying program, it is reasonable for a given program to assume that all visible characters are treated equally.

If the program contains the character ‘\’, the escape sequence introduction character, this will be treated differently than other characters. To use a Pascaline implementation that implements Annex E for such programs, one  of three methods are used:

1.      The ISO 7185 compliance switch is enabled (see ISO 7185 5.1 “Processors” note 2).

2.      A switch that enables or disables character escapes is set to disable.

3.      All instances of ‘\’ within character strings are changed to ‘\\’.

4.4      Compliance with ISO 7185

ISO 7185 5.2 “Processors” allows an implementation to be considered compliant if it is accompanied by a list of the requirements for which it does not comply. Pascaline specifically does not allow such exceptions. A processor is Pascaline compliant only if it has the following characteristics:

1.      The complete requirements of ISO 7185 are followed, without exception.

2.      The complete requirements of Pascaline, in this document, are followed without exception.

That is, the “list of requirements not complied with” from ISO 7185 5.2 “processors” is neither allowed as a starting point for Pascaline, nor carried forward into the language Pascaline.

4.5      ISO 7185 level 0 only

Pascaline is compliant with “level 0” Pascal only, as allowed for by the ISO 7185 standard (ISO 7185 5 “Compliance”). Conformant arrays are not specified in Pascaline, nor are they specified as an option under Pascaline. However, such conformant arrays could well be implemented as an extension to Pascaline.

4.6      Extensions to Pascaline

Extensions to Pascaline are changes to language features in this standard that do not cause a program complying with this standard to fail to compile, interpret, run or otherwise function with the exception that one or more additional spellings of symbols may be reserved to the processor. That is, additional reserved word-symbols may be defined.

An example of an extension that does not comply with this standard is a modal change such as redefining the functionality of the “mod” operator. This would cause otherwise complying programs to fail to function.

4.7      Compliance statement

Complying processors with Pascaline shall issue the statement:

<This processor> complies with the requirements of Pascaline version X.X [and the annexes A, B, C…]

Where:

 <This processor>                    Is the name of the complying processor

X.X                                          Is the version number of the Pascaline specification complied with.

[and the annexes A, B, C..]      Is an optional list of the annexes also compiled with]

There is no minimum requirement for the number of annexes complied with. The processor may comply with any number from zero to all of them. In some cases, it may be inappropriate for a particular implementation to have compliance with a particular annex. For example, the graphical display annex K in conjunction with a system that has no graphical display. Just as compliance with the basic Pascaline standard implies that a program will or will not run, the presence or absence of an annex a program relies on may cause it to compile and run, or fail to do so.

4.8      Compliance switch

If the processor complying with this standard contains extensions (defined in 4.6 “Extensions to Pascaline”), it shall contain a switch for compliance with Pascaline with the following characteristics:

On:

1.      Causes the Pascaline compliance statement to be issued (4.7 “Compliance statement”).

2.      Causes any restriction on spelling of identifiers to be removed (no additional reserved words beyond those of Pascaline).

3.      Causes any extension to the Pascaline standard to be removed.

Off:

1.      Causes the Pascaline compliance statement to be removed (4.7 “Compliance statement”).

2.      Enables any extensions to the Pascaline standard.

3.      Does not cause any program complying with the Pascaline standard to fail to compile, interpret, run or otherwise function, with the exception of restriction of spelling of identifiers (additional reserved words).

Note that if the processor contains extensions that do not comply with the Pascaline definition of extensions (4.6 “Extensions to Pascaline”), the processor will, by definition, not comply with the “Off” switch requirement above.

4.9      Similarities with the ISO 7185 standard document

In general much of the form and manner of the original ISO 7185 standard document was followed in this document. However, in one case there is a distinct difference. The original ISO 7185 document does not distinguish between errors at compile time and at runtime, which sometimes overlap. In this standard, all runtime errors are represented as exceptions, and a list of exceptions appears as an annex.

The use of “equivalent code” occurs many times in this document. That is, a built-in or standard operation or statement is explained in terms of other statements in ISO 7185 Pascal or Pascaline. This creates a concrete and exact explanation of standard actions.


 

5       Relationship to the Pascal-P6 series compiler

In 1972 A project was begun to create a portable compiler that accepted and processed a subset of the original Jensen and Wirth Pascal standard. This compiler went through several versions, and ended as the Pascal-P4 compiler. In its final iteration, it still a subset compiler, with several features of J&W left out. This compiler was extensively documented by both the Zurich originators and in “Pascal Implementation: the P4 Compiler” [S. Pemberton and M.C. Daniels].

In 1982, the ISO 7185 standard was issued, and this was accompanied by the ISO 7185 compiler in A model Implementation of Standard Pascal [Welsh], and by a BSI (British Standards Institute) test suite designed to fully test existing compilers.

In 2009 a project was begun to improve the original Zurich Pascal-P compiler to accept and process the ISO 7185 Pascal standard. This resulted in Pascal-P5, which replaces the model implementation. It was accompanied by an extensive document and by a new test suite designed to replace the BSI test suite, which is no longer available.

In 2011 a project was begun to implement the Pascaline language as an increment to the Pascal-P5 compiler, and create a new test suite to verify the result, and also a new working document for the compiler.

The Pascal-P6 implementation provides a freely available, public domain example implementation of Pascaline whose test suite is also freely available. This can be used as an example for a new Pascaline implementation, as a starting point for such an implementation, and/or as a source of tests for such an implementation, or simply as a reasonable implementation in its own right.

Pascal-P6 and its associated tests provide the proving system for the Pascaline language. It is expected that when the Pascal-P6 implementation is complete and tested, that this standard will reach a 1.0 version.


 

6       Language extensions for Pascaline

6.1      Word-symbols

word-symbol = 'and' | 'array' | 'begin' | 'case' | 'const' | 'div' | 'do' | 'downto' | 'else' | 'end' | 'file' | 'for' | 'function' | 'goto' | 'if' | 'in' | 'label' | 'mod' | 'nil' | 'not' | 'of' | 'or' | ‘xor’ | 'packed' | 'procedure' | 'program' | 'record' | 'repeat' | 'set' | 'then' | 'to' | 'type' | 'until' | 'var' | 'while' | 'with' | 'forward' | 'module' | 'uses' | 'private' | 'external' | 'view' | 'fixed' | 'process' | 'monitor' | ' share' | 'class' | 'is' | 'overload' | 'override' | 'reference | 'joins' | 'static' | 'inherited' | 'self' | virtual' | 'try' | 'except' | 'extends' | ‘on’ | ‘result’ | ‘operator’ | ‘out’ | ‘property’ | ‘channel’ | ‘liaison’.

Notes:

1.      The directives "external" and "forward" in ISO 7185 Pascal are promoted to word-symbols in Pascaline.

2.      The function of the directive “external” in Pascaline is not defined, just as it was not defined in ISO 7185 Pascal.

6.2      Special symbols

special-symbol = '+' | '-' | '*' | '/' | '=' | '<' | '>' | '[' | ']' | '.' | ',' | ':' | ';' | '^' | '(' | ')' | '<>' | '<=' | '>=' | ':=' | '..' | '(.' | '.)' | '@' | word-symbol .

Note that the alternative symbols ‘(.’, ‘.)’, and ‘@’ were optional in ISO 7185 Pascal, and remain optional in Pascaline.

6.3      Comments

The character ‘!’ introduces a “Line Comment”. All characters up to and including the next end of line are ignored. This allows a comment form that is short, and automatically terminated by the end of line:

!

! A simple program

!

program p;

 

begin

 

   writeln(‘Hello, world’) ! print to console

 

end.

 

Notes:

1.      The ‘!’ character must appear between Pascaline symbols and not within any symbol.

2.      Any other comment characters within a line comment are ignored, ‘{‘, ‘}’, ‘(*’, or ‘*)’.

6.4      Identifiers

Identifiers in Pascaline are identical to ISO 7185 Pascal, with the addition of the break character '_'. An identifier can start with any of 'a'..'z' or '_', and continue with 'a'..'z', '_' and '0'..'9'. As in ISO 7185 Pascal, identifiers are not case sensitive.

identifier = letter | '_' { letter | digit | '_' }.

Example identifiers:

one_more_time

_last_time

6.5      Labels

Labels, used for goto purposes, can use the same format as identifiers under Pascaline. The original "apparent value" numeric labels of ISO 7185 Pascal are accepted as well.

label = digit-sequence | identifier .

Example label:

program p;

 

label exit;

 

{ declarations }

 

begin

 

   goto exit

 

   { statements to be skipped }

 

   exit:

 

end.

 

6.6      Numeric constants

unsigned-integer = decimal-integer | hex-integer | octal-integer | binary-integer .

decimal-integer = digit-sequence .

hex-integer = '$' hex-digit-sequence .

octal-integer = '&' octal-digit-sequence .

binary-integer = '%' binary-digit-sequence .

digit-sequence = digit { digit } .

hex-digit-sequence = hex-digit { hex-digit }

octal-digit-sequence = octal-digit { octal-digit }

binary-digit-sequence = octal-digit { binary-digit }

digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' '_'.

hex-digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | '_' .

octal-digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '_' .

binary-digit = '0' | '1' | '_' .

Both standard integer and real specifications are available. In addition, three "radix specifier" formats are available:

$1234 - Specifies hexadecimal format (base 16)

&1234 - Specifies octal format (base 8)

%1010 - Specifies binary format (base 2)

Each alternative format is specified with a "radix introduction" character. These formats can be specified anywhere the Pascaline construct unsigned-constant is specified.

Pascaline accepts a "break character" within numeric constants. The "_" character can be used anywhere within a number:

123_456_789

It cannot be used as the first character of a number, which would make it an identifier.

The meaning of the number is considered without the break characters. The number:

1_2_3

is equivalent to:

123

Break characters can be used in any radix. They are useful for grouping digits so that the result is more readable:

12_334_222 { marked in thousands }

$5566_1212 { marked in 16 bit sections }

6.7      Constant expressions

constant = [ sign ] constant-term { adding-operator constant-term } .

constant-term = constant-factor { multiplying-operator constant-factor } .

constant-factor = '(' constant ')' | 'not' constant-factor | character-string | constant-identifier | unsigned-integer .

multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' .

adding-operator = '+' | '-' | 'or' | 'xor' .

Whenever a constant appears in Pascal, Pascaline is able to accept a constant expression. Constant expression expressions have a syntax that is similar, but not identical to standard expressions in Pascal. Constant expressions can only operate on other constants or constant expression, and cannot include variables.

Note:

1.      The operator xor is defined in 6.8 “Boolean integer operations”.

6.8      Boolean integer operations

expression = simple-expression [ relational-operator simple-expression ] .

simple-expression = [ sign ] term { adding-operator term } .

term = factor { multiplying-operator factor } .

factor = variable-access | unsigned-constant | function-designator | type-identifier '(' expression ')' | set-constructor | '(' expression ')' | 'not' factor .

multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' .

adding-operator = '+' | '-' | 'or' | 'xor' .

Besides the use of and, or and not on Booleans in Pascal, Pascaline allows the use of and, or and not with integer operands. The result is the bitwise 'and', ‘or’ or ‘not’of the bits in the integer.

Pascaline defines a new operator, xor, which has the same precedence as and. It gives the bitwise exclusive or of integers. It can also be used on boolean types, but in that case is equivalent to the operation a <> b.

Boolean operations on negative values are not defined, and may be treated as errors, caught at either compile time or run time, by the implementation.

The boolean integer or operation is equivalent to:

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

 

var i, r, p: integer;

 

begin

 

   if (a < 0) or (b < 0) throw(NegativeInteger);

   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;

 

The boolean integer and operation is equivalent to:

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

 

var i, r, p: integer;

 

begin

 

   if (a < 0) or (b < 0) throw(NegativeInteger);

   r := 0; { clear result }

   p := 1; { set 1st power }

   i := maxint; { set maximum 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;

 

The boolean integer xor operation is equivalent to:

 

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

 

var i, r, p: integer;

 

begin

 

   if (a < 0) or (b < 0) throw(NegativeInteger);

   r := 0; { clear result }

   p := 1; { set 1st power }

   i := maxint; { set maximum 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;

 

6.9      View and out parameters

formal-parameter-list = '(' formal-parameter-section { ';' formal-parameter-section } ')' .

formal-parameter-section = value-parameter-specification | variable-parameter-specification | view-parameter-specification | out-parameter-specification | procedural-parameter-specification | functional-parameter-specification .

value-parameter-specification = identifier-list ':' type-identifier .

variable-parameter-specification = 'var' identifier-list ':' type-identifier .

view-parameter-specification = 'view' identifier-list ':' type-identifier .

out-parameter-specification = 'out' identifier-list ':' type-identifier .

procedural-parameter-specification = procedure-heading .

functional-parameter-specification = function-heading .

A parameter to a procedure or function has a type and a "mode", that indicates the method of its passage.

Besides the Pascal parameter modes of var and value, Pascaline adds a mode introduced by view:

program p;

 

type a = packed array [1..100] of char;

 

procedure x(view b: a);

 

begin

 

   { use, but don’t change, b }

 

end;

 

begin

end.

 

view parameters have the same characteristics as value parameters, and can be treated identically to value parameters. A view parameter cannot be modified or "threatened" in the procedure or function it belongs to. The meaning of "threatened" is the same as for for index variables of ISO 7185 6.8.3.9, and means that the parameter cannot be assigned, used as an index in a for loop, or passed to another routine as a var parameter.

view parameters enable the underlying implementation to create more efficient code in many cases. If the above example was:

program p;

 

type a = packed array [1..100] of char;

 

procedure x(b: a);

 

begin

 

   { code to use array b }

 

end;

 

begin

end.

 

The code would have to copy the actual parameter to b, which can be very inefficient for large arrays. The use of the view parameter allows the system to treat the parameter as a var parameter, but allow any expression to be passed as a value parameter would.

An out parameter is functionally identical to a var parameter except that it indicates that the parameter will be used only to return results to the caller, and that the contents of the variable passed will not be initialized on entry. This allows the processor to check for accesses to the variable before it has been assigned.

program p;

 

type a = packed array [1..100] of char;

 

procedure x(out b: a);

 

begin

 

   { set new contents for the array }

   for i := 1 to 100 do b[i] := i+10

 

end;

 

begin

end.

 

6.10    Extended case statements

case-statement = 'case' case-index 'of' case-list-element { ';' case-list-element } [ ';' ] 'end' .

case-list-element = case-list-statement | case-list-default .

case-list-statement = case-constant-list ':' statement .

case-list-default = 'else' statement .

case-constant-list = case-constant-range { ',' case-constant-range } .

case-constant-range = case-constant [ '..' case-constant ] .

case-index = expression .

A case statement can feature an else clause at the end of all case selects for a given case statement:

program p(output);

 

var y: integer;

 

begin

 

   { code that sets y }

 

   case y of

 

      1: write('one');

      2: write('two')

      else write('value unknown')

 

   end

 

end.

 

The statement indicated as else will be executed if the case select value does not match any of the values in the case list.

A case select value can appear as a range of values:

program x;

 

var y: integer;

 

begin

 

   case x of

 

      1: write('one');

      2: write('two');

      3..5: write('three to five')

 

   end

 

end.

 

Is equivalent to:

program p;

 

var y: integer;

 

begin

 

   { statements that set y }

   case y of

 

      1: write('one');

      2: write('two');

      3, 4, 5: write('three to five')

 

   end

 

end.

 

6.11    Variant record case ranges

The case constants on a variant record specification can appear as ranges:

record-type = 'record' field-list 'end' .

field-list = [ ( fixed-part [ ';' variant-part ] | variant-part ) [ ';' ] ] .

variant-part = 'case' variant-selector 'of' variant { ';' variant } .

variant = case-constant-list ':' '(' field-list ')' .

case-constant-list = case-constant-range { ',' case-constant-range } .

case-constant-range = case-constant [ '..' case-constant ] .

 

program p;

 

type sr = 1..5;

 

var r: record

 

          i: integer;

          case s: sr of

 

             1: (q: integer; b: boolean);

             2: (z: real; t: array 10 of integer);

             3..5: (o: set of char; j: integer)

 

       end;

 

begin { program p }

end.

 

Is equivalent to:

program p;

 

type sr = 1..5;

 

var r: record

 

          i: integer;

          case s: sr of

 

             1: (q: integer; b: boolean);

             2: (z: real; t: array 10 of integer);

             3, 4, 5: (o: set of char; j: integer)

 

       end;

 

begin { program p }

end.

 

Notes:

1.      For each case range, the starting constant must be less than or equal to the ending constant.

2.      The ISO 7185 Pascal requirement that all values of the tagfield be present remains.

6.12    Array type shorthand

array-type = 'array' [ dimension-specifier ] 'of' component-type .

dimension-specifier = index-specifier | range-specifier .

index-specifier = '[' index-type { ',' index-type } ']' .

range-specifier = unsigned-integer { ',' unsigned-integer } .

Pascaline features a special declaration format for the most common case of integer indexed arrays:

type x = packed array 10 of char;

type y = array 20,10 of integer;

 

are equivalent to:

type x = packed array [1..10] of char;

type y = array [1..20,1..10] of integer;

 

Denoting an array index by size, instead of by an index specification, uses a different syntax, without the '[' and ']' characters, to make it clear what kind of array specification is being used.

6.13    Container arrays

array-type = 'array' [ dimension-specifier ] 'of' component-type .

The specification of only fixed arrays in ISO 7185 Pascal caused several practical issues with the language. Pascaline has the concept of "container arrays", which are array types specified without index specifications.

type a = array of integer;

 

Container arrays are a "template type" which cannot be used to directly specify a static variable without qualification. For example:

{ incorrect example }

 

program p;

 

type a = array of integer;

 

var b: a;

 

begin

end.

 

Would not be correct because type a does not contain enough information, namely the size of the array, to define the static variable b.

The power of container arrays is their ability to be bound to a fully defined static array at a time later than when the program is compiled. This can happen in three different ways:

1.      When a parameter is accepted for a procedure or function.

2.      As a result of the creation of an anonymous array in dynamic storage.

3.      By use of a parameterized variable declaration (see 6.14 “Parameterized variables”).

It is important to understand that Pascaline does not specify what are called "dynamic arrays", which is the ability to resize an array at runtime.  Pascaline simply provides the means to create fixed arrays of any size at runtime and bind to them, or to create generate purpose procedures or functions that can bind to any size array at runtime. This distinction may seem to be unnecessary, but in practice it dramatically simplifies implementation of the concept.

Container types can have multiple index levels:

type a = array of array of array of boolean;

 

Container array types are compatible with other container and fixed array types that:

1.      Have the same base types.

2.      Have the same packed/unpacked status.

3.      Have the same number of index levels.

Thus, the following types are compatible:

type a = packed array [1..100] of char;

 

and

type b = packed array of char;

 

type a = array [1..10, 1..100] of integer;

 

and

type b = array of array of integer;

 

A container array can be used for a procedure or function parameter:

type string = packed array of char;

 

procedure x(var s: string);

 

And can use any mode.

As with ISO 7185 Pascal array parameters, if the parameter is passed by value, there can be considerable expense associated with copying the array to private location for the procedure or function.

When container arrays are used as parameters, they are simply serving as holders for an existing array. In the case of variable parameters, the array was created elsewhere in the code and the parameter simply points to it. In the case of value parameters, the array is created anew in a private location, and the existing array copied to it. In both cases, the information needed to complete the template for the array exists elsewhere.

Another way to allocate a container array is to use new to allocate it dynamically:

program p;

 

type ap = ^a;

     a  = packed array of char;

 

var b: ap;

 

begin

 

   new(b, 10);

   b := 'hi there  ';

 

end.

 

The call of new must specify the size of all indices, in the same order as the indices appear in the declaration.

Container arrays have the interesting property that they are free of index typing. Container arrays are considered to be compatible with other arrays (standard or container) that have the same number of base elements.

This means that the following assignments are possible:

program p;

 

type a = packed array [20..120] of char;

     b = array of char;

     c = ^b;

 

var q: a;

    x: c;

 

begin

 

   new(x, 100);

 

   x^ := q;

 

   q := x^;

 

end.

 

It does not matter what the first or last element of the array is. When elements are copied from or to a compatible container, or when a container is used to reference a standard array, the elements are matched up from the first to the last without regard to the exact number of the index used. In the last example, q[20] and x[1] refer to the same element. The equivalent of the above copy operation is:

program p;

 

type a = packed array [20..120] of char;

     b = array of char;

     c = ^b;

 

var q: a;

    x: c;

 

begin

 

   new(x, 100);

 

   { x := q; }

 

   for i := 1 to 100 do x^[i] := q[i+20-1];

 

   { q := x; }

 

   for i := 1 to 100 do q[i+20-1] := x^[i]

 

end.

 

When a container array is indexed, the method of specifying its indices is always the integers 1 to n, where n is last element of the array. The last element of a container array, which happens to also be its length, can be found by the predefined function:

max(a, l);

 

Where a is the container array, and l is the indexing level. For example:

program p;

 

type a = array of array of array of integer;

     b = ^a;

 

var c: b;

    i: integer;

 

begin

 

   new(c, 10, 20, 30);

 

   i := max(c, 2)

 

end.

 

Finds the second level index length of b, which is 20.

Specifying a level for max is optional. The function call:

max(a);

 

is equivalent to:

max(a, 1);

 

Container arrays make it possible to have a type that represents a string, or packed array of characters with a starting index of 1:

type string = packed array of char;

 

This is a standard system definition in Pascaline. In addition, a pointer to a string is also standard:

type pstring = ^string;

 

6.14    Parameterized Variables

Although containers cannot be directly used as the type of a variable, or part of a variable, they can be used for the type of a parameterized variable declaration:

variable-declaration = identifier-list [ ‘(‘ expression { ‘,’ expression ‘)’ ] ':' type-denoter .

variable-declaration-part = [ 'var' variable-declaration ';' { variable-declaration ';' } ] .

program p;

 

type z = array of integer;

 

procedure q(v: z);

 

var a(max(v)): array of integer;

    i:         integer;

 

begin

 

   for i := 1 to max(v) do a[i] := v[i]+1

 

end;

 

begin

end.

 

Variables which are declared using containers use a parameterized form that takes one or more expressions on the left side, which are used to fulfill the indices that appear in the type of the variable on the right side.

The parameter expressions must be integer.

Each expression will be used to match an index in the type. If the type is formed from a nested declaration, the indices are processed from the outermost declaration to innermost. If multiple dimension arrays exist, the indices appear from major to minor.

Every index in the type must be matched. If there are more or fewer index expressions that there are indices in the type, it is an error.

The expression used for an index parameter is not limited. Variables, parameters and functions can be used, but all of the elements used must be fully defined.

The evaluation of the index parameters is performed before the code in the block for which the variable is declared is executed. The indices do not vary during the execution of the declaring block. This means the following variant of the above code would function correctly:

program p;

 

type z = array of integer;

 

procedure q(l: integer; v: z);

 

var a(l): array of integer;

    i:    integer;

 

begin

 

   l := 5;

   for i := 1 to l do a[i] := v[i]+1

 

end;

 

var r(10): z;

    i:     integer;

 

begin

 

   for i := 1 to 10 do r[i] := i+10;

   q(10, r)

 

end.

 

If a parameterized variable statement contains only constant parameters, the compiler may treat the variable as equivalent to a fixed type with the same parameters. This allows a container type to be used as a “template” type to create static variables:

program p;

 

type z = array of integer;

 

var a(10): z; ! an array of 10 integers

    b(20): z; ! an array of 20 integers

 

begin

 

end.

 

If the parameterized variable expression contains local variables, it is an error, since such variables are, by definition, undefined at the start of the block. Note that this does not apply to parameters, which are initialized externally to the procedure or function that contains the parameterized variable statement.

Parameterized variables allow the specification of fixed types from abstract types. This allows both the use of types for general classes of types, as well as moving the sizes of arrays out of type descriptions.

6.15    Extended write/writeln statements

Pascaline extends the meaning of field width parameters in ISO 7185 6.9.3.1 to include negative or zero field widths. The appearance of a negative value as a field width has the same effect as the absolute value of the field width, except that the resulting character translation is set left justified within its field. i.e., the spaces that are specified to pad each output format to the field width are output after the contents of the field, not before.

program p(output);

 

var i: integer;

 

begin

 

   write(i:-10)

 

end.

 

Would output the integer i in 10 spaces at least, with any padding to the right side of the number.

The behavior of a fielded write for integers is equivalent to:

program p(output);

 

procedure WriteInteger(var f: text; i: integer; fl: integer);

 

var c: integer;

    p: integer;

 

begin

 

   if fl < 0 then begin ! left justified

 

      ! determine the number of required characters

 

      c := 0;

      if i < 0 then c := c+1; ! count sign

      p = maxint; ! set maximum power

      ! count digits

      while p > 0 do

         begin if abs(i) >= p then c := c+1; p := p div 10 end;

      write(f, i:1); ! output minimum format

      if f > c then write(f, ‘ ‘:fl-c) ! complete justification

 

   end else write(f, i:fl); ! output regular format

 

end;

 

begin

 

   WriteInteger(output, 20, -10)

 

end.

 

For real values in the floating point format, there is no change for left justified formatting. This occurs because there are no blanks used to justify such a number. The precision of the fraction is simply extended to fill the field. Thus:

program p(output);

 

var r: real;

 

begin

 

   write(r:-20)

 

end.

 

Is equivalent to:

program p(output);

 

var r: real;

 

begin

 

   write(r:20)

 

end.

 

There is no difference between the left justified format for a floating point representation, but there is also no error.

For a real value output in fixed point format:

program p(output);

 

var r: real;

 

begin

 

   write(r:-20:5)

 

end.

 

The equivalent code is:

program p(output);

 

procedure WriteRealFixed(var f: text; r: real; fl: integer;

                         fr: integer);

 

var c: integer;

    p: real;

 

begin

 

   if fl < 0 then begin ! left justified

 

      ! determine the number of required characters

 

      c := 2; ! minimum field includes ‘0.’

      if r < 0 then c := c+1; ! count sign

      p = 10.0; ! set minimum for extra digits

      ! calculate digits beyond ‘0.’

      while p <= abs(r) do begin c := c+1; p := p*10 end;

      write(f, i:c:fr); ! output minimum format

      if f > c then write(f, ‘ ‘:f-(c+fr)) ! complete justification

 

   end else write(f, i:f); ! output regular format

 

end;

 

begin

 

   WriteRealFixed(output, r, -20, 5)

 

end.

 

A zero field parameter has practical use only with string type and character type parameters. This is because integer and real types have minimum output format sizes. An example of use with strings is:

program p(output);

 

var i: integer;

 

begin

 

   for i := 11 downto 0 do writeln(‘hello there’: i)

 

end.

 

Hello there

Hello ther

Hello the

Hello th

Hello t

Hello

Hello

Hell

Hel

He

H

(blank)

 

In the code:

program p(output);

 

procedure WriteSpaces(s: integer);

 

begin

 

   write(‘ ‘: s)

 

end;

 

begin

 

   WriteSpaces(10)

 

end.

 

Serves to output a given number of spaces, from 0 to N.

6.16    Extended read/readln statements

read/readln statements are symmetrical with their write/writeln counterparts for text files. Variable parameters can accept field specifications. String variables can be read. Constant string parameters can appear, to be matched to input.

The net effect of symmetrical read/readln operations is to allow files generated by write/writeln statements to also be read by read/readln statements.

A standard ISO 7185 Pascal string variable or Pascaline string variable can appear as a read/readln parameter:

program p(input);

 

var s: packed array 10 of char;

 

begin

 

   read(s);

 

end.

 

The equivalent code is:

program p(input);

 

var s: packed array 10 of char;

 

procedure ReadString(var f: text; var s: string);

 

var i: integer;

 

begin

 

   for i := 1 to max(s) do read(f, s[i]);

 

end;

 

begin

 

   ReadString(input, s)

 

end.

 

If the end of line is encountered, it is read as a space and the read operation continues. If end of file is encountered, it is an error.

For fielded read parameters, an integer value field, which can be any expression, appears after the read parameter:

program p;

 

var f: text;

    i: integer;

 

begin

 

   read(f, i:10);

 

end.

 

The fielded read requires the input integer to be complete within the specified number of characters, disregarding any leading or trailing blanks.

The equivalent code to read an integer is:

program p;

 

var f: text;

    i: integer;

 

procedure ReadInteger(var f: text; var i: integer; fl: integer);

 

var s: integer;

 

function NextChar: char;

 

begin

 

   { if past the field, terminate with space }

   if fl = 0 then NextChar := ‘ ‘

   else NextChar := f^

 

end;

 

procedure GetChar;

 

begin

 

   get(f);

   fl := fl-1

 

end;

 

begin

 

   s := +1; { set sign }

   { skip leading spaces }

   while (NextChar = ‘ ‘) and not eoln(f) do GetChar;

   if not (NextChar in [‘+’, ‘-‘, ‘0’..’9’]) then

      throw(InvalidIntegerFormat);

   if NextChar = ‘+’ then GetChar

   else if NextChar = ‘-‘ then begin GetChar(f); s := -1 end;

   if not (NextChar in [‘0’..’9’]) then throw(InvalidIntegerFormat);

   i := 0; { clear initial value }

   while (NextChar in [‘0’..’9’]) do begin { parse digit }

 

      i := i*10+ord(NextChar)-ord(‘0’); { add in new digit }

      GetChar

 

   end;

   { make sure the rest of the field is spaces }

   while fl > 0 do begin

 

      if NextChar <> ‘ ‘ then throw(InvalidIntegerFormat);

      GetChar

 

   end

 

end;

 

begin

 

   ReadInteger(f, i, 10)

 

end.

 

Reading a character with a field is similar

program p;

 

var f: text;

    c: char;

 

begin

 

   read(f, c:10);

 

end.

 

The equivalent code is:

program p;

 

var f: text;

    c: char;

 

procedure ReadChar(var f: text; var c: char; fl: integer);

 

begin

 

   read(f, c); ! get the character

   ! make sure the rest of the field is spaces

   while fl > 0 do begin

 

      if f^ <> ‘ ‘ then throw(FieldNotBlank);

      get(f);

      fl := fl-1

 

   end

 

end;

 

begin

 

   ReadChar(f, c, 10)

 

end.

 

When reading a string, the default field is equivalent to the number of characters in the string. If a field is present, and is greater than the number of characters in the string, then the string is expected to appear with a number of leading blanks. To specify a number of trailing blanks, a negative field is specified.

In both cases, if the field is smaller than the number of characters in the string, only that number of characters will be read. There is no initialization implied for characters in the string past the number of characters in the field.

If the field is 0, the space padded string mode is entered. In this mode, all characters that are present in the input before any end of line or end of file are read into the string, then the remaining characters in the string are set to blanks. In this mode it is an error if there are more characters present before the end of line or end of file than there are available in the string.

program p;

 

var f: text;

    s: packed array [1..20] of char;

 

begin

 

   read(f, s:10);

 

end.

 

The equivalent code is:

program p;

 

var f: text;

    s: packed array [1..20] of char;

 

procedure ReadString(var f: text; var s: string; fl: integer);

 

var l: integer; { net length of string }

    i: integer;

 

procedure SkipSpaces(c: integer);

 

begin

 

   while c > 0 do begin

 

      if f^ <> ‘ ‘ then throw(FieldNotBlank);

      get(f);

      c := c-1

 

   end

 

end;

 

begin

 

   if fl = 0 then begin { padded mode }

 

      i := 1; { set start of string }

      while not eoln(f) and not eof(f) do begin

 

         if i > max(s) do throw(InputExceedsString);

         read(s[i]);

 

      end;

      { clear the rest of the string to blanks }

      while i < max(s) do s[i] := ‘ ‘

 

   end else begin

 

      l := max(s); { find net length of string }

      if abs(fl) < l then l := fl;

      { skip leading spaces }

      if -fl > max(s) then SkipSpaces(max(s)+fl);

      for i := 1 to l do read(f, s[i]); { get string characters }

      { skip trailing spaces }

      if fl > max(s) then SkipSpaces(max(s)-fl)

 

   end

 

end;

 

begin

 

   ReadString(f, s, 10)

 

end.

 

For real variables, the results are similar to that of integer:

program p;

 

var f: text;

    r: real;

 

begin

 

   read(f, r:10);

 

end.

 

The equivalent code is:

program p;

 

var f: text;

    r: real;

 

procedure ReadReal(var f: text; var r: real; fl: integer);

 

var i: integer;

 

{ find power of ten efficiently }

 

function pwrten(e: integer): real;

 

var t: real; { accumulator }

    p: real; { current power }

 

begin

 

   p := 1.0e+1; { set 1st power }

   t := 1.0; { initalize result }

   repeat

 

      if odd(e) then t := t*p; { if bit set, add this power }

      e := e div 2; { index next bit }

      p := sqr(p) { find next power }

 

   until e = 0;

   pwrten := t

 

end;

 

function NextChar: char;

 

begin

 

   { if past the field, terminate with space }

   if fl = 0 then NextChar := ‘ ‘

   else NextChar := f^

 

end;

 

procedure GetChar;

 

begin

 

   get(f);

   fl := fl-1

 

end;

 

procedure ReadInteger(var i: integer);

 

var s: integer;

 

begin

 

   s := +1; { set sign }

   if not (NextChar in [‘+’, ‘-‘, ‘0’..’9’]) then

      throw(InvalidRealFormat);

   if NextChar = ‘+’ then GetChar

   else if NextChar = ‘-‘ then begin GetChar(f); s := -1 end;

   if not (NextChar in [‘0’..’9’]) then throw(InvalidRealFormat);

   i := 0; { clear initial value }

   while (NextChar in [‘0’..’9’]) do begin { parse digit }

 

      i := i*10+ord(NextChar)-ord(‘0’); { add in new digit }

      GetChar

 

   end

 

end;

 

begin { ReadReal }

 

   { skip leading spaces }

   while (NextChar = ‘ ‘) and (fl > 0) do GetChar;

   ReadInteger(i); { read integer section }

   r := i; { convert integer to real }

   if NextChar in ['.', 'e', 'E'] then begin { it's a real }

 

      if NextChar = '.' then begin { decimal point }

 

         GetChar; { skip '.' }

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

            throw(InvalidRealFormat');

         p := 1.0; { initialize power }

         while NextChar in ['0'..'9'] do begin { parse digits }

 

            p := p/10.0; { find next scale }

            { add and scale new digit }

            r := r+(p * (ord(NextChar) - ord('0')));

            GetChar { next }

 

         end

 

      end;

      if NextChar in ['e', 'E'] then begin { exponent }

 

         GetChar; { skip 'e' }

         if not (NextChar in ['0'..'9', '+', '-']) then

            throw(InvalidRealFormat);

         ReadInteger(i); { get exponent }

         { find with exponent }

         if i < 0 then r := r/pwrten(i) else r := r*pwrten(i)

 

      end

 

   end;

   { make sure the rest of the field is spaces }

   while fl > 0 do begin

 

      if NextChar <> ‘ ‘ then throw(InvalidRealFormat);

      GetChar

 

   end

 

end;

 

begin

 

   ReadReal(f, r, 10)

 

end.

 

Constant strings are allowed to appear in the read/readln parameter list:

program p;

 

var f: text;

    i: integer;

 

begin

 

   read(f, ‘The answer is: ‘, a,  ‘ resulting in: ‘, b);

 

end.

 

The effect of such a constant is that each character of the input is matched to the characters in the string, in turn, regardless of if the end of line is true. If the character is matched, it is read and thrown away. If the character is not matched, it is an error.

The following code shows the equivalent of such a match.

program p;

 

var f: text;

    i: integer;

 

procedure ReadConstant(var f: text; view s: string);

 

begin

 

   for i := 1 to max(s) do

      if f^ <> s[i] then throw(UnmatchedConstantCharacter);

   get(f)

 

end;

 

begin

 

   ReadConstant(f, ‘The answer is: ‘)

 

end.

 

6.17    Type converters/restrictors

expression = simple-expression [ relational-operator simple-expression ] .

simple-expression = [ sign ] term { adding-operator term } .

term = factor { multiplying-operator factor } .

factor = variable-access | unsigned-constant | function-designator | type-identifier '(' expression ')' | set-constructor | '(' expression ')' | 'not' factor .

multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' .

adding-operator = '+' | '-' | 'or' | 'xor' .

Pascal defines the function ord to convert any scalar or character type to integer, and defines the function chr to convert integer to character. Pascaline extends this system to include enumerated types "type converter":

program p;

 

type a = (one, two, three);

 

var x: a;

 

begin

 

   x := a(1);

 

end.

 

In the example  the result of a(1) is the enumerated type constant two. Transfer from an integer to an enumerated type is the only new type conversion defined in Pascaline.

A similar appearing construct is the “type restrictor”:

program p;

 

type a = 20..30;

 

var y: integer;

 

begin

 

   y := a(y+1);

 

end.

 

The assignment y := a(y+1) would seem to have no function. However, the compiler can take this as a hint that instead of promoting the expression y+1 to the full size of an integer, that the operation can be performed in only the precision required for values within 20..30. This can enable more efficient processing of expressions on some machines.

When a type restrictor appears, the compiler can generate an error for values in the restricted value that cannot fit in the range of the target type. Type converters and restrictors never simply discard values.

The value within a type restrictor must be assignment compatible with the type specified in the type restrictor.

6.18    Fixed types

block = { declaration } [ 'private' declaration ] statement-part [ ';' statement-part ] .

declaration = label-declaration-part | constant-definition-part | type-definition-part | variable-declaration-part |fixed-declaration-part | procedure-declaration ';' | function-declaration ';' .

fixed-declaration-part = [ 'fixed' fixed-declaration ';' { fixed-declaration ';' } ] .

fixed-declaration = identifier-list ':' type-denoter '=' value-constructor.

value-constructor = array-value-constructor | record-value-constructor | constant .

array-value-constructor = 'array' value-constructor { ',' value-constructor } 'end' .

record-value-constructor = 'record' value-constructor { ',' value-constructor } 'end' .

In addition to declaring variables, Pascaline can declare a program construct that appears anywhere a variable can, but is defined completely at compile time:

program p;

 

fixed a: integer = 1;

      b: array [1..10] of integer =

            array 5, 6, 8, 2, 3, 5, 9, 1, 12, 85 end;

      c: record a: integer; b: char end = record 1, 'a' end;

      d: array [1..5] of packed array [1..5] of char = array

 

         'tooth',

         'trap ',

         'same ',

         'fall ',

         'radio'

 

      end;

 

begin

end.

 

The declaration of a fixed is similar to a var declaration, but each variable is given a "value" part that contains a value constructor. A value constructor is a series of constants or other value constructors separated by ‘,’s. As in the case of character array constant assignment to character array variables, a constant string can be used to specify the value of a fixed character array, and must have the same number of characters as the definition.

Fixed types can be used anywhere a variable type can, but a fixed type cannot be "threatened" in the sense of the for variable threat of ISO 7185 6.8.3.9.

6.19    Extended file procedures and functions

Pascaline defines several additional functions dealing with files. Files that are not declared as external via the program header are normally given the property that they are anonymous and may be deleted at the end of the program.  In Pascaline, such files can also be named using the function assign:

program p;

 

var f: text;

 

begin

 

   assign(f, 'myfile');

   reset(f);

 

   { statements to use file f }

 

   close(f)

 

end.

 

assign takes any string (defined in ISO 7185 Pascal as a packed array of characters with a starting index of 1 and any length). The format of the file name contained in the string is entirely implementation dependent, but implementations will honor, at minimum, the conventions that:

1.      Leading and trailing spaces in the name are ignored, and removed if required.

2.      That the characters in the set ['a'..'z', 'A'..'Z', '0'..'9', '_'] are valid in a filename.

3.      The filename must begin with characters from the set ['a'..'z', 'A'..'Z','_'].

Notes:

1.      These are the same conventions as used for identifiers in Pascaline.

2.      This is only a subset of implementation defined filename conventions. The particular Pascaline implementation may have its own additional requirements for the formatting of filenames that are a superset of the above conventions.

The Pascaline standard library services has a higher level structuring of filenames that are upward compatible with the above conventions. See Annex G.

The existence of a named file implies, but does not require, that the file is not deleted at the end of the program run. It further implies that applying reset to a named file will allow its preexisting contents to be accessed.

As in ISO 7185 Pascal, applying reset or rewrite to a file causes the file to change from the "undefined" state to "read" for reset, and "write" for rewrite. It is an error to apply assign to a file that is not in the undefined state, that is, to rename it while it is active.

A file must be in the undefined state to have assign applied to it. The effect of multiple assign operations applied to the same file while in the undefined state is itself undefined.

To allow the processing of multiple files by name, the procedure close exists:

 

program p;

 

var f: text;

    names: array 5 of packed array 10 of char = array

 

       ‘myfile    ‘,

       ‘thisfile  ‘,

       ‘thatfile  ‘,

       ‘nextfile  ‘,

       ‘lastfile 

 

    end;

    i: integer;

 

begin

 

   for i := 1 to 5 do begin

 

      assign(f, names[i]);

 

      { statements that use file f }

 

      close(f)

 

   end

 

end.

 

close causes bond between the file variable and the named file itself to be broken, and the file state to be returned back to undefined. In this state, it can have assign applied again. In this way, a sequence of named files can be processed. close implies that if the file is anonymous, it is deleted, and that the file returns to being anonymous unless assigned again.

Because in Pascaline, a named file is implied to persist beyond the end of a program, it is also implied that each file that exists in a read or write state has a close performed on it automatically either when the program ends, or when the file variable falls out of activation.

ISO 7185 Pascal defines files as a series of elements which can be examined in turn. Pascaline defines the standard function length to give the number of elements within a file:

program p(output);

 

var f: file of integer;

 

begin

 

   assign(f, ‘myfile’);

   writeln('The length of the file is: ', length(f));

   close(f)

 

end.

 

The function length is equivalent to:

program p(output);

 

type fi: file of integer;

 

var f: fi;

 

function length(var f: fi): lcardinal;

 

var l, r, p: integer;;

 

begin

 

   l := 0; { clear length }

   r := 0; { clear remainder }

   { find remaining elements }

   while not eof(f) do begin get(f); r := r+1 end;

   { rewind and count the total elements }

   reset(f);

   while not eof(f) do begin get(f); l := l+1 end;

   p := l-r; { find position from length – remainder }

   { find original position }

   reset(f);

   while p > 0 do begin get(f); p := p-1 end;

 

   length := l { return length }

 

end;

 

begin

 

   assign(f, ‘myfile’);

   reset(f);

   writeln(‘Length of myfile: ‘, length(f))

   close(f)

 

end.

 

The length function cannot be applied to a file of type text, because the length of line endings is implementation defined, so the length of a text file is implementation defined as well.

Each element of a Pascal file can be enumerated. In Pascaline, the elements of a file that is not of type text are numbered from 1 to n, where n is the last element of the file. The current location within the file is found with the built in function location:

program p(output);

 

var f: file of integer;

 

begin

 

   writeln('The location in the file is: ', location(f));

 

end.

 

The function location is equivalent to:

program p;

 

type fi: file of integer;

 

var f: fi;

 

function location(var f: fi): lcardinal;

 

var l, r, p, c: integer;

 

begin

 

   l := 0; { clear length }

   r := 0; { clear remainder }

   { find remaining elements }

   while not eof(f) do begin get(f); r := r+1 end;

   { rewind and count the total elements }

   reset(f);

   while not eof(f) do begin get(f); l := l+1 end;

   p := l-r; { find position from length – remainder }

   { find original position }

   reset(f);

   c := p; { set count from position }

   while c > 0 do begin get(f); c := c-1 end;

 

   location := p { return location }

 

end;

 

begin

 

   assign(f, ‘myfile’);

   reset(f);

   writeln(‘Location of myfile: ‘, location(f))

   close(f)

 

end.

 

The current location within a file can be set by the built in procedure position:

program p;

 

var f: file of integer;

 

begin

 

   assign(f, ‘myfile’);

   reset(f);

   position(f, 10)

 

   { statements to use f }

 

   close(f)

 

 

end.

 

The procedure position is equivalent to:

program p;

 

type fi: file of integer;

 

var f: fi;

 

procedure position(var f: fi; p: integer);

 

begin

 

   reset(f);

   while p > 1 do begin get(f); p := p-1 end

 

end;

 

begin

 

   assign(f, ‘myfile’);

   reset(f);

   position(f, 10);

 

   { statements to use f }

 

   close(f)

 

end.

 

position will work with any element from 1 to n+1, where n is the last element of the file. position allows the location to be set one beyond the length of the file so that the file can be extended at the end.

As with length, there is no way to apply either location or position to a text file.

It is an error to apply position to an undefined file.

In ISO 7185 Pascal, there is no way to update a preexisting file with new data. In Pascaline the procedure update can be used instead of rewrite:

program p;

 

var f: file of integer;

 

begin

 

   assign(f, 'myfile');

   update(f);

 

   { statements to use f }

 

end.

 

The procedure update for integers is equivalent to:

program p;

 

type fi: file of integer;

 

procedure update(var f: fi);

 

var cpy: fi;

    i:   integer;

 

begin

 

   ! copy previous contents of file

 

   reset(f);

   rewrite(cpy);

   while not eof(f) do begin read(f, i); write(cpy, i) end;

  

   ! change modes and copy back to original file

 

   rewrite(f);

   reset(cpy);

   while not eof(cpy) do begin read(cpy, i); write(fi, i) end

 

end;

 

var f: fi;

 

begin

 

   assign(f, 'myfile');

   update(f);

 

   ! statements to use f

 

end.

 

The file that update is applied to must exist.

As for rewrite, update places the file in write mode. However, update does not clear the previous contents of the file. Update sets the location within the file at 1, just as reset does. If the common operation of updating a file at the end is wanted, the following code does this:

program p;

 

var f: file of integer;

 

begin

 

   assign(f, 'myfile');

   update(f);

   position(f, length(f)+1);

 

   ! statements to use f

 

end.

 

update only works with non-text files. The built in procedure append performs the same action as above, but works with both text and non-text files:

program p(output);

 

var f: text;

 

begin

 

   assign(f, 'myfile');

   append(f);

   writeln(f, 'hi there');

 

end.

 

The procedure append for text files is equivalent to:

program p;

 

procedure append(var f: text);

 

var cpy: text;

    c:   char;

 

begin

 

   ! copy previous contents of file

 

   reset(f);

   rewrite(cpy);

   while not eof(f) do begin

 

      if eoln(f) then begin readln(f); writeln(cpy) end

      else begin read(f, c); write(cpy, c) end

 

   end;

  

   ! change modes and copy back to original file

 

   rewrite(f);

   reset(cpy);

   while not eof(cpy) do begin

 

      if eoln(cpy) then begin readln(cpy); writeln(f) end

      else begin read(cpy, c); write(f, c) end

 

   end

 

end;

 

var f: text;

 

begin

 

   assign(f, 'myfile');

   append(f);

 

   ! statements to use f

 

end.

 

The file that append is applied to must exist.

To determine if a file by name exists in the system, the function exists can be used:

program p(output);

 

var f: text;

 

begin

 

   if exists(‘thisfile’) then

      { operate on ‘thisfile’ }

 

end.

 

The exists function takes a variable reference to a Pascaline string, and returns a boolean value that is true if the file exists.

The exists function can be used to determine beforehand if a reset will yield an error because of a non-existent file.

To delete a file by name, the delete procedure is used:

program p(output);

 

begin

 

   delete('oldfile')

 

end.

 

delete accepts a variable reference to a string, and causes the file to be removed from the system. It is an error if the file does not exist.

To change the name of an existing file, the change procedure is used:

program p(output);

 

begin

 

   change('newname', 'oldname')

 

end.

 

The file with the name of the second parameter is changed to be the first parameter. Both parameters are variable references to strings. It is an error if the second parameter does not exist in the system, and also if the first parameter exists before the change call. It is also an error if any differences exist in the names besides just their principal names. This rule forbids, for example, the changing of the location or system parameters of the file using the change call.

6.20    Added program header standard bindings

Besides the ISO 7185 Pascal textfile external bindings of input and output, there are three new external bindings defined by Pascaline:

error

 

This file can be used to output error messages or warnings to. It may be aliased to output by an implementation. The purpose of the error file is to provide a output file that will always go to the user's console, and cannot be redefined as routed to another display device.

list

 

This file is used to output for what is assumed to be printout from any attached hard copy device. The implementation may alias this file to the output file if such a device is not available, or if hard copy is not desired.

command

 

The command file is a text line or series of text line that deliver instructions to the running program. Most commonly, it carries a single line containing the remaining text of the command line that activated the running program, after the command name itself is discarded. However, it can contain any instruction line, and can even be directed to be an entire file containing such commands.

The exact format of the commands and parameters contained in file are implementation dependent. If the implementation has no concept of a command line, the file can be assigned to another file, or may appear empty.

Since on many systems a command line exists as a line of text in memory, not as part of a file system, it is understood that the implementation will simulate the access to such a line as a file, if that is required.

In the Pascaline specification, implementers are reminded of the requirements of ISO 7185 6.10 "Programs" wherein it is an error if a program parameter is acted on and cannot complete that action. This clause of ISO 7185 Pascal specifically forbids ignoring the program parameters.

Further, in Pascaline it is strongly suggested that the program parameters which are common text files be connected, or can be caused to connect, to external files by binding to command file names. (See Annex C).

6.21    Redeclaration of forwarded procedures and functions

In Pascaline, the parameters of a forwarded procedure or function can be repeated. As in ISO 7185 Pascal, the names of the parameters are the same as the original names in the forwarded header. The new names, if they happen to be different in the repeated header, are ignored. However, the two parameter lists are checked for "congruency" using the same rules as procedure and function parameters in ISO 7185 6.6.3.6 “Parameter list congruity”.

Repeating the parameters in a forwarded procedure or function both increases the self documenting nature of a program, by keeping the parameters close to the actual body of the procedure or function, as well as making it easier to create such headers, by simple block copy.

6.22    Anonymous function result

Pascaline has an alternate method to indicate a function result:

function-declaration = function-heading ';'directive | function-identification ';' function-block | function-heading ';' function-block .

function-block = block .

block = { declaration } [ 'private' { declaration } ] statement-part [ ';' statement-part ] .

compound-statement = 'begin' statement-sequence [ ‘result’ expression ] 'end' .

At the end of the main block of a function, a result statement can appear:

program p;

 

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

 

begin

 

   result a+b

 

end;

 

The result statement is an alternative to the ISO 7185 arrangement of assigning the result to the name of a function that is active. It can only be used in a function, and it can only be used at the end of the function. It can only give the result of the enclosing function (in contrast to ISO 7185 Pascal function results). It cannot be used in conjunction with a ISO 7185 Pascal assignment to the name of the function appearing in either the block of the function whose result is to be set, nor any nested block. Thus, the following example is illegal:

{ illegal example }

 

program p;

 

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

 

procedure q;

 

begin

 

   y := 1

 

end;

 

begin

 

   result a+b

 

end;

 

But this example is legal:

program p;

 

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

 

function q: integer;

 

begin

 

   y := a+b;

 

   result 1

 

end;

 

begin

 

   a := q

 

end;

 

The assignment to the function result y is legal in q, even though q is using the result method, because the function y is using the ISO 7185 named function result method.

Unnamed function results give a clear way to indicate the function result, that obeys the single entry/single exit rule with the function result formed at the exit. They are also required in order to indicate the result of an operator overload function (See 6.25Operator overloads”).

6.23    Extended Function results

Function results can be any type, including structured:

 

program p;

 

type a: array 10 of integer;

 

function y: a;

 

var z: a;

    i: integer;

 

begin

 

   for i = 1 to 10 do z[i] := i+10;

 

   y := a

 

end;

 

begin

end.

 

Such extended function results imply greater costs due to the need to copy the structure back to the caller.

A function result cannot be a file, nor a structure having any part that is a file..

Function results can be container arrays, but must be compatible with the result.

The ISO 7185 rule that function results must be assignment compatible with the function result type remains.

6.24    Halt procedure

A standard Pascaline procedure halt exists:

program p;

 

begin

 

   if not exists(‘myfile’) begin

 

      writeln(‘needed file does not exist’);

      halt

 

   end

 

end.

 

The halt procedure causes the program, and all of its threads, to immediately terminate. It is equivalent to throwing the unspecified global exception.

The equivalent code for a program block is:

program p;

 

label 99;

 

begin

 

   if not exists(‘myfile’) begin

 

      writeln(‘needed file does not exist’);

      goto 99

 

   end;

 

   99:

 

end.

 

The halt procedure will terminate the enclosing program no matter which module it appears in.

6.25    Overloading of procedures and functions

procedure-heading = attribute 'procedure' identifier [ formal-parameter-list ].

function-heading = attribute 'function' identifier [ formal-parameter-list ] ':' result-type.

attribute = 'overload' | 'static' | 'virtual' | 'override' | ‘operator’ .

The attribute overload can be used to specify that one procedure or function forms an overload group with another:

 

program p;

 

procedure x(y: integer);

 

begin

 

   { statements to operate on parameter y }

 

end;

 

overload procedure x(c: char);

 

begin

 

   { statements to operate on parameter c }

 

end;

 

Any number of procedures or functions with the same name can be joined this way into an overload group. When the procedure or function is called, the compiler determines which of the procedures or functions in the overload group is to be used to satisfy the call. Thus, both of these calls are possible with the definitions above:

x(1);

x('c');

 

The compiler considers three things when determining which procedure or function of an overload group is meant:

1.      If the called context is a procedure or function call.

2.      The number of parameters.

3.      The type compatibility of the parameters.

Overload groups are not allowed to be ambiguous. There is no "preference" or "priority" involved with overloads. If two overloads are ambiguous with respect to each other, then an error will result at the time of the definition of the conflicting overload.

Two calls are ambiguous with each other if they match for procedure/function status, have the same number of parameters, and the parameters are compatible between lists, using the ISO 7185 definition of compatibility according to 6.4.6 “Assignment-compatibility” (where either parameter could be assignment compatible with the other), and also if one parameter is char while the other is a single character string. This means, for example, that having one parameter of type real, and the other of type integer, means those parameters are ambiguous with each other.

When parameter lists are compared, the mode of the parameter, or its var, view or value status is ignored.

It is an error if two parameter lists "converge" with different modes. Two parameter lists are said to converge at any point in the list if that parameter and all parameters to the left of it are found to be compatible using the rules above. An example of an overload declaration that is invalid by this rule is:

! invalid program

 

program p;

 

procedure a(i: integer; c: char; b: boolean);

 

begin

 

   { statements of first overload  of a }

 

end;

 

overload procedure a(i: integer; var c: char; b: boolean; r: real);

 

begin

 

   { statements of second overload of a }

 

end;

 

begin

end.

 

Even though the two parameter lists would be distinct because they differ in number, the lists are convergent at parameter c, and parameter c has conflicting modes, the first being value, and the second being var.

The purpose of the convergence rule is to relieve compilers from having to store all the parameters in a procedure or function call before determining which routine of an overload group matches the call.

Overload groups must be completed within the same declaration block. Different modules, classes, procedures and functions cannot add to each other’s overload groups.

6.26    Operator overloads

operator-declaration = operator-identifier operator-heading ‘[ ‘:’ result-type] .

operator-heading = ‘operator' formal-identifier [ formal-parameter-list ] .

operator-identifier = ‘not’ | ‘+’ | ‘-‘ | ‘*’ | ‘/’ | ‘div’ | ‘mod’ | ‘and’ | ‘or’ | ‘< ‘ | ‘>’ | ‘=’ | ‘<=’ | ‘>=’ | ‘in’ | ‘is’ | ‘:=’ .

Besides overloading procedures and functions, it is also possible to overload expression operators:

program p;

 

type string = packed array of integer;

     pstring = ^string;

 

operator +(a, b: string): pstring;

 

begin

 

   { code to concatenate strings a and b }

 

end;

 

operator :=(a, b: string);

 

begin

 

   { code to assign string b to a }

 

end;

 

begin

end.

 

Where “+” and “:=”are the operators to overload. The following operator overloads are possible:

Program p;

 

type x: record i, r: integer end;

 

operator +(a: x): x; begin result a end;

operator –(a: x): x; begin result a end;

operator not (a: x): x; begin result a end;

operator +(a, b: x): x; begin result a end;

operator -(a, b: x): x; begin result a end;

operator *(a, b: x): x; begin result a end;

operator /(a, b: x): x; begin result a end;

operator div(a, b: x): x; begin result a end;

operator mod(a, b: x): x; begin result a end;

operator and(a, b: x): x; begin result a end;

operator or(a, b: x): x; begin result a end;

operator xor(a, b: x): x; begin result a end;

operator <(a, b: x): x; begin result a end;

operator >(a, b: x): x; begin result a end;

operator =(a, b: x): x; begin result a end;

operator <=(a, b: x): x; begin result a end;

operator >=(a, b: x): x; begin result a end;

operator in(a, b: x): x; begin result a end;

operator is(a, b: x): x; begin result a end;

operator :=(out a: x; b: x): x; begin end;

 

begin

end.

 

The ‘-‘ and ‘+’ operators can be both unary and binary, and they have different priorities. The exact type of operator is indicated by the number of parameters that appear. There is only one operator procedure, which is assignment (‘:=’).

The parameters to an operator function can be any type, but cannot be var parameters.

The parameters to the operator procedure ‘:=’ can be any type, but the first parameter must use out mode.

The results of an operator function cannot be established via a ISO 7185 by name function result assignment. Instead, the unnamed result form is used (see 6.22Anonymous function result”).

The existence of an operator overload does not change the priority of the operator.

Operator overloads follow the same rules as standard overloads. Specifically, operator overloads cannot be ambiguous with either each other, or the parameters of standard , built in operators.

The types of built in operators with the exception of is appears in ISO 7185 6.7.2 “Operators”.

The existence of an operator overload will not cause the built-in operator to be altered in any way. An operator overload simply adds behavior where the built-in operator would indicate a type error.

Note that since the system definition for is is defined for any object, it is not possible to overload the is operator for objects.

The use of an operator overload function to introduce so-called “side effects” will result in ambiguity as to when the side effect occurs, since Pascaline does not specify expression evaluation order.

6.27    Static procedures and functions

procedure-heading = attribute 'procedure' identifier [ formal-parameter-list ].

function-heading = attribute 'function' identifier [ formal-parameter-list ] ':' result-type.

attribute = 'overload' | 'static' | 'virtual' | 'override' | ‘operator’ .

Pascaline defines a static attribute that is used before any function or procedure to indicate that it is used statically.

program p;

 

static procedure z;

 

var x, y: integer;

 

begin

 

   { statements of z }

 

end;

 

static function y;

 

begin

 

   { statements of y }

 

end;

 

begin

 

end.

 

The static word-symbol is used to indicate to the compiler that the procedure or function with that attribute will not recursively call itself, nor be called by any subprocedure or subfunction.

On some processors with limited addressing resources, using static can result in smaller and faster executable programs, sometimes dramatically so. Compilers targeting more advanced processors typically ignore the static word-symbol.

In the case where the procedure or function is contained entirely within a module, and is not visible outside the module (it is within the private section), the compiler can automatically determine the static status of a procedure or function. However, if it is visible outside the module, the compiler must assume it may be recursively called. In this case, the static attribute is required to obtain the improved code.

Note:

1.      The compiler may also detect that a static attributed procedure or function calls itself, either directly or indirectly via another procedure or function, and issue an error.

6.28    Relaxation of declaration order

block = { declaration } statement-part .

declaration = label-declaration-part | constant-definition-part | type-definition-part | variable-declaration-part | fixed-declaration-part | procedure-declaration ';' | function-declaration ';' .

The declaration order in ISO 7185 Pascal of labels, constants, types, variables, then procedures and functions is relaxed. These constructs can appear in any order. However, the rule remains that each identifier must be declared before its use, with the normal ISO 7185 Pascal exception for pointer declarations.

Pointer forward references must resolve within the same var declaration.

Relaxing declaration order in Pascaline is a more natural match for modular compilation.

6.29    Exception handling

try-statement = 'try' (statement-sequence) try-end .

try-end = (except-series | except-unconditional) [ 'else' statement ] .

except-series = except-specifier { except-specifier } [ except-unconditional ] .

except-unconditional = ‘except’ statement .

except-specifier = ‘on’ exception-identifier { ‘,’ exception-identifier } ‘except’ statement .

block = { declaration } [ 'private' { declaration } ] statement-part [ ';' statement-part ] .

statement-part = compound-statement .

compound-statement = 'begin' [try-end] statement-sequence [ ‘result’ expression ] 'end' .

The most common use for interprocedure gotos is to handle error returns easily from deep nested procedures. Pascaline provides an alternative structure.  The try statement executes one or more statements with an "exception guard":

program p;

 

var myexception: exception;

 

begin

 

   try

 

      { ... }

      throw(myexception)

      { ... }

 

   on myexception except { statement to execute on myexception }

   except { statement to be executed on any exception }

   else { statement to be executed if no exception occurs }

 

end.

 

If anywhere within the guarded execution the statement:

throw(myexception);

 

or

throw;

 

is executed, any active procedures or nested statements are removed, and execution resumes with the statement after either the exception clause that matches the given exception, or the general exception statement. If no exception occurs, execution continues either with the else statement, if specified, or the next statement after the try statement.

The program:

program p(output);

 

var myexception: exception;

 

begin

 

   try

 

      { ... }

      throw(myexception)

      { ... }

 

   on myexception except writeln(‘The operation failed’)

   else writeln(‘The operation succeeded’)

 

end.

 

Is equivalent to:

program p(output);