LARD Language Language Reference Manual

Infix Expressions, Precedence and Associativity

Most languages include a fixed set of infix expressions such as the arithmetic operators and statements like if then else. These languages fix the syntax of these limited infix expressions and require any user-defined functions to use a prefix notation, e.g. send(C,v). LARD is more flexible: it allows user-defined functions to be called using an infix syntax. This section describes how infix expressions are declared and parsed.

An infix expression is made up of a sequence of keywords and sub-expressions. The keywords are either symbols, such as :=, or words such as if. The available symbols are:

	!	%	^	&	*	-	=	+	;
	:	@	~	<	>	.	/	?	$
	[	]	:=	->	!=	<=	>=	|	||
	..	{	}	&&	::	>>	<<	=>
Commas count as symbols when enclosed within [ ] or { }, but in all other cases they separate parameters in a prefix expression. [, ], { and } are treated specially by the parser since they are always matched in pairs; [ is treated like [( for example. It is best not to use these symbols in your own infix expressions.

In an infix expression, two keywords can be adjacent but two subexpressions may not be. Subexpressions can be literals, identifiers, prefix expressions, or parenthesised subexpressions.

For each infix expression there is an equivalent prefix expression. The identifier for the prefix expression is constructed by scanning the infix expression, replacing subexpressions by underscores, and including keywords unchanged. For example, if a then b else c is equivalent to if_then_else_(a,b,c) and x*y is equivalent to _*_(x,y). The compiler converts all expressions to prefix notation in an early pass so these equivalent prefix expressions will often appear in error messages and other output.

Some of these equivalent identifiers may not count as valid identifiers according to the normal syntax. The compiler can be forced to recognise any sequence of characters as an identifier by enclosing it in back-quotes.

An infix expression is declared as follows:

prefix-identifier : infix ( priority, associativity ) .

The prefix-identifier is the equivalent prefix identifier as defined above. The priority and associativity are described shortly. The effect of the declaration is to fix all words that appear as keywords in the prefix identifier as keywords and to record the priority and associativity information for when an occurance of this expression is parsed.

All infix declarations have global scope, irrespective of where they are declared.

The infix declaration would typically be immediately followed by a real declaration, which can use either the prefix notation or the newly defined infix notation. For example here is how the repeat until statement is defined in the standard library:

	repeat_until_ : infix(60,right).
	repeat (S:expr(void)) until (c:expr(bool)) : expr(void) = (
	    S;
	    while (!c) do S
	).
This declaration makes repeat and until keywords, so they can never be used as identifiers.

When the compiler encounters a compex infix expression, such as

	if a then b := c else if d then e ; f
it has to parse it into a hierarchy of expressions before converting to prefix form. In this case it has to convert it to

	( if a then ( b := c ) else ( if d then e ) ) ; f
and then into


	_;_(if_then_else(a,_:=_(b,c),if_then_(d,e)),f)
In order to carry out this first conversion each infix expression has a priority and associativity. Expressions with high priorities bind more closely than expressions with low priorities; in the example above _:= has a high priority and _;_ has a low priority.

When an expression contains several expressions with the same priority the associativity is taken into account. A left associative expression, such as _+_, is parsed as follows:

	a + b + c   =>    ( a + b ) + c
On the other hand a right associative expression, such as _._, is parsed as follows:

	D1 . D2 . E   =>   D1 . ( D2 . E )
The priorities and associativities of many of the infix expressions declared in the LARD standard library are taken from the operator precedence rules for C. The following tables show the values used.

Precedence Level Syntactic element Expressions
10 block _._
20 declaration _:_, _:_=_, _::_
30 Compound statements _is_
40 _;_
50 _|_
60 Statements that take other statements as parameters if_then_, while_do_, repeat_until_, forseq_in_to_do_, forpar_do_, if_then_else_, case_when_=>_ etc., _?_
70 Simple statements _:=_, _!_
90 Hierarchy of expressions [_], [_,_], etc. {_}, {_,_}, etc.
100 _||_
110 _&&_
120 _or_
125 _xor_
130 _and_
140 _=_, _!=_
150 _<_, _>_, _<=_, _>=_
155 _<<_, _>>_
160 _+_, _-_, _@_, _^_
170 _*_, _/_, _mod_
180 not_, -_, !_
190 _->_, _[_]
200 ?_