Lexical structure
Comments
Section titled “Comments”xcc uses C-family comment syntax:
// single-line — runs to end of line/* block — runs until the matching closer */Identifiers
Section titled “Identifiers”- Case-sensitive (
Fooandfooare distinct). - Start with a letter; subsequent characters may be letters, digits, or underscore.
- Reserved words may not be used as variable, class, or struct names.
Numeric literals
Section titled “Numeric literals”Three radix prefixes are recognised, and _ is silently ignored anywhere inside a numeric literal so you can group digits for readability.
u16 a = 1234; // decimalu16 b = $1234; // hexu16 c = 0x1234; // hex, the C spelling — identical to the line aboveu8 d = %1010_0101; // binary, with grouping underscoreu32 big = 16_777_216;u32 mask = 0xFFFF_0000; // underscores work in either hex spelling$ comes from 6502 assembler tradition and 0x (or 0X) from C; they mean
exactly the same thing and either can be used anywhere. Binary keeps %.
String and character literals
Section titled “String and character literals”Strings are double-quoted, null-terminated, but the trailing \0 is not counted in length. The recognised escape sequences are:
| Escape | Means |
|---|---|
\n | newline (CR + LF) |
\r | carriage return |
\t | tab |
\0 | end-of-string marker |
\\ | a literal backslash |
\" | a literal " inside a string |
\' | a literal ' inside a character literal |
string greeting = "hello\n";A character literal is a single character (or two characters where the first is \) inside single quotes, evaluated as a u8:
u8 tab = '\t';u8 a = 'A';A single string literal never splits across source lines — but adjacent string literals concatenate, as in C, and a newline between them makes no difference:
Stdio.print("one" "two\n"); // onetwo
Stdio.print("a long message that would " "otherwise be one unbreakable " "source line as wide as itself\n");The join happens in the parser, so the pieces are one literal by the time anything else sees them — there is no run-time concatenation and no cost.
Reserved words
Section titled “Reserved words”These are the words the lexer turns into keyword tokens. They are never identifiers, anywhere.
asm, auto, bool, break, case, catch, class, continue, default, defer, delete, double, else, enum, extern, false, final, float, for, global, i8, i16, i32, if, in, inline, new, optional, pointer, protocol, register, release, retain, return, sizeof, static, string, struct, switch, throw, throws, true, try, typedef, u8, u16, u32, use, void, volatile, while.
Separately, the parser rejects the C reserved words as variable names even where xcc gives them no meaning of its own, so that C-shaped source doesn’t quietly acquire a different meaning:
char, const, do, goto, int, long, restrict, short, signed, union, unsigned — plus those above that C also reserves.
Contextual words
Section titled “Contextual words”A third group is meaningful only in a particular position, and is an ordinary identifier everywhere else: self and super inside a method body; init and dealloc as method names; weak:, banked:, main: and shadow: as declaration qualifiers; va_start / va_arg / va_end inside a variadic; clobbers after an asm block; and the function annotations (:naked, :hwStack, :irq, :vbi, …) documented on the Functions page. Using one of these as a variable name is legal but a reliable way to confuse the next reader.
Block delimiters
Section titled “Block delimiters”A block is { ... }.
void greet(void) { Stdio.print("hi\n");}Statement terminator
Section titled “Statement terminator”Statements terminate with ;. The terminator is not optional — function declarations without a body, variable declarations, and expression statements all end in ;.