Code

Jasmin code comprises the following constructs:

<code> ::=
  | <empty>
  | <instr> <code>

<instr> ::=
  | <instr_assign>
  | <instr_intrinsic>
  | <instr_conditional>
  | <instr_while>
  | <instr_for>
  | <instr_call>

Variable declaration

Variables in Jasmin have both a type (int, bool, u8, u16, u32, …) and a storage qualifier (inline, reg, stack). Variables qualified as inline are removed in compile time, for instance the counter of a for loop that is unrolled. Variables qualified as reg must go into architecture registers or flags, and those qualified as stack must live in the stack. In Jasmin there is no variable spilling: the programmer must do it explicitly. TODO: Add link to variable and type syntax.

Syntax for variable declaration is as follows:

<var_list> ::=
  | <var>
  | <var>, <var_list>

<var_decl> ::=
  | <type> <var_list>;

For instance,

u64 var;
stack u64[N] arr;
inline int i;

Assignments

<instr_assign> ::=
  | <lval> = <expr>;

The basic syntax for assignments is the usual equal sign:

x = y + 1;

and prefixing the equal sign with a binary operator x += y; is simply syntactic sugar for x = x + y;.

There is an expression on the right-hand side of the expression and a left-value on the left-hand side.

Assignments can be made conditional by adding an if clause as a suffix

x = y if b;

This means that the assignment is only performed if the condition b evaluates to true.

Intrinsics

<instr_intrinsic> ::=
  | <lval>, ..., <lval> = #<ident>(<expr>, ..., <expr>);

Intrinsics are architecture-specific instructions. The basic syntax is as follows

of, cf, x = #ROL(y, 4);

where to the left of the equals sign is a list of variables and to the right the architecture-specific instruction is prefixed by a # and used as a function name.

The list of available architecture-specific instructions can be seen using $ jasminc -help-intrinsics.

Conditionals

<instr_conditional> ::=
  | if ( <expr> ) { <code> }
  | if ( <expr> ) { <code> } else { <code> }
  | if ( <expr> ) { <code> } else <instr_conditional>  // else-if syntax.

Conditionals take an expression and two pieces of code, and execute one piece or the other depending on whether the expression evaluates to true or false (conditions cannot be complex expressions). The basic syntax for conditionals is as follows

if (x != y) {
    x += 1;
} else {
    x += 2;
}

where the else branch can be omitted.

Conditionals can be chained as follows

if (x < y) {
    x += 1
} else if (x == y) {
    x += 2;
} else {
    x += 3;
}

where again last else branch can be omitted. This is syntactic sugar for nested conditionals.

For loops

<instr_for> ::=
  | for <ident> = <expr> to <expr> { <code> }
  | for <ident> = <expr> downto <expr> { <code> }

For loops execute a piece of code some fixed number of times. These iterations depend on an inline int counter, that takes values in a given range. The basic syntax for for loops is

for i = 0 to 13 {
    x += x;
    i += 2;
}

where the counter starts taking the value of the first expression, and increases until it reaches the second one. For example, the loop for i = 0 to 5 { ... } executes the code in the body of the loop five times, as i takes the values 0, 1, 2, 3, and 4 in each iteration respectively.

The iteration can be made decreasing as well, as follows

for i = 13 downto 0 {
    x += x;
    i -= 2;
}

While loops

<instr_while> ::=
  | while ( <expr> ) { <code> }  // Usual while loop.
  | while { <code> } ( <expr> )  // do-while loop.
  | while { <code> } ( <expr> ) { <code> }  // Both.

While loops execute a piece of code until a condition is met. The basic syntax for while loops is

while (x <= y) {
    y -= 1;
}

where the condition x <= y is evaluated before each iteration, and the body is executed only if it evaluated to true.

Do-while loops first execute the body and only then evaluate the condition, and are written as follows

while {
    y -= 1;
} (x <= y)

In Jasmin, we can do both: execute some code before evaluating the condition, and also after

while {
    y -= 1;
} (x <= y) {
    y -= x;
}

Function calls

<instr_call> ::=
  | <ident>(<expr>, ..., <expr>);
  | <lval>, ..., <lval> = <ident>(<expr>, ..., <expr>);

The syntax for function calls is as follows

z = add_then_shift_left(x, y, 2);

where to the left of the equals sign we have a comma-separated list of left-values corresponding to the return type of the function and the parentheses contain the arguments as a comma-separated list of expression.

The following is valid syntax for a function that does not return any values:

do_side_effect_computation(x, y);