Commit | Line | Data |
---|---|---|
ad576865 RH |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California | |
3 | */ | |
4 | #ifndef lint | |
f70ab843 | 5 | static char sccsid[] = "@(#)asscan4.c 4.3 %G%"; |
ad576865 RH |
6 | #endif not lint |
7 | ||
8 | #include "asscanl.h" | |
9 | ||
10 | #define reg register | |
11 | #define NUMSIZE 128 /* how many characters long a number can be */ | |
12 | #define FLTCHAR(x) (INCHARSET((x),(DIGIT|SIGN|FLOATEXP|POINT))) | |
13 | ||
14 | static char numbuf[NUMSIZE]; | |
15 | ||
16 | int number(ch, cpp) | |
17 | reg int ch; | |
18 | char **cpp; | |
19 | { | |
20 | int radix; | |
21 | int digit; /* part of number being constructed */ | |
22 | reg int intval; /* number being constructed */ | |
23 | reg char *cp; | |
24 | reg char *inbufptr; | |
25 | char ch1; | |
26 | Bignum floatnumber(); | |
27 | Ovf overflow; /* overflow flag */ | |
28 | int maxstrlg; | |
29 | ||
30 | inbufptr = *cpp; | |
31 | cp = numbuf; | |
32 | radix = 10; | |
33 | ||
34 | switch(ch){ | |
35 | case '0': | |
36 | switch(ch = getchar()){ | |
37 | case 'b': | |
38 | yylval = -1; | |
39 | *cpp = inbufptr; | |
40 | return(BFINT); | |
41 | case 'f': | |
42 | /* | |
43 | * Check if it is a local label by peeking ahead | |
44 | */ | |
45 | ch1 = getchar(); | |
46 | ungetc(ch1); | |
47 | if (!FLTCHAR(ch1)){ | |
48 | yylval = 1; | |
49 | *cpp = inbufptr; | |
50 | return(BFINT); | |
51 | } | |
52 | /*FALLTHROUGH*/ | |
53 | case 'F': ch = 'f'; goto floatnum; | |
54 | case 'd': | |
55 | case 'D': ch = 'd'; goto floatnum; | |
56 | case 'h': | |
57 | case 'H': ch = 'h'; goto floatnum; | |
58 | case 'g': | |
59 | case 'G': ch = 'g'; goto floatnum; | |
60 | ||
61 | case 'x': | |
62 | case 'X': | |
63 | ch = '0'; | |
64 | radix = 16; | |
65 | break; | |
66 | case '0': | |
67 | case '1': case '2': case '3': case '4': | |
68 | case '5': case '6': case '7': case '8': | |
69 | case '9': | |
70 | radix = 8; | |
71 | break; | |
72 | default: /* single 0 */ | |
73 | ungetc(ch); | |
74 | intval = 0; | |
75 | goto smallnum; | |
76 | } | |
77 | break; | |
78 | ||
79 | case '1': case '2': case '3': case '4': | |
80 | case '5': case '6': case '7': case '8': | |
81 | case '9': | |
82 | switch(ch1 = getchar()){ | |
83 | case 'f': | |
84 | yylval = ((ch - '0') + 1); | |
85 | *cpp = inbufptr; | |
86 | return(BFINT); | |
87 | case 'b': | |
88 | yylval = -((ch - '0') + 1); | |
89 | *cpp = inbufptr; | |
90 | return(BFINT); | |
91 | default: | |
92 | ungetc(ch1); /* put back non zero */ | |
93 | } | |
94 | radix = 10; | |
95 | break; | |
96 | } | |
97 | intval = 0; | |
98 | /* | |
99 | * There is a character in ch that must be used to | |
100 | * cons up the number; we can't ungetc it | |
101 | */ | |
102 | do{ | |
103 | digit = ch - '0'; | |
104 | switch(radix){ | |
105 | case 8: | |
106 | intval <<= 3; | |
107 | break; | |
108 | case 10: | |
109 | intval *= 10; | |
110 | break; | |
111 | case 16: | |
112 | intval <<= 4; | |
113 | if (INCHARSET(ch, HEXLDIGIT)){ | |
114 | digit = (ch - 'a') + 10; | |
115 | break; | |
116 | } | |
117 | if (INCHARSET(ch, HEXUDIGIT)){ | |
118 | digit = (ch - 'A') + 10; | |
119 | break; | |
120 | } | |
121 | } | |
122 | *cp++ = ch; | |
123 | /* | |
124 | * Build a negative number, then negate it | |
125 | */ | |
126 | intval -= digit; | |
127 | ||
128 | ch = getchar(); | |
129 | if(!INCHARSET(ch, DIGIT)){ | |
130 | if (radix != 16) | |
131 | break; | |
132 | if(!INCHARSET(ch, (HEXLDIGIT|HEXUDIGIT))) | |
133 | break; | |
134 | } | |
135 | } while (1); | |
136 | ungetc(ch); | |
137 | *cp = 0; | |
138 | maxstrlg = cp - numbuf; | |
139 | /* | |
140 | * See if the number is too large for our previous calculation | |
141 | */ | |
142 | switch(radix){ | |
143 | case 16: | |
144 | if (maxstrlg > 8) | |
145 | goto bignum; | |
146 | break; | |
147 | case 10: | |
148 | if (maxstrlg >= 10) | |
149 | goto bignum; | |
150 | break; | |
151 | case 8: | |
152 | if (maxstrlg > 11) | |
153 | goto bignum; | |
154 | if (maxstrlg == 11 && numbuf[0] > 3) | |
155 | goto bignum; | |
156 | break; | |
157 | } | |
158 | /* | |
159 | * Negate the number | |
160 | */ | |
161 | smallnum: ; | |
162 | yylval = -intval; | |
163 | *cpp = inbufptr; | |
164 | return(INT); | |
165 | bignum: ; | |
166 | yybignum = as_atoi(numbuf, radix, &overflow); | |
167 | *cpp = inbufptr; | |
168 | return(BIGNUM); | |
169 | floatnum: ; | |
170 | *cpp = inbufptr; | |
171 | yybignum = floatnumber(ch, cpp); | |
172 | return(BIGNUM); | |
173 | } | |
174 | ||
175 | #define TOOLONG if(cp == &numbuf[NUMSIZE]){if (passno == 2)yywarning(toolong); goto process;} | |
176 | #define scanit(sign) *cpp = inbufptr; error |= scanint(sign, &cp, cpp); inbufptr = *cpp; ch = getchar(); TOOLONG; | |
177 | ||
178 | Bignum floatnumber(fltradix, cpp) | |
179 | int fltradix; | |
180 | char **cpp; /* call by copy return semantics */ | |
181 | { | |
182 | char *cp; | |
183 | int ch; | |
184 | char *toolong = "Floating number too long."; | |
185 | char *prologue = | |
186 | "Floating 0%c conflicts with exponent %c; choose %c"; | |
187 | /* | |
188 | * This is not implemented yet: | |
189 | * overflow is set on floating overflow. | |
190 | */ | |
191 | Ovf overflow; | |
192 | int error; | |
193 | int fractOK; | |
194 | reg char *inbufptr; | |
195 | ||
196 | inbufptr = *cpp; | |
197 | cp = numbuf; | |
198 | error = 0; | |
199 | fractOK = 0; | |
200 | ||
201 | scanit(1); | |
202 | if(INCHARSET(ch, POINT)){ | |
203 | fractOK++; | |
204 | *cp++ = '.'; | |
205 | scanit(0); | |
206 | } | |
207 | if(INCHARSET(ch, FLOATEXP)){ | |
208 | fractOK++; | |
209 | if(ch != fltradix){ | |
210 | if (passno == 2) | |
211 | yywarning(prologue, fltradix, ch, fltradix); | |
212 | } | |
213 | switch(fltradix){ | |
214 | case 'd': | |
215 | case 'f': | |
216 | *cp++ = 'e'; /* will be read by atof() */ | |
217 | break; | |
218 | default: | |
219 | *cp++ = fltradix; /* will be read by bigatof() */ | |
220 | break; | |
221 | } | |
222 | scanit(1); | |
223 | } | |
224 | if (error || fractOK == 0){ | |
225 | yyerror("Badly formatted floating point number."); | |
226 | } | |
227 | ungetc(ch); | |
228 | *cp++ = 0; | |
229 | ||
230 | process: ; | |
231 | switch(fltradix){ | |
232 | case 'f': fltradix = TYPF; break; | |
233 | case 'd': fltradix = TYPD; break; | |
234 | case 'g': fltradix = TYPG; nGHnumbers++; break; | |
235 | case 'h': fltradix = TYPH; nGHnumbers++; break; | |
236 | } | |
237 | /* | |
238 | * The overflow value is lost in the call to as_atof | |
239 | */ | |
240 | *cpp = inbufptr; | |
241 | return(as_atof(numbuf, fltradix, &overflow)); | |
242 | } | |
243 | /* | |
244 | * Scan an optionally signed integer, putting back the lookahead | |
245 | * character when finished scanning. | |
246 | */ | |
247 | int scanint(signOK, dstcpp, srccpp) | |
248 | int signOK; | |
249 | char **dstcpp; | |
250 | char **srccpp; /* call by copy return */ | |
251 | { | |
252 | int ch; | |
253 | int back = 0; | |
254 | reg char *inbufptr = *srccpp; | |
255 | ||
256 | ch = getchar(); | |
257 | while (INCHARSET(ch, SIGN)){ | |
258 | if (signOK && !back) | |
259 | *((*dstcpp)++) = ch; | |
260 | else | |
261 | back = 1; | |
262 | ch = getchar(); | |
263 | } | |
264 | while (INCHARSET(ch, DIGIT)){ | |
265 | *((*dstcpp)++) = ch; | |
266 | ch = getchar(); | |
267 | } | |
268 | ungetc(ch); | |
269 | *srccpp = inbufptr; | |
270 | return(back); | |
271 | } |