dnl $Id: l2c_util.m4 371 2010-03-23 13:44:24Z eb771 $
dnl --------------------------------------
dnl Utiliy macros for logic2cnf

dnl A for loop, from Michael Breen: http://mbreen.com/m4.html#toc19
dnl permission to distribute under ISC license acquired
dnl FOR(loop_var, lower, upper, block)
dnl FOR(`x',1,5,`x,') -> 1,2,3,4,5
define(`FOR',`ifelse($#,0,``$0'',`ifelse(eval($2<=$3),1,dnl
	`pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),$3,`$4')')')' dnl
)dnl

dnl same but reverse
dnl FOR(loop_var, upper, lower, block)
define(`FORI',`ifelse($#,0,``$0'',`ifelse(eval($2>=$3),1,dnl
	`pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',decr($2),$3,`$4')')')')dnl

dnl express a range of variables
dnl FORVAR(prefix, postfix, sep, min, max)
dnl eg. FORVAR(`edd_is_',`_years_old', ` : ', `0',`10')
define(`FORVAR', `dnl
	FOR(`x',`$4',`$5',``$1'x`$2'ifelse(x,`$5',`',`$3')')dnl
')dnl

dnl same, but counting down
dnl FORVAR(prefix, postfix, sep, max, min)
define(`FORIVAR', `dnl
	FORI(`x',`$4',`$5',``$1'x`$2'ifelse(x,`$5',`',`$3')')dnl
')dnl

dnl hook two bitfields together, so they bi-imply each other
dnl JOIN(input_prefix, input_postfix, output_prefix, output_postfix, num_bits)
define(`JOIN',`
	(
	FOR(`x',`0',`eval($5-1)',`
		(`$1'x`$2' <=> `$3'x`$4')ifelse(x, eval($5-1),`',` . ')
	')
	)
')

dnl encode a decimal number into a logic field
dnl FROM_DEC(prefix, postfix, value, num_bits)
dnl WARNING: flawed! MAX_BVAL can overflow and become 0 :\
dnl XXX DO NOT USE XXX
define(`FROM_DEC',`
# l2c_util::FROM_DEC prefix = [$1], postfix = [$2],
# 	value = [$3], num_bits = [$4]

	errprint(`XXX DO NOT USE FROM_DEC XXX')

dnl	silly bsd m4 does not do exponential operator in m4.
	pushdef(MAX_BVAL,eval(FOR(`x',`1',`$4',`2 ifelse(x,`$4',`',` * ')')-1))dnl
	ifelse(eval($3>MAX_BVAL),1,`errprint(`l2c_util::FROM_DEC: warning: FROM_DEC cannot express a number larger than possible with the field width')m4exit(1)',)
	popdef(MAX_BVAL)

	dnl holds the value yet to be encoded
	pushdef(VAL_LEFT, $3)

	dnl push all of the bit values up on that there stack
	pushdef(`BVAL',`1')
	FOR(`x',`1',`eval($4-1)',`
		pushdef(`BVAL',eval(BVAL*2))	
	')

	(
	FORI(`x',`eval($4-1)',`0',` dnl
		ifelse(eval(VAL_LEFT-BVAL<0),`1',` dnl
			~`$1'x`$2' dnl
		',` dnl
			`$1'x`$2' dnl
			pushdef(`VAL_LEFT', eval(VAL_LEFT-BVAL)) dnl
		') dnl
		popdef(`BVAL') dnl
		ifelse(x,0,, . )
	')
	)

	dnl clear up VAL_LEFT stack
	FOR(`x',`0',`eval($4-1)',`
		ifelse(VAL_LEFT,$3,,popdef(`VAL_LEFT'))
	')
')

dnl ignore an unused variable
dnl Useful if a macro defines inputs you dont wish to use. Silences symbol
dnl checker.
dnl TOUCH(symbol)
define(`TOUCH',`
# l2c_util::TOUCH symbol = [$1]
	( $1 + ~$1 )
')

