[Looking for a book logo 9.5KB]
Click here to see interesting book recommendations!

A2O V3 User's Guide

[modulAware.com/zel logo]

64 bit Alpha Oberon-2 Compiler for HP OpenVMS Alpha

Copyright (1995-1999) by ModulAware.com

Abstract

The OpenVMS Oberon-2 Compiler A2O|H2O are implementations of the programming language Oberon-2. H2O generates VAX and A2O generates Alpha native code. Both compilers are designed to run under the OpenVMS operating system.

The purpose of this manual is to explain how to compile, link and execute (stand-alone) Oberon-2 programs under the OpenVMS Alpha|VAX operating system. Also described are the basic data types, storage allocation and alignment, calling conventions, and system dependent features. The appendix contains language report clarifications, restrictions and extensions, implementation specific programming hints, a summary of the OpenVMS-specific foreign interface modules, the compiler's help file, installation guide, release notes, and an index.

The usage of Alpha Oberon, an extensible, graphical development environment for A2O, is explained in the on-line Alpha Oberon User's Guide (AlphaOberon_Guide.Text)

Revision: A2O|H2O V3.0: Oct-1997

Edited and © (1995-1997) by
Günter Dotzel
http://www.modulaware.com/

AlphaOberon System website (download, updates, and upgrades):
Contact gd at modulaware.com
http://www.modulaware.com/zel/aos/

CONTENTS

 CHAPTER 1       USING Oberon-2 UNDER OpenVMS
 
          1.1    CREATING AND EXECUTING A PROGRAM (OVERVIEW)
          1.2    FILE SPECIFICATIONS AND DEFAULTS
 
 CHAPTER 2       COMPILING A MODULE
 
          2.1    THE H2O COMMAND
          2.2    Oberon-2 COMPILER QUALIFIERS
          2.3    LOCAL CONTROL OF RUN-TIME CHECKS
          2.4    SEARCH STRATEGIES
          2.5    Source Code Analyser
          2.6    Conditional Compilation
 
 CHAPTER 3       LINKING A PROGRAM
 
          3.1    The Link Command
          3.2    Linker Command Qualifiers
          3.2.1  Map File Qualifiers
          3.2.2  Debugging and Traceback Qualifiers
          3.3    Identification Checking
 
 CHAPTER 4       EXECUTING A PROGRAM
 
          4.1    STARTING A PROGRAM
          4.2    DEBUGGING A PROGRAM
 
 CHAPTER 5       INTERNAL REPRESENTATIONOF DATA
 
          5.1    BASIC TYPES
          5.2    STRUCTURED TYPES
          5.3    SYSTEM DEPENDENT TYPES
          5.4    SYSTEM DEPENDENT CONSTANTS
 
 CHAPTER 6       PROCEDURE CALLINGCONVENTIONS
 
          6.1    Parameter Passing Mechanisms
          6.2    Function Return Values
          6.3    Foreign Procedures
 
 CHAPTER 7       SYSTEM DEPENDENTFACILITIES
 
          7.1    Low Level Facilities (module SYSTEM)
          7.2    Storage Management
          7.2.1    The Module Storage
          7.2.2    Storage Allocation
          7.3    Persistent Objects Support
          7.3.1  Module Objects_Types (stand-alone programs)
          7.3.2  Module Types (for AlphaOberon)
          7.3.3  Module Objects
 
 APPENDIX A      COMPLETE EXAMPLE
 APPENDIX B      Oberon-2 Language Report
 APPENDIX C      RESTRICTIONS, EXTENSIONS and CLARIFICATIONS
 APPENDIX D      LIBRARY AND INTERFACEMODULES
 APPENDIX E      -
 APPENDIX F      -
 APPENDIX G      OpenVMS Oberon-2 & Oberon-2 HELP FILE
 APPENDIX H      A2O|H2O DATA SHEET
 APPENDIX I      Programming Hints

Preface

Manual Objectives:

This user guide has been designed to support the development and execution of Oberon-2 programs written in Oberon-2 under OpenVMS. It is based on the OPenVMS Modula-2 (MaX|MVR) user's guide which itself was derived from ETH-Zürich's LIDAS Database System (Modula/R) user's manual.

Product Development History:

A2O|H2O consist of a front- and a back-end. The front-end is based on ETH-Zürich's portable Oberon-2 compiler OP2 written in Oberon[-1]. OP2 was designed by Regis Crelier at ETH-Zürich. OP2 was manually translated to Modula-2 for bootstrap purposes. The front-end incorporates an Oberon-2 source code analyser written in Oberon[-1]. This analyser was developed by Stefan Ludwig at ETH-Zürich in 1992. The back-end of A2O|H2O is based on ModulaWare's OpenVMS Modula-2 Compiler (MaX|MVR) and is also written in Modula-2. It was developed at ModulaWare. So most parts of A2O|H2O are written in Modula-2.

ModulaWare's Oberon-2 (A2O|H2O) and Modula-2 (MaX|MVR) OpenVMS compilers share the same ISO Modula-2 Standard Library under OpenVMS. The library implementation is written in Modula-2 and was also developed at ModulaWare.

Alpha Oberon Support:

Besides OpenVMS object files, A2O can also generate Oberon System specific code-files for AlphaOberon (OLF[64]). AlphaOberon is ModulaWare's 64 bit port of ETH-Zürich's Oberon System V4 for OpenVMS Alpha. The code generated for stand-alone and embedded modules is essentially identical; only the object file format is different. The OLF files are structural much simpler and shorter than the OpenVMS object files. In addition to code, constants, objects and linkage section, OLF files contain data for the automatic garbage collector and symbol information for procedures and variables as well as line-number/program-counter correlation for the AlphaOberon post-mortem and run-time debugger.

After compilation, Oberon code-files can be activated directly from AlphaOberon without linking, whereas stand-alone Oberon-2 programs require linking with the OpenVMS system linker. A2O can be invoked from Alpha Oberon with the usual Oberon System command Compiler.Compile or Folds.Compile, which runs A2O in a spawned process, accepting input from a marked viewer or file selection. Compilation errors are displayed in the system log viewer.

Detailed implementation notes of Alpha Oberon are contained in the ModulaTor issues number #59, #63, #66, #67, #68, and #72 (see below).

Language Definition:

Hanspeter Mössenböck: The Programming Language Oberon-2. ETH-Zürich Report Nr. 160, May 1991, revised May 1992.

Related documents:

The programming language Oberon-2 itself is described in a separate report. Several books about Oberon-2 are available in German and English:

Marc Brandis, Regis Crelier, Michael Franz, Josef Templ: The Oberon System Familiy, ETH-Zürich Report 174, April 1992.

Günter Dotzel: Alpha Alpha/OpenVMS Modula-2 and Oberon-2 Compiler Project (implementation notes). In: Peter Schulthess (Hsg.): Proceedings of the Joint Modular Languages Conference, University of Ulm, Germany, 28-30 September 1994. Universitätsverlag Ulm, 1994

Regis Crelier: OP2: A portable Oberon Compiler. ETH-Zürich Report Nr. 125, Feb-1990.

Hanspeter Mössenböck: Differences between Oberon and Oberon-2. ETH-Zürich Report Nr. 160, May 1991, revised May 1992.

Hanspeter Mössenböck: Objektorientierte Programmierung in Oberon-2. Springer Verlag, 1992. Also available in English in early 1993. Referred to as OOPiO2 in this manual.

Cuno Pfister (ed.), Beat Heep, Josef Templ: Oberon Technical Notes. ETH-Zürich Report Nr. 156, Mar-1991.

Martin Reiser, Niklaus Wirth: Programming in Oberon. Addison Wesley, 1992.

Josef Templ: A Symmetric Solution to the Load/Store problem. ETH-Zürich Report 157, 1991.

The ModulaTor, Modula-2 and Oberon-2 TechJournal:

Further documentation and examples for A2O, H2O and AlphaOberon are contained in the following issues of The ModulaTor:

[1, 8] Elmar Baumgart: The ISO Modula-2 Standard Library - A Collection of Definition Modules with example and test programs, #14

[2,2] Elmar Baumgart: ISO Modula-2 Standard I/O Library Test Programs, #20

[2, 7.1] Elmar Baumgart: Test Program for ISO Modula-2's library modules Processes & Semaphores with an Oberon-2 multi-programming excursion, #25

[2. 7.2] Günter Dotzel: H2O: ModulaWare's new Oberon-2 Compiler for VAX/VMS - Implementation and distribution kit details, #25

[2, 8] Elmar Baumgart: The ISO Modula-2 for Oberon-2 - Definition of Interface Modules with example and test programs, #14.

[2, 9] Günter Dotzel: How to count bits in Modula-2 - The old fashioned type transfer function versus ISO Modula-2's SYSTEM.CAST, #27

[2, 9.1] Günter Dotzel: How to count bits in Oberon-2 - Manually transpiling from Modula-2 to Oberon-2, #27

[3,1] The ModulaTor's Forum by Taylor Hutt, Günter Dotzel: Communication about Persistent Objects in Oberon-2, #30

[3, 1.1] Hartmut Goebel, Günter Dotzel: Persistent Objects in Oberon-2 on OpenVMS, #30

[5, 7] Hartmut Goebel: Alpha Oberon: The Oberon System for Alpha under OpenVMS (6), #59

[5, 11] Günter Dotzel: "Working with AlphaOberon" (3), #63

[6, 2] [6, 3] [6, 4] [6, 5] Dotzel, Günter; Goebel, Hartmut: Porting the Oberon System to Alpha, (22), #66

[6, 6] [6, 7] Dotzel, Günter; Goebel, Hartmut: The AlphaOberon Run-Time Debugger, (8), #67

[6, 8] Dotzel, Günter; Goebel, Hartmut: 64 Bit Address Extension of the Alpha Oberon-2 Compiler, (3), #68

[Nr. 72] Dotzel, Günter; Pirkelbauer, Peter: Object model for AlphaOberon System and Alpha Oberon-2 Compiler, #72

OpenVMS Operating System Manuals:

OpenVMS Symbolic Debugger Reference Manual (not supplied)

OpenVMS Linker Reference Manual (not supplied)

OpenVMS Architecture Handbook (not supplied)

Alpha and VAX Processor Manuals:

[Alpha] Richard L. Sites (ed.): Alpha Architecture Reference Manual. Digital Press, Burlington, 1992

[VAX] Digital: VAX Architecture Handbook, Maynard, 1981

CHAPTER 1: USING Oberon-2 UNDER OpenVMS

1.1 CREATING AND EXECUTING A PROGRAM (OVERVIEW)

Creation and execution of Oberon-2 programs under OpenVMS works as with under language compilers.

In general, Oberon-2 programs are composed of separate modules. The first step in creating an executable program is to edit the different source files containing the compilation units. There is no separation between main module, definition modules, and implementation modules as in Modula-2.

NOTE: The Oberon-2 compiler distinguishes upper and lower case characters. Hence, all identifiers must be spelled exactly as they are defined. All reserved words and standard names must be capitalized.

Source files are compiled separately. The order in which this has to be done depends on the import/export relationships between the modules. Circular and recursive imports are not allowed.

Two kinds of output files are produced (besides an optional listing file):

1. Processing an Oberon-2 source file results in a symbol file, containing a coded module description readable by the compiler. This file is needed each time when the source file is re-compiled or when another compilation unit imports this module. Symbol files store a so-called module key which is used by the compiler to check the interface consistency of separately compiled modules. When compiling a module, a new symbol file is generated and compared to the old one. If the old and new symbol files are identical, then the module's interface part did not change and the new symbol file is deleted. In this case, the old symbol file with the old version key is kept.

2. Except for so-called foreign language interface modules, the result of processing a module is an object file readable by the OpenVMS-linker.

Finally, the separate object files have to be linked together to form an executable image file. Execution of this file can be started by the RUN command.

1.2 FILE SPECIFICATIONS AND DEFAULTS

A full OpenVMS file specification has the form

node::device:[directory]filename.filetype;version

node, device, directory and version are optional items. The filetype specification may be omitted in certain cases. The default type depends on usage:

Default file types:

Oberon-2 and Modula-2 compiler:

MOD Oberon-2 or Modula-2 source file

SYN Oberon-2 symbol file: input to and output from Oberon-2 compiler

SYN64 64 bit Oberon-2 symbol file: input to and output from Oberon-2 compiler

SYO 64 bit Oberon-2 symbol file: input to and output from Oberon-2 compiler with fine-grained symbol-files

OBJ object code file: output from Modula-2 or Oberon-2 compiler (or from any other language compiler under OpenVMS)

OBJ64 64 bit object code file: output from Oberon-2 compiler A2O

OLF 32 bit Oberon load file: output from Oberon-2 compiler A2O for AlphaOberon with fine-grained symbol-files

OLF64 64 bit Oberon load file: output from Oberon-2 compiler A2O for AlphaOberon

MOD_LIS source file listing

DEF Modula-2 definition source file

SYM Modula-2 symbol file: input to and output from Modula-2 compiler

MOC encrypted Modula-2 or Oberon-2 source file

MAR VAX-Assembler source file

Linker:

OBJ and OBJ64 input to linker (default .OBJ)

EXE output from linker

MAP linker map file

CHAPTER 2: COMPILING A MODULE

Each Oberon-2 compilation unit has to be compiled separately. In case of a non-existing symbol file (or when the objects exported from the module are changed) a symbol file is generated in addition to an object file. Optionally a source file listing may be produced. The compiler also searches for and reads the symbol files belonging to imported modules. The same search strategy as with the Modula-2 compiler MaX|MVR is applied.

2.1 THE A2O|H2O COMMAND

The Oberon-2 compiler is invoked by the A2O (Alpha) or H2O (VAX) command which has the following form:

$ A2O { /qualifier } file-spec { /qualifier }

$ H2O { /qualifier } file-spec { /qualifier }

file-spec

determines the source file containing the compilation unit. Only one file is accepted. The default file type for Oberon-2 programs is MOD.

qualifiers

See below. Most of the qualifiers are identical to those of the Modula-2 Compiler MVR.

In interactive mode, you can also enter the file specification on a seperate line by typing a carriage return after the command name. The system responds with a prompt for the file specification:

$ A2O <return>

_File:

Although the compiler is a so-called one-pass compiler, processing of a source file comprises one, two or three phases. On termination the compiler returns a status code in the reserved global symbols $STATUS and $SEVERITY which indicates either a success or a severe error during compilation. This information can be used for controlling the execution of OpenVMS command procedures (see OpenVMS Guide to Using Command Procedures for details). If the compiler run is aborted by ^C or ^Y while using the /list/machinecode qualifiers, then a plain-ascii work file (h2o_interpass.tmp) remains on the default directory and should be deleted or purged to recover disk space.

The normal succession of the Compiler's passes:

                
    Foreign interface modules:        Proper modules:

1. front-end 1. front-end (syntax-, declaration- and body-analysis) 2. symbol file export 2. symbol file export 3. - 3. back-end (code-generation) 4. listing generation (optional) 4. listing generation (optional)
If an error is detected in phase 1, then phases 2 and 3 are skipped and finally if the /list compilation qualifier (see below) is active, phase 4 is executed. If phase 2 exhibits an error, phase 3 will be skipped too. If an error occurs in phase 3 (these are only implementation restrictions and limitations), no object file is generated.

2.2 Oberon-2 COMPILER QUALIFIERS

A2O|H2O command qualifiers control optional compiler settings. For every qualifier there is a negative form to suppress the respective effect. The negative form is indicated by a leading "NO", e.g., "NOLIST" is the negative form of "LIST". The meanings of the qualifiers and their default values are listed below in a short form. See Appendix (Help File) for a detailed description.

ANALYSE[=(OptionList)] Source code analyser; options are intermediate_items, count_statements, redefine_methods, used_before_set, var_parameters, and exported_items; all default.

To be used only in combination with /NoObject /NoMachine_Code /NoSymFile /NoCross_Reference. See 2.5 for a detailed description of the analyser. (This option is unsupported).

CHECK[=(OptionList)] Code is generated to perform run-time checks for out-of-range array index bounds, case label exception for case-statement without else-part, and type tests and guards; options are stackcheck, indexcheck, typecheck, overflowcheck, rangecheck, pointerinit, asserteval (A2O only), and heapinit; all default.

CROSS_REFERENCE cross reference table is included in the source listing. This qualifier is effective only when used in conjunction with LIST. (This option is unsupported).

DEBUG The DEBUG qualifier produces information to be used by the OpenVMS Symbolic Debugger (or the symbol dump in AlphaOberon trap handler) and the run-time error reporting mechanism.

INTEGER_type_match_pointerSize This qualifier determines together with the qualifier /PointerSize the size of the pervasive type INTEGER. For default (/NoInteger/PointerSize=32), the basic data types SHORTINT is a 8 Bit, INTEGER is a 16 Bit and LONGINT is a 32 Bit signed number. When using /Integer, the types SHORTINT and LONGINT are no longer pervasive. With /Integer/PointerSize=32,

the pervasive data type INTEGER is a 32 Bit signed number (same as INTEGER in MaX Modula-2) and with /Integer/PointerSize=64, it is a 64 Bit signed number. Always available are SYSTEM.SIGNED_8, SYSTEM.SIGNED_16, SYSTEM.SIGNED_32 and SYSTEM.SIGNED_64. Attention, when swapping this compilation option, because the symbol file will change when an object containing INTEGER is exported.

Size of SHORTINT/INTEGER/LONGINT in bits ("-" = type is not available):

                
                 | /PointerSize=32 | /PointerSize=64

/NoInteger | 8/16/32 | 8/16/64 /Integer | -/32/- | -/64/-
LIST A listing file is written. The qualifier has the general form: /LIST[=file-spec-list] You may include a file specification for the listing file. If no specification is given a file of type MOD_LIS with the name of the source file is created. The file contains at least the source text and the error messages, but further listings are added by applying CROSS_ REFERENCE and/or MACHINE_CODE.

LOG If the LOG option is enabled, the following information is displayed: compiler version, succession of the compiler phases, and the names of the symbol files read.

MACHINE_CODE A readable representation of the generated code is included in the source listing. This qualifier is effective only in conjunction with the LIST qualifier. In this case a temporary work file is created before the listing generation pass. This file with the file type .TMP is deleted on termination of the compilation process.

OBJECT An object file for the linker is produced. The qualifier has the form: /OBJECT[=file-spec] You may specify a file for the object module. The default is a file of type OBJ which takes the name of the source file. If the source file contains a definition module this qualifier has no effect.

QUERY The QUERY qualifier forces the compiler to ask explicitly for the symbol files to be read. By default, QUERY is disabled and the compiler uses a standard strategy to search for the symbol files (see 2.3). The standard search strategy is also effective when QUERY is enabled but no file specification is given.

POINTERSIZE=x (A2O only): With x=32, pointers, addresses and LONGINT are 32 bit, and with x=64, pointers, addresses and LONGINT are 64 bit quantities. See ModulaTor issue nr. 68. The option value x=64 is not yet supported and would need at least OpenVMS 7.0.

PACKED_RECORD (A2O only): Fields in records are aligned on a byte boundary. Default: NoPacked_Record. AlphaOberon only: A Requirement of the garbage collector is that record field elements of pointer type must be naturally aligned (4 byte boundary). This is only guaranteed autmatically when using /NoPacked_Record.

PARSE_TREE Display a parse tree (unsupported; reserved for use by ModulaWare only).

SYMFILE A new symbol file is created automatically if there is no old symbol file or if the interface specification was modified in the source file. The old file is always looked-up with the search default strategy (file name is contructed from the module-name). The option has the form: /SYMFILE[=file-spec]. You may supply an optional output file specification for the symbol file. The default output file gets the name of the source file with the default file type SYN[64] or SYO with fine-grained

symbol-files. Version limit minimum of at least 2 is required for the compatibility/version check of the symbol file. It is recommended to use the full module name as source file name, e.g. if the module is called Xyz then the file name should be XYZ.MOD.

H2O Command Qualifiers


      Qualifier          Negative Form       Default

/ANALYSE [=(Aopt)] /NOANALYSE /NOANALYSE (all) /AXP /NOAXP /NOAXP (H2O only) /AXP (A2O only) /CHECK [=(Copt)] /NOCHECK /CHECK (all) /COMPLEX /NOCOMPLEX /NOCOMPLEX /CROSS_REFERENCE /NOCROSS_... /NOCROSS_REFERENCE /DEBUG /NODEBUG /NODEBUG /DUMP_SYMFILE /NODUMP_SYMFILE /NODUMP_SYMFILE /FOREIGN_CODE /NOFOREIGN_CODE /NOFOREIGN_CODE /EXTEND_SYMFILE /NOEXTEND_SYMFILE /NOEXTEND_SYMFILE /FINE_GRAINED_SYMFI/NOFINE_GRAINED_SYMF/NOFINE_GRAINED_SYMFILE /IEEE /NOIEEE /NOIEEE (A2O only) /IEEE with /OBERON_LOADFILE /ISO /NOISO /NOISO (currently ignored) /INSTRUCTIONMODE /NOINSTRUCTIONMODE /NOINSTRUCTIONMODE [=(Copt)] /INTEGER /NOINTEGER /NOINTEGER /LIST[=file-spec] /NOLIST /NOLIST (interact.) /LIST (batch) /LOG /NOLOG /NOLOG (interactive) /LOG (batch) /MACHINE_CODE /NOMACHINE_CODE /NOMACHINE_CODE /OBERON_LOADFILE /NOOBERON_LOADFILE /NOOBERON_LOADFILE (A2O only) /OBJECT[=file-spec]/NOOBJECT /OBJECT /OMIT_MODULE_NAME /NOOMIT_MODULE_NAME /NOOMIT_MODULE_NAME /OPTIMIZE[=(Oopt)] / /OPTIMIZE (A2O only) =(rotateSratch) /PACKED_RECORD /NOPACKED_RECORD /NOPACKED_RECORD (A2O only) /POINTERSIZE - /POINTERSIZE=32 (A2O only, =64 only with OpenVMS 7.0 or later) /NAME_SEPARATOR='x'/NONAME_SEPARATOR /NAME_SEPARATOR='.' (H2O) /NAME_SEPARATOR='_' (A2O) /QUERY /NOQUERY /NOQUERY /SYMFIL[=file-spec]/NOSYMFILE /SYMFILE /TRANSFER_VECTOR /NOTRANSFER_VECTOR /TRANSFER_VECTOR (H2O only) /NOTRANSFER_VECTOR (obsolete with A2O; usage reserved) Aopt=(intermediate_items, count_statements,redefine_methods, used_before_set, var_parameters, exported_items) Copt=(stackcheck, indexcheck,typecheck, overflowcheck, rangecheck, pointerinit, asserteval, heapinit) Iopt=(FptTrapB, ChoppedDECRounding,SoftwareDECTrap, UnderflowDECTrap, OverflowDECTrap, ChoppedIEEERounding, DynamicRounding, PlusInftyRounding, MinusInftyRounding, InexactIEEETrap, SoftwareIEEETrap, UnderflowIEEETrap, OverflowIEEETrap, IntTrapB, IntOverflow) Oopt=(schedule, alignCheck, rotatePreserved, rotateScratch, hiddenWriteLc, hiddenWriteInst)

2.3 LOCAL CONTROL OF RUN-TIME CHECKS

In contrast to Modula-2, the Oberon-2 Report doesn't specify any syntax (directive or pseudo comments) for local control of run-time checks to be enabled or disabled. Only global control which affects the whole compilation unit is available via command line qualifier (see the /Check compilation qualifier above).

2.4 SEARCH STRATEGIES

In the default case (i.e., when no file name is specified in query mode) the compiler applies a standard strategy to search for the symbol files needed: The default file name is constructed out of the full module name; if no file can be found, the file name is constructed out of the first 9 characters of the module's name; if no file is found, the last try uses only the first 6 characters of the module's name. A file type SYN is assumed. Note, that the module name is converted to the file name by transforming all lower-case letters to capital letters. The compiler checks, whether the symbol file found contains the correct module; this check is case-sensitive.

The file is first searched in the user's default directory. If the search fails, directories with the logical names MOD$LIB_LIST (may be a directory name list), MOD$LIBRARY, MOD$LIBRARY_1 up to MOD$LIBRARY_9 are searched (in this order). The entire process is performed first in the process logical name table, then in the group logical name table, and finally in the system logical name table. Each search terminates when the first undefined logical name is encountered. If the file has not yet been found, the directories with the logical names MOD$SYSTEM and LIDAS$SYSTEM are searched.

2.5 Oberon-2 Source Code Analyser

Compilation qualifier /Analyse[=(OptionsList)] enables the source code analyser.

The Analyser marks by default:

- all non-exported variables/constants/types/fields that are declared but never used, used before being initialized ( * ), never initialized, and initialized but never used.

- non-exported [type-bound] procedures that are never called.

- modules that are imported but never used.

( * ) For variables declared in a different scope, no warning is produced (see option used_before_set, however).

Options (complementing each other):

intermediate_items: redeclaration of/use of/assignment to intermediate items. Additionally marks items that are already declared in an outer scope. and the use of or assignment to intermediate items (e.g. local variables/parameters declared in an outer scope).

count_statements: number of statements in module. Reports the number of statements (assignments, if, while, proc calls, etc.) in the module. This is convenient for determining the complexity of a program (instead of lines of code).

redefine_methods: redefinition of type bound procedures. Additionally marks the redefinition of type bound procedures.

used_before_set: used before set for different scopes. Additionally marks 'used before set' for variables declared in a different scope.

var_parameters: use of var parameters. Additionally marks variables that are used as var parameters and are therefore not ensured to be initialized.

exported_items: use/initialization of exported items. Additionally marks exported items that are declared but not used by the module itself, used before being initialized, never initialized, and initialized but never used.

2.6 Conditional Compilation

Conditional compilation, usually implemented as compiler directives (or pseudo comments) is not supported in Oberon-2. However there are situations, where system dependent code should be maintained in a single source file to avoid code duplication. AlphaOberon provides an Oberon Texts tool called VersionElems, which allows to manage different versions of source code sections.

CHAPTER 3: LINKING A PROGRAM

After compilation, the separate object modules are linked together to produce an executable OpenVMS image file. Note, linking is not neither required nor possible with AlphaOberon.

3.1 The Link Command

To link the modules, use the LINK command in the following form:

$ LINK { /command qualifier } file-spec-list

command qualifiers

Specify output file options. Refer to the OpenVMS Linker Reference Manual for detailed information.

file-spec-list

Specifies the input files to be linked. File specifications can be separated by commas or plus signs. The first file in the list should contain the main module.

To create executable code you must specify all your object files to be linked, except the ones stored in default object file libraries.

By default, the object files input to the linker are assumed to be of type OBJ. To link a 64 bit object file, append .OBJ64 to the first object file name in the link command. For the rest of the files in the file list the linker then also takes .obj64. If no other specification is given, the executable image file takes the name of the first object file and is of type EXE.

In interactive mode you may enter the file specifications on a separate line by typing a carriage return after the command name. The system responds with a prompt for the file specification.

3.2 Linker Command Qualifiers

Below, a few qualifiers are listed which may be of interest to the Oberon-2 programmer. For some qualifiers there are also negative forms. Refer to the OpenVMS Linker Reference Manual for detailed information.

3.2.1 Map File Qualifiers

The MAP qualifier directs the linker to generate a map file containing a summary of the image's characteristics, a list of contributing modules, and a list of global symbols and values. The qualifier has the form:

/MAP[=file-spec]

where the optional file specification designates the map file. The default is a file of type MAP with the name of the first object file.

By default, MAP is disabled for interactive mode and enabled for batch mode.

In conjunction with /MAP the modifying qualifiers BRIEF or FULL and CROSS_REFERENCE may be used.

/BRIEF and /FULL define the amount of information included in the map file, as follows:

/BRIEF produces a summary of the image's characteristics and a list of contributing modules.

/FULL adds a summary of characteristics of image sections in the linked image to the normal map file.

/CROSS_REFERENCE can be used with /MAP or /MAP/FULL to include cross-reference information for global symbols in the map file.

By default, CROSS_REFERENCE is disabled.

3.2.2 Debugging and Traceback Qualifiers

If the DEBUG qualifier is used, the program will always be executed under the control of the debugger. (You may suppress this by issuing /NODEBUG with the RUN command.)

By default, DEBUG is disabled.

