CX+AI

CX by Example

Real programs, and the output they really produce

GENERATED from DOCS/reference/manuals/CX_Examples_Gallery.html by tests/forge.cx — edit the source, not this page.

CX by example

Real CX, and the output it really produces. Every snippet below is lifted from an example that ships in the CX download, and every "what it prints" block is that example's recorded output -- the same bytes the test suite compares against on Windows, Linux and macOS. Neither is retyped here, so neither can drift from the program it describes.

The full set is larger than this page: the download ships around sixty curated examples across basics, strings, containers, json, files, structs, pointers, events and rules, algorithms, graphics and AI. This is a walk past five of them.

Reverse a string

The whole program. A typed function (.s returns a string), a while loop, and mid() -- which is 1-indexed, a piece of BASIC heritage CX kept on purpose and the single most common thing to trip over. Array indices are 0-based as in C.

// reverse.cx -- reverse a string, the CX way.
//
// CX string helpers used here:
//   len(s)        -- length of a string
//   mid(s, p, n)  -- n characters starting at position p (1-INDEXED, BASIC heritage)
//   +             -- string concatenation

function reverse.s(s.s) {
   out.s = "";
   i.i = len(s);
   while (i >= 1) {
      out = out + mid(s, i, 1);      // walk from the last character back to the first
      i = i - 1;
   }
   return out;
}

words.s = "Hello, CX!";
println(words + "  ->  " + reverse(words));
println("stressed  ->  " + reverse("stressed"));
println("racecar   ->  " + reverse("racecar"));

What it prints:

Hello, CX!  ->  !XC ,olleH
stressed  ->  desserts
racecar   ->  racecar

In the download: examples/strings/02_reverse.cx -- reverse a string with mid().

A struct that points at its own type

C's oldest data structure, written the way C writes it. A field declared node *next may point at the struct it lives in, so CX has linked lists, trees and graphs with no container library involved. new node takes one zeroed node from CX's own allocator and delete p gives it back -- no byte count appears in CX source, because the size comes from the struct's shape. This runs identically on the native backend and on the register VM.

struct node {
    val.i;
    node *next;         // <- points at the struct being declared
}

// Push a value on the front and return the new head. Taking and returning
// `node *` means the caller's head pointer is just reassigned -- no out-param.
//
// Written in C's own declarator form (`node *push(...)`). Since v3.267.0 CX also
// has a suffix spelling for it -- `function push.node*(...)` -- and the two mean
// exactly the same thing; see `408 suffix pointer types.cx` for that side. Both
// are exact. What is NOT exact is `function push.i(...)`: `.i` really does mean
// int, and returning a pointer through it is now CX-E1084 at this line rather
// than a truncation your C compiler catches somewhere in generated code.
node *push(node *head, int val) {
    node *n;
    n = new node;               // one zeroed node from the GC; size from the shape
    n->val  = val;
    n->next = head;
    return n;
}

function sum_list.i(node *head) {
    node *p;
    int total;
    total = 0;
    p = head;
    while (p != 0) {
        total = total + p->val;
        p = p->next;
    }
    return total;
}

What it prints:

=== 1. linked list ===
first three: 25 16 9
sum of all five: 55

=== 2. binary search tree ===
in-order: 20 30 40 50 60 70 80 
depth: 3
smallest: 20

=== 3. forward + mutual reference ===
vertex 1 has 2 outgoing edge(s)
first edge leads to vertex 2
vertex 2 has 0 outgoing edge(s)

In the download: examples/structs/06_linked_structures.cx -- self-referential structs: linked list, binary tree, graph, new/delete.

An array of function pointers

A calculator with no switch in it: four functions, an array of pointers to them, and a loop that calls through the array. array *operations[4] is CX's spelling for "an array that holds pointers", and the call operations[i](x, y) is C's.

array *operations[4];
operations[0] = &add;
operations[1] = &subtract;
operations[2] = &multiply;
operations[3] = &divide;

