Skip to content

Ladder to structured text

Drop a PLCopen LD program here and read it back as IEC 61131-3 structured text. The file never leaves your browser: the conversion runs locally, in JavaScript, the same algorithm as runner/ld_to_st.py, which is what generates the "Structured text, derived" panel on every benchmark page in this suite. This is a reading aid, not a second source of expected verdicts: ESBMC verifies the ladder program itself, never a rendering of it.

Works on any file with a <pou><body><LD> inside, not only files from this suite.

How the translation works

PLCopen XML does not store a rung as a line of contacts; it stores a graph. Every element carries a localId and a connectionPointIn naming the refLocalId(s) it is wired from. The translator starts at each coil and walks that graph backward toward the power rail: one incoming reference is a series link (AND), two or more on the same connectionPointIn are parallel branches (OR). The walk is memoized per localId, so a contact feeding two coils is still evaluated once.

1. The rung, as drawn2. The PLCopen graph, as stored (and as ld_to_st.py walks it)3. The walk from the coil back to the railABCYcontact id=3var: Acontact id=4var: Bcontact id=5, negatedvar: Ccoil id=6var: YconnectionPointInrefLocalId=3, 4refLocalId=5coil 6 reads contact 5's connectionPointIn: one ref, so AND.contact 5 reads refLocalId 3 and 4: two refs, so OR.the walk bottoms out at the rails: 3 and 4 both read TRUE.Y := (A OR B) AND NOT C;

Every function block call is collected the same way, before the coil assignments: a block's inputs are walked first, so a call statement always precedes any expression that reads <instance>.<formal> from it. When two rungs write the same coil, scan order decides which write survives, and the rendered ST marks that target rather than hiding the collision.

Drop a PLCopen XML file here, or click to choose one.

Nothing is uploaded. Parsing happens on this page.

Reading it from the command line instead

The same conversion, as a script:

python3 runner/ld_to_st.py path/to/program.xml

Both the page above and the script read a <pou> element anywhere in the document (not only under <types><pous>, since one vendor export nests it under a proprietary extension instead), handle the tc6_0200 and tc6_0201 PLCopen namespaces, and fall back to a (* ... *) comment rather than guessing when a refLocalId cannot be resolved or a rung has more than one writer to the same coil.