The TRACEBACK qualifier is used to have error messages accompanied by symbolic traceback information.

By default, TRACEBACK is enabled.

/DEBUG implies /TRACEBACK.

Summary: Link Command Qualifiers


  Qualifier              Negative Form   Default

/BRIEF None Not applicable /CROSS_REFERENCE /NOCROSS_... /NOCROSS_REFERENCE /DEBUG /NODEBUG /NODEBUG /FULL None Not applicable /MAP[=file-spec] /NOMAP /NOMAP (interactive) /MAP (batch) /TRACEBACK /NOTRACEBACK /TRACEBACK

3.3 Identification Checking

The OpenVMS Oberon-2 compiler provides identification information for describing the relationship between symbol files and object files belonging to the same module. This identification is in fact the compilation date and time of the corresponding definition module and it is passed to the linker in the form of an Entity Ident Consistency Check subrecord.

The linker checks the Entity Ident Consistency Check subrecord of each object module before it links them together. If object files of two modules importing different versions of the same definition module are encountered the linker issues a warning message. In such a case, the object files giving rise to the message should be replaced by newly compiled ones.

For more information about the Entity Ident Consistency Check subrecords, see the OpenVMS Linker Reference Manual.

CHAPTER 4: EXECUTING A PROGRAM

4.1 STARTING A PROGRAM

The RUN command starts the execution of an executable image file. It has the form:

$ RUN [ /[NO]DEBUG ] file-spec

The file must be specified; the file type may be omitted, EXE is assumed in this case.

The DEBUG qualifier allows to run the program under control of the debugger, even if you have issued the H2O and LINK commands without this qualifier. /NODEBUG will override a /DEBUG given at link time.

Note, with AlphaOberon, running a stand-alone program is accomplished by activating a command of the form ModuleName.ProcName (any exported, parameterless procedure) with the middle mouse button.

4.2 DEBUGGING A PROGRAM

Currently, the OpenVMS Symbolic Debugger runs Oberon-2 programs with the language mode set to PASCAL. Both modes use the syntax of the Pascal language. Because of the differences between the two languages, some features work differently:

-1- No distinction is made between lower and upper case letters in identifiers.

-2- Don't use succ, Succ, SUCC, pred, in, div or mod ... as Oberon-2 identifiers. VAX Pascal is not case sensitive which implies that the OpenVMS degugger in language Pascal is not case sensitive. Since PRED and SUCC are predeclared standard functions in the Debugger in language Pascal, there is no way to access user defined variables with the following names: PRED, Pred, pred, ... SUCC, Succ, and succ.

-3- Module bodies are treated as parameterless procedures with the name of the modules (for setting break points).

Note: The differences 1 to 3 above may lead to name conflicts inside the debugger, which are not always handled properly.

-4- All variables and procedures can only be accessed in the context of the module they are defined in (see OpenVMS debugger commands: use SET MODULE/ALL; SHOW CALL; and SET SCOPE).

-5- Sets are displayed and must be entered in PASCAL's notation, using square brackets ('[', ']').

-6- Open array parameters are known to the debugger as fixed size arrays with lower bound of 0 and upper bound of 2**16-1. Use examine array[0:9] to get the first 10 values of a dynamic array. Multi-dimensional open arrays are currently considered to have one dimension only in the debugger symbol table (DST).

-7- Oberon-2's dynamic arrays, created with NEW can not be examined directly. The pointer variable to such a dymamic array points to a descriptor which consists of a list of dimensions and a pointer to the actual array data, all quadword size.

-8- Constant and type identifiers are not known to the debugger.

-9- Dynamic type of a pointer is not known by the debugger. Use module Objects and Objects_Types (Types with AlphaOberon) to access the run-time type name information. For debugging it is recommended to declare temporary variables of the appropriate static record types, to be able to examine all associated fields and elements of the pointer's base type. This is accomplished by using a with-statement to select the dynamic type and assign the record data to a temporary record variable of the correct static type. Another possibility is to use low-level debugger features. The debugger is able to cast the type of a variable (examine/type=...; see OpenVMS-debugger manual), but this means you must either know the type name or retrieve the dynamic type name using procedure

Objects_Types.TypeName

-10- For multi-dimensional arrays (whose type is static) use the notation a[i][j] instead of a[i,j], for index-ranges use a[m:n].

-11- Single- or multi-dimensional dynamic arrays are implemented as pointer to a contiguous data block consisting of descriptor and array data values. The descriptor consts of n entries with the maximal index for a n-dimensional array LEN(a, 0..n-1) and a pointer to the first data element. Examining dynamic arrays is currently not directly supported by the debugger.

-12- The type SYSTEM.PTR is treated as ADDRESS_32 or ADDRESS_64 depending on /pointersize.

Note, with AlphaOberon, the OpenVMS debugger can't be used. AlphaOberon features a post-mortem debugger which displays a symbolic procedure trace-back and the contents of all local variables (of basic type) of the invocation call chain. A run-time debugger, based on University Linz's RTD, is also available. In contrast to the OpenVMS debugger, RTD can handle variable of dynamic type as well as multi-dimensional open and dynamic arrays.

CHAPTER 5: INTERNAL REPRESENTATION OF DATA

The basic addressable unit is the 8-bit byte on the VAX-11 and 32 bit word on Alpha. On Alpha, the compiler can generate code to deal with smaller types and unaligned access. In the following list for each data type the number of bytes needed in memory and the representation of the values is indicated.

5.1 BASIC TYPES

SIGNED_8 Needs one byte in memory. Minimal value -128; maximal value 127. The type SIGNED_8 is implemented using the VAX-11 signed byte integer data type: bit 7 is the sign bit; bit 6 is the most significant bit. For arithmetic on Alpha, bit 7 is propagated into bits 8 to 63.

SIGNED_16 (in module SYSTEM) Needs two bytes in memory Minimal value -65536; maximal value 65535. The type SIGNED_16 is implemented using the VAX-11 signed word integer data type: bit 15 is the sign bit; bit 14 is the most significant bit. For arithmetic on Alpha, bit 15 is propagated into bits 16 to 63.

SIGNED_32 Needs four bytes in memory. Minimal value -2'147'483'648; maximal value 2'147'483'647. The type SIGNED_32 is implemented using the VAX-11 signed long integer data type: bit 31 is the sign bit; bit 30 is the most significant bit. For arithmetic on Alpha, bit 31 is propagated into bits 32 to 63.

SIGNED_64 (in module SYSTEM; A2O only) Needs eight bytes in memory. Bit 63 is the sign bit; bit 62 is the most significant bit. All relational and arithmetic operators as defined for SIGNED_32 are also defined for SIGNED_64.

UNSIGNED_32 (in module SYSTEM) needs four bytes (32 bits) in memory. No arithmetic or relational operations are currently allowed on this type.

UNSIGNED_64 (in module SYSTEM; A2O only) needs eight bytes (64 bits) in memory. No arithmetic or relational operations are currently allowed on this type.

SHORTINT If the compilation option /NoInteger is selected, this type is identical to SIGNED_8, otherwise this type is not known (pervasive).

INTEGER If the compilation option /NoInteger is selected, this type is identical to SIGNED_16, otherwise the pervasive type INTEGER is identical to SIGNED_x, where x determined by the compilation option /pointersize=x, with x either 32 or 64.

LONGINT If the compilation option /NoInteger is selected, this type is identical to SIGNED_x, where x determined by the compilation option /pointersize=x, with x either 32 or 64. Otherwise, if the compilation option /Integer is selected, this type is not known (pervasive).

BOOLEAN Needs one byte (8 bits) in memory. The type must be considered as an enumeration (FALSE,TRUE) with the values FALSE = 0 and TRUE = 1 (bit 0). Other values may cause problems.

CHAR Needs one byte (8 bits) in memory. ASCII character set is used. The implementation guarantees for variables the range 0..255 (octal 0B..377B). Constants in the range 0X..0FFX or equivalently CHR(0)..CHR(255) are allowed.

REAL Needs four bytes (32 bits) in memory. The type REAL is implemented using the VAX-11 F-FLOATING data type. On Alpha, REAL is S_FLOATING with /IEEE compilation option.

LONGREAL Needs eight bytes (64 bits) in memory. The type REAL is implemented using the VAX-11 D-FLOATING data type. On Alpha, LONGREAL is T_FLOATING with /IEEE compilation option.

COMPLEX Needs eight bytes (64 bits) in memory. The type COMPLEX is implemented using real and imaginary number part of the VAX-11 F-FLOATING data type. On Alpha, the base type of COMPLEX is S_FLOATING with /IEEE compilation option. This type is known only in combination with the compilation qualifier /COMPLEX. No operations are currently allowed with this type.

LONGCOMPLEX Needs eight bytes (128 bits) in memory. The type LONGCOMPLEX is implemented using real and imaginary number part of the VAX-11 D-FLOATING data type. On Alpha, the base type of COMPLEX is T_FLOATING with /IEEE compilation option. This type is known only in combination with the compilation qualifier /COMPLEX. No operations are currently allowed with this type.

SET Needs four bytes (32 bits) in memory (suffix "H" means hexadecimal). Examples:

SYSTEM.VAL(SYSTEM.SIGNED_32, {}) is 00000000H (empty set)

SYSTEM.VAL(SYSTEM.SIGNED_32, {0}) is 00000001H (bit 0)

SYSTEM.VAL(SYSTEM.SIGNED_32, {1}) is 00000002H (bit 1)

. . .

SYSTEM.VAL(SYSTEM.SIGNED_32, {30}) is 40000000H (bit 30)

SYSTEM.VAL(SYSTEM.SIGNED_32, {31}) is 80000000H (bit 31) SYSTEM.VAL(SYSTEM.SIGNED_32, {0..31}) is 0FFFFFFFFH (bit 31)

LONGSET Needs four bytes (64 bits) in memory (suffix "S" means hexadecimal). Examples:

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{}) is 0000000000000000S (empty set)

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{0}) is 0000000000000001S (bit 0)

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{1}) is 0000000000000002S (bit 1)

. . .

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{30}) is 0000000040000000S (bit 30)

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{63}) is 8000000000000000S (bit 63)

SYSTEM.VAL(SYSTEM.SIGNED_64, LONGSET{0..63}) is 0FFFFFFFFFFFFFFFFS (bit 63)

Enumerations Not available in Oberon-2. Their allocation is shown here, to be able to interface to Modula-2 data types: Needs one byte (8 bits) if type contains 256 or less elements; Needs two bytes (16 bits) if type contains more than 256 elements. The first value of the enumeration is represented by the integer value 0; the following enumeration values get the next integer values accordingly.

Subranges Not available in Oberon-2. Their allocation is shown here, to be able to interface to Modula-2 data types: Subrange Types are represented according to their base type.

5.2 STRUCTURED TYPES

Pointer types Need four bytes (32 bits) with /pointersize=32 or eight bytes (64 bits) with /pointersize=64 (A2O only) in memory. Pointers are implemented as virtual addresses in process space (VAX: 32 bits, Alpha: 64 bits). NIL is represented by the value 0. The so-called type-tag is stored at offset -4 (H2O) and -8 (A2O) of the pointer value. The pervasive procedure NEW automatically allocates additional storage needed for the record or array descriptors.

Record types Records are stored field by field. Each field is allocated according to its type and aligned on a byte boundary, in their declaration order. With the default /unpacked_record compilation option, elements are naturally aligned: If the field is of pervasive type T, the record offset is a multiple of MIN( SIZE(T), 8). If the field is of record type T, the record offset is aligned according to the largest pervasive type within type T. If the field is of array type, the record offset is aligned according to the element type.

A type descriptor (type tag) containing information about associated type bound procedures, record key values of possible base types together with symbolic type names and type size are stored in separate read-only program section in the object file.

Array types An array is stored and aligned according to the type of its elements. Every element is also aligned according to its type.

Dynamic array types Are implemented as pointers to dynamic array descriptors (see pointer types above).

5.3 SYSTEM DEPENDENT TYPES (module SYSTEM)

BYTE One byte is needed in memory.

LOC One byte is needed in memory. Synonym for BYTE.

SHORTWORD Two bytes are needed in memory.

WORD Four bytes are needed in memory.

LONGWORD Four bytes are needed in memory. Synonym for WORD.

QUADWORD Eight bytes are needed in memory.

OCTAWORD Sixteen bytes are needed in memory.

ADDRESS_32 Four bytes are needed in memory (POINTER TO BYTE).

ADDRESS_64 Eight bytes are needed in memory (POINTER TO BYTE).

PTR Is identical to ADDRESS_32 with /pointersize=32 or identical to ADDRESS_64 with /pointersize=64 (A2O only). PTR represents the byte address of a storage location. Any pointer can be assigned to PTR. A formal variable parameter of type PTR allows to substitute any pointer variable as actual parameter. PTR is equivalent to Modula-2's SYSTEM.ADDRESS, but no arithmetic operators apply to this type. To do address arithmetic use SYSTEM.VAL to cast PTR to LONGINT.

F_FLOATING Four bytes (32 bits) are needed in memory. With /noieee synonym for the type REAL.

D_FLOATING Eight bytes (64 bits) are needed in memory. With /noieee synonym for the type LONGREAL.

G_FLOATING Eight bytes (64 bits) are needed in memory.

S_FLOATING Four bytes (32 bits) are needed in memory. With /ieee synonym for the type REAL. A2O only.

T_FLOATING Eight bytes (64 bits) are needed in memory. With /ieee synonym for the type LONGREAL. A2O only.

H_FLOATING Sixteen bytes (128 bits) are needed in memory. With /axp synonym for the type G_FLOATING.

F_COMPLEX Eight bytes (64 bits) are needed in memory. With /complex/noieee synonym for the type COMPLEX.

D_COMPLEX Sixteen bytes (128 bits) are needed in memory. With /complex/noieee synonym for the type LONGCOMPLEX.

G_COMPLEX Sixteen bytes (128 bits) are needed in memory.

S_COMPLEX Eight bytes (64 bits) are needed in memory. With /complex/ieee synonym for the type COMPLEX. A2O only.

T_COMPLEX Sixteen bytes (128 bits) are needed in memory. With /complex/ieee synonym for the type LONGCOMPLEX. A2O only.

H_COMPLEX Sixteen bytes (128 bits) are needed in memory. With /axp synonym for the type G_COMPLEX.

