= The programming language Elna :toc: == Introduction Elna is a simple, imperative, low-level programming language. It is intendet to accompany other languages in the areas, where a high-level language doesn't fit well. It is also supposed to be an intermediate representation for a such high-level hypothetical programming language. == Expressions The expression `@r.field` includes 3 expressions: 1. Variable expression `r`. 2. Field access `(r).field`. 3. Address taking `@(r.field)`. The expression is evaluated in the above order. The postfix expressions like field access have higher precedence than prefix operators. === Binary expressions .Operator precedence |=== |Precedence |Operator |Description |1 |* / % |Multiplication, division and remainder. |2 |+ - |Addition and subtraction. |3 |<< >> |Left and right shifts. |4 |= <> > < <= >=| Relational operators. |5 |or xor &| Logical operators. |=== === Unary expressions Unary expressions are expressions with a prefix operator followed by one operand. `@` (*at sign*) takes the address of its operand. The operand expression should be addressable. `-` (*minus*) negates a numeric value. `~` (*tilde*) applied on a boolean acts as logical not. Applied on a numeric – as bitwise not. == Conditional statements == Loop statements == Type system ``` type = array-type | pointer-type | record-type | enumeration-type | procedure-type | identifier. ``` === Primitive types * Pointer * Word * Int * Bool * String * Char === Pointer types ``` pointer-type = "^" type. ``` Example: ``` program; var x: Int; y: ^Int; begin y := @x; y^ := 0 end. ``` === Static array ``` array-type = "[" expression "]" type. ``` Example: ``` program; var array: [3]Int := [1, 2, 3]; begin array[1] := array[2] end. ``` === Procedure types ``` procedure-heading = "proc" identifier-definition "(" [field {"," field}] ")" return-declaration. block = constant-part variable-part statement-part "end". procedure-declaration = procedure-heading ";" (block | "extern"). return-declaration = ["->" "!" | "->" type]. procedure-type = "proc" "(" [types] ")" return-declaration. ``` Example: ``` program; var a: proc(Int) -> Int; proc f(x: Int) -> Int; end; begin a := f; a(0) end. ``` === Records ``` field = identifier ":" type. record-type = "record" ["(" identifier ")"] [field {";" field}] "end". ``` Example: ``` program; type T = record x: Int end; U = record(T) y: Int; z: Int end; var u: U; begin u := U(0, 1, 2); u.x := 3 end. ``` === Enumerations ``` enumeration-type = "(" identifier {"," identifier} ")". ``` Example: ``` program; type E = (one, two, three); var e: E; begin e := E.one end. ``` === Type operations === Cast ``` cast = "cast" "(" expression ":" type ")". ``` The type of an object can be reinterpreted with a cast expression: `cast(object: Type)`. === Traits ``` trait-identifier = "#" identifier. trait = trait-identifier "(" [types] ")". ``` Traits allow to query some information about the types, like their size or field offset or alignment. Calling a trait looks like a procedure call but traits names start with a `#` and their arguments are type expressions and not value expressions. Supported compiler traits: - `#size(T)` queries type size. - `#align(T)` queries type alignment. - `#offset(T, F)` queries the offset of the field `F` in the record `T`. == Appendix === Syntax ``` letter = "A" | "B" | … | "Z" | "a" | "b" | … | "z" | "_". digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9". character = ? a printable character ?. hex-digit = digit | "A" | "B" | … | "F" | "a" | "b" | … | "f". binary-digit = "0" | "1". identifier = letter {letter | digit}. identifier-definition = identifier ["*"]. trait-identifier = "#" identifier. integer-literal = digit {digit}. word-literal = integer-literal "u" | "0" ("X" | "x") hex-digit {hex-digit} | "0" ("B" | "b") binary-digit {binary-digit}. real-literal = digit {digit} "." digit {digit}. string-literal = """ {character} """. character-literal = "'" {character} "'". literal = integer-literal | word-literal | real-literal | string-literal | character-literal | "true" | "false" | "nil". trait = trait-identifier "(" [types] ")". cast = "cast" "(" expression ":" type ")". procedure-call = designator "(" [expressions] ")". relation-operator = "=" | "<>" | "<" | ">" | "<=" | ">=". multiplication-operator = "*" | "/" | "%". addition-operator = "+" | "-". shift-operator = "<<" | ">>". unary-operator = "@" | "~" | "-". selector = "[" expression "]" | "." identifier | "^". case = expressions ":" optional-statements. designator = reference selector | identifier. reference = literal | designator | trait | cast | procedure-call | "(" expression ")". factor = unary-operator factor | reference. term = factor {multiplication-operator factor}. simple-expression = term {addition-operator term}. comparand = simple-expression {shift-operator simple-expression}. relation = comparand {relation-operator comparand}. operand = relation {"&" relation}. expression = operand {("or" | "xor") operand}. expressions = expression {"," expression}. identifier-definitions = identifier-definition {"," identifier-definition}. types = type {"," type}. required-statements = statement {";" statement}. optional-statements = [required-statements]. return-declaration = ["->" "!" | "->" type]. field = identifier ":" type. array-type = "[" expression "]" type. pointer-type = "^" type. record-type = "record" ["(" identifier ")"] [field {";" field}] "end". enumeration-type = "(" identifier {"," identifier} ")". procedure-type = "proc" "(" [types] ")" return-declaration. type = array-type | pointer-type | record-type | enumeration-type | procedure-type | identifier. assignment = designator ":=" expression. if-statement = "if" expression "then" optional-statements {"elsif" expression "then" optional-statements} ["else" optional-statements] "end". while-statement = "while" expression "do" optional-statements {"elsif" expression "do" optional-statements} "end". defer-statement = "defer" optional-statements "end". case-statement = "case" expression "of" case {"|" case} ["else" optional-statements] "end". label-declaration = "." identifier. goto-statement = "goto" identifier. statement = assignment | procedure-call | defer-statement | label-declaration | goto-statement | | while-statement | if-statement | case-statement. statement-part = ["begin" required-statements | "return" expression | "begin" required-statements ";" "return" expression]. constant-declaration = identifier-definition ":=" expression. constant-part = ["const" {constant-declaration ";"}]. variable-declaration = identifier-definitions ":" type [":=" (expression | "extern")]. variable-part = ["var" {variable-declaration ";"}]. type_declaration = identifier-definition "=" type. type-part ["type" {type-declaration ";"}]. import-declaration = identifier {"." identifier}. import-part = ["import" {import_declarations ";"}]. procedure-heading = "proc" identifier-definition "(" [field {"," field}] ")" return-declaration. block = constant-part variable-part statement-part "end". procedure-declaration = procedure-heading ";" (block | "extern"). declaration-sequence = import-part constant-part type-part variable-part {procedure-declaration ";"}. program = "program" ";" declaration-sequence statement-part "end" "." | "module" ";" declaration-sequence "end" "." ```