Dana is a procedural programming language designed for educational purposes. It features:
- Strong static typing with two basic types:
intandbyte - Procedures and functions with pass-by-value and pass-by-reference semantics
- Arrays with compile-time known dimensions
- Layout-sensitive syntax (indentation-based blocks)
- Forward declarations for recursive definitions
and as begin break byte continue
decl def elif else end exit
false if int is loop not
or ref return skip true var
| Category | Operators |
|---|---|
| Arithmetic | + - * / % |
| Bitwise | & | ! |
| Comparison | = <> < > <= >= |
| Logical | and or not |
| Assignment | := |
- Integers: Decimal digits, e.g.,
42,0,123 - Characters: Single-quoted, e.g.,
'a','\n','\x41' - Strings: Double-quoted, e.g.,
"Hello world!\n" - Booleans:
true(value 1),false(value 0)
Single-line comments start with -- and extend to the end of the line:
-- This is a comment
var x is int -- This is also a comment
Multi-line (nested) comments use (* and *):
(* This is a
multi-line comment
(* with nesting support *)
*)
| Type | Description | Size |
|---|---|---|
int |
Signed integer | 32 bits |
byte |
Unsigned byte (0-255) | 8 bits |
Arrays have fixed dimensions known at compile time:
var arr is int[10] -- 1D array of 10 integers
var matrix is byte[3][4] -- 2D array (3×4)
For function parameters, the first dimension can be unspecified:
def printArray: arr as int [], n as int
-- arr's first dimension is unknown, passed as pointer
Variables are declared with var:
var x is int
var a b c is int -- Multiple variables of same type
var buffer is byte[256]
Functions return a value and are defined with def:
def factorial is int: n as int
if n <= 1: return: 1
else: return: n * factorial(n - 1)
Procedures do not return a value:
def printHello
writeString: "Hello!\n"
Use decl for forward declarations (required for mutual recursion):
decl isEven is byte: n as int
def isOdd is byte: n as int
if n = 0: return: false
else: return: isEven(n - 1)
def isEven is byte: n as int
if n = 0: return: true
else: return: isOdd(n - 1)
Default for scalar types:
def double is int: x as int
return: x * 2
Use ref keyword for scalars, or arrays (always by reference):
def swap: x y as ref int
var t is int
t := x
x := y
y := t
def sumArray is int: arr as int [], n as int
-- Arrays are always passed by reference
x := 42
arr[i] := arr[i] + 1
writeString: "Hello"
swap: a, b
writeInteger: x + y
if x > 0:
writeString: "positive"
elif x < 0:
writeString: "negative"
else:
writeString: "zero"
Dana has infinite loops with explicit break and continue:
loop:
if i >= n: break
writeInteger: arr[i]
i := i + 1
Loops can have labels:
loop outer:
loop inner:
if done: break: outer -- Break from outer loop
if skip: continue: inner
def compute is int: x as int
if x < 0: return: 0 -- Return from function with value
-- ...
return: result
def process: x as int
if x < 0: exit -- Exit from procedure (no value)
-- ...
The skip statement does nothing (useful for empty blocks):
if condition:
skip
else:
doSomething
x + y -- Addition
x - y -- Subtraction
x * y -- Multiplication
x / y -- Integer division
x % y -- Modulo (remainder)
+x -- Unary plus
-x -- Unary minus
a & b -- Bitwise AND
a | b -- Bitwise OR
!a -- Bitwise NOT
factorial(5)
readInteger()
strlen("hello")
Conditions are a separate syntactic category from expressions. They appear in if and elif clauses.
x = y -- Equal
x <> y -- Not equal
x < y -- Less than
x > y -- Greater than
x <= y -- Less than or equal
x >= y -- Greater than or equal
cond1 and cond2 -- Logical AND
cond1 or cond2 -- Logical OR
not cond -- Logical NOT
(cond) -- Parenthesized condition
Important: Bare expressions cannot be used as conditions. You must use a comparison:
-- INCORRECT:
if x: -- ERROR: bare expression
-- CORRECT:
if x <> 0: -- Use comparison
if x = true: -- Compare to boolean
| Function | Description |
|---|---|
writeInteger |
Print an integer |
writeByte |
Print a byte as integer |
writeChar |
Print a character |
writeString |
Print a string |
| Function | Description |
|---|---|
readInteger |
Read an integer from stdin |
readByte |
Read a byte from stdin |
readChar |
Read a character from stdin |
readString |
Read a string into buffer |
| Function | Description |
|---|---|
extend |
Convert byte to int (sign extension) |
shrink |
Convert int to byte (truncation) |
| Function | Description |
|---|---|
strlen |
Get string length |
strcmp |
Compare two strings |
strcpy |
Copy string to destination |
strcat |
Concatenate strings |
A Dana program consists of a single top-level procedure definition. This procedure:
- Must have no parameters
- Must not return a value
- Serves as the program entry point
def main
-- local definitions (variables, functions, procedures)
var x is int
def helper is int: n as int
return: n * 2
-- statements
x := readInteger()
writeInteger: helper(x)
writeString: "\n"
Dana uses layout-sensitive syntax similar to Python:
- Blocks are delimited by indentation
- Statements at the same indentation level are siblings
- Guide keywords (
def,if,elif,else,loop) start new blocks - The compiler automatically infers block boundaries
Alternative explicit block syntax with begin/end:
def factorial is int: n as int
begin
if n <= 1: begin return: 1 end
else: begin return: n * factorial(n - 1) end
end
From lowest to highest:
| Precedence | Operators | Associativity |
|---|---|---|
| 1 | or |
Left |
| 2 | and |
Left |
| 3 | | |
Left |
| 4 | & |
Left |
| 5 | + - |
Left |
| 6 | * / % |
Left |
| 7 | + - ! not |
Prefix |
Note: Comparison operators (=, <>, <, >, <=, >=) are not part of expression precedence as they only appear in condition contexts.