5.4 SYSTEM DEPENDENT CONSTANTS

NIL In addition to the purposes described in the Oberon-2 Report, NIL serves as a hidden constant used to indicate that no actual parameter is substitued in a call of a foreign procedure declared in a so-called foreign interface module (FIM) (see 6.3) where the formal parameter passing specification is "optionalPar" (...$O). Substitution of NIL as actual parameter in a procedure call is only allowed if the coresponding formal parameter of the called procedure is specified to be optional. In this case NIL is compatible with any data type even when the formal parameter is a variable parameter (VAR).

Access violation at run-time may result in case of abuse of NIL. NIL is the only way to indicate omission of parameters. But there is another way to have different declarations for the same procedure: The module name of a FIM is ignored at link time. This allows to omit trailing parameters in the declaration. Assume the system service sys$optional is specified to have an optional second parameters. It can be declared in and imported from two FIMs with different declaration:


  MODULE X$;
    PROCEDURE sys$optional* (x1: LONGINT);
    END sys$optional;
  END X$.

  MODULE Y$;
    PROCEDURE sys$optional* (x1: LONGINT; x2$O: LONGINT);
    END sys$optional;
  END Y$.

  MODULE user;
  IMPORT X:=X$, Y:=Y$;
  VAR x1, x2: LONGINT;
  BEGIN
    X.sys$optional(x1);    
(* 2nd param omitted *)
    Y.sys$optional(x1,NIL); (* 2nd param omitted
*)
    Y.sys$optional(x1,x2);
  END user.

CHAPTER 6: PROCEDURE CALLING CONVENTIONS

In the context of the OpenVMS operating system, a procedure is a routine entered by a CALL (VAX) or JSR (Alpha) instruction. In a Oberon-2 program, such a routine can be a function or a procedure written in Oberon-2 an OpenVMS system service routine, a Run-Time Library (RTL) procedure or a procdure written in a foreign language.

This chapter provides information on calling conventions used by the OpenVMS Oberon-2 compiler and on calling OpenVMS system services and OpenVMS RTL procedures. A basic knowledge of the OpenVMS procedure calling and argument passing mechanisms is assumed. For more information see the OpenVMS Run-Time Library Reference Manual and the VAX or Alpha linker reference and calling conventions as well as the processor architecture handbook.

OpenVMS VAX Oberon-2 uses the VAX-11 CALLS instruction to call procedures. Each time a procedure is called, the Oberon-2 compiler constructs an argument list on the stack. The arguments in the list are based on the parameter type and the parameter kind (value or reference) specified in the formal parameter list and the values in the actual parameter list.

OpenVMS Alpha Oberon-2 uses the Alpha JSR instruction to call procedures. Each time a procedure is called, the Oberon-2 compiler stores the address of first 6 arguments in the processor registers R16 to R21. This is the standard OpenVMS parameter passing mode, for value and variable parameter.

Only in system services, RTL routines or foreign procedures, the parameter passing mode could be by immediate value. In this case, the values are passed in R16 to R21 when integer or in F16 to F21 when floating point. Complex data types are passed as a pair of floating point values (real and imaginary part); they are passed in consecutive places. If there are more than 6 parameters, the compiler constructs a quadword aligned argument list on the stack. The arguments in the list are based on the parameter type and the parameter kind (value or reference) specified in the formal parameter list and the values in the actual parameter list.

6.1 Parameter Passing Mechanisms

The OpenVMS procedure calling standard defines three mechanisms by which arguments are passed to procedures:

1. by-reference

2. by-immediate-value

3. by-descriptor

The following table describes the mechanisms that are used by the OpenVMS Oberon-2 compiler, depending on the type and the kind of the formal parameter. The additional data types of the Modula-2 language, marked by an "*", are also shown for the case of mixed language programmming.


  type          | value parameter      | reference (VAR)parameter
  --------------+----------------------+--------------------------
  BOOLEAN       |                      |
  CHAR          |                      |
  SHORTINT      |                      |
  INTEGER       |                      |
  LONGINT       |                      |
  POINTER       |                      |
  SET           |                      |
  LONGSET       |                      |
  BYTE          |                      |
  SHORTWORD     |                      |
  WORD          |                      |
  PTR           |                      |
  ADDRESS_32    |                      |
  ADDRESS_64    |                      |
  REAL          |                      |
  LONGREAL      |                      |
  COMPLEX       |                      |
  LONGCOMPLEX   |                      |
  F_FLOATING    |                      |
  D_FLOATING    |                      |
  G_FLOATING    |  by-reference        |  by-reference
  S_FLOATING    |                      |
  T_FLOATING    |                      |
  H_FLOATING    |                      |
  F_COMPLEX     |                      |
  D_COMPLEX     |                      |
  G_COMPLEX     |                      |
  S_COMPLEX     |                      |
  T_COMPLEX     |                      |
  H_COMPLEX     |                      |
  QUADWORD      |                      |
  SIGNED_64     |                      |
  UNSIGNED_64   |                      |
  OCTAWORD      |                      |
  CARDINAL*     |                      |
  BITSET*       |                      |
  Enumeration*  |                      |
  Subrange*     |                      |
  PROCESS*      |                      |
  --------------+----------------------+---------------------------------
  RECORD        | by-reference         | by-reference(tag by value and
                |                      | record address by reference;
                |                      | in Modula-2, the tag value is 0)
  --------------+----------------------+---------------------------------
  ARRAY         |  by-reference        | by-reference
  --------------+----------------------+---------------------------------
  PROCEDURE     | entry address by-reference(VAX)
                | address of the procedure descriptor by reference (Alpha)
  --------------+----------------------+----------------------------------
Open Arrays:

An open array parameter is passed by n+1 arguments, where n is the number of dimensions.

The parameter list created by the compiler for the open array formal parameter definition

(...; [VAR] A: ARRAY OF [ARRAY...] type; ...)

is equivalent to the following foreign parameter definition (see 6.3 for a description of the $I-suffix)

(...; high_0$I: CARDINAL; [high_1$I: CARDINAL; ...] adrA$I : SYSTEM.PTR; ...)

with adrA$I = ADR(A) and high_n$I = LEN(A, n)-1. In case of a value parameter, the called procedure is reponsible for making a local copy of the array on the stack. This is automatically done in the entry or prologue code of procedure.

Variable Record Parameters:

The parameter list created by the compiler for the formal variable record parameter definition

(...; VAR R: Record_Type; ...)

is equivalent to the following foreign parameter definition (see 6.3 for a description of the $I- and $R-suffixes)

(...; tag$I: CARDINAL; adrR$I : SYSTEM.PTR; ...)

with adrr$I = ADR(R) and tag$I = record type tag pointer value which points to the records base type with extension level 0 (key[0]).

6.2 Function Return Values

A function returns a value to the calling program. The method by which a value is returned depends on its type as listed below:


   type         |     return method
  --------------+--------------------------------------------
  BOOLEAN       |
  CHAR          |
  SHORTINT      |
  INTEGER       |
  LONGINT       |
  SET           |
  LONGSET       |
  POINTER       |
  BYTE          |
  SHORTWORD     |
  WORD          |     Register R0
  LONGWORD      |
  PTR           |
  ADDRESS_32    |
  ADDRESS_64    |
  CARDINAL*     |
  BITSET*       |
  Enumeration*  |
  Subrange*     |
  PROCESS*      |
  --------------+--------------------------------------------
  REAL          |
  F_FLOATING    |    Register R0 (VAX);     F0 (Alpha)
  S_FLOATING    |
  --------------+--------------------------------------------
  QUADWORD      |
  SIGNED_64     |    Registers R0,R1 (VAX); R0 (Alpha)
  ADDRESS_64    |
  --------------+--------------------------------------------
  LONGREAL      |
  D_FLOATING    |    Registers R0,R1 (VAX); F0 (Alpha)
  G_FLOATING    |
  T_FLOATING    |
  --------------+--------------------------------------------
  COMPLEX       |    Registers R0,R1 (VAX); F0,F1 (Alpha)
  F_COMPLEX     |
  --------------+--------------------------------------------
  LONGCOMPLEX   |     hiddenfirst variable parameter (VAX),
  D_COMPLEX     |    i.e.: by reference as the first
  G_COMPLEX     |    parameter in the function's
  S_COMPLEX     |    parameter list;
  T_COMPLEX     |    F0,F1 (Alpha)
  H_FLOATING    |
  --------------+--------------------------------------------
  OCTAWORD      |    hidden first variable parameter
  --------------+--------------------------------------------

6.3 Foreign Procedures/Foreign Interface Modules

Access to procedures written in other VAX|Alpha programming languages, especially to the OpenVMS system services and Run-Time Library routines, and access to external variables (global symbols) of any type including any procedure types is provided through special modules, so-called foreign interface or definitions modules (FIMs). They serve only to export the descriptions (symbol file) of the respective procedures and have no corresponding Oberon-2 implementation modules.

Motivation: The goal was not to extend the Oberon-2 syntax with additional keywords %FOREIGN, %IMMED, %STDESCR, and %REF as in Modula-2 (MaX|MVR). The simplest syntactic extension with the at least the power of expressiveness compared to Modula-2 (MaX|MVR) was to allow dollar-signs in identifiers within a limited scope of FIMs only. Since under OpenVMS all operating system service routines contain at least one "$"-sign in their names, this extension of the syntax for Oberon-2 identifiers could not be avoided.

A "$"-sign contained anywhere in the module name defines the module being a FIM. This is no limitation of the scope for module names, since the compiler declares all entries exported in the interface as external symbols. The name of a FIM is ignored at the linker level. Note, in Modula-2 (MaX|MVR), this is accomplished by the keyword "%FOREIGN" which prefixes the keywords "DEFINITION MODULE".

There is no different syntax for an Oberon-2 FIM. This means that procedure declarations must have a "END proc_name". The procedure's body "BEGIN " before the "END proc_name" is optional as defined in the Oberon-2 Report. But it is recommended to use only

PROCEDURE proc_name ...; END proc_name;

instead of

PROCEDURE proc_name ...; BEGIN END proc_name;

because Oberon-2 syntactically requires a "RETURN expression" if the procedure is a function.

This section contains the formal definitions of foreign procedures and variables to be linked to Oberon-2 programs. Procedure and variable names must be known to the linker and the calling convention must match at the linker level.

To allow full utilisation of the OpenVMS procedure calling standard, additional parameter passing specifiers have been introduced for parameter names, applicable only within FIMs (Modula-2 notation):

Oberon-2 parameter name suffixes defining parameter passing mechanism:

...$I denotes passing by immediate value; not allowed for formal parameter being open array or VAR parameter. Parameter's type size must be either 1, 2, 3, 4, 8, 12, or 16 bytes (in Modula-2: %IMMED p: T). On Alpha, complex data types are treated as two paramters (real and imaginary part)

...$R denotes passing by reference; allowed for variable or value formal parameters, but makes sense only for open arrays or VAR record types (in this case, ...$N is implied), because otherwise this is the default mechanism. (in Modula-2: [VAR] %REF p: T)

...$N denotes passing by reference without Oberon-2's additional type descriptor provided for any VAR parameter record (VarParRec). Only allowed for variable formal parameters of record type. (Modula-2 has no type descriptors/tags; MaX uses a dummy tag with value 0 to be compatible with A2O; MVR does not know about VarParRec tags.)

...$O denotes optional parameter for any parameter type (value and variable); it can be used as well as other suffixes. ...$O implies ...$N (no type descriptor). An actual parameter being a constant expression with the value NIL or 0 indicates parameter omission. ...$O makes only sense for parameter values passed by reference.

Immediate parameters can't be optional, otherwise the called routine can't detect whether the caller wants to pass a NIL value or whether the parameter is omitted. (In Modula-2, SYSTEM.NOP serves the same purpose as NIL in H2O|A2O)

...$S denotes passing by string descriptor; to be used only for one-dimensional open arrays with element type CHAR.

A manually constructed variable of record TYPE

STDESCR* = RECORD len: LONGINT; a: SYSTEM.PTR END;

could also be used with parameter passing specification

...$R (see above). (in Modula-2: [VAR] %STDESCR s: ARRAY OF CHAR)

Note, that these ...$x suffixes can't be combined. Only one suffix is evaluated.

As an example, a FIM called CommandLangInterface$ is shown which allows access to some screen handling procedures:


    MODULE CommandLangInterface$;

       TYPE CARDINAL* = LONGINT;

       PROCEDURE CLI$PRESENT*
          (    entityDesc$S: ARRAY OF CHAR): CARDINAL;

       PROCEDURE CLI$GET_VALUE*
          (     entityDesc$S: ARRAY OF CHAR;
           VAR  retdesc$S:    ARRAY OF CHAR;
           VAR  retlength: CARDINAL): CARDINAL;
       ...

     END CommandLangInterface$.
In contrast to Modula-2 (MVR), the Oberon-2 solution is more powerful in respect to external procedure variables. If a variable is of procedure type, then their parameters can also contain parameter passing specifiers.

Warning: Foreign definition modules should not be written without knowledge about the parameter passing mechanisms involved. See example in Appendix (Examples for foreign language interface definitions).

CHAPTER 7: SYSTEM DEPENDENT FACILITIES

7.1 Low Level Facilities: The Module SYSTEM

There are applications (e.g., system programming) for which the language rules may turn out to be too restrictive. For this reason, Oberon-2 provides some means for "low level programming"; most of them are implementation dependent.

The programmer is urged to use these low level facilities very carefully and only if it seems unavoidable. He will be much less protected against errors because low level facilities are not checked for consistency with language rules.

7.1.1 SYSTEM.VAL type casting (Type Transfer Functions)

Clarifications:

VAL (T, expression) allowed where an expression of type T is allowed.