array opNames.s[4];
opNames[0] = "add";
opNames[1] = "subtract";
opNames[2] = "multiply";
opNames[3] = "divide";

x = 20;
y = 4;
i = 0;

while (i < 4) {
    result = operations[i](x, y);
    print(opNames[i++], "(", x, ", ", y, ") = ", result, "");
}

What it prints:

=== Function Pointer Test ===
Test 1: Basic Function Pointer
add(10, 5) via pointer = 15
subtract(10, 5) via pointer = 5
multiply(10, 5) via pointer = 50
divide(10, 5) via pointer = 2
Test 2: Calculator with Function Pointer Array
add(20, 4) = 24
subtract(20, 4) = 16
multiply(20, 4) = 80
divide(20, 4) = 5
Test 3: Function Pointer as Parameter
applyOperation(15, 3, add) = 18
applyOperation(15, 3, multiply) = 45
Test 4: Dynamic Operation Selection
Choice = 2 (multiply)
Result: 7 * 6 = 42
=== Function Pointer Tests Complete ===

In the download: examples/pointers/04_function_pointers.cx -- function pointers.

Backtracking, with one array as the whole state

The N-Queens counter from Rosetta Code. Plain recursion over a single 1-D int array -- cols[r] is the column of the queen in row r -- and nothing else. This is the shape of C code CX is meant to leave alone: there is no CX-specific idiom here at all, and that is the point.

func absInt.i(x.i) {
   if (x < 0) { return 0 - x; }
   return x;
}

// True if placing a queen at (row, col) is safe given queens already placed
// in rows 0..row-1.
func safe.i(row.i, col.i) {
   r.i = 0;
   while (r < row) {
      if (cols[r] == col)                             { return 0; }
      if (absInt(cols[r] - col) == absInt(r - row))   { return 0; }
      r = r + 1;
   }
   return 1;
}

What it prints:

=== Rosetta: N-Queens ===

[PASS] assertEqual: 2 == 2
[PASS] assertEqual: 10 == 10
[PASS] assertEqual: 4 == 4
[PASS] assertEqual: 40 == 40
[PASS] assertEqual: 92 == 92
[PASS] assertEqual: 352 == 352
[PASS] assertEqual: 724 == 724
  4-queens: 2 solutions
  5-queens: 10 solutions
  6-queens: 4 solutions
  7-queens: 40 solutions
  8-queens: 92 solutions
  9-queens: 352 solutions
  10-queens: 724 solutions

=== ALL N-QUEENS COUNTS VERIFIED ===
asserts: 7 PASS / 0 FAIL

In the download: examples/algorithms/01_n_queens.cx -- N-queens (backtracking).

Behaviour that is data

A CX rule is a short C body over an entity, and it is a string the program holds -- it can come from a config file, or from a model, and be swapped while the program runs. _rules is the spelling that writes one plainly instead of inside an escaped string literal, and it hands the body to the real rules frontend at build time, so a typo is an error on this line rather than a rule that silently never fires. ruleExec then compiles and runs it.

_rules COMBAT { { float dmg = 0; json hits = e["hits"]; foreach hits { json it = jsonGet(hits); dmg = dmg + it; } e["hull"] = e["hull"] - dmg; if (e["hull"] < 30) raise(50, e); } }

ruleExec(ship, COMBAT);

What it prints:

ALARM: Falcon hull critical at 15
hull=15

In the download: examples/events_rules/02_rules_engine.cx -- the rules / automation engine.

Running them

Every example above is a complete file in the download. From the folder you unpacked:

cx examples/strings/02_reverse.cx --run       # build a native binary and run it
cx examples/strings/02_reverse.cx --runvm     # run the same program on the register VM

The two commands are expected to print the same thing, and the suite checks that they do. Where a program can only work one way -- graphics, or anything reaching a native library -- CX says so by name rather than quietly producing a different answer.