Technical Capabilities
Having trouble finding what you need?
Get in touch with us, so we can answer your specific questions directly.
Get In Touch

PAS$ – PASCAL Support Routines

Overview

PAS$ is a call-compatible re-implementation of the OpenVMS Pascal runtime support routines for x86 and ARM Linux. It provides the PAS$ facility entry points and the Pascal built-in support that DEC and VSI Pascal object code calls at run time, so migrated Pascal applications link and execute while preserving language semantics, value string handling, and VMS system interactions. It is the runtime the recompiled or translated Pascal links against, not the compiler and not the source translator.

The library is delivered as libvxpas and integrates with VX/RT. It unifies every Pascal string flavour into one dynamic string type so natural Pascal operators survive translation, exposes the Pascal file I/O verbs over Sector7's RMS layer, and carries the PAS$ and SYS$ service shims that OpenVMS Pascal programs depend on. Applications that link against PAS$ port directly and keep their original behaviour.

Architecture and components

On OpenVMS, PAS$ is the facility prefix of the DEC and VSI Pascal Run-Time Library: the routines the Pascal compiler emits calls to for I/O, string handling, math built-ins, condition handling, and RMS file operations. PAS$ re-implements that runtime for Linux as a linkable C++ library so recompiled or translated Pascal links and runs unchanged. It is not a server process and there is nothing to administer.

Two layers live behind the runtime:

  • Pascal built-in support. Functions that stand in for Pascal predeclared functions and I/O verbs (Present, Index, Substr, Hex, Date, and the file verbs), the bulk of the library.
  • PAS$ facility shims. The lower-level pas$ entry points that mirror the OpenVMS PAS$ and system-service calls (pas$assign, pas$trnlnm, pas$getjpi, and the rest), plus the RMS block accessors PAS$FAB and PAS$RAB.
OpenVMS Pascal concernPAS$ implementationRoleStatus
Pascal STRING / VARYING OF CHARThe _String dynamic string typeOne value-semantic string type behind fixed and varying Pascal strings and literals.live
String descriptors (dsc$descriptor)Descriptor bridgingConverts strings to and from VMS descriptors so descriptor-based calls resolve.live
File and RMS I/OFile_t plus the Pascal I/O verbsPascal Open, Get, Put, Read, and Write over the RMS layer; PAS$FAB and PAS$RAB expose the RMS blocks.live
Radix and formatting built-insHex, Oct, Bin, Dec, UdecConvert numeric values to formatted strings.live
Date and time built-insDate, Fdate, Time, Ftime, GettimestampCurrent date and time, plus binary-time formatting.live
Math intrinsicsMax, Min, Mod, Rem, Sqrt, Fabs, LabsPascal predeclared math functions.live
Argument presence (VMS stack)PresentReproduces VMS stack argument counting for PRESENT and NOT PRESENT.live
Condition handlingEstablish, Halt, Status, StatusvInstall VMS condition handlers and read run-time status.live
Sets and membership_Set and membership listsPascal set types and set-membership tests.live
Heap management (NEW / DISPOSE)Allocator with optional debug trackingPascal heap allocation and disposal.live
PAS$ and SYS$ shimspas$assign, pas$crelnm, pas$trnlnm, and othersSystem-service call shims the Pascal RTL depends on.live
No daemon to run. PAS$ is delivered as the linkable libvxpas library. The migrated application links it directly, so there is no separate runtime service to install or manage on the Linux host.

The _String runtime type

The heart of PAS$ string handling is a single dynamic string type, _String, onto which the translator maps every Pascal string flavour: fixed PACKED ARRAY OF CHAR, VARYING [n] OF CHAR, and string literals. It carries both a fixed and a varying organisation with a discriminator for which is live, plus declared lower and upper bounds, and a flag for whether it owns its buffer or is a view over caller memory. That design lets emitted C++ keep Pascal value semantics and Pascal's natural operators.

Operator surface