VAL (T, variable_designator) allowed where an expression or variable designator of type T is allowed. This is not a language extension, its a feature of the ETH Oberon-2 front-end used in H2O|A2O (Crelier's OP2).

VAL changes the type of the second parameter. VAL does not involve any actual computation but modify the compiler's type checking. For instance, if c is an expression of type LONGINT then VAL(SET,c) is interpreted as the corresponding value of type SET. This is a correspondance determined by the underlying system and not by the programming language itself. Therefore, using type transfer functions requires familiarity with the internal representation and storage allocation scheme of the corresponding data types. In contrast to Modula-2 where code is generated for transfers from and to SYSTEM's word types with different sizes (zero fill-in of most significant bits), Oberon-2 simply takes the source expression or designator with the size of the target type T.

7.1.2. SYSTEM.CAST (reserved, but not yet implemented)

SYSTEM.CAST (T, expression) defined as in ISO Modula-2 (minimum of size of T or type size of expression is taken).

7.1.3. Other facilities of module SYSTEM

Module SYSTEM offers some further facilities of the Oberon-2 language. Most of them are implementation dependent and/or refer to the given processor. Facilities of that kind are sometimes necessary for the so called "low level programming".

The module SYSTEM is known to the compiler because its exported objects obey special rules, that must be checked by the compiler. If a compilation unit imports objects from module SYSTEM, no symbol file has to be supplied for this module.

Objects exported from module SYSTEM are constants, types, procedures and function procedures. Module SYSTEM is defined in the Oberon-2 Report. The following lists only extensions and clarifications:

Constants exported from SYSTEM: none.

Types exported from SYSTEM:

BYTE (=LOC), SHORTWORD, WORD (=LONGWORD), QUADWORD, OCTAWORD

Objects of these types represent individually accessible storage units (BYTE = one byte, SHORTWORD = two bytes, WORD = four bytes, QUADWORD = eight bytes, OCTAWORD = sixteen bytes). Only assignment is allowed for variables of these types.

A parameter of type BYTE, SHORTWORD, WORD, QUADWORD or OCTAWORD may be substituted by an actual parameter of any type with the same size or if the size of the formal and actual parameter differs, up-to the size of the formal paramter (maximum WORD on VAX and QUADWORD on Alpha). The same holds for the substitution of a variable open array parameter with elements of type BYTE, SHORTWORD, WORD, QUADWORD or OCTAWORD by a value of a type which size is not an integral multiple of the open array element size.

PTR (Modula-2's ADDRESS) Objects of type PTR represent the byte address of a storage location.

F_FLOATING, D_FLOATING, G_FLOATING, S_FLOATING, T_FLOATING, H_FLOATING

The Oberon-2 standard type REAL is implemented using the VAX-11 F_FLOATING data type. The other VAX-11 floating point data types are made available in the VAX-11 Oberon-2 compiler through export from module SYSTEM.

All operators defined in Oberon-2 for the type pervasive type REAL are also defined for the types F_FLOATING, D_FLOATING, G_FLOATING, S_FLOATING T_FLOATING and H_FLOATING.

With the /ieee/axp compilation option, the type of floating point literals is S_FLOATING or T_FLOATING, whereas /noieee sets the literal types to F_FLOATING or D_FLOATING.

Constant expressions of foating point type are evaluated at compile time.

The Oberon-2 compiler doesn't allow constants to be of type G_FLOATING or H_FLOATING.

Also, in contrast to Modula-2, different floating point types can be mixed in expressions (i.e., there is implicit conversion) except from G_ to D_ and vice versa. The standard procedures ENTIER and SYSTEM.LENTIER are applicable to all floating point data types.

Functions exported from SYSTEM:

PROCEDURE ADR(designator): LONGINT;

Returns the storage address of the variable or string constant argument. Clarification: Constant strings are also allowed as argument of ADR. This is not a language extension; it is allowed by OP2.

Description of other functions is contained in the Oberon-2 Report.

PROCEDURE LENGTH (s: ARRAY OF CHAR): LONGINT;

Returns the length of a string as defined in ISO Modula-2. Restriction for VAX only: The VAX instruction LOCC is used and hence the return value must be in the range between 0 and 65535. See also Appendix (Restrictions, extensions and clarifications).

PROCEDURE SYSTEM.LENTIER (t: SYSTEM.T_FLOATING): SYSTEM.SIGNED_64;

converts a floating point argument to 64 bit integer (A2O only) with the semantics of the pervasive function ENTIER. With /pointersize=64, SYSTEM.LENTIER is synonymous with the pervasive function procedure ENTIER.

Procedures exported from SYSTEM:

PROCEDURE SYSTEM.NEW (VAR p: SYSTEM.PTR; n: LONGINT);

allocates n bytes of storage on the heap. SYSTEM.NEW is the same as pervasive procedure NEW, except that no type descriptor is allocated for p. With A2O, a type descriptor (sysblock) is always generated (needed by Garbage Collector).

Register access:

SYSTEM.GETREG(n, v)

n must be a constant expression. 0<= num <= 31; if num=31 is used, 0 is returned (R31/F31 is read-as-zero, RAZ).

SYSTEM.PUTREG(n, x)

n must be a constant expression. 0<= num <= 31; if num=31 is used, R31/F31 is not modified (these registers are always zero).

The Alpha has two disjoint sets of integer and floating point registers. The argument type of the variable v and expression x in GETREG and PUTREG determines whether an integer or floating point register is used.

Exception handling support for OpenVMS Alpha (A2O only):

The way exception handling (LIB$ESTABLISH and LIB$REVERT) work on OpenVMS Alpha changed radically when compared to OpenVMS VAX, in that these routines are no longer available in the run-time system and in fact they can't be implemented as routines. Two functions procedures are exported from SYSTEM and they produce in-line code. The exception model chosen is dynamic. The declaration of the SYSTEM functions LIB$ESTABLISH and LIB$REVERT is

PROCEDURE SYSTEM.ESTABLISH (handle$I: HANDLER): HANDLER;

PROCEDURE SYSTEM.REVERT(): HANDLER;

The result type of both functions is of type HANDLER and the parameter of ESTABLISH should be structurally compatible with

HANDLER = PROCEDURE(VAR sigargs: SigArgs; mechArgs: MechArgs): LONGINT;

but the compiler does not check this type; it requires a proc type with LONGINT function result. Note, the type HANDLER is not exported from SYSTEM. The foreign interface module VMS$Exceptions declares all types and procedures necessary for exception handling.

Module Test_Exceptions illustrates how to catch and process an exception in Oberon-2 under OpenVMS Alpha.


MODULE VMSExceptions;
(*
  \251 (1996) Guenter Dotzel

  hG/19-Jun-1996: Record declarations for VMS$Exceptions
*)

IMPORT SYSTEM;

TYPE
  LONGINT   = SYSTEM.SIGNED_32;
  ADDRESS  *= LONGINT;
  ADDRESS64*= SYSTEM.SIGNED_64;
  INTEGER64*= SYSTEM.SIGNED_64;

  MechArgs *= POINTER TO RECORD
    args      *: LONGINT;
    flags     *: SET;
    frame     *: ADDRESS64;
    depth     *: LONGINT;
    resvdf1   *: LONGINT;
    dAddr     *: ADDRESS64;
    esfAddr   *: ADDRESS64;
    sigAddr   *: ADDRESS64;
    savR      *: ARRAY15 OF SYSTEM.QUADWORD;(*use indices below for access*)
    savF      *: ARRAY23 OF SYSTEM.QUADWORD;(*use indices below for access*)
    sig64Addr *: ADDRESS64;
  END;

  SigArgs64* = POINTER TO RECORD
    noArgs*,
    ss_signal64*   :LONGINT;  (* = SS$SIGNAL64 *)
    args*         :ARRAY 257 OF INTEGER64;
  END;


CONST (* LIBICB$K_INVO_CONTEXT_BLK_SIZE: *)
  LIBICB_K_INVO_CONTEXT_BLK_SIZE = 544;

TYPE
  InnerInvoContext = RECORD
    length *: LONGINT;
    flags  *: SET;    (* upper 8 bits are version byte *)
    procDesc  *: ADDRESS64;
    progCnt   *: ADDRESS64;
    procStatus*: SYSTEM.QUADWORD; (* 64 bit flagfield *)
    iReg *: ARRAY 31 OF SYSTEM.SIGNED_64;
    fReg *: ARRAY 31 OF SYSTEM.QUADWORD;
  END;

  InvoContext *= RECORD (InnerInvoContext)
    system: ARRAY LIBICB_K_INVO_CONTEXT_BLK_SIZE- SIZE(InnerInvoContext)
      OF SYSTEM.BYTE;
  END;

END VMSExceptions.

MODULE VMS$Exceptions; (* \251 (1996-1997) Guenter Dotzel A2O version of MaX's foreign definition module VMS_Exceptions GD/18-Aug-1995, hG/22-Aug-1995: corrected for AXP hG/19-Jun-1996: moved record type defs into VMSExceptions.def *) IMPORT SYSTEM, SS := SS$Definitions, PSL := PSL$Definitions, EX := VMSExceptions; TYPE LONGINT = SYSTEM.SIGNED_32; (* PP *) ADDRESS *= LONGINT; ADDRESS64*= SYSTEM.SIGNED_64; INTEGER64*= SYSTEM.SIGNED_64; SigArgs *= ARRAY 257 OF LONGINT; CONST (* NB. the SIGARGS() macro starts at 1 for sigArgs, and2 for sigName. * But these here are indixes for the array *) sigArgs *= 0; (* n = Additional Longwords *) sigName *= 1; (*sigPC *= n-1*) (*sigPSL*= n *) TYPE MechArgs *= EX.MechArgs; SigArgs64*= EX.SigArgs64; CONST savR0 *=0; savR1 *=1; savR16*=2; savR17*=3;savR18*=4; savR19*=5; savR20*=6; savR21*=7; savR22*=8; savR23*=9;savR24*=10; savR25*=11; savR26*=12; savR27*=13; savR28*=14; savF0 *=0; savF1 *=1; savF10*=2; savF11*=3; savF12*=4; savF13*=5; savF14*=6; savF15*=7; savF16*=8; savF17*=9; savF18*=10; savF19*=11; savF20*=12; savF21*=13; savF22*=14; savF23*=15; savF24*=16;savF25*=17; savF26*=18; savF27*=19; savF28*=20; savF29*=21; savF30*=22; (* todo: add Continue_64 and Resignal_64 *) SS$_RESIGNAL * = SS.SS$_RESIGNAL; SS$_CONTINUE * = SS.SS$_CONTINUE; SS$_UNWIND * = SS.SS$_UNWIND; SS$_SIGNAL64 * = SS.SS$_SIGNAL64; SS$_RESIGNAL_64 * = SS.SS$_RESIGNAL_64; SS$_CONTINUE_64 * = SS.SS$_CONTINUE_64; PSL$C_USER *= PSL.PSL$C_USER; TYPE ExceptionHandler * = PROCEDURE(VAR sigargs: SigArgs; mechArgs$I:MechArgs): LONGINT; (* Oberon does not allow to declare $I parameters in non-foreignprocedures *) OberonExceptionHandler * = PROCEDURE(VAR sigargs: SigArgs;mechArgs: MechArgs): LONGINT; (*--- call chain stuff ---*) CONST LIBICB$V_EXCEPTION_FRAME *= 0; LIBICB$V_AST_FRAME *= 1; LIBICB$V_BOTTOM_OF_STACK *= 2; LIBICB$V_BASE_FRAME *= 3; LIBICB$K_INVO_HANDLE_SIZE *= 4; TYPE InvoContext *= EX.InvoContext; Invo_Context *= InvoContext; (* VMS style aliases *) Invo_Context_Blk *= InvoContext; HANDLE *= LONGINT; (* invocationhandle, 4 Bytes *) InvoHandle *= HANDLE; Invo_Handle *= HANDLE; CONST LIB$K_INVO_HANDLE_NULL *= 0; PROCEDURE LIB$GET_INVO_CONTEXT *( invoHandle$I: InvoHandle; VAR invoContext$N: InvoContext): BOOLEAN; END LIB$GET_INVO_CONTEXT; PROCEDURE LIB$GET_CURRENT_INVO_CONTEXT *( VAR invoContext$N: InvoContext); END LIB$GET_CURRENT_INVO_CONTEXT; PROCEDURE LIB$GET_PREV_INVO_CONTEXT *( VAR invoContext$N: InvoContext): LONGINT; END LIB$GET_PREV_INVO_CONTEXT; PROCEDURE LIB$GET_INVO_HANDLE *( invoContext: InvoContext): InvoHandle; END LIB$GET_INVO_HANDLE; PROCEDURE LIB$GET_PREV_INVO_HANDLE *( invoHandle$I: InvoHandle): InvoHandle; END LIB$GET_PREV_INVO_HANDLE; PROCEDURE LIB$SIG_TO_RET* ( VAR sigargs: SigArgs; mechArgs: MechArgs): LONGINT; END LIB$SIG_TO_RET; PROCEDURE LIB$SIGNAL* (signal$I: LONGINT); END LIB$SIGNAL; PROCEDURE SYS$UNWIND* ( depadr$O: LONGINT; newpc$I: ADDRESS): LONGINT; END SYS$UNWIND; PROCEDURE SYS$GOTO_UNWIND* ( targetInvo: InvoHandle; targetPC$O: ADDRESS; newR0$O, newR1$O: INTEGER64): LONGINT; END SYS$GOTO_UNWIND; PROCEDURE SYS$PUTMSG* ( msgvec$I: ADDRESS64; actrtn$I: ADDRESS64; facnam$S: ARRAY OF CHAR; (* 32 or 64Bit Stringdescriptor*) actprm$I: LONGINT): LONGINT; END SYS$PUTMSG; PROCEDURE SYS$SETEXV* ( vector$I: LONGINT; newhnd$I: ExceptionHandler; acmode$I: LONGINT; VAR prvhnd$O: ExceptionHandler): LONGINT; END SYS$SETEXV; END VMS$Exceptions.
MODULE Test_Exceptions; (* ModulaWare.com Exception handling example for A2O Oberon-2 for OpenVMSAXP DW/20-Jul-1994 GD/18-Aug-1995: transpiled into Oberon-2 for A2O *) IMPORT S:=SYSTEM, EX:=VMS$Exceptions, STextIO, SWholeIO; VAR old: LONGINT; (*PROC;*) i: LONGINT; PROCEDURE MyHandler (VAR x: EX.SigArgs; y: EX.MechArgs): LONGINT; VAR s: LONGINT; BEGIN (* Convert exception to return condition value *) (*DEC(x[EX.sigArgs],2); s := EX.SYS$PUTMSG(S.ADR(x), 0, NIL, 0); *) RETURN EX.LIB$SIG_TO_RET(x, y); END MyHandler; PROCEDURE DivByZeroTry1():LONGINT; VAR x,y: REAL; BEGIN old := S.ESTABLISH(EX.LIB$SIG_TO_RET); y := 0.0; x := 5.0 / y; RETURN ENTIER(x); END DivByZeroTry1; PROCEDURE DivByZeroTry2():LONGINT; VAR x,y: REAL; BEGIN old := S.ESTABLISH(MyHandler); y := 0.0; x := 5.0 / y; RETURN ENTIER(x); END DivByZeroTry2; BEGIN old := S.REVERT(); (* A NoOp - because LIB$ESTABLISH *) i := 0; (* has not been called yet *) i := DivByZeroTry2(); IF ~ ODD(i) THEN SWholeIO.WriteInt(i, 12); STextIO.WriteString(" Arithmetic error in DivByZeroTry2"); STextIO.WriteLn; END; i := 0; i := DivByZeroTry1(); IF ~ ODD(i) THEN SWholeIO.WriteInt(i, 12); STextIO.WriteString(" Arithmetic error in DivByZeroTry1"); STextIO.WriteLn; EX.LIB$SIGNAL(i); (* Re-raise exception *) END; END Test_Exceptions.

7.2 Storage Management

7.2.1 The Module Storage

H2O stand-alone programs: The storage management procedures ALLOCATE and DEALLOCATE which serve to dynamically obtain and return storage space can be imported from the library module Storage:

PROCEDURE ALLOCATE (VAR p: SYSTEM.PTR; size: SYSTEM.SIGNED_32);

PROCEDURE DEALLOCATE (VAR p: SYSTEM.PTR; size: SYSTEM.SIGNED_32);

The pervasive procedure NEW internally calls LIB$GET_VM from within the Oberon-2 run-time system (MOD$MEMALLOC).

A2O stand-alone programs: The pervasive procedures NEW and SYSTEM.NEW internally call

- Storage64.ALLOCATE_32 with /pointersize=32

- Storage64.ALLOCATE with /pointersize=64.


MODULE Storage64;
(* Oberon-2 module for H2O by hG/18-Aug-1996
   ALLOCATE,    DEALLOCATE    -> 64 bit pointers 
   ALLOCATE_32, DEALLOCATE_32 -> 32 bit pointers
GD/11-Oct-1997: ADDRESS_32, ADDRESS_64 eliminated

   32 bit and 64 bit Storage module
   [DE]ALLOCATE: 64 bit (VLM) with /pointersize=64
   [DE]ALLOCATE: 32 bit       with /pointersize=32

   File Storage64.Mod

   Copyright (1999) Guenter Dotzel, http://www.modulaware.com/

   hG/19-Dec-1997: 64-bit version
   GD/27-Jan-1999: automatic detection of VLM.
     Uses LIB$GET_/LIB$FREE_VM instead of LIB$GET_/LIB$FREE_VM_64
     when operating system version is pre V7.0 or /pointersize=32
*)
IMPORT SYSTEM,
  lib := LIB$,
  vms:=VMS$,
  syi := SYI$Definitions;

TYPE
 ADDRESS_32 = SYSTEM.SIGNED_32;
 ADDRESS_64 = SYSTEM.SIGNED_64;

VAR os64: BOOLEAN;

PROCEDURE ALLOCATE_32 * (VAR v: SYSTEM.SIGNED_32; n: SYSTEM.SIGNED_32);
VAR Result: lib.CARDINAL;
BEGIN
  Result := lib.LIB$GET_VM (n, v);
  IF ~ ODD(Result) THEN lib.LIB$SIGNAL(Result) END;
END ALLOCATE_32;

PROCEDURE DEALLOCATE_32 * (VAR v: SYSTEM.SIGNED_32; n: SYSTEM.SIGNED_32);
VAR Result: lib.CARDINAL;
BEGIN
  Result := lib.LIB$FREE_VM (n, v);
  IF ~ ODD(Result) THEN lib.LIB$SIGNAL(Result) END;
  v := SYSTEM.VAL(SYSTEM.SIGNED_32, NIL);
END DEALLOCATE_32;

PROCEDURE ALLOCATE * (VAR v: SYSTEM.SIGNED_64; n: SYSTEM.SIGNED_64);
VAR Result: lib.CARDINAL; addr32: ADDRESS_32; addr64: ADDRESS_64;
BEGIN
  IF os64 THEN
    Result := lib.LIB$GET_VM_64 (n, addr64);
    v := addr64;
  ELSE
    Result := lib.LIB$GET_VM (SYSTEM.SHORT(n), addr32);
    v := addr32;
  END;
  IF ~ ODD(Result) THEN lib.LIB$SIGNAL(Result) END;
END ALLOCATE;

PROCEDURE DEALLOCATE * (VAR v: SYSTEM.SIGNED_64; n: SYSTEM.SIGNED_64);
VAR Result: lib.CARDINAL; addr: ADDRESS_32;
BEGIN
  IF os64 THEN
    Result := lib.LIB$FREE_VM_64 (n, v);
  ELSE
    addr := SYSTEM.SHORT(v);
    Result := lib.LIB$FREE_VM (SYSTEM.SHORT(n), addr);
  END;
  IF ~ ODD(Result) THEN lib.LIB$SIGNAL(Result) END;
  v := SYSTEM.VAL(SYSTEM.SIGNED_64, NIL);
END DEALLOCATE;

  PROCEDURE Adr32 (VAR s :ARRAY OF SYSTEM.BYTE):SYSTEM.SIGNED_32;
  VAR i :SYSTEM.SIGNED_64;
  BEGIN 
    i := SYSTEM.ADR(s);
    RETURN SYSTEM.SHORT(i) 
  END Adr32;       

PROCEDURE Init;
VAR iList :ARRAY 2 OF vms.item_desc;
    str   :ARRAY 9 OF CHAR;
    cs,
    cv,
    len   :SYSTEM.SIGNED_32;
BEGIN
  len := 8;
  iList[0].buff_len := SYSTEM.VAL(SYSTEM.SHORTWORD, 8);
  iList[0].item_code := SYSTEM.VAL(SYSTEM.SHORTWORD, syi.SYI$_VERSION);
  iList[0].buff_addr := Adr32(str);
  iList[0].len_addr := Adr32(len);
  iList[1].buff_len := SYSTEM.VAL(SYSTEM.SHORTWORD, 0); iList[1].item_code := iList[1].buff_len;
  cv := vms.SYS$GETSYIW(0, 0, NIL, iList, 0, 0, 0);
  ASSERT (ODD(cv) & (len >= 0) & (len < 9));
  str[len] := 0X;
  ASSERT (str[2]="."); (* now "V7.1   ", but what if we get to V10.0? *)
  os64 := (SIZE(LONGINT)=8) & ((ORD(str[1]) - ORD("0")) > 6);
END Init;

BEGIN
  Init
END Storage64.

Before the call of ALLOCATE[_32], the compiler generates code to add the tag- and the descriptor-size to the size to be allocated and rounds the total size up to a multiple of 32 bytes.

Dispose is not featured by the Oberon-2 language. Normally a garbage collector (GC) retrieves unreachable memory blocks under certain conditions at specific events when running under control of an Oberon System. In contrast to AlphaOberon, stand-alone applications generated with A2O|H2O under OpenVMS don't have a GC.

To dispose (recover) heap space which is no longer needed, explicit calls are necessary for stand-alone programs. Since module Storage calls procedure LIB$GET_VM for ALLOCATE, its complement procedure Storage.DEALLOCATE could be used in stand-alone Oberon-2 to dispose storage. This feature must used with utmost care. In particular, disposal of a pointer shall also deallocate the type descriptor. Module Objects_Types (see 7.3.1) exports disposal procedures, which allow to dispose objects depending on their dynamic type.

Storage.ALLOCATE[_32] signals an OpenVMS exception whenever there is not enough free heap space (virtual memory limit).

When writing your own storage management procedures you should care for an appropriate declaration.

7.2.2 Storage Allocation

The following table summarizes the storage allocation and alignment for variables of unstructured and set type. Note that "word", "longword", "quadword", and "octaword" are DEC-terms. (A "*" marks Modula-2 types):


  type       | storage allocation    | alignment boundary
  -----------+-----------------------+-----------------------
  BOOLEAN    |                       |
  CHAR       |                       |
  BYTE       |  8 bits (1 byte)      |   byte
  SHORTINT   |                       |
  SIGNED_8   |                       |
  -----------+-----------------------+-----------------------
  SHORTWORD  |                       |
  INTEGER    |  16 bits (1 word)     |   word     /NoInteger
  SIGNED_16  |                       |
  -----------+-----------------------+-----------------------
  SET        |                       |
  BITSET*    |                       |
  INTEGER    |                       |
  LONGINT    |                       |            /Integer
  SIGNED_32  |                       |
  CARDINAL*  |                       |
  REAL       |  32 bits(1 longword)  |   longword
  F_FLOATING |                       |
  S_FLOATING |                       |
  WORD       |                       |
  POINTER    |                       |         /pointersize=32
  PTR        |                       |         /pointersize=32
  ADDRESS_32 |                       |
  -----------+-----------------------+-----------------------
  LONGSET    |                       |
  LONGINT    |                       |         /pointersize=64
  SIGNED_64  |                       |
  LONGREAL   |                       |
  D_FLOATING |                       |
  G_FLOATING |                       }
  T_FLOATING |                       |
  COMPLEX    |  64 bits (1 quadword) |   longword (VAX)
  F_COMPLEX  |                       |   quadword (Alpha)
  S_COMPLEX  |                       |
  QUADWORD   |                       |
  POINTER    |                       |         /pointersize=64
  PTR        |                       |         /pointersize=64
  ADDRESS_64 |                       |
  -----------+-----------------------+-----------------------
  H_FLOATING |                       |
  LONGCOMPLEX|                       |   quadword (Alpha)
  D_COMPLEX  | 128 bits (1 octaword) |  longword (VAX)
  G_COMPLEX  |                       |
  T_COMPLEX  |                       |
  OCTAWORD   |                       |
  -----------+-----------------------+-----------------------
  Enumeration|  8 bits (1 byte) if   |  byte
            *|  type contains 256 or |
             |  less elements;       |
             |  16 bits (1 word)     |   word
             |  if type contains more|
             |  then 256 elements    |
  -----------+-----------------------+-----------------------
  SET OF*    |   8 bits (1 byte),    |   byte
             |  16 bits (1 word), or |   word
             |  32 bits (1 longword),|   longword
             |  64 bits (1 quadword),|   quadword
             | 128 bits (1 octaword),|   quadword
             | 256 bits(2 octawords),|   quadword
             |  according to         |
             |  cardinality of base  |
             |  type                 |

Variables of Modula-2 subrange type are allocated and aligned in the same way as variables of their base type.

An array is stored and aligned according to the type of its elements. Every element is also aligned according to its type.

Records are stored field by field. Each field is allocated according to its type and aligned on a byte boundary (see also /packed_record compilation qualifier). The associated type tag is allocated separately in a read-only program section (stand-alone programs).

Local variables on the stack are always aligned on a 4 byte boundary, (longword aligned on VAX) and 8 byte boundary (quadword aligned on Alpha).

7.3 Persistent Objects Support

7.3.1 The Module Objects_Types (for stand-alone programs)

Module Objects_Types is a low level run-time system module written in Oberon-2. It is indirectly called by any module body during initialisation phase to register all module names. If a module declares any non-anonymous record types, their type names are also registered.

H2O only: The call to the Oberon-2 run-time-system procedure mod$storemodobjects (which is part of the module ModRTS in library Modula.OLB) is automatically peformed after calling the initialisation part of any imported modules.

A2O only: The call to Objects_Types.StoreModObjects is automatically peformed after calling the initialisation part of any imported modules.

Objects_Types exports procedures for type-to-name, name-to-type conversion, allocation, cloning and disposal of objects. Module Objects_Types is described in The ModulaTor, Vol. 3, Nr. 1 (Feb-1993).


DEFINITION Objects_Types;

  CONST
    QuadwordSize = 8;
    adrSize = 8;
    maxIdentLen = 32;
    tagSize = 8;

  TYPE
    ADDRESS_64 = SYSTEM.SIGNED_64;
    Name = ARRAY 32 OF CHAR;
    NamePtr = POINTER TO RECORD
      name: Name;
    END ;
    Object = POINTER TO ObjectDesc;
    ObjectDesc = RECORD END ;
    Size = SYSTEM.SIGNED_64;
    Tag = SYSTEM.SIGNED_64;
    Type = POINTER TO TypeDesc;
    TypeDesc = RECORD
      module: NamePtr;
      name: Name;
    END ;

  VAR
    Modules-: ARRAY 256 OF ModEntryDesc;

  PROCEDURE DisposeArray (VAR o: SYSTEM.ADDRESS_64);
  PROCEDURE DisposeObj (VAR o: Object);
  PROCEDURE NewObj (VAR o: Object; t: Type);
  PROCEDURE SizeOf (o: Object): SYSTEM.SIGNED_64;
  PROCEDURE StoreModObjects (typeDescBase: TypesArray);
  PROCEDURE This (module, name: ARRAY OF CHAR): Type;
  PROCEDURE TypeName (typ: Type; VAR module, name: ARRAY OF CHAR);
  PROCEDURE TypeOf (o: Object): Type;

END Objects_Types.

7.3.2 The Module Types (for AlphaOberon)

Module Types is a low level run-time system module written in Oberon-2. It accesses the type information constructed during module loading

Types exports procedures for type-to-name, name-to-type conversion, allocation, and cloning of objects. Disposal of unreachable objects is the task of the GC.


DEFINITION Types;

  IMPORT Modules, A2OLayout;

  TYPE
    Module = Modules.Module;

    Name = A2OLayout.Name;

    Object = SYSTEM.ADDRESS_64;

    Type = POINTER TO TypeDesc;


  PROCEDURE BaseOf (t: Type; lev: INTEGER): Type;
  PROCEDURE LevelOf (t: Type): INTEGER;
  PROCEDURE NewObj (VAR o: SYSTEM.ADDRESS_64; typ: Type);
  PROCEDURE SizeOf (o: SYSTEM.ADDRESS_64): SYSTEM.SIGNED_64;
  PROCEDURE This (m: Modules.Module; name: ARRAY OF CHAR): Type;
  PROCEDURE TypeName (typ: Type; VAR module, name: ARRAY OF CHAR);
  PROCEDURE TypeOf (o: SYSTEM.ADDRESS_64): Type;

END Types.

7.3.3 The Module Objects

The generic module Objects provides the so-called load/store-mechanism for persistent objects. There are two implementations:

- For stand-alone programs, Objects is based on the above module Objects_Types and ISO Modula-2 library modules IOChan and RawIO.

- For AlphaOberon, Objects is based on the above module Types and Oberon System modules Files and Modules

Module Objects is described in detail in Chap. 8 (persistent objects) in OOPiO2 and in The ModulaTor, Vol. 3, Nr. 1 (Feb-1993). The latter contains full source code and an application example illustrating so-called up-calls.


DEFINITION Objects;

  IMPORT A2OLayout, Files;

  CONST
    maxIdentLen = 32;

  TYPE
    ModuleTypeName = RECORD
      module, type: A2OLayout.Name;
    END ;

    Object = POINTER TO ObjectDesc;
    ObjectDesc = RECORD
      PROCEDURE (o: Object) Load (VAR stream: Stream);
      PROCEDURE (o: Object) Store (VAR stream: Stream);
    END ;

    Stream = RECORD (Files.Rider)
      PROCEDURE (VAR r: Stream) ReadString (VAR s: A2OLayout.Name);
      PROCEDURE (VAR r: Stream) WriteString (s: A2OLayout.Name);
    END ;

    TypeName = A2OLayout.Name;


  PROCEDURE CopyObj (orig: Object; VAR copy: Object);
  PROCEDURE DisposeObj (VAR o: Object);
  PROCEDURE InitStream (VAR r: Stream);
  PROCEDURE NameToObj (name: ModuleTypeName; VAR o: Object);
  PROCEDURE ObjToName (o: Object; VAR name: ModuleTypeName);
  PROCEDURE ReadObj (VAR r: Stream; VAR x: Object);
  PROCEDURE WriteObj (VAR r: Stream; x: Object);

END Objects.

APPENDIX A: COMPLETE EXAMPLE

In order to provide the user with a first entry into the use of the Oberon-2 Compiler, a complete example how to compile, link and execute a Oberon-2 program that consists of several modules is shown in the following. All inputs to be made by the user are on lines marked by the OpenVMS-"$"-prompt. Program output is printed in Courier font.

Suppose you have two source files,

a module EXAMPLE.MOD,


  MODULE Example;
    . . .
  END Example.
and a module MAIN.MOD

  MODULE Main;
  IMPORT Example;
    . . .
  END Main.
The dialog to run the complete program might look as follows:

$ A2O EXAMPLE/log/list <return>
                          | modules to be used must be compiled
                          | prior to their import.
                          | Compiles EXAMPLEDB.MOD and
                          | produces a source listing.
                          | LOG is enabled:

OpenVMS Oberon-2 V3.0 by ModulaWare
  compiling SYS$USER:[H2OTST]EXAMPLE.MOD;1
   Example: SYS$USER:[H2OTST]EXAMPLE.SYN;1
   new symbol file generated.

 $ A2O MAIN/log <return>
 OpenVMS Oberon-2 V3.0 by ModulaWare
  compiling SYS$USER:[H2OTST]MAIN.MOD;1
   Example: SYS$USER:[H2OTST]EXAMPLE.SYN;1
                          | standard search strategy
   Main: SYS$USER:[H2OTST]MAIN.SYN;1
   new symbol file generated.


 $ LINK MAIN,EXAMPLE <return>
                          | links MAIN.OBJ and EXAMPLE.OBJ


 $ RUN MAIN <return>
                          | executes MAIN.EXE and uses
APPENDIX B: Oberon-2 Language Report

APPENDIX C: RESTRICTIONS, EXTENSIONS and CLARIFICATIONS

APPENDIX D: LIBRARY AND INTERFACE MODULES

D.1 ISO Modula-2 Standard Library

Oberon-2 programmers developing stand-alone applications are encouraged to use the ISO Modula-2 Standard Library. The full set of their Oberon-2 interface modules are provided with the A2O|H2O distribution kit.

The annotated interface definition modules have the file extension .DEF; their associated Oberon-2 interface definition modules have the extension .MOD. The definition modules for the ISO Modula-2 Standard Library are also listed in The ModulaTor, Sep-1992.

D.3 The Uni* library modules

When migrating from ModulaWare's Modula-2 to Oberon-2: The Oberon-2 interface modules for the Modula-2 Uni* library are not part of the A2O|H2O distribution kit. If certain modules are needed when migrating from Modula-2 to Oberon-2, their interfaces must be converted manually.

D.4 Definitions of the OpenVMS-specific Foreign Modules

D.4.1 Status Codes, Function Codes and other OpenVMS Constants

The following is a list of the foreign interface modules/file names that are distributed with the A2O|H2O distribution kit.

The module names are constructed out of the first two or three or four characters of the file name followed by "$" and the word "Definitions", and then shortened to 9 characters.

For example the module contained in CLI$DEFIN.DEF is named CLI$Definitions. The definitions of this service was extracted from the $CLIDEF Macro.


CIN$DEFIN.DEF
CLI$DEFIN.DEF
DC$DEFINI.DEF
DEV$DEFIN.DEF
DSC$DEFIN.DEF
DTIF$DEFI.DEF
DVI$DEFIN.DEF
HLP$DEFIN.DEF
IO$DEFINI.DEF
JPI$DEFIN.DEF
LBR$DEFIN.DEF
LCK$DEFIN.DEF
LIB$DEFIN.DEF
LNM$DEFIN.DEF
MNT$DEFIN.DEF
MOD$DEFIN.DEF
MTH$DEFIN.DEF
NMA$DEFIN.DEF
OBJ$DEFIN.DEF
OTS$DEFIN.DEF
PQL$DEFIN.DEF
PRC$DEFIN.DEF
PRV$DEFIN.DEF
PSL$DEFIN.DEF
QUI$DEFIN.DEF
RMS$DEFIN.DEF
SEC$DEFIN.DEF
SMG$DEFIN.DEF
SMG$MSGDE.DEF
SS$DEFINI.DEF
STR$DEFIN.DEF
SYI$DEFIN.DEF
TT$DEFINI.DEF
TT2$DEFIN.DEF
D.4.2 OpenVMS Operating System Services and Run-Time Library Interface

All modules containing a "$"-sign in the module/file name are foreign interface modules without Modula-2 or Oberon-2 implementation.

Modules with the extension .DEF are Oberon-2 interface definitions for the Modula-2 implementation module located in MOD$SYSTEM:Modula.OLB.

Modules with the extension .MOD are Oberon-2 source modules.

Modules with the extension .MOC are encrypted Oberon-2 source modules.


CONVERSIO.DEF     number string conversions (decimal, hex, octal),
                  number type conversions between Byte, ShortWord,
                  LongWord (Integer, Cardinal), F_,D_,G_,H_FLOATING.
                  (.obj in Modula.olb)

Grapical User Interfaces:
DECW$XLIBDEF.DEF  XWindow declarations and procedures
DECW$XLIBMSG.DEF  XWindow message declarations
DECW$MOTIF.DEF    OSF/Motif declarations and procedures

                 
OpenVMS Layered Products Support
FDV$DEF.DEF       FMS Forms Management System
GKS$DEFS.DEF      GKS$ declarations and procedures
GKS$MSGS.DEF      GKS$ message number definitions

LIB$.DEF         
LIB$ routines
MTH$.DEF         
MTH$ routines
NUMBER$CO.DEF     MTH$ number conversion routines
OTS$.DEF          32 bit and 64 bit signed and unsigned modulus and division

OUTPUT$CO.DEF     selection of FOR$, OTS$ routines

                 
OpenVMS Record Management System:
RMS$.DEF         
RMS$ Oberon-2 data structures and declarations
RMS$FILES.DEF     RMS$FilesSignal, procedure LIB$SIGNAL for RMSAccess
RMSAccess.MOD     RMS Oberon-2 procedures (combination of Modula-2's
                  RMS and RMSFiles modules, with Oberon-2 implementation)

SMG$.DEF         
SMG$ Screen Management procedures
SMG$MSGDE.DEF     SMG$ Screen Management
messages

STR$.DEF         
STR$ and LIB$ String handling procedures
STRINGS.MOC       Alternate ISO Modula-2 Std Lib implementation module
                  for string handling.
                 
The Modula-2 implementation is in Modula.OLB
                 
Unfortunately, there is different module
with the same name in AlphaOberon, which leads
to version conflicts, when recompiled.

VIR$.DEF         
SYS$ OpenVMS virtual memory and event-flag procedures
VMS$.DEF         
SYS$ OpenVMS Systems services procedures

ModulaWare developed a tool ForeignDefToO2 (written in Oberon-2), which semi-automatically converts Modula-2's foreign definition modules and proper definition modules to Oberon-2.

If you require further modules such as PPL or UIS (VWS) or if you have special Modula-2 foreign interface modules, please contact ModulaWare.

APPENDIX E: - (Empty)

APPENDIX F: - (Empty)

APPENDIX G: OpenVMS Oberon-2 Help File

The layout of the following text is in the format suited for the OpenVMS help facility. The ascii text is contained in file H2O.HLP on the distribution kit.

H2O
Invokes the OpenVMS Alpha|VAX Oberon-2 compiler to compile an
Oberon-2
compilation unit. This command is described in detail in the
OpenVMS Alpha|VAX Oberon-2 User's Guide (H2OUM).

 Format:

     A2O file-spec
     H2O file-spec

2 Parameters file-spec
 Specifies one Oberon-2 source program file to be compiled.
 If you do not specify a file type, the default file type MOD is used.
 For default a Oberon-2 program module is compiled.
2 Qualifiers

/ANALYSE[=(AoptionList)]
/NOANALYSE (D)
 Source code analyser to be used only in combination with the qualifiers
 NoObject, NoMachine_Code, NoSymFile, NoCross_Reference.

 optionList=(intermediate_items, count_statements, redefine_methods,
           used_before_set, var_parameters, exported_items)

 (This feature of A2O|H2O is unsupported).
 See H2O User's Guide for a detailed description of the analyser.

/AXP (D; Alpha/A2O only)
/NOAXP (D; VAX/H2O only)

Determines whether code is generated for Alpha or VAX.

/CHECK[=(CoptionList)] (D)
/NOCHECK
 Indicates whether the compiler should generate additional code
 to perform run-time checks, clear local pointers and heap memory
 or assertion evaluation.

  CoptionList=(stackcheck, indexcheck, typecheck, overflowcheck,
              rangecheck, pointerinit, asserteval, heapinit)

 (a) array index bound (indexcheck),
 (b) case label for case without else-clause (indexcheck),
 (c) set element index in IN relation, set constructor, and
     predeclared procedures INCL and EXCL(rangecheck),
 (d) when evaluating an integer expressions with operators
     +, -, negation, *, MOD, and DIV (overflowcheck),
 (e) using predeclared function ABS, and ASH (overflowcheck),
 (f) using predeclared procedures INC and DEC procedures (overflowcheck),
 (g) integer to integer conversion with SHORT (overflowcheck),
 (h) integer to character conversion with CHR (overflowcheck), and
 (i) real to integer conversion with ENTIER (overflowcheck),
 (j) for 0 < dimensions and total size < 2^31 in NEW for dynamic arrays
     (rangecheck),
 (k) for dynamic pointer type-tag test (typecheck),
 (l) to clear all localy declared pointer variables at procedure entry
     (pointerinit),
 (m) to clear the heap allocated with NEW or SYSTEM.NEW (heapinit),
 (o) to evaluate the expression in ASSERT procedure (asserteval).
 (p) to check the stack at procedure entry (stackcheck).
     Stackcheck is only required if any procedure of the compilation
     unit may be called from a (Modula-2) coroutine.

/COMPLEX
/NOCOMPLEX (D)
 Controls whether the compiler knows the data type COMPLEX and
 LONGCOMPLEX, the pervasive functions CMPLX, RE and IM and the associated
 operations of ISO Modula-2.
 Note that Oberon-2 allows redeclaration of any pervasive type name.

/CROSS_REFERENCE
/NOCROSS_REFERENCE    (D)
 Controls whether the compiler creates a  cross-reference  listing
 as part of the listing file.
 The  default  is /NOCROSS_REFERENCE, which does not create
 a cross-reference listing.
 The cross-reference listing generation may fail if the source is not
 free of syntactical errors.
 This qualifier is ignored if no listing file is being generated.

/DEBUG
/NODEBUG    (D)
 Controls whether  the  compiler  makes  local  symbol  table  and
 traceback  information available to the VAX/VMS Symbolic Debugger
 and  the  run-time  error-reporting  mechanism.  The  default  is
 NODEBUG, which produces only traceback information.

/DUMP_SYMFILE
/NODUMPSYMFILE   (D)
 Produces a modestly readable form of the symbol file being produced
 on SYS$OUTPUT (unsupported; reserved for use by ModulaWare only)

/EXTEND_SYMFILE
/NOEXTEND_SYMFILE (D)

 This qualifier allows to extend a fine-grained symbol file
 (object model) and is only applicable in combination
 with /FINE_GRAINED_SYMFILE.


/FINE_GRAINED_SYMFILE
/NOFINE_GRAINED_SYMFILE (D)

 This qualifier enables the so-called object model, which
 allows to export additional constants, types, variables,
 procedures and as long as the clients don't use SIZE(recordType),
 it is allowed to extend record types with additional
 exported and hidden fields. Object model symbol-files
 contain a so-called finger-print per exported item,
 whereas the non-object model symbol-files contain a single
 module-key.
 All inconsistencies with existing clients will be detected at
 load-time in AlphaOberon.
 /Fine_Grained_SymFile can only be used in combination with
 /Oberon_Loadfile and /PointerSize=64.

 Symbol- and object-file extensions:

 /PointerSize=32    | /fine_grained_symfile   /NOfine_grained_symfile

/ Oberon_LoadFile | -disallowed- -disallowed- /NOOberon | -disallowed- .syn, .obj /PointerSize=64 | /fine_grained_symfile /NOfine_grained_symfile
/ Oberon_LoadFile | .syo, .olf .syn64, .olf64 /NOOberon | -disallowed- .syn64, .obj64 When symbol files with the extension .syn64 is not found, the compiler tries .syn. /FOREIGN_CODE (D on Alpha) /NOFOREIGN_CODE (D on VAX) Use this qualifier only if Oberon-2 or Modula-2 procedures may also be called by other languages than Oberon-2 or Modula-2. It is not needed if procedures written in languages other than Oberon-2 are called by the Oberon-2 program. Remember that procedures can be exported via explicit export or via assignment to procedure variables or procedure parameters or via ADR). Note, this affects only the code generation and has nothing to do with so-called foreign interface modules (those with a "$"-sign in the module name) whose only purpose is to generate a dummy symbol file. NOTE: The FOREIGN_CODE qualifier is only needed if a procedure of the module is called from within a coroutine and if a stack-check is enabled; see /optimize. /INTEGER_type_match_pointerSize /NOINTEGER_type_match_pointerSize (D) For default (/NoInteger), the pervasive data type SHORTINT is a 8 Bit, INTEGER is a 16 Bit and LONGINT is a 32 Bit signed number. If /Integer is selected, the pervasive type INTEGER is a signed number with bits, where x is the qualifier value of /pointersize (default 32). Using /Integer makes the pervasive type INTEGER compatible (identical) to the pervasive type LONGINT of a module which was compiled with /NoInteger. Attention, symbol file will change when objects of type INTEGER are exported when this qualifier is swapped at recompilation. If /Integer is selected, the pervasive types SHORTINT and LONGINT are not known. The types SYSTEM.SIGNED_(8,16,32,64) are allways available. Don't use these new system types if avoidable; this is a feature of the A2O|H2O implementation; they are not available in other Oberon-2 compilers and hence are not portable. /IEEE (Alpha only) /NOIEEE (D) Determines the pervasive type REAL and LONGREAL. With IEEE, they are synonymous for F_ and D_FLOATING, with NOIEEE, they are synonymous for S_ and T_FLOATING. The type of real number literals depends on the actual type of REAL and LONGREAL. /INSTRUCTIONMODE[=IoptionList] (Alpha only) /NOINSTRUCTIONMODE (D) IoptionList = (FptTrapB, ChoppedDECRounding, SoftwareDECTrap, UnderflowDECTrap, OverflowDECTrap, ChoppedIEEERounding, DynamicRounding, PlusInftyRounding, MinusInftyRounding, InexactIEEETrap, SoftwareIEEETrap, UnderflowIEEETrap, OverflowIEEETrap, IntTrapB, IntOverflow) These options enable the corresponding Alpha instruction qualifiers as explained in the DEC Alpha architecture reference manual. If precise trap delivery is required, enable FptTrapB together with the SoftwareIEEETrap and SoftwareDECTrap. This slows down execution of floating point arithmetic. /ISO /NOISO (D) Controls whether the compiler accepts certain language extensions and modifications. Reserved; not yet used. /LIST[=file-spec] /NOLIST (D) Controls whether the compiler creates a listing file. If you issue the H2O command from interactive mode, the compiler, by default, does not produce a listing file. However, if the H2O command is executed from batch mode, /LIST is the default. In either case, the listing file is not automatically printed. You must use the PRINT command to obtain a line printer copy of the Oberon-2 listing file. Note that the /LIST qualifier permits you to include a file specification for the listing file. If you omit the file specification, the compiler defaults to the name of the input source file, the default directory, and a file type of LIS. /LOG /NOLOG (D) Specifies whether the compiler displays information on its running version, the succession of the different compiler passes and the symbol files read. /NOLOG is the default for interactive mode, /LOG is the default for batch. /MACHINE_CODE /NOMACHINE_CODE (D) Specifies whether the listing file should include a representation of the machine code generated by the compiler. If no listing file is being generated, this qualifier is ignored. No machine code is generated if errors are detected in the source program. The default is /NOMACHINE_CODE. /NAME_SEPARATOR="_" (D; Alpha) /NAME_SEPARATOR="." (D; VAX) /NONAME_SEPARATOR Specifies the separator character between module and procedure name. Only the first character of the string given is evaluated. The string may be empty. /NONAME_SEPARATOR defaults to the Oberon-2 standard separator which is the same as the default value. See also /OMIT_MODULE_NAME to get rid of the module name plus separator. /Oberon_LoadFile (Alpha only) /NOOberon_LoadFile (D) Generates an .OLF[64] file instead of an .OBJ[64] file. The .OLF files can only be activated from within AlphaOberon (AOS). The generation of .OBJ[64] files can be suppressed by using /OBJECT=NL: /OBJECT[=file-spec] (D) /NOOBJECT Controls whether the compiler creates an object module. The /NOOBJECT qualifier is useful when you want to test the source program for compilation errors. By default, /OBJECT is enabled; the compiler produces an object module with the same file name as source file name, but with the file extension OBJ[64] or OLF[64] (see /Fine_Grained_SymFile). /OMIT_MODULE_NAME /NOOMIT_MODULE_NAME (D) Controls whether the procedure entries of the object file are pre- fixed with the module name and a separator (see also /NAME_SEPARATOR which is used to alter the separator character). The qualifier /OMIT_MODULE_NAME only influences the symbols to be resolved by the linker and is only used to generate object modules with procedure names that are callable by programs written in another languages than Oberon-2 This option may be used with or without the /FOREIGN_CODE qualifier. When compiling a foreign interface module, this option enables generation an object file which is otherwise suppressed (unsupported feature). By default all procedure names are prefixed e.g. by the string "X_" if the name of module is "X" ("_" being the separator character determined by the option /NAME_SEPARATOR="_"). Only those procedures and functions marked for export by an "*" in addition to the module body (module initialisation part) which is a parameterless procedure with the name of the module, are visible to the outside. Exported and hidden method entries are also visible but only for the linker to fill in the method references of the type descriptors. Although possible, methods should not be called from foreign languages (the receiver is the first parameter in the parameter list and is treated like any other parameter). /OPTIMIZE[=OoptionList] (D; list=(rotateScratch, stackCheck); Alpha only) /NOOPTIMIZE OoptionList = (schedule, alignCheck, rotatePreserved, rotateScratch, stackCheck, eliminateUnreachableCode) Schedule allows the Alpha instruction scheduler to run during code generation. Using this option could improve the execution speed of a program. This option is not recommended when you plan to use the symbolic debugger with the module compiled, since instructions are moved around within so-called basic scheduling blocks to avoid instruction latencies and to take advantage of the Alpha's feature to execute multiple instruction in the same cycle. For more details see Alpha architecture manual. NOTE: When using /OBERON_LOADFILE, one must use /NODEBUG, in order to use the Alpha instruction scheduler. This because the Oberon System Runtime Debugger can not work on instruction scheduled programms. Aligncheck tells the compiler to generate code to check pointer and variable parameter addresses for alignment before accessing the data. Code is only generated in circumstances where the compiler can not know whether the data is aligned or not. The start address of global and local variables is always aligned. Using this option is called "pessimistic approach" because there is an overhead even if the addresses are already naturally aligned. NoAlignCheck is the optimistic approach and improves the speed of an application program when using properly aligned data fields (see also /PACKED_RECORDS). If an alignment trap occurs in this case, the access trap must be handled by the operating system which could significantly slow down the performance of the application program, especially if the trap occurs in the inner loop of an application program. The rotate register options tells the code generator to use different registers when allocating registers. This allows the scheduler to rearrange more instructions. There is no penalty when allowing the rotation of scratch registers. However, when allowing the rotation of preserved registers, the entry code of each procedure gets larger because more registers have to be saved and restored for the caller. Rotating preserved registers is only recommended if the procedures in the compiled module are not called in the inner loop of an application program or if the procedures themselves contain CPU-bound processing loops. Stackcheck is enabled by default and should be turned off only if it is guaranteed that procedures of the module compiled are not called from a coroutine. You may also turn it off if you know that there is always going to be enough coroutine workspace and you like to live dangerously. EliminateUnreachableCode allows the suppression of so-called dead-code, such as the ... statement sequence in IF FALSE THEN ... END. /PARSE_TREE /NOPARSE_TREE (D) Display the front-end parse tree on SYS$OUTPUT (unsupported; reserved for use by ModulaWare only) /POINTERSIZE=x (A2O only) /POINTERSIZE=32 (D) With x=32, pointers, addresses and LONGINT have 32 bit size. SYSTEM.PTR is identical to SYSTEM.ADDRESS_32. The object file extension is .OBJ with /NoOberon_LoadFile. With x=64, pointers, addresses and LONGINT have 64 bit size. SYSTEM.PTR is identical to SYSTEM.ADDRESS_64. The object file extension is .OBJ64 with /NoOberon_LoadFile otherwise it is either .OLF64 (/noFine_Grained_SymFile) or else .OLF. The option value x=64 requires at least OpenVMS V7.1. /PACKED_RECORDS (D on VAX and Alpha) /NOPACKED_RECORDS (D on Alpha if /Oberon_LoadFile is used) This qualifier controls the storage alignment and allocation of record fields. Fields of records are aligned to a byte address if PACKED_RECORDS or are naturally aligned with NOPACKED_RECORDS. In the latter case, the memory allocated for fields could be larger than the field's type size. This qualifier affects only record type declarations, i.e. variable declaration use the record type option which was in effect when compiling the record type declaration. This option should be used consistently in applications and application specific libraries because otherwise the record type size of structural equivalent record types could be different. All stand-alone library modules supplied by ModulaWare are compiled using packed records. For AlphaOberon, record fields should always be naturally aligned otherwise the garbage collector is not able to find local pointer variables. /QUERY /NOQUERY (D) Specifies whether the compiler explicitly asks for the symbol files to be read in. By default, the compiler uses a standard strategy to lookup the necessary symbol files. /SYMFILE[=file-spec] (D) /NOSYMFILE Controls whether the compiler creates a symbol file. By default, the compiler produces a symbol file each time the exported objects change in number or type structure. This applies to hidden method headers which are also stored in the symbol file. To be able to check the new versus the old symbol file, the version limit of the working directory (directories in case of the default directory being a search list) should have a minimum of two. The file name of the imported modules are always constructed from the module names. This qualifier optionally specifies the output file name with the default file type of SYN or with /PointerSize=64, SYN64 or SYO (see /Fine_Grained_SymFile). /TRANSFER_VECTOR (D; VAX only) /NOTRANSFER_VECTOR (D; Alpha only; don't change) H2O only: Controls whether the compiler generates a transfer vector section in the object file. This feature may be helpful when working with shared images (see OpenVMS-linker reference) with modules written in Oberon-2. For standard linking and generation of executables this option has no effect. By default, the compiler produces transfer vectors. With A2O, transfer vectors in the form of procedure descriptors are always generated (OpenVMS Alpha requirement). Hence a special provision for shareable images is not required. With MaX, this option is now used for special purposes during installation time.

