/***************************************************************************** * * at.c * * Arithmetic types. * *****************************************************************************/ #include "m4.h" F STDCALL fWhiteTch(TCH tch); /***************************************************************************** * * AddExpAt * * Add the (unsigned) arithmetic value to the Exp hold. * * Since the value is never very large, we may as well be recursive. * *****************************************************************************/ void STDCALL AddExpAt(AT at) { if (at > 9) { AddExpAt(at / 10); } AddExpTch((TCH)(TEXT('0') + at % 10)); } /***************************************************************************** * * PushAtRadixCtch * * Push onto the input stream the specified arithmetic value, in the * requested radix, padded with zeros to the requested width. * * The type is always considered signed. * * If a negative value needs to be padded, the zeros are inserted after * the leading minus sign. * * QUIRK! Under AT&T, the leading minus sign does *not* contribute * to the count! I emulate this quirk... * * FEATURE! If the radix is invalid, force it to 10. AT&T doesn't * check the radix, but I will. * * QUIRK! Under AT&T, a negative width is treated as zero. * I emulate this quirk... * * INTERESTING HACK! Since characters are pushed LIFO, we can generate * the entire output string without needing to use a hold or anything * else gross like that. * *****************************************************************************/ void STDCALL PushAtRadixCtch(AT atConvert, unsigned radix, CTCH ctch) { AT at; if ((int)ctch < 0) { #ifdef WARN_COMPAT Warn("Negative eval width %d silently converted to zero"); #endif ctch = 0; } if (radix < 2 || radix > 36) { #ifdef WARN_COMPAT Warn("Invalid radix %d silently converted to 10"); #endif radix = 10; } at = atConvert < 0 ? -atConvert : atConvert; do { TCH tch = (TCH)((unsigned long)at % radix); at = (unsigned long)at / radix; if (tch < 10) { PushTch((TCH)(tch + '0')); } else { PushTch((TCH)(tch + 'A' - 10)); } ctch--; } while (at); while ((int)ctch > 0) { PushTch('0'); --ctch; } if (atConvert < 0) { PushTch('-'); } } /***************************************************************************** * * PushAt * * Common case where we want to display the value in base 10 * with no padding. * *****************************************************************************/ void STDCALL PushAt(AT at) { PushAtRadixCtch(at, 10, 0); } /***************************************************************************** * * SkipWhitePtok * * Skip leading whitespace in a token, *MODIFYING* the token in place. * *****************************************************************************/ void STDCALL SkipWhitePtok(PTOK ptok) { AssertSPtok(ptok); Assert(fScratchPtok(ptok)); while (!fNullPtok(ptok) && fWhiteTch(*ptchPtok(ptok))) { EatHeadPtokCtch(ptok, 1); } } /***************************************************************************** * * atRadixPtok * * Parse a number out of a token, given the radix. Leading whitespace * must already have been streipped. * * The token is *MODIFIED* to point to the first unconsumed character. * If no valid digits are found, then zero is returned and the token * is unchanged. * *****************************************************************************/ AT STDCALL atRadixPtok(unsigned radix, PTOK ptok) { AT at = 0; while (!fNullPtok(ptok)) { AT atDigit = (TBYTE)*ptchPtok(ptok) - '0'; if ((unsigned)atDigit > 9) { atDigit = ((TBYTE)*ptchPtok(ptok) | 0x20) - 'a'; if ((unsigned)atDigit > 5) { break; } atDigit += 10; } if ((unsigned)atDigit > radix) { break; } at = at * radix + atDigit; EatHeadPtokCtch(ptok, 1); } return at; } /***************************************************************************** * * fEvalPtokPat * * Parse a number out of a token. Leading whitespace must already have * been stripped. A leading minus sign is not permitted. (`eval' * would have already parsed it out as a unary operator.) A leading * zero forces the value to be parsed as octal; a leading `0x' as hex. * * The token is *MODIFIED* to point to the first unconsumed character. * If no valid number is found, then zero is returned. Otherwise, * nonzero is returned and pat is filled with the parsed value. * *****************************************************************************/ F STDCALL fEvalPtokPat(PTOK ptok, PAT pat) { AT at; AssertSPtok(ptok); Assert(fScratchPtok(ptok)); if (!fNullPtok(ptok)) { PTCH ptchStart; unsigned radix; /* * Get the radix... */ if (*ptchPtok(ptok) == '0') { if (ctchSPtok(ptok) > 2 && (ptchPtok(ptok)[1] | 0x20) == 'x') { EatHeadPtokCtch(ptok, 2); radix = 16; } else { radix = 8; } } else { radix = 10; } ptchStart = ptchPtok(ptok); /* Remember the start */ at = atRadixPtok(radix, ptok); if (ptchStart == ptchPtok(ptok)) { if (radix == 16) { EatHeadPtokCtch(ptok, (CTCH)-2); /* Restore the `0x' */ } return 0; } else { *pat = at; return 1; } } return 0; /* No number found */ } /***************************************************************************** * * atTraditionalPtok * * Parse a number out of a token. Leading whitespace is ignored. * A leading minus sign is permitted. Octal and hex notation is * not permitted. No space is permitted between the optional * minus sign and the digit string. An invalid input is parsed as zero. * *****************************************************************************/ AT STDCALL PURE atTraditionalPtok(PCTOK ptok) { TOK tok; AssertSPtok(ptok); DupStaticPtokPtok(&tok, ptok); D(tok.tsfl |= tsflScratch); SkipWhitePtok(&tok); if (!fNullPtok(&tok)) { AT at; BOOL fSign; if (*ptchPtok(&tok) == '-') { fSign = 1; EatHeadPtokCtch(&tok, 1); } else { fSign = 0; } at = atRadixPtok(10, &tok); if (fSign) { at = -at; } return at; } else { return 0; } }