Grammar¶
This is the complete formal grammar of ik8b, in EBNF, reproduced from the
EBNF file at the root of the repository. It is the authoritative syntax
specification; where prose elsewhere in this manual is less precise, this
grammar and the compiler are correct.
(* ============================================================================
ik8b Formal Grammar (EBNF)
Version: 1.0
Strongly-Typed Embedded Programming Language with Context Sigils
============================================================================ *)
Program ::= { TopLevelStatement }
TopLevelStatement ::= ImportStatement
| targetStatement
| CompileTimeCondition
| ConstDeclaration
| FunctionDeclaration
| IsrDeclaration
ImportStatement ::= "import" Identifier
targetStatement ::= "target" Identifier
CompileTimeCondition ::= "?" "target" "==" Identifier "{" { TopLevelStatement } "}"
(* Two kinds of compile-time constant, distinguished by the leading sigil:
- "const" "%NAME" ... a hardware register / memory-mapped address; a
"%NAME" reference reads or writes that location.
- "const" "NAME" ... a plain value constant (bit mask, command word,
feature flag); a "NAME" reference folds to the
immediate value. *)
ConstDeclaration ::= "const" ( RegisterIdentifier | ConstIdentifier ) ":" PrimitiveType "=" Number
FunctionDeclaration ::= FunctionIdentifier [ "(" [ ParameterList ] ")" ] [ "->" Type ] Block
(* An interrupt service routine bound to a named device vector. Has no
parameters or return value; the backend emits a vector-table jump,
a full context save/restore, and reti. *)
IsrDeclaration ::= "isr" Identifier Block
ParameterList ::= Parameter { "," Parameter }
Parameter ::= VariableIdentifier ":" Type
Block ::= "{" { BlockItem } "}"
(* Inside a block, a compile-time condition may appear alongside regular
statements. The condition gates a nested block of statements, not
top-level declarations. *)
BlockItem ::= CompileTimeBlockCondition
| Statement
CompileTimeBlockCondition ::= "?" "target" "==" Identifier Block
Statement ::= VariableDeclaration
| Assignment
| LoopStatement
| ConditionalStatement
| SwitchStatement
| ReturnStatement
| ExpressionStatement
(* --- Variable declarations -------------------------------------------------
Three forms share a leading storage space. Pointer and string declarations
use a dedicated keyword. Scalar/array/function-pointer declarations carry
an explicit mutability and a type after the ":". *)
VariableDeclaration ::= PointerDeclaration
| StringDeclaration
| ScalarDeclaration
(* The storage-space keyword in a pointer declaration names the memory space
the pointer points into. The pointer variable itself lives in SRAM. *)
PointerDeclaration ::= StorageSpace "ptr" Type VariableIdentifier "=" Expression
StringDeclaration ::= ( "ram" | "flash" ) "str" VariableIdentifier "=" Expression
(* For scalar declarations, the type is either a primitive type token or a
function-pointer type `fn(...)`. Pointer and string types use their
own dedicated declaration forms above. *)
ScalarDeclaration ::= StorageSpace ( "mut" | "imut" ) VariableIdentifier ":" ScalarType [ "[" Number "]" ] "=" Expression
ScalarType ::= PrimitiveType | FunctionType
StorageSpace ::= "ram" | "eeprom" | "flash"
Assignment ::= Expression ( "->" | "->+" | "->-" | "->&" | "->|" | "->^" ) Expression
LoopStatement ::= InfiniteLoop | RangeLoop
InfiniteLoop ::= "loop" "*" Block
RangeLoop ::= "loop" Expression ".." Expression "->" VariableIdentifier Block
ConditionalStatement ::= "?" Expression Block [ ":" Block ]
SwitchStatement ::= "switch" Expression "{" { CaseBranch } [ DefaultBranch ] "}"
CaseBranch ::= Expression "->" Block
DefaultBranch ::= "*" "->" Block
ReturnStatement ::= "return" [ Expression ]
ExpressionStatement ::= Expression
(* --- Expressions (lowest to highest precedence) ----------------------------
All binary levels are left-associative and allow chaining. *)
Expression ::= LogicalOr
LogicalOr ::= LogicalAnd { "||" LogicalAnd }
LogicalAnd ::= BitwiseOr { "&&" BitwiseOr }
BitwiseOr ::= BitwiseXor { "|" BitwiseXor }
BitwiseXor ::= BitwiseAnd { "^" BitwiseAnd }
BitwiseAnd ::= Equality { "&" Equality }
Equality ::= Relational { ( "==" | "!=" ) Relational }
Relational ::= Additive { ( "<" | ">" | "<=" | ">=" ) Additive }
Additive ::= Multiplicative { ( "+" | "-" ) Multiplicative }
Multiplicative ::= Unary { ( "*" | "/" | "%" ) Unary }
(* In operand position "&" is address-of and "*" is dereference, distinct from
the infix bitwise-AND / multiply consumed above. Unary operators are
right-associative. *)
Unary ::= ( "!" | "~" | "-" | "&" | "*" ) Unary
| Primary
Primary ::= Number
| FloatLiteral
| StringLiteral
| CallExpression
| IdentifierExpression
| "(" Expression ")"
(* A function call: direct @name(...) or indirect @$name(...). Both lex as
a single "@"-prefixed Identifier token followed by parenthesised args. *)
CallExpression ::= FunctionCallTarget "(" [ ArgumentList ] ")"
FunctionCallTarget ::= FunctionIdentifier (* "@name" — direct call *)
| "@" VariableIdentifier (* "@$name" — indirect call *)
(* A variable, register, or array-element reference. Array indexing is valid
in any expression position (both reads and assignment targets). *)
IdentifierExpression ::= ( VariableIdentifier | RegisterIdentifier ) [ "[" Expression "]" ]
| ConstIdentifier (* a value constant — folds to its immediate *)
| FunctionIdentifier (* bare @name without call — e.g. for &@name *)
ArgumentList ::= Expression { "," Expression }
VariableIdentifier ::= "$" Identifier
FunctionIdentifier ::= "@" Identifier
RegisterIdentifier ::= "%" Identifier
ConstIdentifier ::= Identifier (* a value-constant name (no sigil) *)
(* --- Types ----------------------------------------------------------------- *)
Type ::= ( PrimitiveType | PointerType | StringType | FunctionType ) [ "[" Number "]" ]
PrimitiveType ::= "u8" | "u16" | "i8" | "i16" | "bool" | "char" | "r8" | "r16" | "void"
PointerType ::= "ptr" PointerSpace Type
(* In type-specifier position (parameters, returns), only "str ram" is accepted.
"str flash" is valid only as a variable declaration form. *)
StringType ::= "str" "ram"
FunctionType ::= "fn" "(" [ Type { "," Type } ] ")" [ "->" Type ]
PointerSpace ::= "ram" | "eeprom" | "flash"
(* --- Lexical --------------------------------------------------------------- *)
Identifier ::= ( Letter | "_" ) { Letter | Digit | "_" | "/" | "." }
Number ::= DecimalNumber | HexNumber
DecimalNumber ::= [ "-" ] Digit { Digit }
HexNumber ::= "0x" HexDigit { HexDigit }
(* A fractional literal is resolved to a scaled fixed-point integer (r8/r16). *)
FloatLiteral ::= [ "-" ] Digit { Digit } "." Digit { Digit }
(* Boolean literals are lexed directly as numeric constants (true = 1, false = 0),
so they appear as Number tokens to the parser. *)
BooleanLiteral ::= "true" | "false"
StringLiteral ::= '"' { StringChar | StringEscape } '"'
CharacterLiteral ::= "'" ( PrintableChar | CharEscape ) "'"
(* String escape sequences support \xHH hex escapes in addition to the
common named escapes. *)
StringEscape ::= "\" ( "n" | "r" | "t" | "0" | "\" | '"' )
| "\x" HexDigit HexDigit
(* Character escape sequences: a subset of string escapes. Hex escapes
(\xHH) and double-quote escapes (\") are NOT supported in char literals. *)
CharEscape ::= "\" ( "n" | "r" | "t" | "0" | "\" | "'" )
Comment ::= "#" { any character except newline }
Letter ::= "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
HexDigit ::= Digit | "a" | "b" | "c" | "d" | "e" | "f" | "A" | "B" | "C" | "D" | "E" | "F"
StringChar ::= any ASCII character except double quote or backslash
PrintableChar ::= any ASCII character except single quote or backslash