VX/ACMS - OpenVMS ACMS(TDF,MDF,GDF,ADF) to C++
Overview
VX/ACMS is an ACMS migration tool that translates OpenVMS ACMS ADF, MDF, GDF, and TDF definitions into C++ and provides a runtime that mirrors the original VMS ACMS. Migrated ACMS applications run on Linux and Windows without a transaction monitor: the ADU toolchain compiles the four definition-file types into loadable modules, and the C++ runtime binds the task, menu, and procedure components directly into a single compiled executable.
The translated C++ stays close to the original ACMS structure, so the code remains readable and maintainable. Translation can be a one-time conversion, where you keep the generated C++ from then on, or part of a continuous-integration workflow that recompiles and relinks the ACMS system on every build. Control flow, workspaces, procedure servers, and step processing are all preserved, while commit and rollback are delegated to the database layer such as Oracle.
<!-- Webflow embed (min). Source: acms-to-c-page-technical/acmsc-tech-body-embed-dark.html → python3 website/embeds/minify_webflow_embed.py … -->
<div class="s7-tech-embed" data-vxacmscd-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="translation">Translating ACMS to C++</h2><p>
VX/ACMS translates OpenVMS ACMS <strong>ADF, MDF, GDF, and TDF</strong> definitions into
<strong>C++</strong>, preserving the logic and structure of the original ACMS application. The
generated code follows the shape of the original definitions closely, so an existing ACMS
system migrates with minimal rewriting and the result reads like the ACMS it came from.
</p><div class="table-wrapper"><table><thead><tr><th>Workflow</th><th>What happens</th><th>When to use it</th></tr></thead><tbody><tr><td>One-time conversion</td><td>Translate the ACMS definition files to C++ once, then maintain the C++ from that point onward.</td><td>You are leaving ACMS behind and want C++ as the system of record.</td></tr><tr><td>Continuous integration</td><td>Keep the ACMS sources authoritative and re-run the translator on every build, recompiling and relinking the system automatically.</td><td>You still edit ACMS definitions and want the C++ regenerated on each change.</td></tr></tbody></table></div><div class="callout"><strong>Readable output by design.</strong> The compiled C++ structure closely follows the
original ACMS syntax, so developers who know the ACMS application can read and maintain the
translated code without learning a new internal representation.
</div><h6>From definitions to a running executable</h6><p>
At its simplest, VX/ACMS bundles the TDF, MDF, and procedures (built as dynamic libraries) into
a single executable unit. This mirrors how ACMS applications behave on VMS, but instead of
requiring a separate transaction monitor, VX/ACMS integrates these components directly into the
C++ runtime.
</p><style>.s7-tech-embed .acms-flow {margin: 1.5rem 0;padding: 16px;border: 1px solid var(--s7t-border);border-radius: 10px;background: rgba(255, 255, 255, 0.01);}.s7-tech-embed .acms-flow-grid,.s7-tech-embed .acms-relationship {display: grid;gap: 10px;}.s7-tech-embed .acms-flow-grid {grid-template-columns: repeat(3, minmax(0, 1fr));}.s7-tech-embed .acms-card {min-width: 0;padding: 14px 16px;border-radius: 8px;background: var(--s7t-surface);color: var(--s7t-text);}.s7-tech-embed .acms-card strong,.s7-tech-embed .acms-card span:last-child {display: block;}.s7-tech-embed .acms-card strong {margin-bottom: 4px;}.s7-tech-embed .acms-card span:last-child {color: var(--s7t-muted);font-size: 0.9em;line-height: 1.45;}.s7-tech-embed .acms-label,.s7-tech-embed .acms-connector {font-family: var(--s7t-mono);color: var(--s7t-accent);font-size: 0.76em;font-weight: 700;letter-spacing: 0.08em;text-transform: uppercase;}.s7-tech-embed .acms-label {margin-bottom: 8px;}.s7-tech-embed .acms-connector {padding: 10px;text-align: center;}.s7-tech-embed .acms-stage {border-top: 3px solid var(--s7t-accent);background: var(--s7t-surface2);}.s7-tech-embed .acms-output {border: 1px solid var(--s7t-note-bd);background: var(--s7t-note-bg);}.s7-tech-embed .acms-relationship {grid-template-columns: minmax(0, 1fr) 140px minmax(0, 1fr);align-items: center;}.s7-tech-embed .acms-branches {display: grid;grid-template-columns: repeat(3, minmax(0, 1fr));gap: 10px;margin-top: 10px;}.s7-tech-embed .acms-branch {border-top: 3px solid var(--s7t-accent);background: var(--s7t-surface2);}@media (max-width: 800px) {.s7-tech-embed .acms-flow-grid,.s7-tech-embed .acms-relationship,.s7-tech-embed .acms-branches {grid-template-columns: 1fr;}}</style><div class="acms-flow" aria-label="ACMS source inputs converge through translation and compilation"><div class="acms-label">Inputs</div><div class="acms-flow-grid"><div class="acms-card"><strong>ACMS definitions</strong><span>ADF, GDF, MDF, and TDF sources</span></div><div class="acms-card"><strong>CDD record layouts</strong><span>Shared workspace structures</span></div><div class="acms-card"><strong>.MSG message files</strong><span>VSI message definitions</span></div></div><div class="acms-connector">All inputs converge into translation</div><div class="acms-card acms-stage"><strong><code>adu</code> translate</strong><span>Selects the translator for each input file type.</span></div><div class="acms-connector">Produces</div><div class="acms-card acms-stage"><strong>Readable C++ source</strong><span>Preserves the structure of the original ACMS definitions.</span></div><div class="acms-connector">Optional <code>--compile</code></div><div class="acms-card acms-output"><strong>.so or executable</strong><span>The C++ compiler produces a loadable module or single runtime.</span></div></div><p>
The same codebase serves two integration levels. The simplest embedded deployment binds the
components into one executable with no transaction monitor. The full deployment is a live,
multi-process ACMS runtime built from the same translated modules, so a project can start
embedded and grow into the process model without re-translating.
</p><h2 id="definition-files">The four definition files</h2><p>
ACMS applications are described in four VMS Application Definition Utility source languages. The
<code>adu</code> translator compiles all four, plus VSI <code>.MSG</code> message files. The
source kind is auto-detected from the file extension, or forced with a flag.
</p><div class="table-wrapper"><table><thead><tr><th>Extension</th><th>Name</th><th>Opening line</th><th>Translates to</th><th>Flag</th></tr></thead><tbody><tr><td><code>.TDF</code></td><td>Task Definition File</td><td><code>REPLACE TASK <path>:<name></code></td><td>Task step program plus workspace declarations.</td><td><code>--tdf</code></td></tr><tr><td><code>.GDF</code></td><td>task Group Definition File</td><td><code>REPLACE GROUP <path>:<name></code></td><td>One server module per SERVER, plus the procedure table.</td><td><code>--gdf</code></td></tr><tr><td><code>.ADF</code></td><td>Application Definition File</td><td><code>REPLACE APPLICATION <path>:<name></code></td><td>Application module binding task groups and server pools.</td><td><code>--adf</code></td></tr><tr><td><code>.MDF</code></td><td>Menu Definition File</td><td><code>REPLACE MENU <path>:<name></code></td><td>Menu module, a C-style menu structure that mimics MENU/TASK definitions.</td><td><code>--mdf</code></td></tr><tr><td><code>.MSG</code></td><td>VSI message file</td><td><code>.FACILITY ... .SEVERITY ...</code></td><td>A <code>.h</code> header, a COBOL copybook, and a runtime message catalog.</td><td><code>--msg</code></td></tr></tbody></table></div><h6>How the four relate</h6><p>
The MDF names the tasks a submitter can select; the ADF binds task groups and server pools; the
GDF rosters servers, procedures, workspaces, and tasks; each TDF is one task's step program.
Workspace record layouts come from CDD, which keeps a workspace's C struct and its COBOL copybook
byte-identical.
</p><div class="acms-flow" aria-label="Relationships among ACMS application, group, task, menu, procedure, and workspace definitions"><div class="acms-relationship"><div class="acms-card"><span class="acms-label">Application</span><strong>ADF</strong><span>Binds task groups, server control attributes, task defaults, and server pools.</span></div><div class="acms-connector">Task group is</div><div class="acms-card acms-stage"><span class="acms-label">Task group</span><strong>GDF</strong><span>Rosters the servers, procedures, workspaces, and tasks used by the application.</span></div></div><div class="acms-connector">GDF branches to its runtime definitions</div><div class="acms-branches"><div class="acms-card acms-branch"><span class="acms-label">Servers are</span><strong>Procedures</strong><span>COBOL or C shared objects</span></div><div class="acms-card acms-branch"><span class="acms-label">Workspaces are</span><strong>CDD records</strong><span>Byte-identical C structs and COBOL copybooks</span></div><div class="acms-card acms-branch"><span class="acms-label">Tasks are</span><strong>TDF</strong><span>One step program for each task</span></div></div><div class="acms-connector">Entries select a task in the application</div><div class="acms-card acms-output"><span class="acms-label">Menu</span><strong>MDF</strong><span><code>ENTRIES: TASK IS <t> IN <app></code> drives task selection.</span></div></div><h6>A Task Definition File (TDF)</h6><p>
A TDF declares its workspaces and task arguments, then a labelled sequence of steps. This banking
demo task reads a customer record through an exchange step, dispatches to a server procedure, and
uses a <code>CONTROL FIELD</code> action part to branch on the operator's key:
</p>
<pre><span class="kw">REPLACE TASK</span> banking_task:funds_transfer_task
<span class="kw">DEFAULT FORM IS</span> banking_form;
<span class="kw">USE WORKSPACES</span> account_wksp,
transfer_wksp,
sendctrl_wksp,
audit_wksp;
<span class="kw">TASK ARGUMENTS ARE</span> account_wksp <span class="kw">WITH ACCESS</span> MODIFY,
transfer_wksp <span class="kw">WITH ACCESS</span> READ,
audit_wksp <span class="kw">WITH ACCESS</span> WRITE;
<span class="kw">BLOCK WITH FORM I/O</span>
get_request:
<span class="kw">EXCHANGE</span>
<span class="kw">TRANSCEIVE RECORD</span> account_wksp, transfer_wksp
<span class="kw">SENDING</span> account_wksp
<span class="kw">RECEIVING</span> account_wksp, transfer_wksp
<span class="kw">WITH SEND CONTROL</span> sendctrl_wksp;
<span class="kw">ACTION IS</span>
<span class="kw">CONTROL FIELD</span> sendctrl_wksp.ctrl_key
<span class="str">"QUIT"</span> : <span class="kw">EXIT TASK</span>;
<span class="str">"CANCL"</span> : <span class="kw">EXIT TASK</span>;
NOMATCH : <span class="kw">MOVE</span> <span class="str">" "</span> <span class="kw">TO</span> sendctrl_wksp.ctrl_key;
<span class="kw">END CONTROL</span>;
post_debit:
<span class="kw">PROCESSING</span>
<span class="kw">CALL PROCEDURE</span> debit_account_proc
<span class="kw">IN</span> banking_write_server
<span class="kw">USING</span> account_wksp, transfer_wksp, audit_wksp;
<span class="kw">ACTION IS</span>
<span class="kw">IF</span> (ACMS$T_STATUS_TYPE = <span class="str">"B"</span>) <span class="kw">THEN</span>
<span class="kw">GET MESSAGE INTO</span> audit_wksp.messagepanel;
<span class="kw">GOTO PREVIOUS EXCHANGE</span>;
<span class="kw">END IF</span>;
<span class="kw">END DEFINITION</span>;</pre>
<h6>A Group Definition File (GDF)</h6><p>
The GDF binds servers, procedures, workspaces, and tasks. Both the plural
<code>PROCEDURES ARE</code> and singular <code>PROCEDURE IS</code> server clauses are accepted.
The <code>adu --gdf</code> pass emits one server module per SERVER, with a procedure table indexed
by procedure id:
</p>
<pre><span class="kw">SERVERS ARE</span>
banking_read_server:
<span class="kw">PROCEDURE SERVER IMAGE IS</span> <span class="str">"banking_default:banking_read_server.exe"</span>;
<span class="kw">INITIALIZATION PROCEDURE IS</span> banking_read_init;
<span class="kw">RUNDOWN ON CANCEL IF INTERRUPTED</span>;
<span class="kw">PROCEDURES ARE</span> find_customer_proc, read_account_proc,
account_details_proc;
banking_write_server:
<span class="kw">PROCEDURE SERVER IMAGE IS</span> <span class="str">"banking_default:banking_write_server.exe"</span>;
<span class="kw">INITIALIZATION PROCEDURE IS</span> banking_write_init;
<span class="kw">PROCEDURE IS</span> debit_account_proc;
<span class="kw">END SERVER</span>;
<span class="kw">TASKS ARE</span>
funds_transfer_task : <span class="kw">TASK IS</span> banking_task:funds_transfer_task;
enquiry_task : <span class="kw">TASK IS</span> banking_task:enquiry_task;
<span class="kw">END TASKS</span>;</pre>
<h2 id="control-flow">Task control flow in C++</h2><p>
All TDF control statements are supported, and the translated C++ stays close to the original TDF
logic. The task step engine and the TDL parser agree on the same set of statement kinds, so a step
that parses is a step that runs. The commonly cited control structures are a subset of the full
step set below.
</p><h6>Supported TDF control structures</h6><div class="kw-grid"><div>IF THEN ELSE</div><div>WHILE DO</div><div>SELECT FIRST TRUE</div><div>CONTROL FIELD</div><div>GOTO</div></div><h6>Full step and statement set</h6><div class="table-wrapper"><table><thead><tr><th>Statement kind</th><th>TDL construct</th><th>Role</th></tr></thead><tbody><tr><td>BLOCK</td><td><code>BLOCK ... END BLOCK</code> (incl. <code>WITH FORM I/O</code>, <code>WITH TRANSACTION</code>)</td><td>Step-block container.</td></tr><tr><td>EXCHANGE</td><td><code>EXCHANGE ... TRANSCEIVE / SEND RECORD</code></td><td>Form I/O step.</td></tr><tr><td>PROCESSING</td><td><code>PROCESSING ... CALL PROCEDURE ... IN ... USING</code></td><td>Server-procedure call step.</td></tr><tr><td>IF</td><td><code>IF (cond) THEN ... ELSE ... END IF</code></td><td>Conditional.</td></tr><tr><td>SELECT FIRST TRUE</td><td><code>SELECT FIRST TRUE (cond): ... OTHERWISE:</code></td><td>Multi-way select.</td></tr><tr><td>CONTROL FIELD</td><td><code>CONTROL FIELD <f> "lit": ... NOMATCH:</code></td><td>Value dispatch.</td></tr><tr><td>WHILE</td><td><code>WHILE DO</code></td><td>Loop.</td></tr><tr><td>MOVE</td><td><code>MOVE <src> TO <dst></code></td><td>Field assignment (multi-pair).</td></tr><tr><td>GOTO</td><td><code>GOTO (NEXT | PREVIOUS) (STEP | EXCHANGE | PROCESSING) [label]</code></td><td>Relative or labelled jump.</td></tr><tr><td>REPEAT</td><td><code>REPEAT STEP</code> / <code>REPEAT TASK</code></td><td>Backward-goto loops (safety-capped).</td></tr><tr><td>EXIT</td><td><code>EXIT BLOCK</code> / <code>EXIT TASK</code> / <code>CANCEL TASK</code></td><td>Flow exits and task cancel.</td></tr><tr><td>ATOMIC</td><td><code>... WITH TRANSACTION</code> / <code>ATOMIC</code> block</td><td>Transaction bracket.</td></tr><tr><td>COMMIT / ROLLBACK</td><td><code>COMMIT TRANSACTION</code> / <code>ROLLBACK TRANSACTION</code></td><td>Explicit transaction statements (executed by the database layer).</td></tr><tr><td>RAISE</td><td><code>RAISE ... EXCEPTION</code></td><td>Raise a condition.</td></tr><tr><td>GET MESSAGE</td><td><code>GET [ERROR] MESSAGE INTO <field></code></td><td>Message retrieval into a workspace field.</td></tr></tbody></table></div><div class="callout"><strong>CDD workspaces become C structs.</strong> CDD workspace definitions are translated into
packed C structures with fixed-width, space-padded text fields, pinned to the original byte
layout with <code>static_assert</code>. This keeps the code compatible even on platforms that do
not run a common data dictionary, so a workspace's layout is identical whether it is read from C
or from a COBOL copybook.
</div><h2 id="runtime">Executable structure and runtime</h2><p>
Many teams value the step-based processing model of ACMS. VX/ACMS preserves that model, but keeps
the execution flow inside a single compiled executable. This removes the need for an external
transaction monitor while maintaining the integrity of the ACMS workflow: the same steps run in
the same order, with the same workspace semantics.
</p><h6>Procedure servers and dynamic linking</h6><p>
Procedure servers follow the same rules as ACMS, using dynamic linking. VX/ACMS maps ACMS dynamic
calls onto the Linux equivalents <code>dlopen</code> and <code>dlsym</code>, so compiled ACMS
procedures behave like their VMS counterparts. This also lets ACMS tasks call VX/DCL when the TDF
permits it. A server image is a <code>.so</code> that exports one registry symbol, which the
server-process host loads and validates by ABI version before dispatch:
</p>
<pre><span class="kw">typedef struct</span> acms_server_module_v1 {
uint32_t abi_version; <span class="cmt">/* == ACMS_MODULE_ABI_VERSION (1) */</span>
<span class="kw">const char</span> *server_name; <span class="cmt">/* matches SERVER name in the GDF */</span>
<span class="kw">const char</span> *runtime; <span class="cmt">/* "c" | "cxx" | "netcobol" | "gnucobol" */</span>
uint32_t n_procedures;
<span class="kw">const</span> acms_proc_t *procedures; <span class="cmt">/* static, indexed by proc_id (0..N-1) */</span>
acms_status_t (*init) (acms_runtime *rt);
acms_status_t (*term) (acms_runtime *rt);
acms_status_t (*cancel)(acms_runtime *rt, uint32_t task_id);
uint64_t layout_hash; <span class="cmt">/* over all workspace layouts */</span>
} acms_server_module_v1;</pre>
<p>
Dispatch is by index (procedure id), not by name: the controller learns the name-to-id mapping from
the server's startup frame, then issues indexed calls. Each procedure entry is
<code>{ name, entry, n_workspaces }</code>, and the entry signature passes workspace handles by
reference so a procedure reads and writes the shared workspace directly.
</p><h6>Procedure-callable services</h6><p>
A step procedure may call only the three exception raisers. Because <code>$</code> is not a
portable C identifier character, the link symbols use underscores, and the VX tools reconcile the
real <code>ACMS$RAISE_*</code> callers:
</p><div class="table-wrapper"><table><thead><tr><th>Service</th><th>Effect</th><th>Status</th></tr></thead><tbody><tr><td><code>ACMS_RAISE_STEP_EXCEPTION</code></td><td>Raise a step exception; the enclosing block's exception handler runs and the step is abandoned.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>ACMS_RAISE_TRANS_EXCEPTION</code></td><td>Raise a transaction exception; the surrounding atomic block rolls back.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>ACMS_RAISE_NONREC_EXCEPTION</code></td><td>Raise a non-recoverable exception; the task is cancelled.</td><td><span class="ac-live">live</span></td></tr></tbody></table></div><h6>ACMS$ service surface</h6><p>
The agent-facing service library exposes the OpenVMS <code>ACMS$</code> callable API. Condition
values follow the VMS convention, where bit 0 set means success.
</p><div class="table-wrapper"><table><thead><tr><th>Group</th><th>Services</th><th>Status</th></tr></thead><tbody><tr><td>Session</td><td><code>ACMS$SIGN_IN</code>, <code>ACMS$SIGN_OUT</code>, <code>ACMS$GET_SUBMITTER_INFO</code></td><td><span class="ac-live">live</span></td></tr><tr><td>Procedure-callable</td><td><code>ACMS$RAISE_STEP / TRANS / NONREC_EXCEPTION</code></td><td><span class="ac-live">live</span></td></tr><tr><td>Agent forwarding</td><td><code>AGENT_CALL_ACMS</code> (server-to-server, cross-instance)</td><td><span class="ac-live">live</span></td></tr><tr><td>Task calls</td><td><code>ACMS$CALL</code>, <code>ACMS$START_CALL</code>, <code>ACMS$WAIT_FOR_CALL_END</code>, <code>ACMS$CANCEL_CALL</code>, <code>ACMS$QUEUE_TASK</code></td><td><span class="ac-v1">v1 soon</span></td></tr></tbody></table></div><h2 id="transactions">Transactions, menus, and RMS</h2><h6>Transaction handling</h6><p>
VX/ACMS does not execute commit and rollback itself. That responsibility is assumed to belong to
Oracle or another modern transaction manager. The original ACMS commit and rollback structure is
kept intact in the translated code, but the database layer is now what actually executes it.
</p><div class="callout"><strong>Structure preserved, execution delegated.</strong> The task keeps its original ACMS
commit and rollback statements, so the control flow is unchanged. At runtime, those statements
drive the database layer's transaction, rather than a VMS transaction monitor.
</div><h6>Menus and user interfaces</h6><p>
MDF (Menu Definition Files) generate a C-style menu structure that closely mimics MENU and TASK
definitions. The menus can be displayed in <strong>VX/DECFORMS</strong> or processed into standard
console-based menu systems, so legacy ACMS menus behave the same way inside the Linux and Windows
runtime.
</p><h6>RMS recovery</h6><p>
VX/ACMS supports the RMS Recovery syntax, so a task that uses it still translates and runs.
Recovery logic itself is not yet implemented in VX/RMS; RMS support is planned to extend based on
client needs. Tasks that rely on RMS recovery therefore translate cleanly today, with the recovery
behaviour arriving in a later VX/RMS update.
</p><h2 id="adu">The adu compiler</h2><p><code>adu</code> is the ACMS Application Definition Utility: the command that translates the four
definition-file types (and message files) into C++, and optionally invokes the C++ compiler to
produce a loadable <code>.so</code>. The source kind is detected from the file extension, or forced
with <code>--tdf</code>, <code>--gdf</code>, <code>--mdf</code>, <code>--adf</code>, or
<code>--msg</code>.
</p><h6>Command-line flags</h6><div class="table-wrapper"><table><thead><tr><th>Flag</th><th>Purpose</th></tr></thead><tbody><tr><td><code>--tdf</code> / <code>--gdf</code> / <code>--mdf</code> / <code>--adf</code></td><td>Force the source kind, rather than auto-detecting by extension.</td></tr><tr><td><code>--msg</code></td><td>Compile a VSI <code>.MSG</code> message file into a header, a COBOL copybook, and a catalog.</td></tr><tr><td><code>--cdd <db></code></td><td>Open a CDD dictionary so workspace layouts come from CDD rather than the built-in registry.</td></tr><tr><td><code>--compile</code></td><td>After translating, invoke the C++ compiler to produce a <code>.so</code>.</td></tr><tr><td><code>--parse-only</code></td><td>Parse and gate only; emit no output.</td></tr><tr><td><code>--strict</code></td><td>Fail on any lexer or grammar-gap diagnostic.</td></tr><tr><td><code>--pedantic</code></td><td>Also fail when a construct was tolerantly skipped, an include was missing, or a step lowered to a no-op.</td></tr><tr><td><code>--skip-report</code></td><td>Print the skipped-construct inventory after parsing.</td></tr><tr><td><code>--decompile</code></td><td>Parse a source file and print its intermediate representation back out (round-trip check).</td></tr><tr><td><code>--manifest <project.man></code></td><td>Batch-compile a whole project (CDD, output directory, and file lists).</td></tr><tr><td><code>--standin</code></td><td>Emit a self-contained stand-in server so an application can be built and hosted with no COBOL or database.</td></tr></tbody></table></div><div class="callout"><strong>The compile flag is <code>--compile</code>.</strong> When set, <code>adu</code> runs the
C++ compiler on the generated source (for example
<code>c++ -std=c++20 -shared -fPIC ... out.cpp -o out.so</code>). This is the flag that turns a
translation into a loadable module.
</div><h6>Build steps</h6><div class="table-wrapper"><table><thead><tr><th>Step</th><th>Command</th><th>Input</th><th>Output</th></tr></thead><tbody><tr><td>Ingest dictionary</td><td><code>vxcdd --cdd=cdd.db --adddir=CDD/</code></td><td><code>.CDO</code> or SQL DDL</td><td><code>cdd.db</code></td></tr><tr><td>Compile a task</td><td><code>adu --cdd cdd.db --tdf task.tdf out.cpp</code></td><td><code>.TDF</code> plus CDD</td><td><code>task_<NAME>.cpp</code></td></tr><tr><td>Compile a group</td><td><code>adu --gdf group.gdf out.cpp</code></td><td><code>.GDF</code></td><td><code><server>_transfer.cpp</code> per server</td></tr><tr><td>Compile app / menu</td><td><code>adu --adf app.adf out.cpp</code> / <code>adu --mdf menu.mdf out.cpp</code></td><td><code>.ADF</code> / <code>.MDF</code></td><td>Application / menu module</td></tr><tr><td>Compile messages</td><td><code>adu --msg vrmsg.msg out</code></td><td><code>.MSG</code></td><td><code>out.h</code> + <code>.cob</code> + catalog</td></tr><tr><td>Translate and build <code>.so</code></td><td><code>adu --compile ... src out.cpp</code></td><td>Any of the above</td><td><code>out.cpp</code> plus <code>out.so</code></td></tr></tbody></table></div><p>
The ADU command-line interface is intentionally minimal today. VX/ACMS is designed to move ACMS
applications forward into C++, rather than to perpetuate the traditional ACMS command surface, so
the focus is on translation quality rather than reproducing every legacy operator command.
</p><h2 id="status">Compatibility and status</h2><p>
The table below is the honest have-versus-need for the migration path. It reflects what translates
and runs today, what is arriving soon, and what is delegated elsewhere by design.
</p><div class="table-wrapper"><table><thead><tr><th>Capability</th><th>Status</th><th>Notes</th></tr></thead><tbody><tr><td>Parse all four definition grammars (TDF, GDF, ADF, MDF)</td><td><span class="ac-live">live</span></td><td>The full sample application parses with no skipped constructs.</td></tr><tr><td>TDF to C++ codegen (all control flow lowered)</td><td><span class="ac-live">live</span></td><td>No remaining no-ops in task codegen.</td></tr><tr><td>GDF to server-module codegen</td><td><span class="ac-live">live</span></td><td>One server module per SERVER, procedures indexed by id.</td></tr><tr><td>MDF / ADF module emission</td><td><span class="ac-v1">partial</span></td><td>Menu and application module loading has landed; some emission is still called partial.</td></tr><tr><td><code>.MSG</code> message compiler</td><td><span class="ac-live">live</span></td><td>Header, copybook, and catalog output, including multiline and quoted text.</td></tr><tr><td>Runtime: controller, server pool, task engine, workspace shm, IPC</td><td><span class="ac-live">live</span></td><td>The multi-process runtime is in place.</td></tr><tr><td>Menu display through VX/DECFORMS</td><td><span class="ac-live">live</span></td><td>Real DECforms rendering via the forms shim.</td></tr><tr><td><code>ACMS$CALL</code> family C-API entry points</td><td><span class="ac-v1">v1 soon</span></td><td>In-process and remote call paths exist; the C-API entry points are still being finished.</td></tr><tr><td>Transaction commit and rollback execution</td><td><span class="ac-no">delegated</span></td><td>Owned by Oracle or the database layer by design; VX/ACMS keeps the ACMS structure.</td></tr><tr><td>VX/RMS recovery logic</td><td><span class="ac-v2">v2</span></td><td>RMS Recovery syntax is supported; the recovery behaviour itself is planned.</td></tr><tr><td>Distributed two-phase commit</td><td><span class="ac-no">out of scope</span></td><td>No distributed transactions in v1.</td></tr></tbody></table></div><h6>Divergences from OpenVMS ACMS, and why</h6><div class="table-wrapper"><table><thead><tr><th>Divergence</th><th>Reason</th></tr></thead><tbody><tr><td>No transaction monitor required; components can bundle into one executable.</td><td>Linux has no ACMS system service, so the C++ runtime integrates the tiers directly.</td></tr><tr><td>Commit and rollback delegated to the database.</td><td>VX/ACMS keeps the ACMS commit and rollback structure, but the database layer executes it.</td></tr><tr><td><code>$</code> in <code>ACMS$</code> symbols mapped to <code>_</code>.</td><td><code>$</code> is not a portable C identifier character; the VX tools reconcile the real callers.</td></tr><tr><td>Dispatch by procedure id, not by name.</td><td>Matches the VMS transfer-module contract: one indexed load and one indirect call per step.</td></tr><tr><td>Workspaces shared by reference in POSIX shared memory.</td><td>The Linux equivalent of ACMS workspace sharing; only slot indices cross the process boundary.</td></tr><tr><td>Forms rendering links the real VX/DECFORMS library.</td><td>The runtime reuses the existing forms engine rather than reimplementing form rendering.</td></tr><tr><td>CDD is used through its callable API, not reimplemented.</td><td>All workspace codegen resolves record layouts through VX/CDD.</td></tr></tbody></table></div><h2 id="quickref">Quick reference</h2><h6>Definition file types</h6><div class="kw-grid"><div>.TDF task</div><div>.GDF task group</div><div>.ADF application</div><div>.MDF menu</div><div>.MSG messages</div></div><p>Each opens with <code>REPLACE <KIND> <path>:<name></code> and closes with <code>END DEFINITION;</code>.</p><h6>adu command line</h6>
<pre>adu [--cdd db] [--tdf|--gdf|--mdf|--adf|--msg] [--compile]
[--parse-only] [--strict] [--pedantic] [--skip-report] <src> <out>
adu --decompile <src>
adu --manifest project.man
adu --standin</pre>
<h6>Compile to a shared object</h6>
<pre>adu --compile ... out.cpp
runs: c++ -std=c++20 -shared -fPIC ... out.cpp -o out.so</pre>
<h6>Supported TDF control structures</h6><div class="kw-grid"><div>IF THEN ELSE</div><div>WHILE DO</div><div>SELECT FIRST TRUE</div><div>CONTROL FIELD</div><div>GOTO</div><div>EXCHANGE</div><div>PROCESSING</div><div>MOVE</div><div>REPEAT STEP</div><div>REPEAT TASK</div><div>RAISE</div><div>GET MESSAGE</div></div><h6>Procedure-callable services</h6><div class="kw-grid"><div>ACMS_RAISE_STEP_EXCEPTION</div><div>ACMS_RAISE_TRANS_EXCEPTION</div><div>ACMS_RAISE_NONREC_EXCEPTION</div></div><h6>Session API</h6><div class="kw-grid"><div>ACMS$SIGN_IN</div><div>ACMS$SIGN_OUT</div><div>ACMS$GET_SUBMITTER_INFO</div></div><h6>Success test</h6><p>Condition values follow the VMS convention: <strong>bit 0 set means success</strong>. <code>ACMS$_NORMAL</code> is the canonical success code.</p><h6>Runtime dependencies</h6><div class="kw-grid"><div>C++20</div><div>CMake / Ninja</div><div>SQLite (for VX/CDD)</div><div>VX/DECFORMS (forms)</div></div></div>