APPENDIX H: DATA SHEET

APPENDIX I: PROGRAMMING HINTS

I.1. Benchmarks with Oberon-2

Quality of generated:

When comparing the execution time of programs written in Oberon-2 and DEC Fortran77 or DEC Pascal one must take into account, that the Oberon Compiler doesn't produce a highly optimized code, except for

- Evaluation of constant expression at compile time.

- Boolean expression with one constant operand: (TRUE & x) and (FALSE OR x) are replaced by x.

- Dead code elimination: unreachable code due to a constant condition in an IF-ELSIF-ELSE statement is removed.

- Conversions: conversions are never applied to constants. LONG(LONG(shortint)) and SHORT(SHORT(longint)) need only one conversion, SHORT(LONG(i)) needs no conversion, LONG(SHORT(i)) needs two conversions because of range check.

- Integer multiplication by a power of two are replaced by arithmetic shifts. Note, that due to an implementation restriction with DIV and MOD, integer divison by a power of two can not be replaced by arithmetic shift and modulus by a power of two can not be replaced by a bit mask operation.

- LEN(a[expr1, expr2, ... exprn], n) is replaced by LEN(a,m+n).

- currently for H2O only: Assignments with common destination and source designator of the form a := a mostDyadicOperator b; are optimized. This is especially usefull for common designators being indexed or pointers.

