ABCalc Expression Language — Complete Syntax Reference

This document is a single-file reference for the full syntax of the ABCalc expression language. It covers everything needed to write complex expressions and custom functions, and serves as the authoritative guide for adding new built-in functions to the ABCalc codebase.

Related pages: Values · Operators · Expressions · Functions · Variables


Table of Contents

  1. Literal Values
  2. Variables and Memory
  3. Operators
  4. Indexing and Slicing
  5. Expressions and Statements
  6. Function Calls
  7. Custom Function Definitions
  8. Type System

1. Literal Values

Integer Numbers

Integer literals can be written in four bases. Underscores and number group separators (e.g., ,) are allowed anywhere for readability.

Form Prefix Example
Decimal (none) 123456, 1_000_000
Hexadecimal 0x 0xFFFF, 0xBE_EF
Octal 0o 0o1777
Binary 0b 0b1010_1010

Negative integer literals use a leading - sign: -42. ABCalc automatically promotes integers to long (64-bit) or BigInteger when the value overflows.

123456        // decimal
0xFF          // 255 in hex
0b1101        // 13 in binary
0o17          // 15 in octal
1_000_000     // one million (underscores for readability)

Floating-Point Numbers

Floating-point literals support standard and scientific notation. The decimal separator is locale-dependent (typically . or ,; see ABCalc settings). A number with no integer part may omit the leading zero.

3.14
.5            // same as 0.5
1E-2          // 0.01 (scientific)
6.022E23      // Avogadro's number
1.5e+18

Booleans

true    false    // case-insensitive: TRUE, False, etc.

Integer 0 is treated as false and any non-zero integer as true when a boolean is expected.

When ternary logic is enabled, null acts as undefined.

Strings

Strings may be delimited by single quotes '…', double quotes "…", or backquotes `…`.

Single-quote and double-quote strings are decoded — escape sequences are replaced:

Escape Character
\' Single quote
\" Double quote
\\ Backslash
\n Newline
\r Carriage return
\t Tab
\b Backspace
\f Form feed
\v Vertical tab
\0 Null (code 0)
\a Bell (code 7)
\uXXXX Unicode code point (4 hex digits)
\xXXXX Unicode code point (4 hex digits)

Verbatim / raw strings — no escape processing:

  • Backquote strings: `no escapes here, \n is literal`
  • @"…" prefix: @"no escapes, \n stays as-is"

Strings are concatenated with +:

'Hello' + ', ' + 'World!'   // "Hello, World!"

Characters

A single character in single quotes is a char value, not a string:

'A'     // character A (Unicode 65)
'\n'    // newline character

Characters compare equal to their Unicode code points: 'A' == 65 is true.

Dates and Time Periods

Date/time literals are enclosed in #…#. The format follows system regional settings or ISO 8601.

