readnum.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 1996-2016 The NASM Authors - All Rights Reserved
  4. * See the file AUTHORS included with the NASM distribution for
  5. * the specific copyright holders.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following
  9. * conditions are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials provided
  16. * with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  19. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  20. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  30. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. * ----------------------------------------------------------------------- */
  33. /*
  34. * nasmlib.c library routines for the Netwide Assembler
  35. */
  36. #include "compiler.h"
  37. #include <ctype.h>
  38. #include "nasmlib.h"
  39. #include "error.h"
  40. #include "nasm.h" /* For globalbits */
  41. #define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_')
  42. static int radix_letter(char c)
  43. {
  44. switch (c) {
  45. case 'b': case 'B':
  46. case 'y': case 'Y':
  47. return 2; /* Binary */
  48. case 'o': case 'O':
  49. case 'q': case 'Q':
  50. return 8; /* Octal */
  51. case 'h': case 'H':
  52. case 'x': case 'X':
  53. return 16; /* Hexadecimal */
  54. case 'd': case 'D':
  55. case 't': case 'T':
  56. return 10; /* Decimal */
  57. default:
  58. return 0; /* Not a known radix letter */
  59. }
  60. }
  61. int64_t readnum(const char *str, bool *error)
  62. {
  63. const char *r = str, *q;
  64. int32_t pradix, sradix, radix;
  65. int plen, slen, len;
  66. uint64_t result, checklimit;
  67. int digit, last;
  68. bool warn = false;
  69. int sign = 1;
  70. *error = false;
  71. while (nasm_isspace(*r))
  72. r++; /* find start of number */
  73. /*
  74. * If the number came from make_tok_num (as a result of an %assign), it
  75. * might have a '-' built into it (rather than in a preceeding token).
  76. */
  77. if (*r == '-') {
  78. r++;
  79. sign = -1;
  80. }
  81. q = r;
  82. while (lib_isnumchar(*q))
  83. q++; /* find end of number */
  84. len = q-r;
  85. if (!len) {
  86. /* Not numeric */
  87. *error = true;
  88. return 0;
  89. }
  90. /*
  91. * Handle radix formats:
  92. *
  93. * 0<radix-letter><string>
  94. * $<string> (hexadecimal)
  95. * <string><radix-letter>
  96. */
  97. pradix = sradix = 0;
  98. plen = slen = 0;
  99. if (len > 2 && *r == '0' && (pradix = radix_letter(r[1])) != 0)
  100. plen = 2;
  101. else if (len > 1 && *r == '$')
  102. pradix = 16, plen = 1;
  103. if (len > 1 && (sradix = radix_letter(q[-1])) != 0)
  104. slen = 1;
  105. if (pradix > sradix) {
  106. radix = pradix;
  107. r += plen;
  108. } else if (sradix > pradix) {
  109. radix = sradix;
  110. q -= slen;
  111. } else {
  112. /* Either decimal, or invalid -- if invalid, we'll trip up
  113. further down. */
  114. radix = 10;
  115. }
  116. /*
  117. * `checklimit' must be 2**64 / radix. We can't do that in
  118. * 64-bit arithmetic, which we're (probably) using, so we
  119. * cheat: since we know that all radices we use are even, we
  120. * can divide 2**63 by radix/2 instead.
  121. */
  122. checklimit = UINT64_C(0x8000000000000000) / (radix >> 1);
  123. /*
  124. * Calculate the highest allowable value for the last digit of a
  125. * 64-bit constant... in radix 10, it is 6, otherwise it is 0
  126. */
  127. last = (radix == 10 ? 6 : 0);
  128. result = 0;
  129. while (*r && r < q) {
  130. if (*r != '_') {
  131. if (*r < '0' || (*r > '9' && *r < 'A')
  132. || (digit = numvalue(*r)) >= radix) {
  133. *error = true;
  134. return 0;
  135. }
  136. if (result > checklimit ||
  137. (result == checklimit && digit >= last)) {
  138. warn = true;
  139. }
  140. result = radix * result + digit;
  141. }
  142. r++;
  143. }
  144. if (warn)
  145. nasm_error(ERR_WARNING | ERR_PASS1 | WARN_NOV,
  146. "numeric constant %s does not fit in 64 bits",
  147. str);
  148. return result * sign;
  149. }