_String overloads the operators Pascal code relies on, so the translated C++ reads almost the same as the source:

GroupOperatorsPurpose
Concatenateoperator+ (string, char, and const char* forms)Join strings with the same + Pascal uses.
Appendoperator+=Append a char, C string, or another string in place.
Assignoperator=Assign from a char, C string, string, or array with a value copy.
Compareoperator== / operator!=Value comparison against chars, C strings, and strings.
Indexoperator[]Read or write a single character by position.
Testoperator! / operator boolEmpty or non-empty tests.
Descriptor bridgingoperator DXX*, operator const char*Pass a string where a VMS descriptor or C string is expected.

Member helpers cover the common Pascal string operations: substr, subset, pad, length, and reference counting, alongside free helpers such as Length, Substr, Present, and the Pas_str constructor macro that backs the PAS_STR built-in.

Why it matters for migration

Because _String preserves + concatenation, string logic reads the same after migration. Where a Pascal statement concatenates with +, the emitted C++ keeps + rather than falling back to descriptor juggling or explicit copy routines:

{ Pascal source }
A := Me + 'You' + Them;

/* emitted C++ (unchanged operator, value semantics preserved) */
A = Me + "You" + Them;

The same technique is applied throughout the runtime, so migrated code that builds, compares, and slices strings keeps its original shape and behaviour without manual rewriting.

Intrinsic runtime routines

PAS$ provides the Pascal predeclared functions and I/O helpers the compiler emits calls to. Each is a call-compatible entry point, so translated code invokes them exactly as the original Pascal did. The table lists the most commonly used routines and their behaviour.

RoutineSignature (as declared)PurposeStatus
Presentbool Present(const T&)VMS argument-presence test; safe on a null reference, returning false when an argument was not passed.live
Indexint32_t Index(_String, _String)Substring position; returns 0 when not found and -1 for a null pattern.live
Substr_String Substr(_String, int32_t start, int32_t size)Substring extraction.live
Pad_String Pad(_String, char fill, uint32_t size)Blank or character pad to a length.live
Lengthuint32_t Length(const _String&)String length.live
Hex / Oct / Bin_String Hex(int64_t, int32_t length, int32_t min_digits)Radix conversion of a numeric value to a formatted string.live
Dec / Udec_String Dec(int64_t, int32_t, int32_t)Signed and unsigned decimal conversion to string.live
Chr / Ord_String Chr(int32_t), int32_t Ord(int32_t)Ordinal to character and character to ordinal.live
Date / Timeint32_t Date(_String&), int32_t Time(_String&)Current date and time text.live
Fdate / Ftime_String Fdate(Time_t), _String Ftime(Time_t)Format a binary time value to text.live
Max / Mindouble Max(uint32_t nargs, ...)Variadic maximum and minimum.live
Mod / Remuint32_t Mod(int32_t, int32_t)Modulo and remainder.live
Sqrt / Fabs / Labsdouble Sqrt(double)Square root and absolute value.live
Status / Statusvint32_t Status(File_t&)File status code and global status value.live
Halt / Establishvoid Halt()Terminate the program, or install a VMS condition handler.live

A built-in end to end

Every intrinsic follows the same pattern: set up a VMS-style descriptor, call the runtime's system-service implementation, and marshal the result into a _String. The Date built-in shows the shape, including the OpenVMS status convention where the low bit of the return value marks success:

extern "C" uint32_t SYS_D_ASCTIM(U16 *, void *, void *pqtime, uint32_t flag);

int32_t Date( _String &v )
{
    char buffer[64];              // buffer to hold the date string
    $DESCRIPTOR64( d, buffer );   // VMS-style descriptor for the buffer
    int32_t rc;
    U16 len = 0;

    rc = SYS_D_ASCTIM( &len, &d ); // system call fills the buffer
    buffer[len] = 0;              // null-terminate
    v = buffer;                   // _String::operator= copies it in
    return rc;                    // VMS status (bit 0 = success)
}

