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