Infix Notation

One of LARD's more unusual features is the ability to write user-defined infix functions. Using infix notation can make functions more concise and possibly more intuitive.

This example demonstrates the infix notation by writing a function that extracts a bit field from an integer. Here's what we want to do:

	opcode:=instr:0..3;  /* opcode in bits 0-3 */
	reg1:=instr:4..7;    /* register 1 in bits 4-7 */
	reg2:=instr:8..11;   /* register 2 in bits 8-11 */
That is, we want the following syntax:

integer-expression : start-index .. end-index

The first step is to choose parser priority and associativity values for this expression. Priority determines how tightly the new expression binds to surrounding expressions compared to other infix expressions. For example, should a+b:1..2 be parsed as (a+b):1..2 or as a+(b:1..2)? If the new expression has a lower priority than + the former interpretation applies. If the new expression has a higher priority than + the latter interpretation applies. In this case it seems natural to assign a high priority, and consulting the table in the reference manual a value of 200 would be appropriate.

Assoicativity refers to whether an expression such as a op b op c should be parsed as ( a op b ) op c or a op ( b op c ). Associativity isn't very meaningful for expressions with multiple keywords so in this case we have associativity of none.

We can now write down an infix declaration:

	_:_.._ : infix(200,none).
Note that the prototype of this declaration is an identifier that is made up from the keywords of the new infix expression, with _s introduced in place of the expressions.

Having made this declaration a fairly conventional function declaration can be made using the new infix notation:

	(n:val(int)) : (start:val(int)) .. (end:val(int)) : expr(int) = (
	  (n>>start) and ((1<<(end-start+1))-1)
	).
Subsequent code can use the function as illustrated at the beginning.