Two migration-relevant details are visible here. The rc & 1 style success test is the OpenVMS convention preserved verbatim, and assigning a C string into a _String uses the value-copy assignment operator so the result keeps Pascal string semantics.

Pascal built-ins provided

ABS
ADDRESS
ARCTAN
ASSERT
BIN
CHR
COS
DATE
DEC
DISPOSE
EOF
EOLN
EXP
HALT
HEX
INDEX
LENGTH
LOWER
MALLOC
MAX
MIN
NEW
OCT
ODD
ORD
PAD
PAS_STR
PRED
PRESENT
ROUND
SIN
SIZE
SQRT
STATUS
SUBSTR
SUCC
TIME
TRUNC
UDEC
UPPER

File I/O and RMS support

PAS$ implements the Pascal file I/O verbs over Sector7's RMS layer through a File_t object per open file. All RMS file organizations, record formats, and access modes from VMS Pascal are supported, so record-oriented programs keep their file semantics on Linux. Each verb accepts an error-processing option and defaults to continuing, matching the Pascal runtime.

VerbRoleStatus
Open / FcloseOpen and close a file, building the RMS control blocks.live
Get / PutRead the current record, or write the record buffer.live
Read / ReadvRecord read, including the formatted-read helper.live
WriteRecord write, including formatted write.live
UpdateUpdate a record in place.live
Reset / ResetkReposition to the start, or reset by key for keyed access.live
Rewrite / FindRewrite the file, or locate a record without reading it.live
Extend / TruncateExtend or truncate the file.live
Delete_file / Create_directoryDelete a file, or create a directory.live
Eof / EolnEnd-of-file and end-of-line tests.live

The file option model

File behaviour is driven by an option model. Each family is a distinct set of values, and the families that carry the RMS claims map directly onto OpenVMS RMS concepts:

Option familyMembersCovers
OrganizationSEQUENTIAL, RELATIVE, INDEXEDRMS file organizations.
Record typeFIXED, VARIABLE, stream formsRMS record formats.
Access methodSEQUENTIAL, DIRECT, KEYEDRMS access modes.
Historynew, readonly, old, unknownOpen disposition on existing files.
Sharingnone, readonly, readwriteFile sharing mode.
Dispositionsave, delete, print, submitClose-time disposition, including print and submit.
Carriage controlnone, list, carriage, fortranCarriage-control handling on output.

RMS block access

PAS$FAB and PAS$RAB. The uppercase accessors PAS$FAB(File_t&) and PAS$RAB(File_t&) return pointers to the File Access Block and Record Access Block for an open file. This is the seam that lets migrated code which poked FAB or RAB fields directly keep working against the RMS layer.

Real call path (banking example)

A migrated Pascal program opens a keyed account file and reads a record by key. The file option values and I/O verbs are the same ones the original ran on OpenVMS:

{ open an indexed account master for keyed access }
Open( ACCOUNT_FILE,
      FILE_NAME := 'BANKING$DATA:ACCOUNT_MASTER.DAT',
      ORGANIZATION := INDEXED,
      ACCESS_METHOD := KEYED,
      HISTORY := OLD );

{ position by customer id, then read the record buffer }
Resetk( ACCOUNT_FILE, KEY := 0, RELATION := EQL, KEY_VALUE := CUST_ID );
Get( ACCOUNT_FILE );
ACCT_RECORD := ACCOUNT_FILE^;

{ ... update fields, then write the record back in place ... }
ACCOUNT_FILE^ := ACCT_RECORD;
Update( ACCOUNT_FILE );

Fclose( ACCOUNT_FILE );

PAS$ and SYS$ service shims

Some routines carry the literal PAS$ facility name on OpenVMS: the shims the Pascal RTL uses to reach system services. PAS$ declares these with C linkage and the VMS-style return convention, where the low bit of the returned condition value marks success. Each maps onto a familiar OpenVMS system service or library routine.

