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 | /* |
35 | * nasmlib.c library routines for the Netwide Assembler |
36 | */ |
37 | |
38 | #include "compiler.h" |
39 | |
40 | #include <ctype.h> |
41 | |
42 | #include "nasmlib.h" |
43 | #include "error.h" |
44 | #include "nasm.h" /* For globalbits */ |
45 | |
46 | #define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_') |
47 | |
48 | static int radix_letter(char c) |
49 | { |
50 | switch (c) { |
51 | case 'b': case 'B': |
52 | case 'y': case 'Y': |
53 | return 2; /* Binary */ |
54 | case 'o': case 'O': |
55 | case 'q': case 'Q': |
56 | return 8; /* Octal */ |
57 | case 'h': case 'H': |
58 | case 'x': case 'X': |
59 | return 16; /* Hexadecimal */ |
60 | case 'd': case 'D': |
61 | case 't': case 'T': |
62 | return 10; /* Decimal */ |
63 | default: |
64 | return 0; /* Not a known radix letter */ |
65 | } |
66 | } |
67 | |
68 | int64_t readnum(const char *str, bool *error) |
69 | { |
70 | const char *r = str, *q; |
71 | int32_t pradix, sradix, radix; |
72 | int plen, slen, len; |
73 | uint64_t result, checklimit; |
74 | int digit, last; |
75 | bool warn = false; |
76 | int sign = 1; |
77 | |
78 | *error = false; |
79 | |
80 | while (nasm_isspace(*r)) |
81 | r++; /* find start of number */ |
82 | |
83 | /* |
84 | * If the number came from make_tok_num (as a result of an %assign), it |
85 | * might have a '-' built into it (rather than in a preceeding token). |
86 | */ |
87 | if (*r == '-') { |
88 | r++; |
89 | sign = -1; |
90 | } |
91 | |
92 | q = r; |
93 | |
94 | while (lib_isnumchar(*q)) |
95 | q++; /* find end of number */ |
96 | |
97 | len = q-r; |
98 | if (!len) { |
99 | /* Not numeric */ |
100 | *error = true; |
101 | return 0; |
102 | } |
103 | |
104 | /* |
105 | * Handle radix formats: |
106 | * |
107 | * 0<radix-letter><string> |
108 | * $<string> (hexadecimal) |
109 | * <string><radix-letter> |
110 | */ |
111 | pradix = sradix = 0; |
112 | plen = slen = 0; |
113 | |
114 | if (len > 2 && *r == '0' && (pradix = radix_letter(r[1])) != 0) |
115 | plen = 2; |
116 | else if (len > 1 && *r == '$') |
117 | pradix = 16, plen = 1; |
118 | |
119 | if (len > 1 && (sradix = radix_letter(q[-1])) != 0) |
120 | slen = 1; |
121 | |
122 | if (pradix > sradix) { |
123 | radix = pradix; |
124 | r += plen; |
125 | } else if (sradix > pradix) { |
126 | radix = sradix; |
127 | q -= slen; |
128 | } else { |
129 | /* Either decimal, or invalid -- if invalid, we'll trip up |
130 | further down. */ |
131 | radix = 10; |
132 | } |
133 | |
134 | /* |
135 | * `checklimit' must be 2**64 / radix. We can't do that in |
136 | * 64-bit arithmetic, which we're (probably) using, so we |
137 | * cheat: since we know that all radices we use are even, we |
138 | * can divide 2**63 by radix/2 instead. |
139 | */ |
140 | checklimit = UINT64_C(0x8000000000000000) / (radix >> 1); |
141 | |
142 | /* |
143 | * Calculate the highest allowable value for the last digit of a |
144 | * 64-bit constant... in radix 10, it is 6, otherwise it is 0 |
145 | */ |
146 | last = (radix == 10 ? 6 : 0); |
147 | |
148 | result = 0; |
149 | while (*r && r < q) { |
150 | if (*r != '_') { |
151 | if (*r < '0' || (*r > '9' && *r < 'A') |
152 | || (digit = numvalue(*r)) >= radix) { |
153 | *error = true; |
154 | return 0; |
155 | } |
156 | if (result > checklimit || |
157 | (result == checklimit && digit >= last)) { |
158 | warn = true; |
159 | } |
160 | |
161 | result = radix * result + digit; |
162 | } |
163 | r++; |
164 | } |
165 | |
166 | if (warn) |
167 | nasm_error(ERR_WARNING | ERR_PASS1 | WARN_NOV, |
168 | "numeric constant %s does not fit in 64 bits" , |
169 | str); |
170 | |
171 | return result * sign; |
172 | } |
173 | |