(* This macro application combinator provides call-by-value semantics: the actual argument is evaluated up front and its value is bound to a variable, which is passed as an argument to the macro [F]. *) #def APPLY(F : [.], X : .) (let __x = (X) in F(__x)) (* Multiple lines permitted; no backslash required. *) #enddef (* Some trivial tests. *) #define ID(X) X #define C 42 let forty_one = APPLY(ID, 41) let forty_two = APPLY(ID, C ) (* A [for]-loop macro. *) #def LOOP(start, finish, body : [.]) ( for __index = start to finish-1 do body(__index) done ) #enddef (* A [for]-loop macro that performs unrolling. *) #def UNROLLED_LOOP(start, finish, body : [.]) ( (* #define can be nested inside #def. *) #define BODY(i) APPLY(body, i) (* #def can be nested inside #def. *) #def INCREMENT(i, k) i := !i + k #enddef let __finish = (finish) in let __index = ref (start) in while !__index + 2 <= __finish do BODY(!__index); BODY(!__index + 1); INCREMENT(__index, 2) done; while !__index < __finish do BODY(!__index); INCREMENT(__index, 1) done ) #enddef (* In the examples that follow, #scope ... #endscope is used to avoid the need to #undefine local macros such as BODY and F. *) (* Iteration over an array, with a normal loop. *) let iter f a = #scope #define BODY(i) (f a.(i)) LOOP(0, Array.length a, BODY) #endscope (* Iteration over an array, with an unrolled loop. *) let unrolled_iter f a = #scope #define BODY(i) (f a.(i)) UNROLLED_LOOP(0, Array.length a, BODY) #endscope (* Printing an array, with a normal loop. *) let print_int_array a = #scope #define F(i) Printf.printf "%d" a.(i) LOOP(0, Array.length a, F) #endscope (* A higher-order macro that produces a definition of [iter], and accepts an arbitrary definition of the macro [LOOP]. *) #def DEFINE_ITER(iter, LOOP : [..[.]]) #scope #define BODY(i) (f a.(i)) let iter f a = LOOP(0, Array.length a, BODY) #endscope #enddef (* Some noise, which does not affect the above definitions. *) #define BODY(i) "noise" DEFINE_ITER(iter, LOOP) DEFINE_ITER(unrolled_iter, UNROLLED_LOOP) (* Just because we can, undefine BODY. *) #undef BODY