RoutineOpenVMS analoguePurpose
pas$assignSYS$ASSIGNAssign an I/O channel to a device or mailbox.
pas$crelnmSYS$CRELNMCreate a logical name.
pas$dellnmSYS$DELLNMDelete a logical name.
pas$trnlnmSYS$TRNLNMTranslate a logical name.
pas$getjpi / pas$getjpiwSYS$GETJPI / SYS$GETJPIWGet job and process information.
pas$setprvSYS$SETPRVSet process privileges.
pas$sndjbc / pas$sndjbcwSYS$SNDJBC / SYS$SNDJBCWSend a request to the job controller.
pas$cvt_vectimLIB$CVT_VECTIMConvert a seven-word time vector to a binary time.
pas$set_logicalLIB$SET_LOGICALSet a logical name from Pascal.
Return convention preserved. These shims return a VMS condition value by value, so migrated code that tests the low bit of the status (success when odd) behaves the same on Linux as it did on OpenVMS.

Compatibility and divergences

PAS$ is built to let OpenVMS Pascal applications run on Linux without source changes. A few behaviours differ from the original VMS runtime by design, because the host platform differs. Each divergence keeps application-visible behaviour intact while adapting to Linux.

DivergenceReason
The runtime is a linkable C++ library (libvxpas) rather than a shareable image such as PASRTL.EXE.The host is Linux, which has no VMS image activator.
System services are re-implemented as SYS_ and pas$ functions that call the VX/RT runtime.There is no VMS executive on Linux, so each service is provided by the Sector7 runtime.
Every Pascal string flavour is unified into one _String type with an organisation discriminator.C++ has no native VARYING OF CHAR; one type keeps value semantics and + concatenation.
The VMS success test is kept as status & 1 in emitted code.This preserves the behaviour of code that inspects RTL status directly.
Present returns false on a null reference.Linux has no VMS register argument-count, so a not-passed argument is emulated this way.
Optional C-string caching and standard-library string interop are off by default.Defaults match the VMS memory layout; the extra behaviours are opt-in at build time.
Integrates with VX/RT. PAS$ works alongside the rest of the OpenVMS run-time services on Linux, so a Pascal application picks up string handling, file I/O, built-ins, and service shims together with the wider VX/RT surface.

Quick reference

Library and core types

ItemValue
Librarylibvxpas, linked directly into the migrated Pascal application.
Core string type_String (dynamic Pascal string with value semantics).
File objectFile_t, one per open file over the RMS layer.
DescriptorsVMS string descriptor bridging to and from _String.
Sets_Set and membership lists.
Delivered withVX/RT run-time services on Linux.
Target platformsx86 and ARM Linux.

Built-ins

Present
Index
Substr
Pad
Length
Hex
Oct
Bin
Dec
Udec
Chr
Ord
Date
Fdate
Time
Ftime
Gettimestamp
Max
Min
Mod
Rem
Sqrt
Fabs
Labs
Eof
Eoln
Status
Statusv
Halt
Establish

File I/O verbs

Open
Fclose
Get
Put
Read
Readv
Write
Update
Reset
Resetk
Rewrite
Find
Extend
Truncate
Delete_file
Create_directory

RMS file model

FamilyMembers
Organizationsequential, relative, indexed
Record typefixed, variable, stream
Access methodsequential, direct, keyed

PAS$ and SYS$ shims

pas$assign
pas$crelnm
pas$dellnm
pas$trnlnm
pas$getjpi
pas$getjpiw
pas$setprv
pas$sndjbc
pas$sndjbcw
pas$cvt_vectim
pas$set_logical
PAS$FAB
PAS$RAB

Frequently Asked Questions

Curious about how Sector7 can facilitate your application migration? Explore our FAQs for expert insights.

What is VX/PASCAL and how does it help with OpenVMS Pascal migration?

