1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 08:34:22 +03:00
inform7/retrospective/6L02/I6T/Number.i6t
2019-02-05 00:44:07 +00:00

87 lines
2.5 KiB
Plaintext

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:Plugins::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:Plugins::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; ];