🔍
v1.3.8

Literals

Literals are fixed values written directly in your source code. TSharkRex supports integer, floating-point, time, string, and boolean literals. Understanding the correct syntax for each type is essential - especially hexadecimal notation, which you will use extensively when working with CAN data and hardware registers.

Integer Literals

Integer literals represent whole numbers. They can be written in decimal or hexadecimal notation, and may be negative.

Decimal Integers

Standard base-10 numbers, optionally prefixed with a minus sign for negative values:

VAR
    speed : INT := 123;
    offset : INT := -45;
    bigVal : DINT := 1000000;
END_VAR;

Hexadecimal Integers

Hexadecimal literals use the 0x prefix. This is the dominant notation in TSharkRex code because CAN IDs, byte masks, and register addresses are almost always expressed in hex.

VAR
    canId : DINT := 0x1F002E80;
    mask : BYTE := 0xFF;
    flag : BYTE := 0x01;
    pattern : INT := 0x00FA;
END_VAR;
Note: TSharkRex uses the 0x prefix for hexadecimal values. Some IEC 61131-3 implementations use 16# instead - that syntax is not supported here.

Boolean Values as Integers

TRUE and FALSE are integer literals equal to 1 and 0 respectively. They can appear anywhere an integer is expected:

VAR
    active : BOOL := TRUE;   // 1
    stopped : BOOL := FALSE; // 0
END_VAR;

A practical example combining integer literal forms:

VAR
    canId : DINT := 0x320;
    dlc : BYTE := 8;
    enabled : BOOL := TRUE;
    retryCount : INT := 3;
    errorCode : INT := -1;
    SENDDATA : ARRAY[0..7] OF BYTE;
    CANSEND : CAN_TX;
END_VAR;
IF enabled THEN
    SENDDATA[0] := 0xFA;
    SENDDATA[1] := 0x55;
    CANSEND(ENABLE := TRUE, ID := canId, EXT := FALSE, DATALENGTH := dlc, DATA := SENDDATA);
END_IF;

Floating-Point Literals

TSharkRex supports two floating-point precisions. A plain decimal number produces a REAL (single precision, 32-bit). Appending the suffix d produces an LREAL (double precision, 64-bit).

VAR
    voltage : REAL;
    precise : LREAL;
    factor : REAL;
    temp : REAL;
END_VAR;
// Single precision (REAL) - assign in code body, not in VAR
voltage := 3.14;
precise := 3.14d;     // Double precision (LREAL) - use d suffix
factor := 0.001;
temp := -25.5;
Tip: Use REAL for most purposes. Switch to LREAL (with the d suffix) only when you need extra precision - for example, accumulating very small increments over long periods.

Floating-point literals in expressions:

VAR
    rawAdc : INT;
    scaledVoltage : REAL;
    calibrationOffset : REAL;
END_VAR;
calibrationOffset := 0.05;

// Convert a raw ADC reading to voltage
scaledVoltage := SINT_TO_FP(rawAdc, REAL) * 0.001 + calibrationOffset;

Time Literals

Time literals express durations using the T# prefix followed by one or more time components. The general format is:

T#[days]d[hours]h[minutes]m[seconds]s[milliseconds]ms

Each component is optional, but at least one must be present. Components can be combined in any order (though by convention they appear from largest to smallest unit).

Basic Time Examples

T#1s          // 1 second (1000 ms)
T#500ms       // 500 milliseconds
T#2m30s       // 2 minutes and 30 seconds
T#1h30m       // 1 hour and 30 minutes
T#1d12h       // 1 day and 12 hours

Underscore Separators

You can use underscores between components for readability. They are ignored by the compiler:

T#2s_500ms           // 2.5 seconds
T#1h_30m_15s         // 1 hour, 30 minutes, 15 seconds

Combined Time Literal

The most complete form uses all components:

T#10d10h10m10s10ms   // 10 days, 10 hours, 10 minutes, 10 seconds, 10 ms
Internal representation: TIME values are stored internally as UDINT (unsigned 32-bit integer) representing the total number of milliseconds. This means T#1s is stored as 1000, and the maximum representable duration is approximately 49.7 days.

Time literals are most commonly used with timer function blocks:

VAR_SIGNAL
    SIGNAL_TANDNING : BOOL;    // Ignition signal
END_VAR;

VAR
    debounceTimer : TON;
    blinkTimer : TON;
    isActive : BOOL;
    blinkState : BOOL;
END_VAR;

// Debounce an input signal for 200 ms
debounceTimer(IN := SIGNAL_TANDNING, PT := T#200ms);
isActive := debounceTimer.Q;

// Create a 500ms blink pattern
blinkTimer(IN := NOT blinkTimer.Q, PT := T#500ms);
blinkState := blinkTimer.Q;

String Literals

String literals are enclosed in double quotes. They support the \n escape sequence for newlines:

"Hello World"
"Line1\nLine2"
"CAN Error: timeout"
Not Yet Supported

The STRING data type is not currently supported by the TSharkRex compiler. String literals (e.g., "Hello") can only be used in specific contexts such as description labels in VAR_OUTPUT declarations (e.g., HELLJUS ["Helljus"] : OUTPUT;). You cannot declare STRING variables or perform string operations in recipes.

Boolean Literals

The two boolean literals are TRUE and FALSE. They are equivalent to the integer values 1 and 0, which means they can participate in arithmetic expressions.

VAR
    isRunning : BOOL := TRUE;
    isStopped : BOOL := FALSE;
    multiplier : INT;
END_VAR;

// Boolean in arithmetic: TRUE = 1, FALSE = 0
multiplier := isRunning * 1000;   // 1000 when running, 0 when stopped

This property is useful for conditional scaling without an IF statement:

VAR
    SIGNAL_HELLJUS : BOOL;
    SIGNAL_HALVLJUS : BOOL;
    outputLevel : INT;
END_VAR;

// Combine boolean flags into a priority value
// HELLJUS (high beam) = 2, HALVLJUS (low beam) = 1, neither = 0
outputLevel := SIGNAL_HELLJUS * 2 + SIGNAL_HALVLJUS * 1;
Tip: The boolean-as-integer trick is a compact alternative to nested IF statements. Use it when you need to scale or weight values based on flags.

Summary

Literal Type Examples Stored As
Decimal integer 123, -45 INT, DINT, BYTE
Hexadecimal integer 0x1F, 0xFF00 INT, DINT, BYTE
Boolean TRUE, FALSE BOOL (1 or 0)
Single-precision float 3.14, 0.001 REAL (32-bit)
Double-precision float 3.14d LREAL (64-bit)
Time T#1s, T#500ms UDINT (milliseconds)
String "Hello" STRING (not yet supported as a data type; used in labels only)