Keywords (no quotes or #):

Keyword Meaning
now Current date and time
today Current date (no time)
yesterday Current date minus 24 hours (midnight, the beginning of the previous day)
tomorrow Current date plus 24 hours (midnight, the beginning of the next day)

Date literals:

#2024-12-15#                  // ISO 8601 date
#2024-12-15T10:30:00Z#        // ISO 8601 datetime
#15.12.2024#                  // European format (locale-dependent)
#15.12.2024 10:30:05#
#in 3 days#
#5 years ago#
#before 2 months#
#3 days later#

Time period (TimeSpan) literals:

#5:00#          // 5 hours
#00:03:00#      // 3 minutes
#2.12:00:00#    // 2 days, 12 hours
#5 min 30 sec#
#5d3h30min#
#3 years 1 day#

Important for custom functions: Date literals are evaluated at parse time, not call time. Use Today() and Now() functions instead of #today# or #now# inside custom function bodies to get the current date at runtime.

Complex Numbers

i           // imaginary unit (√−1)
3i          // 0+3i
4+2i        // complex: real part 4, imaginary part 2
(7+5i) * (3-2i)   // complex arithmetic (parentheses required here)

Vectors

Vectors are written with square brackets and semicolon-separated numeric components:

[1; 2; 3]           // 3-component vector
[1.0; 0.0; 0.0]     // unit X vector

Arithmetic operators (+, -, *, /) work component-wise on vectors of the same dimension. Dot product, cross product, and other vector operations are available via built-in functions.

Lists

Lists are parenthesized semicolon-separated values. Commas also work but may conflict with locale decimal/group separators, so semicolons are preferred.

(1; 2; 3)
('a'; 'b'; 'c')
(1; 'hello'; true; null)   // mixed types allowed

Use MakeList(n) or MakeList(n; defaultValue) to construct lists programmatically:

MakeList(5)        // (null; null; null; null; null)
MakeList(3; 0)     // (0; 0; 0)
MakeList(4; "x")   // ("x"; "x"; "x"; "x")

Percent Values

A % suffix marks a value as a percent:

5%          // 5 percent
(1+2)%      // 3 percent

Percent values interact with arithmetic operators as expected: 200 + 10% yields 220.

Named Constants

Name Value
pi π ≈ 3.14159265358979…
e Euler's number ≈ 2.71828182845905…
phi Golden ratio ≈ 1.61803398874989…
unit_XXX Conversion unit (see Convert() function)

Constants are read-only — they cannot be assigned.

Previous Result (@)

The @ character alone refers to the result of the most recently evaluated expression. Returns null if no previous result exists.

100 * 5       // result: 500
@ / 2         // result: 250  (half of the previous 500)

2. Variables and Memory

Variables ("memory cells") are named storage slots. Names are case-insensitive (MyVar and myvar refer to the same cell). A variable that has never been set returns null.

Reserved names: mc0mc9 (mapped to the memory buttons in the UI). Constants (pi, e, phi, unit_XXX) cannot be used as variable names.

Basic Assignment

a := 42          // standard assignment (always available)
myVar := 'hello'

If the option to use = for assignment is enabled in settings, plain = also assigns:

x = 100          // only if the setting is on

Compound Assignment

Operator Meaning
+= Add and store
-= Subtract and store
*= Multiply and store
/= Divide and store
&= Bitwise AND and store
|= Bitwise OR and store
^= Bitwise XOR and store
a := 10; a += 5; a   // 15
b := 0b1111; b &= 0b1010; b   // 10

Indexed Element Update

A string or list stored in a variable can be updated element-by-element:

mc0 := "abcdefg";
mc0[3] := 'X';
mc0   // "abcXefg"

3. Operators

Operator Precedence (Highest to Lowest)

Priority Operators Associativity
1 (highest) ! !! !!! (postfix factorial) Left
2 % (postfix percent) Left
3 ** ^(Programmer) (exponentiation) Right
4 Unary - + not ¬ bit_not ~(Programmer) !(Programmer) Right
5 * / \\ div mod %(Programmer) Left
6 + - Left
7 << >> Left
8 < <= > >= Left
9 == = != <> IN NOT IN LIKE NOT LIKE Left
10 BIT_AND &(Programmer) Left
11 BIT_XOR ^(Programmer) Left
12 BIT_OR \|(Programmer) Left
13 and && Left
14 xor Left
15 or \|\| Left
16 (lowest) ? : (ternary) Right

Assignment operators (:=, +=, -=, *=, /=, &=, \|=, ^=) have the lowest binding of all and are not part of the table above because they are statements, not sub-expressions.


Factorial (postfix !)

Applied after an integer value or parenthesized expression. Multiple ! characters give multifactorials.

5!          // 120  (standard factorial)
10!!        // double factorial
(3+2)!      // 120

Percent (postfix %)

Marks a value as a percentage. Arithmetic between a number and a percent uses the percent contextually:

100 + 10%   // 110   (add 10% of 100)
200 - 5%    // 190   (subtract 5% of 200)
100 * 5%    // 5     (5% of 100)
50 / 5%     // 1000  (50 divided by 5%)
5% + 2%     // 7%    (percent + percent = percent)

Exponentiation

2 ** 10      // 1024
2 ** 0.5     // √2 ≈ 1.4142…

In Programmer's layout, ^ is exponentiation. In standard layout, ^ is bitwise XOR — use ** to be unambiguous.

Unary Operators

Operator Meaning
- Arithmetic negation
+ Unary positive (no-op)
not, ¬ Logical NOT
bit_not Bitwise NOT (ones complement)
(U+221A) Square root
(U+221B) Cube root
(U+221C) Fourth root
! (Programmer) Logical NOT
~ (Programmer) Bitwise NOT
-5
not true        // false
bit_not 0b1010  // ones complement
√16             // 4
∛27             // 3

Multiplicative Operators

Operator Meaning
*, ×, Multiplication
/, , ÷ Division (always floating-point)
\\, div Integer division (truncates both operands first)
mod Remainder (modulus)
% (Programmer) Remainder
10 / 4        // 2.5
10 \\ 3       // 3   (integer division)
10 div 3      // 3   (same as \\)
10 mod 3      // 1
7.9 \\ 2.1   // 3   (truncates to 7 and 2, then divides)

// is not integer division — it starts a line comment. Use \\ or div.

Time periods can be multiplied or divided by a number:

#00:01:00# * 5    // 5-minute TimeSpan
#01:00:00# / 4    // 15-minute TimeSpan

Additive Operators

Operator Meaning
+ Addition; string concatenation
- Subtraction

Date arithmetic:

#2024-01-01# + #00:02:00#   // 2024-01-01 00:02:00
#2024-03-01# - #2024-01-01# // TimeSpan of 60 days
#2024-01-01# - #00:01:00#   // 2023-12-31 23:59:00

Relational Operators

Equality / Inequality

Operator Meaning
==, = Equal (use == when = might be assignment)
!=, <>, Not equal

Values of incompatible types are considered not equal. Characters compare equal to their Unicode code points.

Comparison

< <= > >=

IN / NOT IN

'cat' IN ('dog'; 'cat'; 'fish')   // true
42 NOT IN (1; 2; 3)               // true
'hi' IN 'this is a hint'          // true (substring check)

LIKE / NOT LIKE

Pattern matching for strings. % matches any sequence; _ matches any single character.

'HelloWorld' LIKE 'Hello%'        // true
'2024-08-28' LIKE '2024-08-__'   // true
'Test123' NOT LIKE 'Test__'       // false

Bitwise Operators

Operate on the integer part of values.

Operator Meaning
<< Left shift
>> Right shift
BIT_AND Bitwise AND
BIT_OR Bitwise OR
BIT_XOR Bitwise XOR

Programmer-layout symbols: & (AND), \| (OR), ^ (XOR).

1 << 4                     // 16
0b1100 BIT_AND 0b1010      // 8  (0b1000)
0b1100 BIT_OR  0b1010      // 14 (0b1110)
0b1100 BIT_XOR 0b1010      // 6  (0b0110)

Logical Operators

Operator Meaning
and, &&, Logical AND (short-circuit)
or, ||, Logical OR (short-circuit)
xor, , Logical XOR
not, ¬ Logical NOT

Precedence: not > and > xor > or.

Short-circuit: the right-hand side of and is not evaluated when the left is false; the right-hand side of or is not evaluated when the left is true.

true or false and true     // true  (and binds tighter)
(1 == 1) || false          // true
true xor true              // false

By default, null or a non-boolean operand in a logical expression causes an error. Enable Ternary Logic in settings to use Kleene's three-valued logic, where null is treated as Unknown.

Ternary Operator

condition ? value_if_true : value_if_false

Only one branch is evaluated.

x > 0 ? x : -x          // absolute value of x
a != null ? a * 2 : 0   // null-safe multiplication

Assignment Operators

:= is the primary assignment operator (always available). = may also assign if the setting is enabled.

x := 10
x += 1    // x := x + 1
x -= 1
x *= 2
x /= 4
x &= 0xFF
x |= 0x01
x ^= 0b1010

Null Propagation

null propagates through arithmetic: any operation with a null operand yields null.

null + 1        // null
5 * null        // null
null / 2 + 10   // null

Guard with ternary or iff():

x != null ? x * 2 : 0
iff(x != null; x * 2; 0)

4. Indexing and Slicing

Applies to strings, lists, and variables holding strings or lists. Indices are zero-based.

Single Element

"abcdef"[2]           // 'c'
(10; 20; 30)[1]       // 20

Range / Slice

expr[lower..upper]    // from lower (inclusive) to upper (exclusive)
expr[lower..]         // from lower to the end
expr[..upper]         // from the start to upper (exclusive)

Caret (^) — Count from End

^1 = last element, ^2 = second-to-last, etc.

"abcde"[^1]           // 'e'
"abcde"[^2]           // 'd'
"abcde"[..^1]         // "abcd"
"abcde"[1..^1]        // "bcd"
(1;2;3;4)[^2..]       // (3;4)

5. Expressions and Statements

Statement Groups

Multiple expressions separated by ; (semicolon) form a sequence. The value of a sequence is the value of its last expression.

a := 1; b := 2; a + b    // yields 3

Wrap a sequence in {…} to treat it as a single expression (required when passing a group as a function argument or in if/while bodies):

{ a := 1; a * 2 }        // yields 2

Conditionals

if / else statement:

if (condition) { consequent }
if (condition) { consequent } else { alternative }
if (a < 5) { a += 1; }
if (x > 0) x else -x    // braces optional for single expressions

No semicolon is needed after an if/else block.

iff() function (expression form):

iff(condition; value_if_true; value_if_false)
iff(x < 0; -x; x)       // same as: x < 0 ? -x : x

ifs() function (multi-branch):

ifs(cond1; val1; cond2; val2; ...; default)
ifs(score >= 90; 'A'; score >= 80; 'B'; score >= 70; 'C'; 'F')

Loops

while (condition) { body }

Maximum 65535 iterations (safety limit).

i := 1; total := 0;
while (i <= 10) { total += i; i += 1; }
total    // 55

Flow control inside loops:

Keyword Effect
break Exit the loop
continue Skip to the next iteration
return expr Exit the loop and the entire expression with a value
list := (3; 7; 1; 9; 4);
i := 0;
while (i < Count(list)) {
    if (list[i] > 5) { return list[i]; };
    i += 1;
}
// returns 7  (first element greater than 5)

Return

return expr exits the current expression (or function body) immediately and produces expr as the result:

a := 1; if (a > 0) { return a * 10; }; a + 1
// returns 10, never reaches "a + 1"

Comments

// single-line comment (to end of line)

/* block comment
   spanning multiple lines */

/// documentation comment (used to describe custom functions — see below)

// always starts a comment. It is not integer division. Use \\ or div for integer division.


6. Function Calls

Function names are case-insensitive. Arguments are separated by ; (semicolons). Commas also work but may conflict with locale decimal/group separators.

Sqrt(16)               // 4
Round(3.14159; 2)      // 3.14
Max(1; 2; 3)           // 3
Log(100; 10)           // 2

Function calls are expressions and can be nested:

Max(Min(a; b); c)
Abs(Round(x; 2) - Round(y; 2))

7. Custom Function Definitions

Custom functions can be defined inline within an expression or stored in a library file (.abcf, ABCalc Plus).

Syntax Forms

Full body:

fn FunctionName(param1; param2) 
{
    // body: one or more statements
    return result;
};

Arrow (short) form:

fn FunctionName(param1; param2) => expression;

Documentation Comments

A /// comment immediately before fn attaches a description. In library files, documented functions appear in the ABCalc function list alongside built-in functions.

/// Returns the hypotenuse of a right triangle.
fn Hypotenuse(a; b) => Sqrt(a*a + b*b);

Optional Parameters

Optional parameters follow mandatory ones and declare a default value with =:

fn MyRound(value; up = false) => up ? Ceil(value) : Trunc(value);

fn Power(base; exp = 2) => base ** exp;
Power(3)      // 9  (uses default exp=2)
Power(3; 3)   // 27

Return Value

A function returns the value of its last expression, or an explicit return:

fn Clamp(x; lo; hi) {
    if (x < lo) { return lo; };
    if (x > hi) { return hi; };
    x    // implicit return
};

Memory Scope

Inline functions share memory with the outer expression. Library functions have isolated memory. In both cases, parameter names shadow same-named memory cells.

Complete Example

/// Computes the sum of integers from 1 to n.
fn GaussSum(n) => n * (n + 1) / 2;

/// Finds the first list element satisfying a threshold.
fn FirstAbove(lst; threshold)
{
    i := 0;
    while (i < Count(lst)) {
        if (lst[i] > threshold) { return lst[i]; };
        i += 1;
    };
    return null;
};

GaussSum(10)                      // 55
FirstAbove((3; 7; 1; 9; 4); 5)   // 7

8. Type System

Value Types

Type Examples Notes
int / long 42, 0xFF Auto-promotes to BigInteger on overflow
BigInteger Very large integers Arbitrary precision
double 3.14, 1E-5 Default floating-point type
BigDecimal Arbitrary-precision decimal Used when precision matters
bool true, false Also accepts integer 0/non-zero
string 'text' Immutable sequence of chars
char 'A' Single Unicode character
DateTime #2024-01-01# Date and/or time
TimeSpan #1:30:00# Duration
ComplexNumber 3+2i Real + imaginary
Vector [1;2;3] Multi-component numeric
Percent 5% Contextual percentage
null (absent value) Propagates through arithmetic

Automatic Type Promotion

  • Integer arithmetic: intlongBigInteger (on overflow)
  • Mixed integer+float: integer is widened to double or BigDecimal
  • Division (/) returns an integer (when possible) or a floating-point result

Character ↔ Integer

A char value equals its Unicode code point in comparisons and arithmetic:

'A' == 65    // true
'A' + 1      // 66 (becomes integer)

Null

null propagates through arithmetic. Use iff() or the ternary operator to guard.