B/numt: Number Template.
 
@Purpose: Support for parsing integers.
 
@-------------------------------------------------------------------------------

@p Understanding.
In our target virtual machines, numbers are stored in twos-complement form,
so that a 16-bit VM can hold the range of integers $-2^{15} = -32768$ to
$2^{15}-1 = +32767$, while a 32-bit VM can hold $-2^{31} = -2147483648$ to
$2^{31}-1 = +2147483647$: the token below accepts exactly those ranges.

@c
[ DECIMAL_TOKEN wnc wna r n wa wl sign base digit digit_count original_wn group_wn;
	wnc = wn; original_wn = wn; group_wn = wn;
{-call:PL::Parsing::Tokens::Values::number}
	wn = wnc;
	r = ParseTokenStopped(ELEMENTARY_TT, NUMBER_TOKEN);
	if ((r == GPR_NUMBER) && (parsed_number ~= 10000)) return r;
	wn = wnc;
	wa = WordAddress(wn);
	wl = WordLength(wn);
	sign = 1; base = 10; digit_count = 0;
	if (wa->0 ~= '-' or '$' or '0' or '1' or '2' or '3' or '4'
		or '5' or '6' or '7' or '8' or '9')
		return GPR_FAIL;
	if (wa->0 == '-') { sign = -1; wl--; wa++; }
	if (wl == 0) return GPR_FAIL;
	n = 0;
	while (wl > 0) {
		if (wa->0 >= 'a') digit = wa->0 - 'a' + 10;
		else digit = wa->0 - '0';
		digit_count++;
		switch (base) {
			2:  if (digit_count == 17) return GPR_FAIL;
			10:
				#Iftrue (WORDSIZE == 2);
				if (digit_count == 6) return GPR_FAIL;
				if (digit_count == 5) {
					if (n > 3276) return GPR_FAIL;
					if (n == 3276) {
						if (sign == 1 && digit > 7) return GPR_FAIL;
						if (sign == -1 && digit > 8) return GPR_FAIL;
					}
				}
				#Ifnot; ! i.e., if (WORDSIZE == 4)
				if (digit_count == 11) return GPR_FAIL;
				if (digit_count == 10) {
					if (n > 214748364) return GPR_FAIL;
					if (n == 214748364) {
						if (sign == 1 && digit > 7) return GPR_FAIL;
						if (sign == -1 && digit > 8) return GPR_FAIL;
					}
				}
				#Endif; 
			16: if (digit_count == 5) return GPR_FAIL;
		}
		if (digit >= 0 && digit < base) n = base*n + digit;
		else return GPR_FAIL;
		wl--; wa++;
	}
	parsed_number = n*sign; wn++;
	return GPR_NUMBER;
];

@p Truth states.
And although truth states are not strictly speaking numbers, this seems as
good a point as any to parse them:

@c
[ TRUTH_STATE_TOKEN original_wn wd;
	original_wn = wn;
{-call:PL::Parsing::Tokens::Values::truth_state}
	wn = original_wn;
	wd = NextWordStopped();
	if (wd == 'true') { parsed_number = 1; return GPR_NUMBER; }
	if (wd == 'false') { parsed_number = 0; return GPR_NUMBER; }
	wn = original_wn;
	return GPR_FAIL;
];

@p Absolute value.
It's convenient to have this around somewhere:

@c
[ NUMBER_TY_Abs x; if (x<0) return -x; return x; ];
