CREXX

REXX Language implementation

View the Project on GitHub adesutherland/CREXX

Running cRexx on Linux, macOS, and Windows

cRexx programs are compiled before they run. The compiler emits rxas assembly, the assembler emits rxbin bytecode, and a VM executable runs this bytecode.

For most users, the crexx driver is the simplest entry point.

A First Program

Create hello.crexx:

options levelb
import rxfnsb

say "hello cREXX world!"
say "today is" date("w")
return 0

Run it with:

crexx hello.crexx

The driver compiles, assembles, and executes the program. It keeps intermediate files by default so you can inspect the generated .rxas and .rxbin while learning or debugging.

Headerless Scripts

For small top-level scripts, crexx accepts a convenient headerless form:

say "hello cREXX world!"
say "today is" date("w")

Headerless top-level scripts are compiled as Level B with rxfnsb imported. Reusable libraries, tests, and examples should still write the explicit options levelb and import lines. That keeps source behaviour independent from driver convenience.

Running the Individual Tools

The equivalent explicit tool sequence is:

rxc hello.crexx
rxas hello.rxas
rxvme hello.rxbin

rxvme includes the shipped core bytecode images used by Level B, Level C, and Level G programs: the base and class libraries, native-provider declarations, the Classic compatibility library, the Level G library, and RexxScript. Application libraries remain explicit runtime inputs. The base rxvm can also run bytecode, but programs that call library functions need the relevant library image or linked modules available.

You can pass program arguments after -a:

rxvme hello.rxbin -a first second third

The VM also accepts multiple bytecode files when a program is split across modules.

Profiling VM execution

A VM configured with -DCREXX_VM_PROFILING=ON supports instruction, transition, procedure/method, native-call, and interrupt timing:

rxvme --profile hello.rxbin
rxvme --profile-output hello-profile.txt hello.rxbin
rxvme --profile-output hello-profile.csv hello.rxbin

The default report is a table on standard error. It includes instruction and transition timing plus per-procedure/method call counts, elapsed time, inclusive body time, self time, and measured VM entry/exit mechanics. Native plugin calls are included with call count and total time only. A profile output filename ending in .csv (case-insensitive) selects CSV; other filenames use the table format. Profiling support and its command-line options are absent from normal builds.

The profiling build also supports a separate dynamic instruction-sequence extractor. It records the volume of sequential two-, three-, or four-instruction windows in a compact, sparse binary .rxseq file:

rxvm --sequence-count=3 --sequence-output hello.rxseq hello.rxbin
rxseq hello.rxseq hello.rxbin --output hello-candidates.csv

Pass rxseq the same complete RXBIN module set used by rxvm; it verifies module names and content hashes before decoding. The candidate report groups patterns by register/constant reuse and sums loop execution counts. Candidate patterns may contain any number of distinct encoded symbols; the report is input to later safety and optimizer review, not an automatic bytecode transformation.

The complete build instructions, report-field definitions, measurement boundaries, tested example, CSV schema, sequence semantics, and troubleshooting guide are in Profiling cREXX VM Execution.

Imports and Libraries

Level B imports are explicit:

options levelb
import rxfnsb
import rxjson

At compile time, rxc -s adds source import roots and rxc -i adds binary import roots. With the crexx driver, -s[path] and -i[path] affect the compiler phase only. Runtime/native loading still uses the runtime library path controlled by -l.

For a specific external library, pass an explicit path such as -l /approved/runtime/contracts.rxbin or -l ./contracts.rxbin. The driver uses paths containing a directory component exactly; only bare packaged names are resolved below CREXX_HOME/bin. Runtime code that calls loadmodule() should likewise receive the intended module filename explicitly rather than searching user-controlled directories.

The source file’s directory is not an implicit binary import root. If a local .rxbin is meant to provide compile-time signatures or class/interface metadata, pass that directory with -i; this keeps stale generated .rxbin files from unexpectedly winning over source edits.

Linked Images

For deployable bytecode, link the needed modules:

rxlink -o hello_linked.rxbin hello.rxbin library.rxbin
rxvme hello_linked.rxbin

The exact library image names depend on the build and packaging layout. The key point is that rxlink produces a compact shared-pool image that the VM can load as a normal RXBIN file.

Native Executables

The crexx driver can package a native executable:

crexx hello.crexx -native

Native packaging links the bytecode image, serializes it with rxcpack, and uses the platform C toolchain to build an executable. Optional plugins and platform libraries depend on build configuration, so test packaged binaries on the target platform before release.