But otherwise no optimization are done that can be done by the programmer, e.g. common subexpression elimination, procedure in-lining, etc..

Comparing Benchmark Results:

When comparing performance with Fortran, make a fair comparison by using only local variables, not global ones and don't use nested procedures with access to variables of outer local scope. Use VAR parameters for arrays and records to force paramater-passing by reference (like Fortran), to avoid that the values are copied to the procedure's stack frame.

Also note, that Oberon-2 is a safe and powerful language that provides you with pointer initialisation, full type safety, minimal but powerful object-oriented language extensions, run-time type information for dynamic data types, multi-dimensional open and dynamic arrays together with Modula-2's proven separate modul concept.

It is a good idea to use /nocheck when comparing code quality with compilers that don't check anything.

I.2. Case Statement

Avoid large CASE label ranges. Each value of the label's range will produce an entry in a jump table. Use the IF-statement instead:


  IF (-32000<=i) & (i<=-1) THEN ...
  ELSIF i=0 THEN ...
  ELSIF (1<=i) & (i<=32000) THEN ...
  END;
Don't write:

  CASE i OF
    -32000..-1: ...
  | 0: ...
  | 1..32000: ...
  END;

I.3. Local pointer variables in procedures

Avoid the declaration of large local arrays which contain pointers or local arrays of record type which (maybe indirectly) contain pointer fields. Code is generated to clear each of these pointers variables in the entry code of the procedure. This is a safety aspect in stand-alone programs and a garbage collector requirement in AlphaOberon.


This is end of the A2O User's Guide. Hope you enjoyed reading it.
Send any comments to gd at modulaware.com

The Alignment Trap :: Navigator

[ The Alignment Trap Home
| About The Alignment Trap
| Oberon System and Compiler Implementations (OSCI)
| Comparison of Oberon-2 with Modula-2
| From C/C++ to Oberon-2
| Oberon-2 Language Report
| AlphaOberon-2 Compiler User's Guide
| Download AlphaOberon for OpenVMS Alpha ]

modulAware.com home

Copyright (1999-2011) by modulAware.com
First published 27-Apr-1999, last revised 01-Mar-2011

Disclaimer: The banner advertisement at the top of this page is dynamically inserted by the web-site hosting service; The banner image content and the URL it refers to is outside the responsibility of modulAware.com