VX/PASCAL is an automated transpiler that converts OpenVMS Pascal to ANSI-compliant C++ for execution on Linux. It carries VMS-specific extensions, CDD data structures, and RMS file handling across to Linux, so the translated program behaves the same as it did on OpenVMS. To explore VX/PASCAL for your migration, contact us.

How does the VX/PASCAL migration process work technically?

VX/PASCAL automates migration in four steps: source code analysis, transpile to C++, compile with GNU C++, and validate with automated testing to ensure identical behavior.

What customization options are available in VX/PASCAL?

VX/PASCAL is driven by a setup table read from a customer setup file, so output can be tuned to house conventions without editing source. Variable naming, code formatting (braces, indentation and line breaks), VMS logical-name translation, POSIX error-code mapping and inherited system-file handling are all controllable, and runtime checks (case, array bounds, nil pointers, allocation and file state) can be enabled together for a validation build.

What are the key benefits and proven results of using VX/PASCAL?

VX/PASCAL translates OpenVMS and VAX Pascal to ANSI C++ automatically, with zero code freeze: teams keep developing in Pascal while each release is migrated. Any construct the translator cannot fully represent is named with a numbered diagnostic rather than dropped. Contact us to discuss your requirements.

What makes VX/PASCAL different from other migration tools?

VX/PASCAL converts OpenVMS PASCAL to readable, maintainable C++ code, allowing programs to compile, link, and run on Linux with no manual code changes. Our PASCAL Process Control bundle preserves the behaviour of the original application.

What is PAS$?

PAS$ is Sector7's call-compatible re-implementation of the OpenVMS Pascal runtime support routines for x86 and ARM Linux. It provides the PAS$ entry points and Pascal built-in support that DEC and VSI Pascal object code calls at run time, delivered as the libvxpas library. It is the runtime your migrated Pascal links against, not the compiler and not the source translator.

Do I have to rewrite my Pascal application to use PAS$?

No. PAS$ is call-compatible, so recompiled or translated Pascal links against it and runs without source changes. Pascal string handling, file I/O, built-in functions, and VMS system-service calls keep their original behaviour on Linux.

How does PAS$ relate to VX/PASCAL and VX/RT?

VX/PASCAL translates OpenVMS Pascal source to C++. PAS$ is the runtime library that the translated code links against so it behaves as it did on OpenVMS. PAS$ integrates with VX/RT, so a Pascal application picks up the runtime support routines alongside the wider OpenVMS runtime services on Linux.

How does PAS$ handle Pascal string handling in C++?

PAS$ unifies every Pascal string flavour into one dynamic string type that preserves value semantics and operators. A Pascal concatenation written with + stays a + in the emitted C++, so string logic reads the same after migration and does not need manual rewriting.

Which file and RMS operations does PAS$ support?

PAS$ implements the Pascal file I/O verbs over Sector7's RMS layer. It supports the RMS file organizations (sequential, relative, indexed), record formats (fixed, variable, stream), and access methods (sequential, direct, keyed), and exposes the RMS File and Record Access Blocks through PAS$FAB and PAS$RAB.

Does PAS$ support the VMS PRESENT and NOT PRESENT keywords on Linux?

Yes. VMS argument presence relies on stack argument counting, which Linux does not provide natively. PAS$ reproduces this through its Present routine, which returns false when an argument was not passed, so code that checks PRESENT and NOT PRESENT behaves the same on Linux.

Which VMS system services can Pascal code still call through PAS$?

PAS$ carries the PAS$ facility shims that mirror common OpenVMS system services and library routines, including channel assignment, logical name creation and translation, process information, privilege setting, and job controller requests. They keep the VMS status return convention, so existing status checks continue to work.

Which platforms does PAS$ run on?

PAS$ runs on x86 and ARM Linux and is delivered as the libvxpas runtime library alongside VX/RT.

Transform Your Legacy Software Today!

Get In Touch
Unlock the potential of your legacy software with our expert migration services.