Autonomy industrial automation software logoAutonomy®, industrial automation platform

STRUC++

The open-source Structured Text compiler behind OpenPLC.

STruC++ compiles IEC 61131-3 Structured Text into clean, readable C++14. It ships with a built-in unit testing framework, an interactive REPL and a reusable library system, in a single binary.

29K+
Downloads of the compiler
60+
Releases since launch
85+
Stars on GitHub
Native
Machine code, no interpreter at runtime

Why a new compiler

For two decades, virtually every open-source PLC project depended on a single compiler, limited to the second edition of IEC 61131-3 and generating macro-heavy C. When we rebuilt OpenPLC as v4, the compiler was the last piece left from the old stack. STruC++ is its replacement, written from scratch.

What makes it different

Readable C++, not macros

Function blocks become classes, interfaces become virtual methods and generics become templates. You can read the output, debug it and link it into an existing C++ project.

Unit tests in ST

The test runner is built into the compiler. Write TEST blocks with assertions, mocks, SETUP/TEARDOWN and simulated time, and run them on any machine with no PLC attached, ideal for CI pipelines.

Interactive REPL

Build a program with --build and step through it: set inputs, run cycles, inspect and force variables, and view the ST and the generated C++ side by side.

Zero runtime dependencies

The compiler is a single binary and the C++ runtime is header-only. Nothing else to install on the target.

Structured Text in, C++ out

A function block becomes a C++ class with its inputs and outputs as members and its logic in a call operator.

counter.st
FUNCTION_BLOCK Counter
  VAR_INPUT
    enable : BOOL;
    reset  : BOOL;
  END_VAR
  VAR_OUTPUT
    count : INT;
  END_VAR

  IF reset THEN
    count := 0;
  ELSIF enable THEN
    count := count + 1;
  END_IF;
END_FUNCTION_BLOCK
Generated C++
namespace strucpp {

class Counter {
public:
    IEC_BOOL enable;
    IEC_BOOL reset;
    IEC_INT count;

    void operator()();
};

void Counter::operator()() {
    if (reset) {
        count = 0;
    } else if (enable) {
        count = count + 1;
    }
}

}  // namespace strucpp

Language coverage

A broad subset of IEC 61131-3 Edition 3, plus common extensions used across the industry.

Data types

Every elementary type including 64-bit integers, strings and L-variants of time and date, plus arrays, structs, enums and subranges.

POUs and variables

PROGRAM, FUNCTION, FUNCTION_BLOCK and INTERFACE, with inputs, outputs, globals, constants, RETAIN and located variables.

Object orientation

Methods, properties with GET and SET, EXTENDS, IMPLEMENTS, ABSTRACT, FINAL, OVERRIDE and access modifiers.

Pointers and references

POINTER TO, REF_TO, REFERENCE_TO, ADR, dereferencing and dynamic allocation.

Standard library

Over 80 standard functions plus timers, counters, edge detectors and bistables. The OSCAT Basic library compiles out of the box.

Project model

CONFIGURATION, RESOURCE and TASK, with program scheduling.

Runs where you work

Command line

Standalone binaries for Linux x64 and ARM64, macOS Intel and Apple Silicon, and Windows x64.

In the browser

Also a JavaScript and TypeScript library with no native dependencies, for Node.js, browsers, Deno and Bun.

In VS Code

The STruC++ extension brings real-time diagnostics, autocomplete, go to definition and debugging to Structured Text.

On microcontrollers

The output targets C++14 so it builds with the toolchains Arduino boards ship with, down to avr-g++ 7.3.

Open source, and your programs stay yours

The compiler is licensed under GPL-3.0. The C++ runtime and standard libraries carry the STruC++ Runtime Library Exception, so the programs you compile can be distributed under any license.

Try STruC++

Download a release, compile your first ST file and run its tests, no PLC required.